source: rtems/cpukit/score/include/rtems/score/threadqimpl.h @ 12f93fbb

5
Last change on this file since 12f93fbb was 12f93fbb, checked in by Sebastian Huber <sebastian.huber@…>, on 07/27/15 at 11:19:17

score: Add thread queue for self-contained objects

  • Property mode set to 100644
File size: 15.6 KB
RevLine 
[a112364]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/*
[ed7a028]11 *  COPYRIGHT (c) 1989-2014.
[a112364]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
[c499856]16 *  http://www.rtems.org/license/LICENSE.
[a112364]17 */
18
19#ifndef _RTEMS_SCORE_THREADQIMPL_H
20#define _RTEMS_SCORE_THREADQIMPL_H
21
22#include <rtems/score/threadq.h>
[d8752860]23#include <rtems/score/chainimpl.h>
24#include <rtems/score/rbtreeimpl.h>
[a112364]25#include <rtems/score/thread.h>
26
27#ifdef __cplusplus
28extern "C" {
29#endif
30
31/**
32 *  @addtogroup ScoreThreadQueue
33 */
34/**@{*/
35
[12f93fbb]36/**
37 * @brief Thread queue with a layout compatible to struct _Thread_queue_Queue
38 * defined in Newlib <sys/lock.h>.
39 */
40typedef struct {
41  Thread_queue_Queue Queue;
42
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} Thread_queue_Syslock_queue;
53
[d7665823]54RTEMS_INLINE_ROUTINE void _Thread_queue_Queue_initialize(
55  Thread_queue_Queue *queue
56)
57{
58  queue->heads = NULL;
[0e3c59d6]59#if defined(RTEMS_SMP)
60  _SMP_ticket_lock_Initialize( &queue->Lock );
61#endif
[d7665823]62}
63
[0e3c59d6]64RTEMS_INLINE_ROUTINE void _Thread_queue_Queue_do_acquire_critical(
[e2735012]65  Thread_queue_Queue *queue,
[0e3c59d6]66#if defined(RTEMS_SMP) && defined(RTEMS_PROFILING)
67  SMP_lock_Stats     *lock_stats,
68#endif
[e2735012]69  ISR_lock_Context   *lock_context
70)
71{
[0e3c59d6]72#if defined(RTEMS_SMP)
73  _SMP_ticket_lock_Acquire(
74    &queue->Lock,
75    lock_stats,
76    &lock_context->Lock_context.Stats_context
77  );
78#else
79  (void) queue;
80  (void) lock_context;
81#endif
[e2735012]82}
83
[0e3c59d6]84#if defined(RTEMS_SMP) && defined( RTEMS_PROFILING )
85  #define \
86    _Thread_queue_Queue_acquire_critical( queue, lock_stats, lock_context ) \
87    _Thread_queue_Queue_do_acquire_critical( queue, lock_stats, lock_context )
88#else
89  #define \
90    _Thread_queue_Queue_acquire_critical( queue, lock_stats, lock_context ) \
91    _Thread_queue_Queue_do_acquire_critical( queue, lock_context )
92#endif
93
[e2735012]94RTEMS_INLINE_ROUTINE void _Thread_queue_Queue_release(
95  Thread_queue_Queue *queue,
96  ISR_lock_Context   *lock_context
97)
98{
[0e3c59d6]99#if defined(RTEMS_SMP)
100  _SMP_ticket_lock_Release(
101    &queue->Lock,
102    &lock_context->Lock_context.Stats_context
103  );
104#endif
105  _ISR_lock_ISR_enable( lock_context );
[e2735012]106}
107
[02c4c441]108RTEMS_INLINE_ROUTINE void _Thread_queue_Acquire_critical(
109  Thread_queue_Control *the_thread_queue,
110  ISR_lock_Context     *lock_context
111)
112{
[e2735012]113  _Thread_queue_Queue_acquire_critical(
114    &the_thread_queue->Queue,
[0e3c59d6]115    &the_thread_queue->Lock_stats,
[e2735012]116    lock_context
117  );
[02c4c441]118}
119
120RTEMS_INLINE_ROUTINE void _Thread_queue_Acquire(
121  Thread_queue_Control *the_thread_queue,
122  ISR_lock_Context     *lock_context
123)
124{
125  _ISR_lock_ISR_disable( lock_context );
126  _Thread_queue_Acquire_critical( the_thread_queue, lock_context );
127}
128
129RTEMS_INLINE_ROUTINE void _Thread_queue_Release(
130  Thread_queue_Control *the_thread_queue,
131  ISR_lock_Context     *lock_context
132)
133{
[0e3c59d6]134  _Thread_queue_Queue_release(
135    &the_thread_queue->Queue,
136    lock_context
137  );
[02c4c441]138}
139
[a112364]140/**
141 *  The following type defines the callout used when a remote task
142 *  is extracted from a local thread queue.
143 */
144typedef void ( *Thread_queue_Flush_callout )(
145                  Thread_Control *
146             );
147
148/**
149 *  @brief Gets a pointer to a thread waiting on the_thread_queue.
150 *
151 *  This function returns a pointer to a thread waiting on
152 *  the_thread_queue.  The selection of this thread is based on
153 *  the discipline of the_thread_queue.  If no threads are waiting
154 *  on the_thread_queue, then NULL is returned.
[3250664]155 *
156 *  - INTERRUPT LATENCY:
157 *    + single case
[a112364]158 */
159Thread_Control *_Thread_queue_Dequeue(
160  Thread_queue_Control *the_thread_queue
161);
162
163/**
[cc366ec]164 * @brief Blocks the thread and places it on the thread queue.
[a112364]165 *
[cc366ec]166 * This enqueues the thread on the thread queue, blocks the thread, and
167 * optionally starts the thread timer in case the timeout interval is not
168 * WATCHDOG_NO_TIMEOUT.
[a112364]169 *
[02c4c441]170 * The caller must be the owner of the thread queue lock.  This function will
171 * release the thread queue lock and register it as the new thread lock.
[cc366ec]172 * Thread dispatching is disabled before the thread queue lock is released.
173 * Thread dispatching is enabled once the sequence to block the thread is
174 * complete.  The operation to enqueue the thread on the queue is protected by
175 * the thread queue lock.  This makes it possible to use the thread queue lock
176 * to protect the state of objects embedding the thread queue and directly
177 * enter _Thread_queue_Enqueue_critical() in case the thread must block.
178 *
179 * @code
180 * #include <rtems/score/threadqimpl.h>
181 * #include <rtems/score/statesimpl.h>
182 *
183 * typedef struct {
184 *   Thread_queue_Control  Queue;
185 *   Thread_Control       *owner;
186 * } Mutex;
187 *
188 * void _Mutex_Obtain( Mutex *mutex )
189 * {
190 *   ISR_lock_Context  lock_context;
191 *   Thread_Control   *executing;
192 *
193 *   _Thread_queue_Acquire( &mutex->Queue, &lock_context );
194 *
195 *   executing = _Thread_Executing;
196 *
197 *   if ( mutex->owner == NULL ) {
198 *     mutex->owner = executing;
199 *     _Thread_queue_Release( &mutex->Queue, &lock_context );
200 *   } else {
201 *     _Thread_queue_Enqueue_critical(
[e2735012]202 *       &mutex->Queue.Queue,
203 *       mutex->Queue.operations,
[cc366ec]204 *       executing,
205 *       STATES_WAITING_FOR_MUTEX,
206 *       WATCHDOG_NO_TIMEOUT,
207 *       0,
208 *       &lock_context
209 *     );
210 *   }
211 * }
212 * @endcode
[a112364]213 *
[e2735012]214 * @param[in] queue The actual thread queue.
215 * @param[in] operations The thread queue operations.
[02c4c441]216 * @param[in] the_thread The thread to enqueue.
217 * @param[in] state The new state of the thread.
218 * @param[in] timeout Interval to wait.  Use WATCHDOG_NO_TIMEOUT to block
219 * potentially forever.
[f5d6c8b]220 * @param[in] timeout_code The return code in case a timeout occurs.
[02c4c441]221 * @param[in] lock_context The lock context of the lock acquire.
[a112364]222 */
[02c4c441]223void _Thread_queue_Enqueue_critical(
[e2735012]224  Thread_queue_Queue            *queue,
225  const Thread_queue_Operations *operations,
226  Thread_Control                *the_thread,
227  States_Control                 state,
228  Watchdog_Interval              timeout,
229  uint32_t                       timeout_code,
230  ISR_lock_Context              *lock_context
[a112364]231);
232
[cc366ec]233/**
234 * @brief Acquires the thread queue lock and calls
235 * _Thread_queue_Enqueue_critical().
236 */
[02c4c441]237RTEMS_INLINE_ROUTINE void _Thread_queue_Enqueue(
238  Thread_queue_Control *the_thread_queue,
239  Thread_Control       *the_thread,
240  States_Control        state,
[f5d6c8b]241  Watchdog_Interval     timeout,
242  uint32_t              timeout_code
[02c4c441]243)
244{
245  ISR_lock_Context lock_context;
246
247  _Thread_queue_Acquire( the_thread_queue, &lock_context );
248  _Thread_queue_Enqueue_critical(
[e2735012]249    &the_thread_queue->Queue,
250    the_thread_queue->operations,
[02c4c441]251    the_thread,
252    state,
253    timeout,
[f5d6c8b]254    timeout_code,
[02c4c441]255    &lock_context
256  );
257}
258
[a112364]259/**
[cc366ec]260 * @brief Extracts the thread from the thread queue, restores the default wait
261 * operations and restores the default thread lock.
[a112364]262 *
[cc366ec]263 * The caller must be the owner of the thread queue lock.  The thread queue
264 * lock is not released.
[a112364]265 *
[e2735012]266 * @param[in] queue The actual thread queue.
267 * @param[in] operations The thread queue operations.
[cc366ec]268 * @param[in] the_thread The thread to extract.
[e709aa85]269 *
270 * @return Returns the unblock indicator for _Thread_queue_Unblock_critical().
271 * True indicates, that this thread must be unblocked by the scheduler later in
272 * _Thread_queue_Unblock_critical(), and false otherwise.  In case false is
273 * returned, then the thread queue enqueue procedure was interrupted.  Thus it
274 * will unblock itself and the thread wait information is no longer accessible,
275 * since this thread may already block on another resource in an SMP
276 * configuration.
[a112364]277 */
[e709aa85]278bool _Thread_queue_Extract_locked(
[e2735012]279  Thread_queue_Queue            *queue,
280  const Thread_queue_Operations *operations,
281  Thread_Control                *the_thread
[cc366ec]282);
283
284/**
285 * @brief Unblocks the thread which was on the thread queue before.
286 *
287 * The caller must be the owner of the thread queue lock.  This function will
288 * release the thread queue lock.  Thread dispatching is disabled before the
289 * thread queue lock is released and an unblock is necessary.  Thread
290 * dispatching is enabled once the sequence to unblock the thread is complete.
291 *
[e709aa85]292 * @param[in] unblock The unblock indicator returned by
293 * _Thread_queue_Extract_locked().
[e2735012]294 * @param[in] queue The actual thread queue.
[cc366ec]295 * @param[in] the_thread The thread to extract.
296 * @param[in] lock_context The lock context of the lock acquire.
297 */
298void _Thread_queue_Unblock_critical(
[e709aa85]299  bool                unblock,
[e2735012]300  Thread_queue_Queue *queue,
301  Thread_Control     *the_thread,
302  ISR_lock_Context   *lock_context
[cc366ec]303);
304
305/**
306 * @brief Extracts the thread from the thread queue and unblocks it.
307 *
308 * The caller must be the owner of the thread queue lock.  This function will
309 * release the thread queue lock and restore the default thread lock.  Thread
310 * dispatching is disabled before the thread queue lock is released and an
311 * unblock is necessary.  Thread dispatching is enabled once the sequence to
312 * unblock the thread is complete.  This makes it possible to use the thread
313 * queue lock to protect the state of objects embedding the thread queue and
314 * directly enter _Thread_queue_Extract_critical() to finalize an operation in
315 * case a waiting thread exists.
316 *
317 * @code
318 * #include <rtems/score/threadqimpl.h>
319 *
320 * typedef struct {
321 *   Thread_queue_Control  Queue;
322 *   Thread_Control       *owner;
323 * } Mutex;
324 *
325 * void _Mutex_Release( Mutex *mutex )
326 * {
327 *   ISR_lock_Context  lock_context;
328 *   Thread_Control   *first;
329 *
330 *   _Thread_queue_Acquire( &mutex->Queue, &lock_context );
331 *
332 *   first = _Thread_queue_First_locked( &mutex->Queue );
333 *   mutex->owner = first;
334 *
335 *   if ( first != NULL ) {
336 *     _Thread_queue_Extract_critical(
[e2735012]337 *       &mutex->Queue.Queue,
338 *       mutex->Queue.operations,
[cc366ec]339 *       first,
340 *       &lock_context
341 *   );
342 * }
343 * @endcode
344 *
[e2735012]345 * @param[in] queue The actual thread queue.
346 * @param[in] operations The thread queue operations.
[cc366ec]347 * @param[in] the_thread The thread to extract.
348 * @param[in] lock_context The lock context of the lock acquire.
349 */
350void _Thread_queue_Extract_critical(
[e2735012]351  Thread_queue_Queue            *queue,
352  const Thread_queue_Operations *operations,
353  Thread_Control                *the_thread,
354  ISR_lock_Context              *lock_context
[cc366ec]355);
[a112364]356
[ed7a028]357/**
[cc366ec]358 *  @brief Extracts thread from thread queue.
[ed7a028]359 *
[22788bc]360 *  This routine removes @a the_thread its thread queue
[ed7a028]361 *  and cancels any timeouts associated with this blocking.
362 *
363 *  @param[in] the_thread is the pointer to a thread control block that
364 *      is to be removed
365 */
[cc366ec]366void _Thread_queue_Extract( Thread_Control *the_thread );
[91e7b0c]367
[a112364]368/**
369 *  @brief Extracts the_thread from the_thread_queue.
370 *
371 *  This routine extracts the_thread from the_thread_queue
372 *  and ensures that if there is a proxy for this task on
373 *  another node, it is also dealt with.
374 */
[600bb68f]375void _Thread_queue_Extract_with_proxy(
[a112364]376  Thread_Control       *the_thread
377);
378
379/**
[02c4c441]380 * @brief Returns the first thread on the thread queue if it exists, otherwise
[cc366ec]381 * @c NULL.
[02c4c441]382 *
[cc366ec]383 * The caller must be the owner of the thread queue lock.  The thread queue
384 * lock is not released.
[02c4c441]385 *
386 * @param[in] the_thread_queue The thread queue.
[a112364]387 *
[02c4c441]388 * @retval NULL No thread is present on the thread queue.
389 * @retval first The first thread on the thread queue according to the enqueue
390 * order.
391 */
[cc366ec]392RTEMS_INLINE_ROUTINE Thread_Control *_Thread_queue_First_locked(
[02c4c441]393  Thread_queue_Control *the_thread_queue
[cc366ec]394)
395{
[d7665823]396  Thread_queue_Heads *heads = the_thread_queue->Queue.heads;
397
398  if ( heads != NULL ) {
399    return ( *the_thread_queue->operations->first )( heads );
400  } else {
401    return NULL;
402  }
[cc366ec]403}
[02c4c441]404
405/**
406 * @brief Returns the first thread on the thread queue if it exists, otherwise
407 * @c NULL.
[a112364]408 *
[02c4c441]409 * @param[in] the_thread_queue The thread queue.
[a112364]410 *
[02c4c441]411 * @retval NULL No thread is present on the thread queue.
412 * @retval first The first thread on the thread queue according to the enqueue
413 * order.
[a112364]414 */
415Thread_Control *_Thread_queue_First(
416  Thread_queue_Control *the_thread_queue
417);
418
419/**
420 *  @brief Unblocks all threads blocked on the_thread_queue.
421 *
422 *  This routine unblocks all threads blocked on the_thread_queue
423 *  and cancels any associated timeouts.
424 *
425 *  @param[in] the_thread_queue is the pointer to a threadq header
426 *  @param[in] remote_extract_callout points to a method to invoke to
427 *             invoke when a remote thread is unblocked
428 *  @param[in] status is the status which will be returned to
429 *             all unblocked threads
430 */
431void _Thread_queue_Flush(
432  Thread_queue_Control       *the_thread_queue,
433  Thread_queue_Flush_callout  remote_extract_callout,
434  uint32_t                    status
435);
436
437/**
438 *  @brief Initialize the_thread_queue.
439 *
440 *  This routine initializes the_thread_queue based on the
441 *  discipline indicated in attribute_set.  The state set on
442 *  threads which block on the_thread_queue is state.
443 *
444 *  @param[in] the_thread_queue is the pointer to a threadq header
445 *  @param[in] the_discipline is the queueing discipline
446 */
447void _Thread_queue_Initialize(
[f5d6c8b]448  Thread_queue_Control     *the_thread_queue,
449  Thread_queue_Disciplines  the_discipline
[a112364]450);
451
[0e3c59d6]452#if defined(RTEMS_SMP) && defined(RTEMS_PROFILING)
453  #define THREAD_QUEUE_FIFO_INITIALIZER( designator, name ) { \
454      .Queue = { \
455        .heads = NULL, \
456        .Lock = SMP_TICKET_LOCK_INITIALIZER, \
457      }, \
458      .Lock_stats = SMP_LOCK_STATS_INITIALIZER( name ), \
459      .operations = &_Thread_queue_Operations_FIFO \
460    }
461
462  #define THREAD_QUEUE_PRIORITY_INITIALIZER( designator, name ) { \
463      .Queue = { \
464        .heads = NULL, \
465        .Lock = SMP_TICKET_LOCK_INITIALIZER, \
466      }, \
467      .Lock_stats = SMP_LOCK_STATS_INITIALIZER( name ), \
468      .operations = &_Thread_queue_Operations_priority \
469    }
470#elif defined(RTEMS_SMP)
[d8752860]471  #define THREAD_QUEUE_FIFO_INITIALIZER( designator, name ) { \
[e2735012]472      .Queue = { \
[d7665823]473        .heads = NULL, \
[0e3c59d6]474        .Lock = SMP_TICKET_LOCK_INITIALIZER, \
[d8752860]475      }, \
[e2735012]476      .operations = &_Thread_queue_Operations_FIFO \
[d8752860]477    }
478
[9341773]479  #define THREAD_QUEUE_PRIORITY_INITIALIZER( designator, name ) { \
[e2735012]480      .Queue = { \
[d7665823]481        .heads = NULL, \
[0e3c59d6]482        .Lock = SMP_TICKET_LOCK_INITIALIZER, \
[d8752860]483      }, \
[e2735012]484      .operations = &_Thread_queue_Operations_priority \
[d8752860]485    }
486#else
487  #define THREAD_QUEUE_FIFO_INITIALIZER( designator, name ) { \
[d7665823]488      .Queue = { .heads = NULL }, \
[d8752860]489      .operations = &_Thread_queue_Operations_FIFO \
490    }
491
[9341773]492  #define THREAD_QUEUE_PRIORITY_INITIALIZER( designator, name ) { \
[d7665823]493      .Queue = { .heads = NULL }, \
[d8752860]494      .operations = &_Thread_queue_Operations_priority \
495    }
496#endif
497
[02c4c441]498RTEMS_INLINE_ROUTINE void _Thread_queue_Destroy(
499  Thread_queue_Control *the_thread_queue
500)
501{
[0e3c59d6]502#if defined(RTEMS_SMP)
503  _SMP_ticket_lock_Destroy( &the_thread_queue->Queue.Lock );
504  _SMP_lock_Stats_destroy( &the_thread_queue->Lock_stats );
505#endif
[02c4c441]506}
507
[a112364]508/**
[ed7a028]509 * @brief Compare two thread's priority for RBTree Insertion.
510 *
511 * @param[in] left points to the left thread's RBnode
512 * @param[in] right points to the right thread's RBnode
513 *
[e0eb07a]514 * @retval 1 The @a left node is more important than @a right node.
515 * @retval 0 The @a left node is of equal importance with @a right node.
516 * @retval 1 The @a left node is less important than @a right node.
[a112364]517 */
[60fe374]518RBTree_Compare_result _Thread_queue_Compare_priority(
[ed7a028]519  const RBTree_Node *left,
520  const RBTree_Node *right
521);
[a112364]522
[568af83]523extern const Thread_queue_Operations _Thread_queue_Operations_default;
524
525extern const Thread_queue_Operations _Thread_queue_Operations_FIFO;
526
527extern const Thread_queue_Operations _Thread_queue_Operations_priority;
528
[a112364]529/**@}*/
530
531#ifdef __cplusplus
532}
533#endif
534
535#endif
536/* end of include file */
Note: See TracBrowser for help on using the repository browser.