source: rtems/cpukit/score/include/rtems/score/threadqimpl.h @ 7f616dd

5
Last change on this file since 7f616dd was 059529e, checked in by Sebastian Huber <sebastian.huber@…>, on 07/21/16 at 08:15:02

score: Add debug support to chains

This helps to detect

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