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

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

score: Add thread queue for self-contained objects

  • Property mode set to 100644
File size: 15.6 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/thread.h>
26
27#ifdef __cplusplus
28extern "C" {
29#endif
30
31/**
32 *  @addtogroup ScoreThreadQueue
33 */
34/**@{*/
35
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
54RTEMS_INLINE_ROUTINE void _Thread_queue_Queue_initialize(
55  Thread_queue_Queue *queue
56)
57{
58  queue->heads = NULL;
59#if defined(RTEMS_SMP)
60  _SMP_ticket_lock_Initialize( &queue->Lock );
61#endif
62}
63
64RTEMS_INLINE_ROUTINE void _Thread_queue_Queue_do_acquire_critical(
65  Thread_queue_Queue *queue,
66#if defined(RTEMS_SMP) && defined(RTEMS_PROFILING)
67  SMP_lock_Stats     *lock_stats,
68#endif
69  ISR_lock_Context   *lock_context
70)
71{
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
82}
83
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
94RTEMS_INLINE_ROUTINE void _Thread_queue_Queue_release(
95  Thread_queue_Queue *queue,
96  ISR_lock_Context   *lock_context
97)
98{
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 );
106}
107
108RTEMS_INLINE_ROUTINE void _Thread_queue_Acquire_critical(
109  Thread_queue_Control *the_thread_queue,
110  ISR_lock_Context     *lock_context
111)
112{
113  _Thread_queue_Queue_acquire_critical(
114    &the_thread_queue->Queue,
115    &the_thread_queue->Lock_stats,
116    lock_context
117  );
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{
134  _Thread_queue_Queue_release(
135    &the_thread_queue->Queue,
136    lock_context
137  );
138}
139
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.
155 *
156 *  - INTERRUPT LATENCY:
157 *    + single case
158 */
159Thread_Control *_Thread_queue_Dequeue(
160  Thread_queue_Control *the_thread_queue
161);
162
163/**
164 * @brief Blocks the thread and places it on the thread queue.
165 *
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.
169 *
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.
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(
202 *       &mutex->Queue.Queue,
203 *       mutex->Queue.operations,
204 *       executing,
205 *       STATES_WAITING_FOR_MUTEX,
206 *       WATCHDOG_NO_TIMEOUT,
207 *       0,
208 *       &lock_context
209 *     );
210 *   }
211 * }
212 * @endcode
213 *
214 * @param[in] queue The actual thread queue.
215 * @param[in] operations The thread queue operations.
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.
220 * @param[in] timeout_code The return code in case a timeout occurs.
221 * @param[in] lock_context The lock context of the lock acquire.
222 */
223void _Thread_queue_Enqueue_critical(
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
231);
232
233/**
234 * @brief Acquires the thread queue lock and calls
235 * _Thread_queue_Enqueue_critical().
236 */
237RTEMS_INLINE_ROUTINE void _Thread_queue_Enqueue(
238  Thread_queue_Control *the_thread_queue,
239  Thread_Control       *the_thread,
240  States_Control        state,
241  Watchdog_Interval     timeout,
242  uint32_t              timeout_code
243)
244{
245  ISR_lock_Context lock_context;
246
247  _Thread_queue_Acquire( the_thread_queue, &lock_context );
248  _Thread_queue_Enqueue_critical(
249    &the_thread_queue->Queue,
250    the_thread_queue->operations,
251    the_thread,
252    state,
253    timeout,
254    timeout_code,
255    &lock_context
256  );
257}
258
259/**
260 * @brief Extracts the thread from the thread queue, restores the default wait
261 * operations and restores the default thread lock.
262 *
263 * The caller must be the owner of the thread queue lock.  The thread queue
264 * lock is not released.
265 *
266 * @param[in] queue The actual thread queue.
267 * @param[in] operations The thread queue operations.
268 * @param[in] the_thread The thread to extract.
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.
277 */
278bool _Thread_queue_Extract_locked(
279  Thread_queue_Queue            *queue,
280  const Thread_queue_Operations *operations,
281  Thread_Control                *the_thread
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 *
292 * @param[in] unblock The unblock indicator returned by
293 * _Thread_queue_Extract_locked().
294 * @param[in] queue The actual thread queue.
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(
299  bool                unblock,
300  Thread_queue_Queue *queue,
301  Thread_Control     *the_thread,
302  ISR_lock_Context   *lock_context
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(
337 *       &mutex->Queue.Queue,
338 *       mutex->Queue.operations,
339 *       first,
340 *       &lock_context
341 *   );
342 * }
343 * @endcode
344 *
345 * @param[in] queue The actual thread queue.
346 * @param[in] operations The thread queue operations.
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(
351  Thread_queue_Queue            *queue,
352  const Thread_queue_Operations *operations,
353  Thread_Control                *the_thread,
354  ISR_lock_Context              *lock_context
355);
356
357/**
358 *  @brief Extracts thread from thread queue.
359 *
360 *  This routine removes @a the_thread its thread queue
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 */
366void _Thread_queue_Extract( Thread_Control *the_thread );
367
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 */
375void _Thread_queue_Extract_with_proxy(
376  Thread_Control       *the_thread
377);
378
379/**
380 * @brief Returns the first thread on the thread queue if it exists, otherwise
381 * @c NULL.
382 *
383 * The caller must be the owner of the thread queue lock.  The thread queue
384 * lock is not released.
385 *
386 * @param[in] the_thread_queue The thread queue.
387 *
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 */
392RTEMS_INLINE_ROUTINE Thread_Control *_Thread_queue_First_locked(
393  Thread_queue_Control *the_thread_queue
394)
395{
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  }
403}
404
405/**
406 * @brief Returns the first thread on the thread queue if it exists, otherwise
407 * @c NULL.
408 *
409 * @param[in] the_thread_queue The thread queue.
410 *
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.
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(
448  Thread_queue_Control     *the_thread_queue,
449  Thread_queue_Disciplines  the_discipline
450);
451
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)
471  #define THREAD_QUEUE_FIFO_INITIALIZER( designator, name ) { \
472      .Queue = { \
473        .heads = NULL, \
474        .Lock = SMP_TICKET_LOCK_INITIALIZER, \
475      }, \
476      .operations = &_Thread_queue_Operations_FIFO \
477    }
478
479  #define THREAD_QUEUE_PRIORITY_INITIALIZER( designator, name ) { \
480      .Queue = { \
481        .heads = NULL, \
482        .Lock = SMP_TICKET_LOCK_INITIALIZER, \
483      }, \
484      .operations = &_Thread_queue_Operations_priority \
485    }
486#else
487  #define THREAD_QUEUE_FIFO_INITIALIZER( designator, name ) { \
488      .Queue = { .heads = NULL }, \
489      .operations = &_Thread_queue_Operations_FIFO \
490    }
491
492  #define THREAD_QUEUE_PRIORITY_INITIALIZER( designator, name ) { \
493      .Queue = { .heads = NULL }, \
494      .operations = &_Thread_queue_Operations_priority \
495    }
496#endif
497
498RTEMS_INLINE_ROUTINE void _Thread_queue_Destroy(
499  Thread_queue_Control *the_thread_queue
500)
501{
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
506}
507
508/**
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 *
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.
517 */
518RBTree_Compare_result _Thread_queue_Compare_priority(
519  const RBTree_Node *left,
520  const RBTree_Node *right
521);
522
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
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.