source: rtems/cpukit/score/include/rtems/score/threadqimpl.h @ 424ffe4d

Last change on this file since 424ffe4d was 424ffe4d, checked in by Sebastian Huber <sebastian.huber@…>, on Aug 11, 2016 at 8:26:57 AM

score: Introduce thread queue surrender operation

This is an optimization for _Thread_queue_Surrender(). It helps to
encapsulate the priority boosting in the priority inheritance thread
queue operations.

  • Property mode set to 100644
File size: 28.4 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_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(
369  Thread_queue_Control *the_thread_queue,
370  ISR_lock_Context     *lock_context
371)
372{
373  _ISR_lock_ISR_disable( lock_context );
374  _Thread_queue_Acquire_critical( the_thread_queue, lock_context );
375}
376
377#if defined(RTEMS_DEBUG)
378RTEMS_INLINE_ROUTINE bool _Thread_queue_Is_lock_owner(
379  const Thread_queue_Control *the_thread_queue
380)
381{
382#if defined(RTEMS_SMP)
383  return the_thread_queue->owner == _SMP_Get_current_processor();
384#else
385  return _ISR_Get_level() != 0;
386#endif
387}
388#endif
389
390RTEMS_INLINE_ROUTINE void _Thread_queue_Release_critical(
391  Thread_queue_Control *the_thread_queue,
392  ISR_lock_Context     *lock_context
393)
394{
395#if defined(RTEMS_DEBUG)
396  _Assert( _Thread_queue_Is_lock_owner( the_thread_queue ) );
397#if defined(RTEMS_SMP)
398  the_thread_queue->owner = SMP_LOCK_NO_OWNER;
399#endif
400#endif
401  _Thread_queue_Queue_release_critical(
402    &the_thread_queue->Queue,
403    lock_context
404  );
405}
406
407RTEMS_INLINE_ROUTINE void _Thread_queue_Release(
408  Thread_queue_Control *the_thread_queue,
409  ISR_lock_Context     *lock_context
410)
411{
412  _Thread_queue_Release_critical( the_thread_queue, lock_context );
413  _ISR_lock_ISR_enable( lock_context );
414}
415
416Thread_Control *_Thread_queue_Do_dequeue(
417  Thread_queue_Control          *the_thread_queue,
418  const Thread_queue_Operations *operations
419#if defined(RTEMS_MULTIPROCESSING)
420  ,
421  Thread_queue_MP_callout        mp_callout
422#endif
423);
424
425/**
426 *  @brief Gets a pointer to a thread waiting on the_thread_queue.
427 *
428 *  This function returns a pointer to a thread waiting on
429 *  the_thread_queue.  The selection of this thread is based on
430 *  the discipline of the_thread_queue.  If no threads are waiting
431 *  on the_thread_queue, then NULL is returned.
432 *
433 *  - INTERRUPT LATENCY:
434 *    + single case
435 */
436#if defined(RTEMS_MULTIPROCESSING)
437  #define _Thread_queue_Dequeue( \
438    the_thread_queue, \
439    operations, \
440    mp_callout \
441  ) \
442    _Thread_queue_Do_dequeue( \
443      the_thread_queue, \
444      operations, \
445      mp_callout \
446    )
447#else
448  #define _Thread_queue_Dequeue( \
449    the_thread_queue, \
450    operations, \
451    mp_callout \
452  ) \
453    _Thread_queue_Do_dequeue( \
454      the_thread_queue, \
455      operations \
456    )
457#endif
458
459/**
460 * @brief Blocks the thread and places it on the thread queue.
461 *
462 * This enqueues the thread on the thread queue, blocks the thread, and
463 * optionally starts the thread timer in case the timeout discipline is not
464 * WATCHDOG_NO_TIMEOUT. Timeout discipline and value are in the queue_context.
465 *
466 * The caller must be the owner of the thread queue lock.  This function will
467 * release the thread queue lock and register it as the new thread lock.
468 * Thread dispatching is disabled before the thread queue lock is released.
469 * Thread dispatching is enabled once the sequence to block the thread is
470 * complete.  The operation to enqueue the thread on the queue is protected by
471 * the thread queue lock.  This makes it possible to use the thread queue lock
472 * to protect the state of objects embedding the thread queue and directly
473 * enter _Thread_queue_Enqueue_critical() in case the thread must block.
474 *
475 * @code
476 * #include <rtems/score/threadqimpl.h>
477 * #include <rtems/score/statesimpl.h>
478 *
479 * #define MUTEX_TQ_OPERATIONS &_Thread_queue_Operations_priority
480 *
481 * typedef struct {
482 *   Thread_queue_Control  Queue;
483 *   Thread_Control       *owner;
484 * } Mutex;
485 *
486 * void _Mutex_Obtain( Mutex *mutex )
487 * {
488 *   Thread_queue_Context  queue_context;
489 *   Thread_Control       *executing;
490 *
491 *   _Thread_queue_Context_initialize( &queue_context );
492 *   _Thread_queue_Acquire( &mutex->Queue, &queue_context.Lock_context );
493 *
494 *   executing = _Thread_Executing;
495 *
496 *   if ( mutex->owner == NULL ) {
497 *     mutex->owner = executing;
498 *     _Thread_queue_Release( &mutex->Queue, &queue_context.Lock_context );
499 *   } else {
500 *     _Thread_queue_Context_set_expected_level( &queue_context, 1 );
501 *     _Thread_queue_Enqueue_critical(
502 *       &mutex->Queue.Queue,
503 *       MUTEX_TQ_OPERATIONS,
504 *       executing,
505 *       STATES_WAITING_FOR_MUTEX,
506 *       0,
507 *       &queue_context
508 *     );
509 *   }
510 * }
511 * @endcode
512 *
513 * @param[in] queue The actual thread queue.
514 * @param[in] operations The thread queue operations.
515 * @param[in] the_thread The thread to enqueue.
516 * @param[in] state The new state of the thread.
517 * @param[in] queue_context The thread queue context of the lock acquire.
518 */
519void _Thread_queue_Enqueue_critical(
520  Thread_queue_Queue            *queue,
521  const Thread_queue_Operations *operations,
522  Thread_Control                *the_thread,
523  States_Control                 state,
524  Thread_queue_Context          *queue_context
525);
526
527/**
528 * @brief Acquires the thread queue lock and calls
529 * _Thread_queue_Enqueue_critical().
530 */
531RTEMS_INLINE_ROUTINE void _Thread_queue_Enqueue(
532  Thread_queue_Control          *the_thread_queue,
533  const Thread_queue_Operations *operations,
534  Thread_Control                *the_thread,
535  States_Control                 state,
536  uint64_t                       timeout,
537  Watchdog_Discipline            discipline,
538  uint32_t                       expected_level
539)
540{
541  Thread_queue_Context queue_context;
542
543  _Thread_queue_Context_initialize( &queue_context );
544  _Thread_queue_Acquire( the_thread_queue, &queue_context.Lock_context );
545  _Thread_queue_Context_set_expected_level( &queue_context, expected_level );
546  if ( discipline == WATCHDOG_ABSOLUTE ) {
547    _Thread_queue_Context_set_absolute_timeout( &queue_context, timeout );
548  } else {
549    _Thread_queue_Context_set_relative_timeout( &queue_context, timeout );
550  }
551  _Thread_queue_Enqueue_critical(
552    &the_thread_queue->Queue,
553    operations,
554    the_thread,
555    state,
556    &queue_context
557  );
558}
559
560bool _Thread_queue_Do_extract_locked(
561  Thread_queue_Queue            *queue,
562  const Thread_queue_Operations *operations,
563  Thread_Control                *the_thread
564#if defined(RTEMS_MULTIPROCESSING)
565  ,
566  const Thread_queue_Context    *queue_context
567#endif
568);
569
570/**
571 * @brief Extracts the thread from the thread queue, restores the default wait
572 * operations and restores the default thread lock.
573 *
574 * The caller must be the owner of the thread queue lock.  The thread queue
575 * lock is not released.
576 *
577 * @param[in] queue The actual thread queue.
578 * @param[in] operations The thread queue operations.
579 * @param[in] the_thread The thread to extract.
580 * @param[in] queue_context The thread queue context.  This parameter is only
581 *   used on multiprocessing configurations.
582 *
583 * @return Returns the unblock indicator for _Thread_queue_Unblock_critical().
584 * True indicates, that this thread must be unblocked by the scheduler later in
585 * _Thread_queue_Unblock_critical(), and false otherwise.  In case false is
586 * returned, then the thread queue enqueue procedure was interrupted.  Thus it
587 * will unblock itself and the thread wait information is no longer accessible,
588 * since this thread may already block on another resource in an SMP
589 * configuration.
590 */
591#if defined(RTEMS_MULTIPROCESSING)
592  #define _Thread_queue_Extract_locked( \
593    unblock, \
594    queue, \
595    the_thread, \
596    queue_context \
597  ) \
598    _Thread_queue_Do_extract_locked( \
599      unblock, \
600      queue, \
601      the_thread, \
602      queue_context \
603    )
604#else
605  #define _Thread_queue_Extract_locked( \
606    unblock, \
607    queue, \
608    the_thread, \
609    queue_context \
610  ) \
611    _Thread_queue_Do_extract_locked( \
612      unblock, \
613      queue, \
614      the_thread \
615    )
616#endif
617
618/**
619 * @brief Unblocks the thread which was on the thread queue before.
620 *
621 * The caller must be the owner of the thread queue lock.  This function will
622 * release the thread queue lock.  Thread dispatching is disabled before the
623 * thread queue lock is released and an unblock is necessary.  Thread
624 * dispatching is enabled once the sequence to unblock the thread is complete.
625 *
626 * @param[in] unblock The unblock indicator returned by
627 * _Thread_queue_Extract_locked().
628 * @param[in] queue The actual thread queue.
629 * @param[in] the_thread The thread to extract.
630 * @param[in] lock_context The lock context of the lock acquire.
631 */
632void _Thread_queue_Unblock_critical(
633  bool                unblock,
634  Thread_queue_Queue *queue,
635  Thread_Control     *the_thread,
636  ISR_lock_Context   *lock_context
637);
638
639/**
640 * @brief Extracts the thread from the thread queue and unblocks it.
641 *
642 * The caller must be the owner of the thread queue lock.  This function will
643 * release the thread queue lock and restore the default thread lock.  Thread
644 * dispatching is disabled before the thread queue lock is released and an
645 * unblock is necessary.  Thread dispatching is enabled once the sequence to
646 * unblock the thread is complete.  This makes it possible to use the thread
647 * queue lock to protect the state of objects embedding the thread queue and
648 * directly enter _Thread_queue_Extract_critical() to finalize an operation in
649 * case a waiting thread exists.
650 *
651 * @code
652 * #include <rtems/score/threadqimpl.h>
653 *
654 * typedef struct {
655 *   Thread_queue_Control  Queue;
656 *   Thread_Control       *owner;
657 * } Mutex;
658 *
659 * void _Mutex_Release( Mutex *mutex )
660 * {
661 *   Thread_queue_Context  queue_context;
662 *   Thread_Control       *first;
663 *
664 *   _Thread_queue_Context_initialize( &queue_context, NULL );
665 *   _Thread_queue_Acquire( &mutex->Queue, &queue_context.Lock_context );
666 *
667 *   first = _Thread_queue_First_locked( &mutex->Queue );
668 *   mutex->owner = first;
669 *
670 *   if ( first != NULL ) {
671 *     _Thread_queue_Extract_critical(
672 *       &mutex->Queue.Queue,
673 *       mutex->Queue.operations,
674 *       first,
675 *       &queue_context
676 *   );
677 * }
678 * @endcode
679 *
680 * @param[in] queue The actual thread queue.
681 * @param[in] operations The thread queue operations.
682 * @param[in] the_thread The thread to extract.
683 * @param[in] queue_context The thread queue context of the lock acquire.
684 */
685void _Thread_queue_Extract_critical(
686  Thread_queue_Queue            *queue,
687  const Thread_queue_Operations *operations,
688  Thread_Control                *the_thread,
689  Thread_queue_Context          *queue_context
690);
691
692/**
693 *  @brief Extracts thread from thread queue.
694 *
695 *  This routine removes @a the_thread its thread queue
696 *  and cancels any timeouts associated with this blocking.
697 *
698 *  @param[in] the_thread is the pointer to a thread control block that
699 *      is to be removed
700 */
701void _Thread_queue_Extract( Thread_Control *the_thread );
702
703/**
704 *  @brief Extracts the_thread from the_thread_queue.
705 *
706 *  This routine extracts the_thread from the_thread_queue
707 *  and ensures that if there is a proxy for this task on
708 *  another node, it is also dealt with.
709 */
710void _Thread_queue_Extract_with_proxy(
711  Thread_Control       *the_thread
712);
713
714/**
715 * @brief Surrenders the thread queue previously owned by the thread to the
716 * first enqueued thread if it exists.
717 *
718 * The owner of the thread queue must be set to NULL by the caller.
719 *
720 * This function releases the thread queue lock.  In addition it performs a
721 * thread dispatch if necessary.
722 *
723 * @param[in] queue The actual thread queue.
724 * @param[in] operations The thread queue operations.
725 * @param[in] heads The thread queue heads.
726 * @param[in] previous_owner The previous owner thread surrendering the thread
727 *   queue.
728 * @param[in] keep_priority Indicates if the previous owner thread should keep
729 *   its current priority.
730 * @param[in] queue_context The thread queue context of the lock acquire.
731 */
732void _Thread_queue_Surrender(
733  Thread_queue_Queue            *queue,
734  const Thread_queue_Operations *operations,
735  Thread_queue_Heads            *heads,
736  Thread_Control                *previous_owner,
737  bool                           keep_priority,
738  Thread_queue_Context          *queue_context
739);
740
741RTEMS_INLINE_ROUTINE bool _Thread_queue_Is_empty(
742  const Thread_queue_Queue *queue
743)
744{
745  return queue->heads == NULL;
746}
747
748/**
749 * @brief Returns the first thread on the thread queue if it exists, otherwise
750 * @c NULL.
751 *
752 * The caller must be the owner of the thread queue lock.  The thread queue
753 * lock is not released.
754 *
755 * @param[in] the_thread_queue The thread queue.
756 * @param[in] operations The thread queue operations.
757 *
758 * @retval NULL No thread is present on the thread queue.
759 * @retval first The first thread on the thread queue according to the enqueue
760 * order.
761 */
762RTEMS_INLINE_ROUTINE Thread_Control *_Thread_queue_First_locked(
763  Thread_queue_Control          *the_thread_queue,
764  const Thread_queue_Operations *operations
765)
766{
767  Thread_queue_Heads *heads = the_thread_queue->Queue.heads;
768
769  if ( heads != NULL ) {
770    return ( *operations->first )( heads );
771  } else {
772    return NULL;
773  }
774}
775
776/**
777 * @brief Returns the first thread on the thread queue if it exists, otherwise
778 * @c NULL.
779 *
780 * @param[in] the_thread_queue The thread queue.
781 *
782 * @retval NULL No thread is present on the thread queue.
783 * @retval first The first thread on the thread queue according to the enqueue
784 * order.
785 */
786Thread_Control *_Thread_queue_First(
787  Thread_queue_Control          *the_thread_queue,
788  const Thread_queue_Operations *operations
789);
790
791/**
792 * @brief Thread queue flush filter function.
793 *
794 * Called under protection of the thread queue lock by
795 * _Thread_queue_Flush_critical() to optionally alter the thread wait
796 * information and control the iteration.
797 *
798 * @param the_thread The thread to extract.  This is the first parameter to
799 *   optimize for architectures that use the same register for the first
800 *   parameter and the return value.
801 * @param queue The actual thread queue.
802 * @param queue_context The thread queue context of the lock acquire.  May be
803 *   used to pass additional data to the filter function via an overlay
804 *   structure.  The filter function should not release or acquire the thread
805 *   queue lock.
806 *
807 * @retval the_thread Extract this thread.
808 * @retval NULL Do not extract this thread and stop the thread queue flush
809 *   operation.  Threads that are already extracted will complete the flush
810 *   operation.
811 */
812typedef Thread_Control *( *Thread_queue_Flush_filter )(
813  Thread_Control       *the_thread,
814  Thread_queue_Queue   *queue,
815  Thread_queue_Context *queue_context
816);
817
818/**
819 * @brief Default thread queue flush filter function.
820 *
821 * @param the_thread The thread to extract.
822 * @param queue Unused.
823 * @param queue_context Unused.
824 *
825 * @retval the_thread Extract this thread.
826 */
827Thread_Control *_Thread_queue_Flush_default_filter(
828  Thread_Control       *the_thread,
829  Thread_queue_Queue   *queue,
830  Thread_queue_Context *queue_context
831);
832
833/**
834 * @brief Status unavailable thread queue flush filter function.
835 *
836 * Sets the thread wait return code of the thread to STATUS_UNAVAILABLE.
837 *
838 * @param the_thread The thread to extract.
839 * @param queue Unused.
840 * @param queue_context Unused.
841 *
842 * @retval the_thread Extract this thread.
843 */
844Thread_Control *_Thread_queue_Flush_status_unavailable(
845  Thread_Control       *the_thread,
846  Thread_queue_Queue   *queue,
847  Thread_queue_Context *queue_context
848);
849
850/**
851 * @brief Status object was deleted thread queue flush filter function.
852 *
853 * Sets the thread wait return code of the thread to STATUS_OBJECT_WAS_DELETED
854 *
855 * @param the_thread The thread to extract.
856 * @param queue Unused.
857 * @param queue_context Unused.
858 *
859 * @retval the_thread Extract this thread.
860 */
861Thread_Control *_Thread_queue_Flush_status_object_was_deleted(
862  Thread_Control       *the_thread,
863  Thread_queue_Queue   *queue,
864  Thread_queue_Context *queue_context
865);
866
867/**
868 * @brief Unblocks all threads enqueued on the thread queue.
869 *
870 * This function iteratively extracts the first enqueued thread of the thread
871 * queue until the thread queue is empty or the filter function indicates a
872 * stop.  The thread timers of the extracted threads are cancelled.  The
873 * extracted threads are unblocked.
874 *
875 * @param queue The actual thread queue.
876 * @param operations The thread queue operations.
877 * @param filter The filter functions is called for each thread to extract from
878 *   the thread queue.  It may be used to alter the thread under protection of
879 *   the thread queue lock, for example to set the thread wait return code.
880 *   The return value of the filter function controls if the thread queue flush
881 *   operation should stop or continue.
882 * @param queue_context The thread queue context of the lock acquire.  May be
883 *   used to pass additional data to the filter function via an overlay
884 *   structure.  The filter function should not release or acquire the thread
885 *   queue lock.
886 *
887 * @return The count of extracted threads.
888 */
889size_t _Thread_queue_Flush_critical(
890  Thread_queue_Queue            *queue,
891  const Thread_queue_Operations *operations,
892  Thread_queue_Flush_filter      filter,
893  Thread_queue_Context          *queue_context
894);
895
896void _Thread_queue_Initialize( Thread_queue_Control *the_thread_queue );
897
898#if defined(RTEMS_SMP) && defined(RTEMS_DEBUG) && defined(RTEMS_PROFILING)
899  #define THREAD_QUEUE_INITIALIZER( name ) \
900    { \
901      .Lock_stats = SMP_LOCK_STATS_INITIALIZER( name ), \
902      .owner = SMP_LOCK_NO_OWNER, \
903      .Queue = { \
904        .heads = NULL, \
905        .Lock = SMP_TICKET_LOCK_INITIALIZER, \
906      } \
907    }
908#elif defined(RTEMS_SMP) && defined(RTEMS_DEBUG)
909  #define THREAD_QUEUE_INITIALIZER( name ) \
910    { \
911      .owner = SMP_LOCK_NO_OWNER, \
912      .Queue = { \
913        .heads = NULL, \
914        .Lock = SMP_TICKET_LOCK_INITIALIZER, \
915      } \
916    }
917#elif defined(RTEMS_SMP) && defined(RTEMS_PROFILING)
918  #define THREAD_QUEUE_INITIALIZER( name ) \
919    { \
920      .Lock_stats = SMP_LOCK_STATS_INITIALIZER( name ), \
921      .Queue = { \
922        .heads = NULL, \
923        .Lock = SMP_TICKET_LOCK_INITIALIZER, \
924      } \
925    }
926#elif defined(RTEMS_SMP)
927  #define THREAD_QUEUE_INITIALIZER( name ) \
928    { \
929      .Queue = { \
930        .heads = NULL, \
931        .Lock = SMP_TICKET_LOCK_INITIALIZER, \
932      } \
933    }
934#else
935  #define THREAD_QUEUE_INITIALIZER( name ) \
936    { .Queue = { .heads = NULL } }
937#endif
938
939RTEMS_INLINE_ROUTINE void _Thread_queue_Destroy(
940  Thread_queue_Control *the_thread_queue
941)
942{
943#if defined(RTEMS_SMP)
944  _SMP_ticket_lock_Destroy( &the_thread_queue->Queue.Lock );
945  _SMP_lock_Stats_destroy( &the_thread_queue->Lock_stats );
946#endif
947}
948
949#if defined(RTEMS_MULTIPROCESSING)
950void _Thread_queue_MP_callout_do_nothing(
951  Thread_Control *the_proxy,
952  Objects_Id      mp_id
953);
954
955void _Thread_queue_Unblock_proxy(
956  Thread_queue_Queue *queue,
957  Thread_Control     *the_thread
958);
959#endif
960
961/**
962 * @brief Helper structure to ensure that all objects containing a thread queue
963 * have the right layout.
964 *
965 * @see _Thread_Wait_get_id() and THREAD_QUEUE_OBJECT_ASSERT().
966 */
967typedef struct {
968  Objects_Control      Object;
969  Thread_queue_Control Wait_queue;
970} Thread_queue_Object;
971
972#define THREAD_QUEUE_OBJECT_ASSERT( object_type, wait_queue_member ) \
973  RTEMS_STATIC_ASSERT( \
974    offsetof( object_type, wait_queue_member ) \
975      == offsetof( Thread_queue_Object, Wait_queue ) \
976    && ( &( ( (object_type *) 0 )->wait_queue_member ) \
977      == ( &( (Thread_queue_Object *) 0 )->Wait_queue ) ), \
978    object_type \
979  )
980
981#define THREAD_QUEUE_QUEUE_TO_OBJECT( queue ) \
982  RTEMS_CONTAINER_OF( \
983    queue, \
984    Thread_queue_Object, \
985    Wait_queue.Queue \
986  )
987
988extern const Thread_queue_Operations _Thread_queue_Operations_default;
989
990extern const Thread_queue_Operations _Thread_queue_Operations_FIFO;
991
992extern const Thread_queue_Operations _Thread_queue_Operations_priority;
993
994extern const Thread_queue_Operations _Thread_queue_Operations_priority_inherit;
995
996/**@}*/
997
998#ifdef __cplusplus
999}
1000#endif
1001
1002#endif
1003/* end of include file */
Note: See TracBrowser for help on using the repository browser.