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

5
Last change on this file since db3a3de was db3a3de, checked in by Sebastian Huber <sebastian.huber@…>, on 10/10/17 at 08:03:48

score: Add _Thread_queue_Dispatch_disable()

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