source: rtems/cpukit/score/include/rtems/score/threadqimpl.h @ 39d97ab

Last change on this file since 39d97ab was 39d97ab, checked in by Gedare Bloom <gedare@…>, on Jul 26, 2016 at 6:13:36 PM

cpukit: refactor nanosleep and use 64-bit timeout for threadq

  • Fixes a bug with elapsed time calculations misusing absolute time arguments in nanosleep_helper by passing the requested relative interval.
  • Fixes a bug with truncation of absolute timeouts by passing the full 64-bit value to Thread_queue_Enqueue.
  • Share yield logic between nanosleep and clock_nanosleep.

updates #2732

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