source: rtems/cpukit/score/include/rtems/score/threadqimpl.h @ 114e408

5
Last change on this file since 114e408 was 114e408, checked in by Sebastian Huber <sebastian.huber@…>, on 08/22/16 at 11:17:05

score: Simplify thread queue acquire/release

  • Property mode set to 100644
File size: 28.8 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/smp.h>
27#include <rtems/score/thread.h>
28
29#if defined(RTEMS_DEBUG)
30#include <string.h>
31#endif
32
33#ifdef __cplusplus
34extern "C" {
35#endif
36
37/**
38 *  @addtogroup ScoreThreadQueue
39 */
40/**@{*/
41
42/**
43 * @brief Representation of a thread queue path from a start thread queue to
44 * the terminal thread queue.
45 *
46 * The start thread queue is determined by the object on which a thread intends
47 * to block.  The terminal thread queue is the thread queue reachable via
48 * thread queue links those owner is not blocked on a thread queue.  The thread
49 * queue links are determined by the thread queue owner and thread wait queue
50 * relationships.
51 */
52struct Thread_queue_Path {
53#if defined(RTEMS_SMP)
54  /**
55   * @brief The chain of thread queue links defining the thread queue path.
56   */
57  Chain_Control Links;
58
59  /**
60   * @brief The start of a thread queue path.
61   */
62  Thread_queue_Link Start;
63#endif
64
65  /**
66   * @brief A potential thread to update the priority via
67   * _Thread_Update_priority().
68   *
69   * This thread is determined by thread queues which support priority
70   * inheritance.
71   */
72  Thread_Control *update_priority;
73};
74
75/**
76 * @brief Thread queue with a layout compatible to struct _Thread_queue_Queue
77 * defined in Newlib <sys/lock.h>.
78 */
79typedef struct {
80#if !defined(RTEMS_SMP)
81  /*
82   * The struct _Thread_queue_Queue definition is independent of the RTEMS
83   * build configuration.  Thus, the storage space for the SMP lock is always
84   * present.  In SMP configurations, the SMP lock is contained in the
85   * Thread_queue_Queue.
86   */
87  unsigned int reserved[2];
88#endif
89
90  Thread_queue_Queue Queue;
91} Thread_queue_Syslock_queue;
92
93/**
94 * @brief Sets the thread wait return code to STATUS_DEADLOCK.
95 */
96void _Thread_queue_Deadlock_status( Thread_Control *the_thread );
97
98/**
99 * @brief Results in an INTERNAL_ERROR_THREAD_QUEUE_DEADLOCK fatal error.
100 */
101void _Thread_queue_Deadlock_fatal( Thread_Control *the_thread );
102
103/**
104 * @brief Initializes a thread queue context.
105 *
106 * @param queue_context The thread queue context to initialize.
107 */
108RTEMS_INLINE_ROUTINE void _Thread_queue_Context_initialize(
109  Thread_queue_Context *queue_context
110)
111{
112#if defined(RTEMS_DEBUG)
113  memset( queue_context, 0, sizeof( *queue_context ) );
114  queue_context->expected_thread_dispatch_disable_level = 0xdeadbeef;
115  queue_context->deadlock_callout = _Thread_queue_Deadlock_fatal;
116#else
117  (void) queue_context;
118#endif
119}
120
121/**
122 * @brief Sets the expected thread dispatch disable level in the thread queue
123 * context.
124 *
125 * @param queue_context The thread queue context.
126 * @param expected_level The expected thread dispatch disable level.
127 *
128 * @see _Thread_queue_Enqueue_critical().
129 */
130RTEMS_INLINE_ROUTINE void
131_Thread_queue_Context_set_expected_level(
132  Thread_queue_Context *queue_context,
133  uint32_t              expected_level
134)
135{
136  queue_context->expected_thread_dispatch_disable_level = expected_level;
137}
138
139/**
140 * @brief Sets an indefinite timeout interval in the thread queue context.
141 *
142 * @param queue_context The thread queue context.
143 * @param timeout The new timeout.
144 *
145 * @see _Thread_queue_Enqueue_critical().
146 */
147RTEMS_INLINE_ROUTINE void
148_Thread_queue_Context_set_no_timeout(
149  Thread_queue_Context *queue_context
150)
151{
152  queue_context->timeout_discipline = WATCHDOG_NO_TIMEOUT;
153}
154
155/**
156 * @brief Sets a relative timeout in the thread queue context.
157 *
158 * @param queue_context The thread queue context.
159 * @param discipline The clock discipline to use for the timeout.
160 *
161 * @see _Thread_queue_Enqueue_critical().
162 */
163RTEMS_INLINE_ROUTINE void
164_Thread_queue_Context_set_relative_timeout(
165  Thread_queue_Context *queue_context,
166  Watchdog_Interval     timeout
167)
168{
169  queue_context->timeout_discipline = WATCHDOG_RELATIVE;
170  queue_context->timeout = timeout;
171}
172
173/**
174 * @brief Sets an absolute timeout in the thread queue context.
175 *
176 * @param queue_context The thread queue context.
177 * @param discipline The clock discipline to use for the timeout.
178 *
179 * @see _Thread_queue_Enqueue_critical().
180 */
181RTEMS_INLINE_ROUTINE void
182_Thread_queue_Context_set_absolute_timeout(
183  Thread_queue_Context *queue_context,
184  uint64_t              timeout
185)
186{
187  queue_context->timeout_discipline = WATCHDOG_ABSOLUTE;
188  queue_context->timeout = timeout;
189}
190
191/**
192 * @brief Sets the deadlock callout in the thread queue
193 * context.
194 *
195 * A deadlock callout must be provided for _Thread_queue_Enqueue_critical()
196 * operations that operate on thread queues which may have an owner, e.g. mutex
197 * objects.  Available deadlock callouts are _Thread_queue_Deadlock_status()
198 * and _Thread_queue_Deadlock_fatal().
199 *
200 * @param queue_context The thread queue context.
201 * @param deadlock_callout The deadlock callout.
202 *
203 * @see _Thread_queue_Enqueue_critical().
204 */
205RTEMS_INLINE_ROUTINE void _Thread_queue_Context_set_deadlock_callout(
206  Thread_queue_Context          *queue_context,
207  Thread_queue_Deadlock_callout  deadlock_callout
208)
209{
210  queue_context->deadlock_callout = deadlock_callout;
211}
212
213/**
214 * @brief Sets the MP callout in the thread queue context.
215 *
216 * @param queue_context The thread queue context.
217 * @param mp_callout Callout to unblock the thread in case it is actually a
218 *   thread proxy.  This parameter is only used on multiprocessing
219 *   configurations.  Used by thread queue extract and unblock methods for
220 *   objects with multiprocessing (MP) support.
221 */
222#if defined(RTEMS_MULTIPROCESSING)
223RTEMS_INLINE_ROUTINE void _Thread_queue_Context_set_MP_callout(
224  Thread_queue_Context    *queue_context,
225  Thread_queue_MP_callout  mp_callout
226)
227{
228  queue_context->mp_callout = mp_callout;
229}
230#else
231#define _Thread_queue_Context_set_MP_callout( queue_context, mp_callout ) \
232  do { \
233    (void) queue_context; \
234  } while ( 0 )
235#endif
236
237#if defined(RTEMS_SMP)
238RTEMS_INLINE_ROUTINE void _Thread_queue_Gate_close(
239  Thread_queue_Gate *gate
240)
241{
242  _Atomic_Store_uint( &gate->go_ahead, 0, ATOMIC_ORDER_RELAXED );
243}
244
245RTEMS_INLINE_ROUTINE void _Thread_queue_Gate_add(
246  Chain_Control     *chain,
247  Thread_queue_Gate *gate
248)
249{
250  _Chain_Append_unprotected( chain, &gate->Node );
251}
252
253RTEMS_INLINE_ROUTINE void _Thread_queue_Gate_open(
254  Thread_queue_Gate *gate
255)
256{
257  _Atomic_Store_uint( &gate->go_ahead, 1, ATOMIC_ORDER_RELAXED );
258}
259
260RTEMS_INLINE_ROUTINE void _Thread_queue_Gate_wait(
261  Thread_queue_Gate *gate
262)
263{
264  while ( _Atomic_Load_uint( &gate->go_ahead, ATOMIC_ORDER_RELAXED ) == 0 ) {
265    /* Wait */
266  }
267}
268#endif
269
270RTEMS_INLINE_ROUTINE void _Thread_queue_Heads_initialize(
271  Thread_queue_Heads *heads
272)
273{
274#if defined(RTEMS_SMP)
275  size_t i;
276
277  for ( i = 0; i < _Scheduler_Count; ++i ) {
278    _Chain_Initialize_node( &heads->Priority[ i ].Node );
279    _RBTree_Initialize_empty( &heads->Priority[ i ].Queue );
280  }
281#endif
282
283  _Chain_Initialize_empty( &heads->Free_chain );
284  _Chain_Initialize_node( &heads->Free_node );
285}
286
287RTEMS_INLINE_ROUTINE void _Thread_queue_Queue_initialize(
288  Thread_queue_Queue *queue
289)
290{
291#if defined(RTEMS_SMP)
292  _SMP_ticket_lock_Initialize( &queue->Lock );
293#endif
294  queue->heads = NULL;
295  queue->owner = NULL;
296}
297
298RTEMS_INLINE_ROUTINE void _Thread_queue_Queue_do_acquire_critical(
299  Thread_queue_Queue *queue,
300#if defined(RTEMS_SMP) && defined(RTEMS_PROFILING)
301  SMP_lock_Stats     *lock_stats,
302#endif
303  ISR_lock_Context   *lock_context
304)
305{
306#if defined(RTEMS_SMP)
307  _SMP_ticket_lock_Acquire(
308    &queue->Lock,
309    lock_stats,
310    &lock_context->Lock_context.Stats_context
311  );
312#else
313  (void) queue;
314  (void) lock_context;
315#endif
316}
317
318#if defined(RTEMS_SMP) && defined( RTEMS_PROFILING )
319  #define \
320    _Thread_queue_Queue_acquire_critical( queue, lock_stats, lock_context ) \
321    _Thread_queue_Queue_do_acquire_critical( queue, lock_stats, lock_context )
322#else
323  #define \
324    _Thread_queue_Queue_acquire_critical( queue, lock_stats, lock_context ) \
325    _Thread_queue_Queue_do_acquire_critical( queue, lock_context )
326#endif
327
328RTEMS_INLINE_ROUTINE void _Thread_queue_Queue_release_critical(
329  Thread_queue_Queue *queue,
330  ISR_lock_Context   *lock_context
331)
332{
333#if defined(RTEMS_SMP)
334  _SMP_ticket_lock_Release(
335    &queue->Lock,
336    &lock_context->Lock_context.Stats_context
337  );
338#else
339  (void) queue;
340  (void) lock_context;
341#endif
342}
343
344RTEMS_INLINE_ROUTINE void _Thread_queue_Queue_release(
345  Thread_queue_Queue *queue,
346  ISR_lock_Context   *lock_context
347)
348{
349  _Thread_queue_Queue_release_critical( queue, lock_context );
350  _ISR_lock_ISR_enable( lock_context );
351}
352
353RTEMS_INLINE_ROUTINE void _Thread_queue_Do_acquire_critical(
354  Thread_queue_Control *the_thread_queue,
355  ISR_lock_Context     *lock_context
356)
357{
358  _Thread_queue_Queue_acquire_critical(
359    &the_thread_queue->Queue,
360    &the_thread_queue->Lock_stats,
361    lock_context
362  );
363#if defined(RTEMS_DEBUG) && defined(RTEMS_SMP)
364  the_thread_queue->owner = _SMP_Get_current_processor();
365#endif
366}
367
368RTEMS_INLINE_ROUTINE void _Thread_queue_Acquire_critical(
369  Thread_queue_Control *the_thread_queue,
370  Thread_queue_Context *queue_context
371)
372{
373  _Thread_queue_Do_acquire_critical(
374    the_thread_queue,
375    &queue_context->Lock_context
376  );
377}
378
379RTEMS_INLINE_ROUTINE void _Thread_queue_Acquire(
380  Thread_queue_Control *the_thread_queue,
381  Thread_queue_Context *queue_context
382)
383{
384  _ISR_lock_ISR_disable( &queue_context->Lock_context );
385  _Thread_queue_Acquire_critical( the_thread_queue, queue_context );
386}
387
388#if defined(RTEMS_DEBUG)
389RTEMS_INLINE_ROUTINE bool _Thread_queue_Is_lock_owner(
390  const Thread_queue_Control *the_thread_queue
391)
392{
393#if defined(RTEMS_SMP)
394  return the_thread_queue->owner == _SMP_Get_current_processor();
395#else
396  return _ISR_Get_level() != 0;
397#endif
398}
399#endif
400
401RTEMS_INLINE_ROUTINE void _Thread_queue_Do_release_critical(
402  Thread_queue_Control *the_thread_queue,
403  ISR_lock_Context     *lock_context
404)
405{
406#if defined(RTEMS_DEBUG)
407  _Assert( _Thread_queue_Is_lock_owner( the_thread_queue ) );
408#if defined(RTEMS_SMP)
409  the_thread_queue->owner = SMP_LOCK_NO_OWNER;
410#endif
411#endif
412  _Thread_queue_Queue_release_critical(
413    &the_thread_queue->Queue,
414    lock_context
415  );
416}
417
418RTEMS_INLINE_ROUTINE void _Thread_queue_Release_critical(
419  Thread_queue_Control *the_thread_queue,
420  Thread_queue_Context *queue_context
421)
422{
423  _Thread_queue_Do_release_critical(
424    the_thread_queue,
425    &queue_context->Lock_context
426  );
427}
428
429RTEMS_INLINE_ROUTINE void _Thread_queue_Release(
430  Thread_queue_Control *the_thread_queue,
431  Thread_queue_Context *queue_context
432)
433{
434  _Thread_queue_Release_critical( the_thread_queue, queue_context );
435  _ISR_lock_ISR_enable( &queue_context->Lock_context );
436}
437
438Thread_Control *_Thread_queue_Do_dequeue(
439  Thread_queue_Control          *the_thread_queue,
440  const Thread_queue_Operations *operations
441#if defined(RTEMS_MULTIPROCESSING)
442  ,
443  Thread_queue_MP_callout        mp_callout
444#endif
445);
446
447/**
448 *  @brief Gets a pointer to a thread waiting on the_thread_queue.
449 *
450 *  This function returns a pointer to a thread waiting on
451 *  the_thread_queue.  The selection of this thread is based on
452 *  the discipline of the_thread_queue.  If no threads are waiting
453 *  on the_thread_queue, then NULL is returned.
454 *
455 *  - INTERRUPT LATENCY:
456 *    + single case
457 */
458#if defined(RTEMS_MULTIPROCESSING)
459  #define _Thread_queue_Dequeue( \
460    the_thread_queue, \
461    operations, \
462    mp_callout \
463  ) \
464    _Thread_queue_Do_dequeue( \
465      the_thread_queue, \
466      operations, \
467      mp_callout \
468    )
469#else
470  #define _Thread_queue_Dequeue( \
471    the_thread_queue, \
472    operations, \
473    mp_callout \
474  ) \
475    _Thread_queue_Do_dequeue( \
476      the_thread_queue, \
477      operations \
478    )
479#endif
480
481/**
482 * @brief Blocks the thread and places it on the thread queue.
483 *
484 * This enqueues the thread on the thread queue, blocks the thread, and
485 * optionally starts the thread timer in case the timeout discipline is not
486 * WATCHDOG_NO_TIMEOUT. Timeout discipline and value are in the queue_context.
487 *
488 * The caller must be the owner of the thread queue lock.  This function will
489 * release the thread queue lock and register it as the new thread lock.
490 * Thread dispatching is disabled before the thread queue lock is released.
491 * Thread dispatching is enabled once the sequence to block the thread is
492 * complete.  The operation to enqueue the thread on the queue is protected by
493 * the thread queue lock.  This makes it possible to use the thread queue lock
494 * to protect the state of objects embedding the thread queue and directly
495 * enter _Thread_queue_Enqueue_critical() in case the thread must block.
496 *
497 * @code
498 * #include <rtems/score/threadqimpl.h>
499 * #include <rtems/score/statesimpl.h>
500 *
501 * #define MUTEX_TQ_OPERATIONS &_Thread_queue_Operations_priority
502 *
503 * typedef struct {
504 *   Thread_queue_Control  Queue;
505 *   Thread_Control       *owner;
506 * } Mutex;
507 *
508 * void _Mutex_Obtain( Mutex *mutex )
509 * {
510 *   Thread_queue_Context  queue_context;
511 *   Thread_Control       *executing;
512 *
513 *   _Thread_queue_Context_initialize( &queue_context );
514 *   _Thread_queue_Acquire( &mutex->Queue, &queue_context.Lock_context );
515 *
516 *   executing = _Thread_Executing;
517 *
518 *   if ( mutex->owner == NULL ) {
519 *     mutex->owner = executing;
520 *     _Thread_queue_Release( &mutex->Queue, &queue_context.Lock_context );
521 *   } else {
522 *     _Thread_queue_Context_set_expected_level( &queue_context, 1 );
523 *     _Thread_queue_Enqueue_critical(
524 *       &mutex->Queue.Queue,
525 *       MUTEX_TQ_OPERATIONS,
526 *       executing,
527 *       STATES_WAITING_FOR_MUTEX,
528 *       0,
529 *       &queue_context
530 *     );
531 *   }
532 * }
533 * @endcode
534 *
535 * @param[in] queue The actual thread queue.
536 * @param[in] operations The thread queue operations.
537 * @param[in] the_thread The thread to enqueue.
538 * @param[in] state The new state of the thread.
539 * @param[in] queue_context The thread queue context of the lock acquire.
540 */
541void _Thread_queue_Enqueue_critical(
542  Thread_queue_Queue            *queue,
543  const Thread_queue_Operations *operations,
544  Thread_Control                *the_thread,
545  States_Control                 state,
546  Thread_queue_Context          *queue_context
547);
548
549/**
550 * @brief Acquires the thread queue lock and calls
551 * _Thread_queue_Enqueue_critical().
552 */
553RTEMS_INLINE_ROUTINE void _Thread_queue_Enqueue(
554  Thread_queue_Control          *the_thread_queue,
555  const Thread_queue_Operations *operations,
556  Thread_Control                *the_thread,
557  States_Control                 state,
558  uint64_t                       timeout,
559  Watchdog_Discipline            discipline,
560  uint32_t                       expected_level
561)
562{
563  Thread_queue_Context queue_context;
564
565  _Thread_queue_Context_initialize( &queue_context );
566  _Thread_queue_Acquire( the_thread_queue, &queue_context );
567  _Thread_queue_Context_set_expected_level( &queue_context, expected_level );
568  if ( discipline == WATCHDOG_ABSOLUTE ) {
569    _Thread_queue_Context_set_absolute_timeout( &queue_context, timeout );
570  } else {
571    _Thread_queue_Context_set_relative_timeout( &queue_context, timeout );
572  }
573  _Thread_queue_Enqueue_critical(
574    &the_thread_queue->Queue,
575    operations,
576    the_thread,
577    state,
578    &queue_context
579  );
580}
581
582bool _Thread_queue_Do_extract_locked(
583  Thread_queue_Queue            *queue,
584  const Thread_queue_Operations *operations,
585  Thread_Control                *the_thread
586#if defined(RTEMS_MULTIPROCESSING)
587  ,
588  const Thread_queue_Context    *queue_context
589#endif
590);
591
592/**
593 * @brief Extracts the thread from the thread queue, restores the default wait
594 * operations and restores the default thread lock.
595 *
596 * The caller must be the owner of the thread queue lock.  The thread queue
597 * lock is not released.
598 *
599 * @param[in] queue The actual thread queue.
600 * @param[in] operations The thread queue operations.
601 * @param[in] the_thread The thread to extract.
602 * @param[in] queue_context The thread queue context.  This parameter is only
603 *   used on multiprocessing configurations.
604 *
605 * @return Returns the unblock indicator for _Thread_queue_Unblock_critical().
606 * True indicates, that this thread must be unblocked by the scheduler later in
607 * _Thread_queue_Unblock_critical(), and false otherwise.  In case false is
608 * returned, then the thread queue enqueue procedure was interrupted.  Thus it
609 * will unblock itself and the thread wait information is no longer accessible,
610 * since this thread may already block on another resource in an SMP
611 * configuration.
612 */
613#if defined(RTEMS_MULTIPROCESSING)
614  #define _Thread_queue_Extract_locked( \
615    unblock, \
616    queue, \
617    the_thread, \
618    queue_context \
619  ) \
620    _Thread_queue_Do_extract_locked( \
621      unblock, \
622      queue, \
623      the_thread, \
624      queue_context \
625    )
626#else
627  #define _Thread_queue_Extract_locked( \
628    unblock, \
629    queue, \
630    the_thread, \
631    queue_context \
632  ) \
633    _Thread_queue_Do_extract_locked( \
634      unblock, \
635      queue, \
636      the_thread \
637    )
638#endif
639
640/**
641 * @brief Unblocks the thread which was on the thread queue before.
642 *
643 * The caller must be the owner of the thread queue lock.  This function will
644 * release the thread queue lock.  Thread dispatching is disabled before the
645 * thread queue lock is released and an unblock is necessary.  Thread
646 * dispatching is enabled once the sequence to unblock the thread is complete.
647 *
648 * @param[in] unblock The unblock indicator returned by
649 * _Thread_queue_Extract_locked().
650 * @param[in] queue The actual thread queue.
651 * @param[in] the_thread The thread to extract.
652 * @param[in] lock_context The lock context of the lock acquire.
653 */
654void _Thread_queue_Unblock_critical(
655  bool                unblock,
656  Thread_queue_Queue *queue,
657  Thread_Control     *the_thread,
658  ISR_lock_Context   *lock_context
659);
660
661/**
662 * @brief Extracts the thread from the thread queue and unblocks it.
663 *
664 * The caller must be the owner of the thread queue lock.  This function will
665 * release the thread queue lock and restore the default thread lock.  Thread
666 * dispatching is disabled before the thread queue lock is released and an
667 * unblock is necessary.  Thread dispatching is enabled once the sequence to
668 * unblock the thread is complete.  This makes it possible to use the thread
669 * queue lock to protect the state of objects embedding the thread queue and
670 * directly enter _Thread_queue_Extract_critical() to finalize an operation in
671 * case a waiting thread exists.
672 *
673 * @code
674 * #include <rtems/score/threadqimpl.h>
675 *
676 * typedef struct {
677 *   Thread_queue_Control  Queue;
678 *   Thread_Control       *owner;
679 * } Mutex;
680 *
681 * void _Mutex_Release( Mutex *mutex )
682 * {
683 *   Thread_queue_Context  queue_context;
684 *   Thread_Control       *first;
685 *
686 *   _Thread_queue_Context_initialize( &queue_context, NULL );
687 *   _Thread_queue_Acquire( &mutex->Queue, queue_context );
688 *
689 *   first = _Thread_queue_First_locked( &mutex->Queue );
690 *   mutex->owner = first;
691 *
692 *   if ( first != NULL ) {
693 *     _Thread_queue_Extract_critical(
694 *       &mutex->Queue.Queue,
695 *       mutex->Queue.operations,
696 *       first,
697 *       &queue_context
698 *   );
699 * }
700 * @endcode
701 *
702 * @param[in] queue The actual thread queue.
703 * @param[in] operations The thread queue operations.
704 * @param[in] the_thread The thread to extract.
705 * @param[in] queue_context The thread queue context of the lock acquire.
706 */
707void _Thread_queue_Extract_critical(
708  Thread_queue_Queue            *queue,
709  const Thread_queue_Operations *operations,
710  Thread_Control                *the_thread,
711  Thread_queue_Context          *queue_context
712);
713
714/**
715 *  @brief Extracts thread from thread queue.
716 *
717 *  This routine removes @a the_thread its thread queue
718 *  and cancels any timeouts associated with this blocking.
719 *
720 *  @param[in] the_thread is the pointer to a thread control block that
721 *      is to be removed
722 */
723void _Thread_queue_Extract( Thread_Control *the_thread );
724
725/**
726 *  @brief Extracts the_thread from the_thread_queue.
727 *
728 *  This routine extracts the_thread from the_thread_queue
729 *  and ensures that if there is a proxy for this task on
730 *  another node, it is also dealt with.
731 */
732void _Thread_queue_Extract_with_proxy(
733  Thread_Control       *the_thread
734);
735
736/**
737 * @brief Surrenders the thread queue previously owned by the thread to the
738 * first enqueued thread if it exists.
739 *
740 * The owner of the thread queue must be set to NULL by the caller.
741 *
742 * This function releases the thread queue lock.  In addition it performs a
743 * thread dispatch if necessary.
744 *
745 * @param[in] queue The actual thread queue.
746 * @param[in] operations The thread queue operations.
747 * @param[in] heads The thread queue heads.
748 * @param[in] previous_owner The previous owner thread surrendering the thread
749 *   queue.
750 * @param[in] keep_priority Indicates if the previous owner thread should keep
751 *   its current priority.
752 * @param[in] queue_context The thread queue context of the lock acquire.
753 */
754void _Thread_queue_Surrender(
755  Thread_queue_Queue            *queue,
756  const Thread_queue_Operations *operations,
757  Thread_queue_Heads            *heads,
758  Thread_Control                *previous_owner,
759  bool                           keep_priority,
760  Thread_queue_Context          *queue_context
761);
762
763RTEMS_INLINE_ROUTINE bool _Thread_queue_Is_empty(
764  const Thread_queue_Queue *queue
765)
766{
767  return queue->heads == NULL;
768}
769
770/**
771 * @brief Returns the first thread on the thread queue if it exists, otherwise
772 * @c NULL.
773 *
774 * The caller must be the owner of the thread queue lock.  The thread queue
775 * lock is not released.
776 *
777 * @param[in] the_thread_queue The thread queue.
778 * @param[in] operations The thread queue operations.
779 *
780 * @retval NULL No thread is present on the thread queue.
781 * @retval first The first thread on the thread queue according to the enqueue
782 * order.
783 */
784RTEMS_INLINE_ROUTINE Thread_Control *_Thread_queue_First_locked(
785  Thread_queue_Control          *the_thread_queue,
786  const Thread_queue_Operations *operations
787)
788{
789  Thread_queue_Heads *heads = the_thread_queue->Queue.heads;
790
791  if ( heads != NULL ) {
792    return ( *operations->first )( heads );
793  } else {
794    return NULL;
795  }
796}
797
798/**
799 * @brief Returns the first thread on the thread queue if it exists, otherwise
800 * @c NULL.
801 *
802 * @param[in] the_thread_queue The thread queue.
803 *
804 * @retval NULL No thread is present on the thread queue.
805 * @retval first The first thread on the thread queue according to the enqueue
806 * order.
807 */
808Thread_Control *_Thread_queue_First(
809  Thread_queue_Control          *the_thread_queue,
810  const Thread_queue_Operations *operations
811);
812
813/**
814 * @brief Thread queue flush filter function.
815 *
816 * Called under protection of the thread queue lock by
817 * _Thread_queue_Flush_critical() to optionally alter the thread wait
818 * information and control the iteration.
819 *
820 * @param the_thread The thread to extract.  This is the first parameter to
821 *   optimize for architectures that use the same register for the first
822 *   parameter and the return value.
823 * @param queue The actual thread queue.
824 * @param queue_context The thread queue context of the lock acquire.  May be
825 *   used to pass additional data to the filter function via an overlay
826 *   structure.  The filter function should not release or acquire the thread
827 *   queue lock.
828 *
829 * @retval the_thread Extract this thread.
830 * @retval NULL Do not extract this thread and stop the thread queue flush
831 *   operation.  Threads that are already extracted will complete the flush
832 *   operation.
833 */
834typedef Thread_Control *( *Thread_queue_Flush_filter )(
835  Thread_Control       *the_thread,
836  Thread_queue_Queue   *queue,
837  Thread_queue_Context *queue_context
838);
839
840/**
841 * @brief Default thread queue flush filter function.
842 *
843 * @param the_thread The thread to extract.
844 * @param queue Unused.
845 * @param queue_context Unused.
846 *
847 * @retval the_thread Extract this thread.
848 */
849Thread_Control *_Thread_queue_Flush_default_filter(
850  Thread_Control       *the_thread,
851  Thread_queue_Queue   *queue,
852  Thread_queue_Context *queue_context
853);
854
855/**
856 * @brief Status unavailable thread queue flush filter function.
857 *
858 * Sets the thread wait return code of the thread to STATUS_UNAVAILABLE.
859 *
860 * @param the_thread The thread to extract.
861 * @param queue Unused.
862 * @param queue_context Unused.
863 *
864 * @retval the_thread Extract this thread.
865 */
866Thread_Control *_Thread_queue_Flush_status_unavailable(
867  Thread_Control       *the_thread,
868  Thread_queue_Queue   *queue,
869  Thread_queue_Context *queue_context
870);
871
872/**
873 * @brief Status object was deleted thread queue flush filter function.
874 *
875 * Sets the thread wait return code of the thread to STATUS_OBJECT_WAS_DELETED
876 *
877 * @param the_thread The thread to extract.
878 * @param queue Unused.
879 * @param queue_context Unused.
880 *
881 * @retval the_thread Extract this thread.
882 */
883Thread_Control *_Thread_queue_Flush_status_object_was_deleted(
884  Thread_Control       *the_thread,
885  Thread_queue_Queue   *queue,
886  Thread_queue_Context *queue_context
887);
888
889/**
890 * @brief Unblocks all threads enqueued on the thread queue.
891 *
892 * This function iteratively extracts the first enqueued thread of the thread
893 * queue until the thread queue is empty or the filter function indicates a
894 * stop.  The thread timers of the extracted threads are cancelled.  The
895 * extracted threads are unblocked.
896 *
897 * @param queue The actual thread queue.
898 * @param operations The thread queue operations.
899 * @param filter The filter functions is called for each thread to extract from
900 *   the thread queue.  It may be used to alter the thread under protection of
901 *   the thread queue lock, for example to set the thread wait return code.
902 *   The return value of the filter function controls if the thread queue flush
903 *   operation should stop or continue.
904 * @param queue_context The thread queue context of the lock acquire.  May be
905 *   used to pass additional data to the filter function via an overlay
906 *   structure.  The filter function should not release or acquire the thread
907 *   queue lock.
908 *
909 * @return The count of extracted threads.
910 */
911size_t _Thread_queue_Flush_critical(
912  Thread_queue_Queue            *queue,
913  const Thread_queue_Operations *operations,
914  Thread_queue_Flush_filter      filter,
915  Thread_queue_Context          *queue_context
916);
917
918void _Thread_queue_Initialize( Thread_queue_Control *the_thread_queue );
919
920#if defined(RTEMS_SMP) && defined(RTEMS_DEBUG) && defined(RTEMS_PROFILING)
921  #define THREAD_QUEUE_INITIALIZER( name ) \
922    { \
923      .Lock_stats = SMP_LOCK_STATS_INITIALIZER( name ), \
924      .owner = SMP_LOCK_NO_OWNER, \
925      .Queue = { \
926        .heads = NULL, \
927        .Lock = SMP_TICKET_LOCK_INITIALIZER, \
928      } \
929    }
930#elif defined(RTEMS_SMP) && defined(RTEMS_DEBUG)
931  #define THREAD_QUEUE_INITIALIZER( name ) \
932    { \
933      .owner = SMP_LOCK_NO_OWNER, \
934      .Queue = { \
935        .heads = NULL, \
936        .Lock = SMP_TICKET_LOCK_INITIALIZER, \
937      } \
938    }
939#elif defined(RTEMS_SMP) && defined(RTEMS_PROFILING)
940  #define THREAD_QUEUE_INITIALIZER( name ) \
941    { \
942      .Lock_stats = SMP_LOCK_STATS_INITIALIZER( name ), \
943      .Queue = { \
944        .heads = NULL, \
945        .Lock = SMP_TICKET_LOCK_INITIALIZER, \
946      } \
947    }
948#elif defined(RTEMS_SMP)
949  #define THREAD_QUEUE_INITIALIZER( name ) \
950    { \
951      .Queue = { \
952        .heads = NULL, \
953        .Lock = SMP_TICKET_LOCK_INITIALIZER, \
954      } \
955    }
956#else
957  #define THREAD_QUEUE_INITIALIZER( name ) \
958    { .Queue = { .heads = NULL } }
959#endif
960
961RTEMS_INLINE_ROUTINE void _Thread_queue_Destroy(
962  Thread_queue_Control *the_thread_queue
963)
964{
965#if defined(RTEMS_SMP)
966  _SMP_ticket_lock_Destroy( &the_thread_queue->Queue.Lock );
967  _SMP_lock_Stats_destroy( &the_thread_queue->Lock_stats );
968#endif
969}
970
971#if defined(RTEMS_MULTIPROCESSING)
972void _Thread_queue_MP_callout_do_nothing(
973  Thread_Control *the_proxy,
974  Objects_Id      mp_id
975);
976
977void _Thread_queue_Unblock_proxy(
978  Thread_queue_Queue *queue,
979  Thread_Control     *the_thread
980);
981#endif
982
983/**
984 * @brief Helper structure to ensure that all objects containing a thread queue
985 * have the right layout.
986 *
987 * @see _Thread_Wait_get_id() and THREAD_QUEUE_OBJECT_ASSERT().
988 */
989typedef struct {
990  Objects_Control      Object;
991  Thread_queue_Control Wait_queue;
992} Thread_queue_Object;
993
994#define THREAD_QUEUE_OBJECT_ASSERT( object_type, wait_queue_member ) \
995  RTEMS_STATIC_ASSERT( \
996    offsetof( object_type, wait_queue_member ) \
997      == offsetof( Thread_queue_Object, Wait_queue ) \
998    && ( &( ( (object_type *) 0 )->wait_queue_member ) \
999      == ( &( (Thread_queue_Object *) 0 )->Wait_queue ) ), \
1000    object_type \
1001  )
1002
1003#define THREAD_QUEUE_QUEUE_TO_OBJECT( queue ) \
1004  RTEMS_CONTAINER_OF( \
1005    queue, \
1006    Thread_queue_Object, \
1007    Wait_queue.Queue \
1008  )
1009
1010extern const Thread_queue_Operations _Thread_queue_Operations_default;
1011
1012extern const Thread_queue_Operations _Thread_queue_Operations_FIFO;
1013
1014extern const Thread_queue_Operations _Thread_queue_Operations_priority;
1015
1016extern const Thread_queue_Operations _Thread_queue_Operations_priority_inherit;
1017
1018/**@}*/
1019
1020#ifdef __cplusplus
1021}
1022#endif
1023
1024#endif
1025/* end of include file */
Note: See TracBrowser for help on using the repository browser.