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

5
Last change on this file since af97ba8f was af97ba8f, checked in by Sebastian Huber <sebastian.huber@…>, on 07/28/17 at 09:57:31

score: Add RTEMS_HAVE_MEMBER_SAME_TYPE()

This fixes some "variably modified" warnings and a clang compile error.

  • Property mode set to 100644
File size: 33.7 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  const char         *name
358)
359{
360#if defined(RTEMS_SMP)
361  _SMP_ticket_lock_Initialize( &queue->Lock );
362#endif
363  queue->heads = NULL;
364  queue->owner = NULL;
365  queue->name = name;
366}
367
368RTEMS_INLINE_ROUTINE void _Thread_queue_Queue_do_acquire_critical(
369  Thread_queue_Queue *queue,
370#if defined(RTEMS_SMP) && defined(RTEMS_PROFILING)
371  SMP_lock_Stats     *lock_stats,
372#endif
373  ISR_lock_Context   *lock_context
374)
375{
376#if defined(RTEMS_SMP)
377  _SMP_ticket_lock_Acquire(
378    &queue->Lock,
379    lock_stats,
380    &lock_context->Lock_context.Stats_context
381  );
382#else
383  (void) queue;
384  (void) lock_context;
385#endif
386}
387
388#if defined(RTEMS_SMP) && defined( RTEMS_PROFILING )
389  #define \
390    _Thread_queue_Queue_acquire_critical( queue, lock_stats, lock_context ) \
391    _Thread_queue_Queue_do_acquire_critical( queue, lock_stats, lock_context )
392#else
393  #define \
394    _Thread_queue_Queue_acquire_critical( queue, lock_stats, lock_context ) \
395    _Thread_queue_Queue_do_acquire_critical( queue, lock_context )
396#endif
397
398RTEMS_INLINE_ROUTINE void _Thread_queue_Queue_release_critical(
399  Thread_queue_Queue *queue,
400  ISR_lock_Context   *lock_context
401)
402{
403#if defined(RTEMS_SMP)
404  _SMP_ticket_lock_Release(
405    &queue->Lock,
406    &lock_context->Lock_context.Stats_context
407  );
408#else
409  (void) queue;
410  (void) lock_context;
411#endif
412}
413
414RTEMS_INLINE_ROUTINE void _Thread_queue_Queue_release(
415  Thread_queue_Queue *queue,
416  ISR_lock_Context   *lock_context
417)
418{
419  _Thread_queue_Queue_release_critical( queue, lock_context );
420  _ISR_lock_ISR_enable( lock_context );
421}
422
423/**
424 * @brief Copies the thread queue name to the specified buffer.
425 *
426 * @param[in] queue The actual thread queue.
427 * @param[in] buffer The buffer for the thread queue name copy.
428 * @param[in] buffer_size The buffer size in characters.
429 * @param[in] id The object identifier in case the thread queue is embedded in
430 *   an object with identifier, otherwise it is set to 0.
431 *
432 * @retval The length of the thread queue name.  May be greater than or equal
433 *   to the buffer size if truncation occurred.
434 */
435size_t _Thread_queue_Queue_get_name_and_id(
436  const Thread_queue_Queue *queue,
437  char                     *buffer,
438  size_t                    buffer_size,
439  Objects_Id               *id
440);
441
442#if defined(RTEMS_SMP)
443void _Thread_queue_Do_acquire_critical(
444  Thread_queue_Control *the_thread_queue,
445  ISR_lock_Context     *lock_context
446);
447#else
448RTEMS_INLINE_ROUTINE void _Thread_queue_Do_acquire_critical(
449  Thread_queue_Control *the_thread_queue,
450  ISR_lock_Context     *lock_context
451)
452{
453  (void) the_thread_queue;
454  (void) lock_context;
455}
456#endif
457
458RTEMS_INLINE_ROUTINE void _Thread_queue_Acquire_critical(
459  Thread_queue_Control *the_thread_queue,
460  Thread_queue_Context *queue_context
461)
462{
463  _Thread_queue_Do_acquire_critical(
464    the_thread_queue,
465    &queue_context->Lock_context.Lock_context
466  );
467}
468
469#if defined(RTEMS_SMP)
470void _Thread_queue_Acquire(
471  Thread_queue_Control *the_thread_queue,
472  Thread_queue_Context *queue_context
473);
474#else
475RTEMS_INLINE_ROUTINE void _Thread_queue_Acquire(
476  Thread_queue_Control *the_thread_queue,
477  Thread_queue_Context *queue_context
478)
479{
480  (void) the_thread_queue;
481  _ISR_lock_ISR_disable( &queue_context->Lock_context.Lock_context );
482}
483#endif
484
485#if defined(RTEMS_DEBUG)
486RTEMS_INLINE_ROUTINE bool _Thread_queue_Is_lock_owner(
487  const Thread_queue_Control *the_thread_queue
488)
489{
490#if defined(RTEMS_SMP)
491  return the_thread_queue->owner == _SMP_lock_Who_am_I();
492#else
493  return _ISR_Get_level() != 0;
494#endif
495}
496#endif
497
498#if defined(RTEMS_SMP)
499void _Thread_queue_Do_release_critical(
500  Thread_queue_Control *the_thread_queue,
501  ISR_lock_Context     *lock_context
502);
503#else
504RTEMS_INLINE_ROUTINE void _Thread_queue_Do_release_critical(
505  Thread_queue_Control *the_thread_queue,
506  ISR_lock_Context     *lock_context
507)
508{
509  (void) the_thread_queue;
510  (void) lock_context;
511  _Assert( _Thread_queue_Is_lock_owner( the_thread_queue ) );
512}
513#endif
514
515RTEMS_INLINE_ROUTINE void _Thread_queue_Release_critical(
516  Thread_queue_Control *the_thread_queue,
517  Thread_queue_Context *queue_context
518)
519{
520  _Thread_queue_Do_release_critical(
521    the_thread_queue,
522    &queue_context->Lock_context.Lock_context
523  );
524}
525
526#if defined(RTEMS_SMP)
527void _Thread_queue_Release(
528  Thread_queue_Control *the_thread_queue,
529  Thread_queue_Context *queue_context
530);
531#else
532RTEMS_INLINE_ROUTINE void _Thread_queue_Release(
533  Thread_queue_Control *the_thread_queue,
534  Thread_queue_Context *queue_context
535)
536{
537  (void) the_thread_queue;
538  _Assert( _Thread_queue_Is_lock_owner( the_thread_queue ) );
539  _ISR_lock_ISR_enable( &queue_context->Lock_context.Lock_context );
540}
541#endif
542
543Thread_Control *_Thread_queue_Do_dequeue(
544  Thread_queue_Control          *the_thread_queue,
545  const Thread_queue_Operations *operations
546#if defined(RTEMS_MULTIPROCESSING)
547  ,
548  Thread_queue_MP_callout        mp_callout
549#endif
550);
551
552/**
553 *  @brief Gets a pointer to a thread waiting on the_thread_queue.
554 *
555 *  This function returns a pointer to a thread waiting on
556 *  the_thread_queue.  The selection of this thread is based on
557 *  the discipline of the_thread_queue.  If no threads are waiting
558 *  on the_thread_queue, then NULL is returned.
559 *
560 *  - INTERRUPT LATENCY:
561 *    + single case
562 */
563#if defined(RTEMS_MULTIPROCESSING)
564  #define _Thread_queue_Dequeue( \
565    the_thread_queue, \
566    operations, \
567    mp_callout \
568  ) \
569    _Thread_queue_Do_dequeue( \
570      the_thread_queue, \
571      operations, \
572      mp_callout \
573    )
574#else
575  #define _Thread_queue_Dequeue( \
576    the_thread_queue, \
577    operations, \
578    mp_callout \
579  ) \
580    _Thread_queue_Do_dequeue( \
581      the_thread_queue, \
582      operations \
583    )
584#endif
585
586/**
587 * @brief Blocks the thread and places it on the thread queue.
588 *
589 * This enqueues the thread on the thread queue, blocks the thread, and
590 * optionally starts the thread timer in case the timeout discipline is not
591 * WATCHDOG_NO_TIMEOUT. Timeout discipline and value are in the queue_context.
592 *
593 * The caller must be the owner of the thread queue lock.  This function will
594 * release the thread queue lock and register it as the new thread lock.
595 * Thread dispatching is disabled before the thread queue lock is released.
596 * Thread dispatching is enabled once the sequence to block the thread is
597 * complete.  The operation to enqueue the thread on the queue is protected by
598 * the thread queue lock.  This makes it possible to use the thread queue lock
599 * to protect the state of objects embedding the thread queue and directly
600 * enter _Thread_queue_Enqueue() in case the thread must block.
601 *
602 * The thread queue context must be set up with the following functions,
603 * otherwise the behaviour is unpredictable
604 *
605 * - _Thread_queue_Context_set_thread_state(),
606 *
607 * - _Thread_queue_Context_set_enqueue_callout() or
608 *   _Thread_queue_Context_set_do_nothing_enqueue_callout(),
609 *
610 * - _Thread_queue_Context_set_no_timeout() or
611 *   _Thread_queue_Context_set_relative_timeout() or
612 *   _Thread_queue_Context_set_absolute_timeout(), and
613 *
614 * - _Thread_queue_Context_set_deadlock_callout().
615 *
616 * @code
617 * #include <rtems/score/threadqimpl.h>
618 * #include <rtems/score/statesimpl.h>
619 *
620 * #define MUTEX_TQ_OPERATIONS &_Thread_queue_Operations_priority
621 *
622 * typedef struct {
623 *   Thread_queue_Control Queue;
624 * } Mutex;
625 *
626 * void _Mutex_Obtain( Mutex *mutex )
627 * {
628 *   Thread_queue_Context  queue_context;
629 *   Thread_Control       *executing;
630 *
631 *   _Thread_queue_Context_initialize( &queue_context );
632 *   _Thread_queue_Acquire( &mutex->Queue, queue_context );
633 *
634 *   executing = _Thread_Executing;
635 *
636 *   if ( mutex->Queue.owner == NULL ) {
637 *     mutex->Queue.owner = executing;
638 *     _Thread_queue_Release( &mutex->Queue, queue_context );
639 *   } else {
640 *     _Thread_queue_Context_set_thread_state(
641 *       &queue_context,
642 *       STATES_WAITING_FOR_MUTEX
643 *     );
644 *     _Thread_queue_Context_set_do_nothing_enqueue_callout( &queue_context );
645 *     _Thread_queue_Context_set_no_timeout( &queue_context );
646 *     _Thread_queue_Context_set_deadlock_callout(
647 *       queue_context,
648 *       _Thread_queue_Deadlock_fatal
649 *     );
650 *     _Thread_queue_Enqueue(
651 *       &mutex->Queue.Queue,
652 *       MUTEX_TQ_OPERATIONS,
653 *       executing,
654 *       &queue_context
655 *     );
656 *   }
657 * }
658 * @endcode
659 *
660 * @param[in] queue The actual thread queue.
661 * @param[in] operations The thread queue operations.
662 * @param[in] the_thread The thread to enqueue.
663 * @param[in] queue_context The thread queue context of the lock acquire.
664 */
665void _Thread_queue_Enqueue(
666  Thread_queue_Queue            *queue,
667  const Thread_queue_Operations *operations,
668  Thread_Control                *the_thread,
669  Thread_queue_Context          *queue_context
670);
671
672#if defined(RTEMS_SMP)
673/**
674 * @brief Enqueues the thread on the thread queue and busy waits for dequeue.
675 *
676 * Optionally starts the thread timer in case the timeout discipline is not
677 * WATCHDOG_NO_TIMEOUT. Timeout discipline and value are in the queue_context.
678 *
679 * The caller must be the owner of the thread queue lock.  This function will
680 * release the thread queue lock and register it as the new thread lock.
681 *
682 * The thread priorities of the owner and the are updated with respect to the
683 * scheduler.  The sticky level of the thread is incremented.  A thread
684 * dispatch is performed if necessary.
685 *
686 * Afterwards, the thread busy waits on the thread wait flags until a timeout
687 * occurs or the thread queue is surrendered to this thread.  So, it sticks to
688 * the processor instead of blocking with respect to the scheduler.
689 *
690 * @param[in] queue The actual thread queue.
691 * @param[in] operations The thread queue operations.
692 * @param[in] the_thread The thread to enqueue.
693 * @param[in] queue_context The thread queue context of the lock acquire.
694 */
695Status_Control _Thread_queue_Enqueue_sticky(
696  Thread_queue_Queue            *queue,
697  const Thread_queue_Operations *operations,
698  Thread_Control                *the_thread,
699  Thread_queue_Context          *queue_context
700);
701#endif
702
703/**
704 * @brief Extracts the thread from the thread queue, restores the default wait
705 * operations and restores the default thread lock.
706 *
707 * The caller must be the owner of the thread queue lock.  The thread queue
708 * lock is not released.
709 *
710 * @param[in] queue The actual thread queue.
711 * @param[in] operations The thread queue operations.
712 * @param[in] the_thread The thread to extract.
713 * @param[in] queue_context The thread queue context.
714 *
715 * @return Returns the unblock indicator for _Thread_queue_Unblock_critical().
716 * True indicates, that this thread must be unblocked by the scheduler later in
717 * _Thread_queue_Unblock_critical(), and false otherwise.  In case false is
718 * returned, then the thread queue enqueue procedure was interrupted.  Thus it
719 * will unblock itself and the thread wait information is no longer accessible,
720 * since this thread may already block on another resource in an SMP
721 * configuration.
722 */
723bool _Thread_queue_Extract_locked(
724  Thread_queue_Queue            *queue,
725  const Thread_queue_Operations *operations,
726  Thread_Control                *the_thread,
727  Thread_queue_Context          *queue_context
728);
729
730/**
731 * @brief Unblocks the thread which was on the thread queue before.
732 *
733 * The caller must be the owner of the thread queue lock.  This function will
734 * release the thread queue lock.  Thread dispatching is disabled before the
735 * thread queue lock is released and an unblock is necessary.  Thread
736 * dispatching is enabled once the sequence to unblock the thread is complete.
737 *
738 * @param[in] unblock The unblock indicator returned by
739 * _Thread_queue_Extract_locked().
740 * @param[in] queue The actual thread queue.
741 * @param[in] the_thread The thread to extract.
742 * @param[in] lock_context The lock context of the lock acquire.
743 */
744void _Thread_queue_Unblock_critical(
745  bool                unblock,
746  Thread_queue_Queue *queue,
747  Thread_Control     *the_thread,
748  ISR_lock_Context   *lock_context
749);
750
751/**
752 * @brief Extracts the thread from the thread queue and unblocks it.
753 *
754 * The caller must be the owner of the thread queue lock.  This function will
755 * release the thread queue lock and restore the default thread lock.  Thread
756 * dispatching is disabled before the thread queue lock is released and an
757 * unblock is necessary.  Thread dispatching is enabled once the sequence to
758 * unblock the thread is complete.  This makes it possible to use the thread
759 * queue lock to protect the state of objects embedding the thread queue and
760 * directly enter _Thread_queue_Extract_critical() to finalize an operation in
761 * case a waiting thread exists.
762 *
763 * @code
764 * #include <rtems/score/threadqimpl.h>
765 *
766 * typedef struct {
767 *   Thread_queue_Control  Queue;
768 *   Thread_Control       *owner;
769 * } Mutex;
770 *
771 * void _Mutex_Release( Mutex *mutex )
772 * {
773 *   Thread_queue_Context  queue_context;
774 *   Thread_Control       *first;
775 *
776 *   _Thread_queue_Context_initialize( &queue_context, NULL );
777 *   _Thread_queue_Acquire( &mutex->Queue, queue_context );
778 *
779 *   first = _Thread_queue_First_locked( &mutex->Queue );
780 *   mutex->owner = first;
781 *
782 *   if ( first != NULL ) {
783 *     _Thread_queue_Extract_critical(
784 *       &mutex->Queue.Queue,
785 *       mutex->Queue.operations,
786 *       first,
787 *       &queue_context
788 *   );
789 * }
790 * @endcode
791 *
792 * @param[in] queue The actual thread queue.
793 * @param[in] operations The thread queue operations.
794 * @param[in] the_thread The thread to extract.
795 * @param[in] queue_context The thread queue context of the lock acquire.
796 */
797void _Thread_queue_Extract_critical(
798  Thread_queue_Queue            *queue,
799  const Thread_queue_Operations *operations,
800  Thread_Control                *the_thread,
801  Thread_queue_Context          *queue_context
802);
803
804/**
805 *  @brief Extracts thread from thread queue.
806 *
807 *  This routine removes @a the_thread its thread queue
808 *  and cancels any timeouts associated with this blocking.
809 *
810 *  @param[in] the_thread is the pointer to a thread control block that
811 *      is to be removed
812 */
813void _Thread_queue_Extract( Thread_Control *the_thread );
814
815/**
816 *  @brief Extracts the_thread from the_thread_queue.
817 *
818 *  This routine extracts the_thread from the_thread_queue
819 *  and ensures that if there is a proxy for this task on
820 *  another node, it is also dealt with.
821 */
822void _Thread_queue_Extract_with_proxy(
823  Thread_Control       *the_thread
824);
825
826/**
827 * @brief Surrenders the thread queue previously owned by the thread to the
828 * first enqueued thread.
829 *
830 * The owner of the thread queue must be set to NULL by the caller.
831 *
832 * This function releases the thread queue lock.  In addition it performs a
833 * thread dispatch if necessary.
834 *
835 * @param[in] queue The actual thread queue.
836 * @param[in] heads The thread queue heads.  It must not be NULL.
837 * @param[in] previous_owner The previous owner thread surrendering the thread
838 *   queue.
839 * @param[in] queue_context The thread queue context of the lock acquire.
840 * @param[in] operations The thread queue operations.
841 */
842void _Thread_queue_Surrender(
843  Thread_queue_Queue            *queue,
844  Thread_queue_Heads            *heads,
845  Thread_Control                *previous_owner,
846  Thread_queue_Context          *queue_context,
847  const Thread_queue_Operations *operations
848);
849
850#if defined(RTEMS_SMP)
851/**
852 * @brief Surrenders the thread queue previously owned by the thread to the
853 * first enqueued thread.
854 *
855 * The owner of the thread queue must be set to NULL by the caller.
856 *
857 * The caller must be the owner of the thread queue lock.  This function will
858 * release the thread queue.
859 *
860 * The thread priorities of the previous owner and the new owner are updated.  The
861 * sticky level of the previous owner is decremented.  A thread dispatch is
862 * performed if necessary.
863 *
864 * @param[in] queue The actual thread queue.
865 * @param[in] heads The thread queue heads.  It must not be NULL.
866 * @param[in] previous_owner The previous owner thread surrendering the thread
867 *   queue.
868 * @param[in] queue_context The thread queue context of the lock acquire.
869 * @param[in] operations The thread queue operations.
870 */
871void _Thread_queue_Surrender_sticky(
872  Thread_queue_Queue            *queue,
873  Thread_queue_Heads            *heads,
874  Thread_Control                *previous_owner,
875  Thread_queue_Context          *queue_context,
876  const Thread_queue_Operations *operations
877);
878#endif
879
880RTEMS_INLINE_ROUTINE bool _Thread_queue_Is_empty(
881  const Thread_queue_Queue *queue
882)
883{
884  return queue->heads == NULL;
885}
886
887/**
888 * @brief Returns the first thread on the thread queue if it exists, otherwise
889 * @c NULL.
890 *
891 * The caller must be the owner of the thread queue lock.  The thread queue
892 * lock is not released.
893 *
894 * @param[in] the_thread_queue The thread queue.
895 * @param[in] operations The thread queue operations.
896 *
897 * @retval NULL No thread is present on the thread queue.
898 * @retval first The first thread on the thread queue according to the enqueue
899 * order.
900 */
901RTEMS_INLINE_ROUTINE Thread_Control *_Thread_queue_First_locked(
902  Thread_queue_Control          *the_thread_queue,
903  const Thread_queue_Operations *operations
904)
905{
906  Thread_queue_Heads *heads = the_thread_queue->Queue.heads;
907
908  if ( heads != NULL ) {
909    return ( *operations->first )( heads );
910  } else {
911    return NULL;
912  }
913}
914
915/**
916 * @brief Returns the first thread on the thread queue if it exists, otherwise
917 * @c NULL.
918 *
919 * @param[in] the_thread_queue The thread queue.
920 *
921 * @retval NULL No thread is present on the thread queue.
922 * @retval first The first thread on the thread queue according to the enqueue
923 * order.
924 */
925Thread_Control *_Thread_queue_First(
926  Thread_queue_Control          *the_thread_queue,
927  const Thread_queue_Operations *operations
928);
929
930/**
931 * @brief Thread queue flush filter function.
932 *
933 * Called under protection of the thread queue lock by
934 * _Thread_queue_Flush_critical() to optionally alter the thread wait
935 * information and control the iteration.
936 *
937 * @param the_thread The thread to extract.  This is the first parameter to
938 *   optimize for architectures that use the same register for the first
939 *   parameter and the return value.
940 * @param queue The actual thread queue.
941 * @param queue_context The thread queue context of the lock acquire.  May be
942 *   used to pass additional data to the filter function via an overlay
943 *   structure.  The filter function should not release or acquire the thread
944 *   queue lock.
945 *
946 * @retval the_thread Extract this thread.
947 * @retval NULL Do not extract this thread and stop the thread queue flush
948 *   operation.  Threads that are already extracted will complete the flush
949 *   operation.
950 */
951typedef Thread_Control *( *Thread_queue_Flush_filter )(
952  Thread_Control       *the_thread,
953  Thread_queue_Queue   *queue,
954  Thread_queue_Context *queue_context
955);
956
957/**
958 * @brief Default thread queue flush filter function.
959 *
960 * @param the_thread The thread to extract.
961 * @param queue Unused.
962 * @param queue_context Unused.
963 *
964 * @retval the_thread Extract this thread.
965 */
966Thread_Control *_Thread_queue_Flush_default_filter(
967  Thread_Control       *the_thread,
968  Thread_queue_Queue   *queue,
969  Thread_queue_Context *queue_context
970);
971
972/**
973 * @brief Status unavailable thread queue flush filter function.
974 *
975 * Sets the thread wait return code of the thread to STATUS_UNAVAILABLE.
976 *
977 * @param the_thread The thread to extract.
978 * @param queue Unused.
979 * @param queue_context Unused.
980 *
981 * @retval the_thread Extract this thread.
982 */
983Thread_Control *_Thread_queue_Flush_status_unavailable(
984  Thread_Control       *the_thread,
985  Thread_queue_Queue   *queue,
986  Thread_queue_Context *queue_context
987);
988
989/**
990 * @brief Status object was deleted thread queue flush filter function.
991 *
992 * Sets the thread wait return code of the thread to STATUS_OBJECT_WAS_DELETED
993 *
994 * @param the_thread The thread to extract.
995 * @param queue Unused.
996 * @param queue_context Unused.
997 *
998 * @retval the_thread Extract this thread.
999 */
1000Thread_Control *_Thread_queue_Flush_status_object_was_deleted(
1001  Thread_Control       *the_thread,
1002  Thread_queue_Queue   *queue,
1003  Thread_queue_Context *queue_context
1004);
1005
1006/**
1007 * @brief Unblocks all threads enqueued on the thread queue.
1008 *
1009 * This function iteratively extracts the first enqueued thread of the thread
1010 * queue until the thread queue is empty or the filter function indicates a
1011 * stop.  The thread timers of the extracted threads are cancelled.  The
1012 * extracted threads are unblocked.
1013 *
1014 * @param queue The actual thread queue.
1015 * @param operations The thread queue operations.
1016 * @param filter The filter functions is called for each thread to extract from
1017 *   the thread queue.  It may be used to alter the thread under protection of
1018 *   the thread queue lock, for example to set the thread wait return code.
1019 *   The return value of the filter function controls if the thread queue flush
1020 *   operation should stop or continue.
1021 * @param queue_context The thread queue context of the lock acquire.  May be
1022 *   used to pass additional data to the filter function via an overlay
1023 *   structure.  The filter function should not release or acquire the thread
1024 *   queue lock.
1025 *
1026 * @return The count of extracted threads.
1027 */
1028size_t _Thread_queue_Flush_critical(
1029  Thread_queue_Queue            *queue,
1030  const Thread_queue_Operations *operations,
1031  Thread_queue_Flush_filter      filter,
1032  Thread_queue_Context          *queue_context
1033);
1034
1035void _Thread_queue_Initialize(
1036  Thread_queue_Control *the_thread_queue,
1037  const char           *name
1038);
1039
1040#if defined(RTEMS_SMP) && defined(RTEMS_DEBUG) && defined(RTEMS_PROFILING)
1041  #define THREAD_QUEUE_INITIALIZER( _name ) \
1042    { \
1043      .Lock_stats = SMP_LOCK_STATS_INITIALIZER( _name ), \
1044      .owner = SMP_LOCK_NO_OWNER, \
1045      .Queue = { \
1046        .Lock = SMP_TICKET_LOCK_INITIALIZER, \
1047        .heads = NULL, \
1048        .owner = NULL, \
1049        .name = _name \
1050      } \
1051    }
1052#elif defined(RTEMS_SMP) && defined(RTEMS_DEBUG)
1053  #define THREAD_QUEUE_INITIALIZER( _name ) \
1054    { \
1055      .owner = SMP_LOCK_NO_OWNER, \
1056      .Queue = { \
1057        .Lock = SMP_TICKET_LOCK_INITIALIZER, \
1058        .heads = NULL, \
1059        .owner = NULL, \
1060        .name = _name \
1061      } \
1062    }
1063#elif defined(RTEMS_SMP) && defined(RTEMS_PROFILING)
1064  #define THREAD_QUEUE_INITIALIZER( _name ) \
1065    { \
1066      .Lock_stats = SMP_LOCK_STATS_INITIALIZER( _name ), \
1067      .Queue = { \
1068        .Lock = SMP_TICKET_LOCK_INITIALIZER, \
1069        .heads = NULL, \
1070        .owner = NULL, \
1071        .name = _name \
1072      } \
1073    }
1074#elif defined(RTEMS_SMP)
1075  #define THREAD_QUEUE_INITIALIZER( _name ) \
1076    { \
1077      .Queue = { \
1078        .Lock = SMP_TICKET_LOCK_INITIALIZER, \
1079        .heads = NULL, \
1080        .owner = NULL, \
1081        .name = _name \
1082      } \
1083    }
1084#else
1085  #define THREAD_QUEUE_INITIALIZER( _name ) \
1086    { \
1087      .Queue = { \
1088        .heads = NULL, \
1089        .owner = NULL, \
1090        .name = _name \
1091      } \
1092    }
1093#endif
1094
1095RTEMS_INLINE_ROUTINE void _Thread_queue_Destroy(
1096  Thread_queue_Control *the_thread_queue
1097)
1098{
1099#if defined(RTEMS_SMP)
1100  _SMP_ticket_lock_Destroy( &the_thread_queue->Queue.Lock );
1101  _SMP_lock_Stats_destroy( &the_thread_queue->Lock_stats );
1102#endif
1103}
1104
1105#if defined(RTEMS_MULTIPROCESSING)
1106void _Thread_queue_MP_callout_do_nothing(
1107  Thread_Control *the_proxy,
1108  Objects_Id      mp_id
1109);
1110
1111void _Thread_queue_Unblock_proxy(
1112  Thread_queue_Queue *queue,
1113  Thread_Control     *the_thread
1114);
1115#endif
1116
1117#if defined(RTEMS_SMP)
1118bool _Thread_queue_Path_acquire_critical(
1119  Thread_queue_Queue   *queue,
1120  Thread_Control       *the_thread,
1121  Thread_queue_Context *queue_context
1122);
1123
1124void _Thread_queue_Path_release_critical(
1125  Thread_queue_Context *queue_context
1126);
1127#endif
1128
1129/**
1130 * @brief Helper structure to ensure that all objects containing a thread queue
1131 * have the right layout.
1132 *
1133 * @see _Thread_Wait_get_id() and THREAD_QUEUE_OBJECT_ASSERT().
1134 */
1135typedef struct {
1136  Objects_Control      Object;
1137  Thread_queue_Control Wait_queue;
1138} Thread_queue_Object;
1139
1140#define THREAD_QUEUE_OBJECT_ASSERT( object_type, wait_queue_member ) \
1141  RTEMS_STATIC_ASSERT( \
1142    offsetof( object_type, wait_queue_member ) \
1143      == offsetof( Thread_queue_Object, Wait_queue ) \
1144    && RTEMS_HAVE_MEMBER_SAME_TYPE( \
1145      object_type, \
1146      wait_queue_member, \
1147      Thread_queue_Object, \
1148      Wait_queue \
1149    ), \
1150    object_type \
1151  )
1152
1153#define THREAD_QUEUE_QUEUE_TO_OBJECT( queue ) \
1154  RTEMS_CONTAINER_OF( \
1155    queue, \
1156    Thread_queue_Object, \
1157    Wait_queue.Queue \
1158  )
1159
1160extern const Thread_queue_Operations _Thread_queue_Operations_default;
1161
1162extern const Thread_queue_Operations _Thread_queue_Operations_FIFO;
1163
1164extern const Thread_queue_Operations _Thread_queue_Operations_priority;
1165
1166extern const Thread_queue_Operations _Thread_queue_Operations_priority_inherit;
1167
1168/**
1169 * @brief The special thread queue name to indicated that the thread queue is
1170 * embedded in an object with identifier.
1171 *
1172 * @see _Thread_queue_Object_initialize().
1173 */
1174extern const char _Thread_queue_Object_name[];
1175
1176/**
1177 * @brief Initializes a thread queue embedded in an object with identifier.
1178 *
1179 * The object must have the layout specified by Thread_queue_Object.  It should
1180 * be ensured with the THREAD_QUEUE_OBJECT_ASSERT() static assertion.
1181 *
1182 * @param[in] the_thread_queue The thread queue.
1183 */
1184void _Thread_queue_Object_initialize(
1185  Thread_queue_Control *the_thread_queue
1186);
1187
1188/**@}*/
1189
1190#ifdef __cplusplus
1191}
1192#endif
1193
1194#endif
1195/* end of include file */
Note: See TracBrowser for help on using the repository browser.