source: rtems/cpukit/score/include/rtems/score/threadqimpl.h @ f6142c19

5
Last change on this file since f6142c19 was f6142c19, checked in by Sebastian Huber <sebastian.huber@…>, on 09/09/16 at 09:00:06

score: Scheduler node awareness for thread queues

Maintain the priority of a thread for each scheduler instance via the
thread queue enqueue, extract, priority actions and surrender
operations. This replaces the primitive priority boosting.

Update #2556.

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