source: rtems/cpukit/include/rtems/score/threadqimpl.h @ 2afb22b

5
Last change on this file since 2afb22b was 2afb22b, checked in by Chris Johns <chrisj@…>, on 12/23/17 at 07:18:56

Remove make preinstall

A speciality of the RTEMS build system was the make preinstall step. It
copied header files from arbitrary locations into the build tree. The
header files were included via the -Bsome/build/tree/path GCC command
line option.

This has at least seven problems:

  • The make preinstall step itself needs time and disk space.
  • Errors in header files show up in the build tree copy. This makes it hard for editors to open the right file to fix the error.
  • There is no clear relationship between source and build tree header files. This makes an audit of the build process difficult.
  • The visibility of all header files in the build tree makes it difficult to enforce API barriers. For example it is discouraged to use BSP-specifics in the cpukit.
  • An introduction of a new build system is difficult.
  • Include paths specified by the -B option are system headers. This may suppress warnings.
  • The parallel build had sporadic failures on some hosts.

This patch removes the make preinstall step. All installed header
files are moved to dedicated include directories in the source tree.
Let @RTEMS_CPU@ be the target architecture, e.g. arm, powerpc, sparc,
etc. Let @RTEMS_BSP_FAMILIY@ be a BSP family base directory, e.g.
erc32, imx, qoriq, etc.

The new cpukit include directories are:

  • cpukit/include
  • cpukit/score/cpu/@RTEMS_CPU@/include
  • cpukit/libnetworking

The new BSP include directories are:

  • bsps/include
  • bsps/@RTEMS_CPU@/include
  • bsps/@RTEMS_CPU@/@RTEMS_BSP_FAMILIY@/include

There are build tree include directories for generated files.

The include directory order favours the most general header file, e.g.
it is not possible to override general header files via the include path
order.

The "bootstrap -p" option was removed. The new "bootstrap -H" option
should be used to regenerate the "headers.am" files.

Update #3254.

  • 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 ) \
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    object_type \
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.