source: rtems/cpukit/score/include/rtems/score/threadqimpl.h @ 3995e6d

Last change on this file since 3995e6d was 3995e6d, checked in by Sebastian Huber <sebastian.huber@…>, on Sep 2, 2015 at 9:58:54 AM

score: Implement SMP-specific priority queue

  • Property mode set to 100644
File size: 15.9 KB
Line 
1/**
2 *  @file  rtems/score/threadq.h
3 *
4 *  Constants and Structures Associated with the Manipulation of Objects
5 *
6 *  This include file contains all the constants and structures associated
7 *  with the manipulation of objects.
8 */
9
10/*
11 *  COPYRIGHT (c) 1989-2014.
12 *  On-Line Applications Research Corporation (OAR).
13 *
14 *  The license and distribution terms for this file may be
15 *  found in the file LICENSE in this distribution or at
16 *  http://www.rtems.org/license/LICENSE.
17 */
18
19#ifndef _RTEMS_SCORE_THREADQIMPL_H
20#define _RTEMS_SCORE_THREADQIMPL_H
21
22#include <rtems/score/threadq.h>
23#include <rtems/score/chainimpl.h>
24#include <rtems/score/rbtreeimpl.h>
25#include <rtems/score/scheduler.h>
26#include <rtems/score/thread.h>
27
28#ifdef __cplusplus
29extern "C" {
30#endif
31
32/**
33 *  @addtogroup ScoreThreadQueue
34 */
35/**@{*/
36
37/**
38 * @brief Thread queue with a layout compatible to struct _Thread_queue_Queue
39 * defined in Newlib <sys/lock.h>.
40 */
41typedef struct {
42  Thread_queue_Queue Queue;
43
44#if !defined(RTEMS_SMP)
45  /*
46   * The struct _Thread_queue_Queue definition is independent of the RTEMS
47   * build configuration.  Thus, the storage space for the SMP lock is always
48   * present.  In SMP configurations, the SMP lock is contained in the
49   * Thread_queue_Queue.
50   */
51  unsigned int reserved[2];
52#endif
53} Thread_queue_Syslock_queue;
54
55RTEMS_INLINE_ROUTINE void _Thread_queue_Heads_initialize(
56  Thread_queue_Heads *heads
57)
58{
59#if defined(RTEMS_SMP)
60  size_t i;
61
62  for ( i = 0; i < _Scheduler_Count; ++i ) {
63    _RBTree_Initialize_empty( &heads->Priority[ i ].Queue );
64  }
65#endif
66
67  _Chain_Initialize_empty( &heads->Free_chain );
68}
69
70RTEMS_INLINE_ROUTINE void _Thread_queue_Queue_initialize(
71  Thread_queue_Queue *queue
72)
73{
74  queue->heads = NULL;
75#if defined(RTEMS_SMP)
76  _SMP_ticket_lock_Initialize( &queue->Lock );
77#endif
78}
79
80RTEMS_INLINE_ROUTINE void _Thread_queue_Queue_do_acquire_critical(
81  Thread_queue_Queue *queue,
82#if defined(RTEMS_SMP) && defined(RTEMS_PROFILING)
83  SMP_lock_Stats     *lock_stats,
84#endif
85  ISR_lock_Context   *lock_context
86)
87{
88#if defined(RTEMS_SMP)
89  _SMP_ticket_lock_Acquire(
90    &queue->Lock,
91    lock_stats,
92    &lock_context->Lock_context.Stats_context
93  );
94#else
95  (void) queue;
96  (void) lock_context;
97#endif
98}
99
100#if defined(RTEMS_SMP) && defined( RTEMS_PROFILING )
101  #define \
102    _Thread_queue_Queue_acquire_critical( queue, lock_stats, lock_context ) \
103    _Thread_queue_Queue_do_acquire_critical( queue, lock_stats, lock_context )
104#else
105  #define \
106    _Thread_queue_Queue_acquire_critical( queue, lock_stats, lock_context ) \
107    _Thread_queue_Queue_do_acquire_critical( queue, lock_context )
108#endif
109
110RTEMS_INLINE_ROUTINE void _Thread_queue_Queue_release(
111  Thread_queue_Queue *queue,
112  ISR_lock_Context   *lock_context
113)
114{
115#if defined(RTEMS_SMP)
116  _SMP_ticket_lock_Release(
117    &queue->Lock,
118    &lock_context->Lock_context.Stats_context
119  );
120#endif
121  _ISR_lock_ISR_enable( lock_context );
122}
123
124RTEMS_INLINE_ROUTINE void _Thread_queue_Acquire_critical(
125  Thread_queue_Control *the_thread_queue,
126  ISR_lock_Context     *lock_context
127)
128{
129  _Thread_queue_Queue_acquire_critical(
130    &the_thread_queue->Queue,
131    &the_thread_queue->Lock_stats,
132    lock_context
133  );
134}
135
136RTEMS_INLINE_ROUTINE void _Thread_queue_Acquire(
137  Thread_queue_Control *the_thread_queue,
138  ISR_lock_Context     *lock_context
139)
140{
141  _ISR_lock_ISR_disable( lock_context );
142  _Thread_queue_Acquire_critical( the_thread_queue, lock_context );
143}
144
145RTEMS_INLINE_ROUTINE void _Thread_queue_Release(
146  Thread_queue_Control *the_thread_queue,
147  ISR_lock_Context     *lock_context
148)
149{
150  _Thread_queue_Queue_release(
151    &the_thread_queue->Queue,
152    lock_context
153  );
154}
155
156/**
157 *  The following type defines the callout used when a remote task
158 *  is extracted from a local thread queue.
159 */
160typedef void ( *Thread_queue_Flush_callout )(
161                  Thread_Control *
162             );
163
164/**
165 *  @brief Gets a pointer to a thread waiting on the_thread_queue.
166 *
167 *  This function returns a pointer to a thread waiting on
168 *  the_thread_queue.  The selection of this thread is based on
169 *  the discipline of the_thread_queue.  If no threads are waiting
170 *  on the_thread_queue, then NULL is returned.
171 *
172 *  - INTERRUPT LATENCY:
173 *    + single case
174 */
175Thread_Control *_Thread_queue_Dequeue(
176  Thread_queue_Control *the_thread_queue
177);
178
179/**
180 * @brief Blocks the thread and places it on the thread queue.
181 *
182 * This enqueues the thread on the thread queue, blocks the thread, and
183 * optionally starts the thread timer in case the timeout interval is not
184 * WATCHDOG_NO_TIMEOUT.
185 *
186 * The caller must be the owner of the thread queue lock.  This function will
187 * release the thread queue lock and register it as the new thread lock.
188 * Thread dispatching is disabled before the thread queue lock is released.
189 * Thread dispatching is enabled once the sequence to block the thread is
190 * complete.  The operation to enqueue the thread on the queue is protected by
191 * the thread queue lock.  This makes it possible to use the thread queue lock
192 * to protect the state of objects embedding the thread queue and directly
193 * enter _Thread_queue_Enqueue_critical() in case the thread must block.
194 *
195 * @code
196 * #include <rtems/score/threadqimpl.h>
197 * #include <rtems/score/statesimpl.h>
198 *
199 * typedef struct {
200 *   Thread_queue_Control  Queue;
201 *   Thread_Control       *owner;
202 * } Mutex;
203 *
204 * void _Mutex_Obtain( Mutex *mutex )
205 * {
206 *   ISR_lock_Context  lock_context;
207 *   Thread_Control   *executing;
208 *
209 *   _Thread_queue_Acquire( &mutex->Queue, &lock_context );
210 *
211 *   executing = _Thread_Executing;
212 *
213 *   if ( mutex->owner == NULL ) {
214 *     mutex->owner = executing;
215 *     _Thread_queue_Release( &mutex->Queue, &lock_context );
216 *   } else {
217 *     _Thread_queue_Enqueue_critical(
218 *       &mutex->Queue.Queue,
219 *       mutex->Queue.operations,
220 *       executing,
221 *       STATES_WAITING_FOR_MUTEX,
222 *       WATCHDOG_NO_TIMEOUT,
223 *       0,
224 *       &lock_context
225 *     );
226 *   }
227 * }
228 * @endcode
229 *
230 * @param[in] queue The actual thread queue.
231 * @param[in] operations The thread queue operations.
232 * @param[in] the_thread The thread to enqueue.
233 * @param[in] state The new state of the thread.
234 * @param[in] timeout Interval to wait.  Use WATCHDOG_NO_TIMEOUT to block
235 * potentially forever.
236 * @param[in] timeout_code The return code in case a timeout occurs.
237 * @param[in] lock_context The lock context of the lock acquire.
238 */
239void _Thread_queue_Enqueue_critical(
240  Thread_queue_Queue            *queue,
241  const Thread_queue_Operations *operations,
242  Thread_Control                *the_thread,
243  States_Control                 state,
244  Watchdog_Interval              timeout,
245  uint32_t                       timeout_code,
246  ISR_lock_Context              *lock_context
247);
248
249/**
250 * @brief Acquires the thread queue lock and calls
251 * _Thread_queue_Enqueue_critical().
252 */
253RTEMS_INLINE_ROUTINE void _Thread_queue_Enqueue(
254  Thread_queue_Control *the_thread_queue,
255  Thread_Control       *the_thread,
256  States_Control        state,
257  Watchdog_Interval     timeout,
258  uint32_t              timeout_code
259)
260{
261  ISR_lock_Context lock_context;
262
263  _Thread_queue_Acquire( the_thread_queue, &lock_context );
264  _Thread_queue_Enqueue_critical(
265    &the_thread_queue->Queue,
266    the_thread_queue->operations,
267    the_thread,
268    state,
269    timeout,
270    timeout_code,
271    &lock_context
272  );
273}
274
275/**
276 * @brief Extracts the thread from the thread queue, restores the default wait
277 * operations and restores the default thread lock.
278 *
279 * The caller must be the owner of the thread queue lock.  The thread queue
280 * lock is not released.
281 *
282 * @param[in] queue The actual thread queue.
283 * @param[in] operations The thread queue operations.
284 * @param[in] the_thread The thread to extract.
285 *
286 * @return Returns the unblock indicator for _Thread_queue_Unblock_critical().
287 * True indicates, that this thread must be unblocked by the scheduler later in
288 * _Thread_queue_Unblock_critical(), and false otherwise.  In case false is
289 * returned, then the thread queue enqueue procedure was interrupted.  Thus it
290 * will unblock itself and the thread wait information is no longer accessible,
291 * since this thread may already block on another resource in an SMP
292 * configuration.
293 */
294bool _Thread_queue_Extract_locked(
295  Thread_queue_Queue            *queue,
296  const Thread_queue_Operations *operations,
297  Thread_Control                *the_thread
298);
299
300/**
301 * @brief Unblocks the thread which was on the thread queue before.
302 *
303 * The caller must be the owner of the thread queue lock.  This function will
304 * release the thread queue lock.  Thread dispatching is disabled before the
305 * thread queue lock is released and an unblock is necessary.  Thread
306 * dispatching is enabled once the sequence to unblock the thread is complete.
307 *
308 * @param[in] unblock The unblock indicator returned by
309 * _Thread_queue_Extract_locked().
310 * @param[in] queue The actual thread queue.
311 * @param[in] the_thread The thread to extract.
312 * @param[in] lock_context The lock context of the lock acquire.
313 */
314void _Thread_queue_Unblock_critical(
315  bool                unblock,
316  Thread_queue_Queue *queue,
317  Thread_Control     *the_thread,
318  ISR_lock_Context   *lock_context
319);
320
321/**
322 * @brief Extracts the thread from the thread queue and unblocks it.
323 *
324 * The caller must be the owner of the thread queue lock.  This function will
325 * release the thread queue lock and restore the default thread lock.  Thread
326 * dispatching is disabled before the thread queue lock is released and an
327 * unblock is necessary.  Thread dispatching is enabled once the sequence to
328 * unblock the thread is complete.  This makes it possible to use the thread
329 * queue lock to protect the state of objects embedding the thread queue and
330 * directly enter _Thread_queue_Extract_critical() to finalize an operation in
331 * case a waiting thread exists.
332 *
333 * @code
334 * #include <rtems/score/threadqimpl.h>
335 *
336 * typedef struct {
337 *   Thread_queue_Control  Queue;
338 *   Thread_Control       *owner;
339 * } Mutex;
340 *
341 * void _Mutex_Release( Mutex *mutex )
342 * {
343 *   ISR_lock_Context  lock_context;
344 *   Thread_Control   *first;
345 *
346 *   _Thread_queue_Acquire( &mutex->Queue, &lock_context );
347 *
348 *   first = _Thread_queue_First_locked( &mutex->Queue );
349 *   mutex->owner = first;
350 *
351 *   if ( first != NULL ) {
352 *     _Thread_queue_Extract_critical(
353 *       &mutex->Queue.Queue,
354 *       mutex->Queue.operations,
355 *       first,
356 *       &lock_context
357 *   );
358 * }
359 * @endcode
360 *
361 * @param[in] queue The actual thread queue.
362 * @param[in] operations The thread queue operations.
363 * @param[in] the_thread The thread to extract.
364 * @param[in] lock_context The lock context of the lock acquire.
365 */
366void _Thread_queue_Extract_critical(
367  Thread_queue_Queue            *queue,
368  const Thread_queue_Operations *operations,
369  Thread_Control                *the_thread,
370  ISR_lock_Context              *lock_context
371);
372
373/**
374 *  @brief Extracts thread from thread queue.
375 *
376 *  This routine removes @a the_thread its thread queue
377 *  and cancels any timeouts associated with this blocking.
378 *
379 *  @param[in] the_thread is the pointer to a thread control block that
380 *      is to be removed
381 */
382void _Thread_queue_Extract( Thread_Control *the_thread );
383
384/**
385 *  @brief Extracts the_thread from the_thread_queue.
386 *
387 *  This routine extracts the_thread from the_thread_queue
388 *  and ensures that if there is a proxy for this task on
389 *  another node, it is also dealt with.
390 */
391void _Thread_queue_Extract_with_proxy(
392  Thread_Control       *the_thread
393);
394
395/**
396 * @brief Returns the first thread on the thread queue if it exists, otherwise
397 * @c NULL.
398 *
399 * The caller must be the owner of the thread queue lock.  The thread queue
400 * lock is not released.
401 *
402 * @param[in] the_thread_queue The thread queue.
403 *
404 * @retval NULL No thread is present on the thread queue.
405 * @retval first The first thread on the thread queue according to the enqueue
406 * order.
407 */
408RTEMS_INLINE_ROUTINE Thread_Control *_Thread_queue_First_locked(
409  Thread_queue_Control *the_thread_queue
410)
411{
412  Thread_queue_Heads *heads = the_thread_queue->Queue.heads;
413
414  if ( heads != NULL ) {
415    return ( *the_thread_queue->operations->first )( heads );
416  } else {
417    return NULL;
418  }
419}
420
421/**
422 * @brief Returns the first thread on the thread queue if it exists, otherwise
423 * @c NULL.
424 *
425 * @param[in] the_thread_queue The thread queue.
426 *
427 * @retval NULL No thread is present on the thread queue.
428 * @retval first The first thread on the thread queue according to the enqueue
429 * order.
430 */
431Thread_Control *_Thread_queue_First(
432  Thread_queue_Control *the_thread_queue
433);
434
435/**
436 *  @brief Unblocks all threads blocked on the_thread_queue.
437 *
438 *  This routine unblocks all threads blocked on the_thread_queue
439 *  and cancels any associated timeouts.
440 *
441 *  @param[in] the_thread_queue is the pointer to a threadq header
442 *  @param[in] remote_extract_callout points to a method to invoke to
443 *             invoke when a remote thread is unblocked
444 *  @param[in] status is the status which will be returned to
445 *             all unblocked threads
446 */
447void _Thread_queue_Flush(
448  Thread_queue_Control       *the_thread_queue,
449  Thread_queue_Flush_callout  remote_extract_callout,
450  uint32_t                    status
451);
452
453/**
454 *  @brief Initialize the_thread_queue.
455 *
456 *  This routine initializes the_thread_queue based on the
457 *  discipline indicated in attribute_set.  The state set on
458 *  threads which block on the_thread_queue is state.
459 *
460 *  @param[in] the_thread_queue is the pointer to a threadq header
461 *  @param[in] the_discipline is the queueing discipline
462 */
463void _Thread_queue_Initialize(
464  Thread_queue_Control     *the_thread_queue,
465  Thread_queue_Disciplines  the_discipline
466);
467
468#if defined(RTEMS_SMP) && defined(RTEMS_PROFILING)
469  #define THREAD_QUEUE_FIFO_INITIALIZER( designator, name ) { \
470      .Queue = { \
471        .heads = NULL, \
472        .Lock = SMP_TICKET_LOCK_INITIALIZER, \
473      }, \
474      .Lock_stats = SMP_LOCK_STATS_INITIALIZER( name ), \
475      .operations = &_Thread_queue_Operations_FIFO \
476    }
477
478  #define THREAD_QUEUE_PRIORITY_INITIALIZER( designator, name ) { \
479      .Queue = { \
480        .heads = NULL, \
481        .Lock = SMP_TICKET_LOCK_INITIALIZER, \
482      }, \
483      .Lock_stats = SMP_LOCK_STATS_INITIALIZER( name ), \
484      .operations = &_Thread_queue_Operations_priority \
485    }
486#elif defined(RTEMS_SMP)
487  #define THREAD_QUEUE_FIFO_INITIALIZER( designator, name ) { \
488      .Queue = { \
489        .heads = NULL, \
490        .Lock = SMP_TICKET_LOCK_INITIALIZER, \
491      }, \
492      .operations = &_Thread_queue_Operations_FIFO \
493    }
494
495  #define THREAD_QUEUE_PRIORITY_INITIALIZER( designator, name ) { \
496      .Queue = { \
497        .heads = NULL, \
498        .Lock = SMP_TICKET_LOCK_INITIALIZER, \
499      }, \
500      .operations = &_Thread_queue_Operations_priority \
501    }
502#else
503  #define THREAD_QUEUE_FIFO_INITIALIZER( designator, name ) { \
504      .Queue = { .heads = NULL }, \
505      .operations = &_Thread_queue_Operations_FIFO \
506    }
507
508  #define THREAD_QUEUE_PRIORITY_INITIALIZER( designator, name ) { \
509      .Queue = { .heads = NULL }, \
510      .operations = &_Thread_queue_Operations_priority \
511    }
512#endif
513
514RTEMS_INLINE_ROUTINE void _Thread_queue_Destroy(
515  Thread_queue_Control *the_thread_queue
516)
517{
518#if defined(RTEMS_SMP)
519  _SMP_ticket_lock_Destroy( &the_thread_queue->Queue.Lock );
520  _SMP_lock_Stats_destroy( &the_thread_queue->Lock_stats );
521#endif
522}
523
524/**
525 * @brief Compare two thread's priority for RBTree Insertion.
526 *
527 * @param[in] left points to the left thread's RBnode
528 * @param[in] right points to the right thread's RBnode
529 *
530 * @retval 1 The @a left node is more important than @a right node.
531 * @retval 0 The @a left node is of equal importance with @a right node.
532 * @retval 1 The @a left node is less important than @a right node.
533 */
534RBTree_Compare_result _Thread_queue_Compare_priority(
535  const RBTree_Node *left,
536  const RBTree_Node *right
537);
538
539extern const Thread_queue_Operations _Thread_queue_Operations_default;
540
541extern const Thread_queue_Operations _Thread_queue_Operations_FIFO;
542
543extern const Thread_queue_Operations _Thread_queue_Operations_priority;
544
545/**@}*/
546
547#ifdef __cplusplus
548}
549#endif
550
551#endif
552/* end of include file */
Note: See TracBrowser for help on using the repository browser.