source: rtems/cpukit/score/include/rtems/score/threadqimpl.h @ 0e3c59d6

5
Last change on this file since 0e3c59d6 was 0e3c59d6, checked in by Sebastian Huber <sebastian.huber@…>, on 06/26/15 at 10:54:33

score: Use a plain ticket lock for thread locks

This enables external libraries to use thread locks since they are
independent of the actual RTEMS build configuration, e.g. profiling
enabled or disabled.

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