source: rtems/cpukit/score/include/rtems/score/threadqimpl.h @ 9809d6e0

5
Last change on this file since 9809d6e0 was 9809d6e0, checked in by Sebastian Huber <sebastian.huber@…>, on 03/30/16 at 09:39:58

score: _Thread_queue_Flush() parameter changes

Change _Thread_queue_Flush() into a macro that invokes
_Thread_queue_Do_flush() with the parameter set defined by
RTEMS_MULTIPROCESSING. For multiprocessing configurations add the
object identifier to avoid direct use of the thread wait information.

Use mp_ prefix for multiprocessing related parameters.

Rename Thread_queue_Flush_callout to Thread_queue_MP_callout since this
type will be re-used later for other operations as well.

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