source: rtems/cpukit/score/include/rtems/score/threadqimpl.h @ 3a27248

5
Last change on this file since 3a27248 was 3a27248, checked in by Sebastian Huber <sebastian.huber@…>, on 10/21/16 at 07:23:58

score: First part of new MrsP implementation

Update #2556.

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