source: rtems/cpukit/include/rtems/score/threadqimpl.h @ 1d39e96

5
Last change on this file since 1d39e96 was 1d39e96, checked in by Sebastian Huber <sebastian.huber@…>, on 10/05/18 at 06:11:09

score: Fix legacy RTEMS_STATIC_ASSERT()

In standard C pointer operands are not allowed in integer constant
expressions. Avoid a static assertion based on an array typedef since
this could lead to warnings ("variably modified 'x' at file scope" and
"typedef 'x' locally defined but not used");

This implementation requires unique messages.

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