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

5
Last change on this file since b3cb2c1 was b3cb2c1, checked in by Sebastian Huber <sebastian.huber@…>, on 12/01/16 at 21:24:02

score: Fix debug thread queue context init

On ARM Thumb we may have function addresses ending with 0x7f, if we are
lucky.

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