source: rtems/cpukit/score/include/rtems/score/threadq.h @ ff2e6c64

Last change on this file since ff2e6c64 was ff2e6c64, checked in by Sebastian Huber <sebastian.huber@…>, on Aug 2, 2016 at 9:26:56 AM

score: Fix and simplify thread wait locks

There was a subtile race condition in _Thread_queue_Do_extract_locked().
It must first update the thread wait flags and then restore the default
thread wait state. In the previous implementation this could lead under
rare timing conditions to an ineffective _Thread_Wait_tranquilize()
resulting to a corrupt system state.

Update #2556.

  • Property mode set to 100644
File size: 12.3 KB
Line 
1/**
2 *  @file
3 *
4 *  @brief Constants and Structures Needed to Declare a Thread Queue
5 *
6 *  This include file contains all the constants and structures
7 *  needed to declare a thread queue.
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_THREADQ_H
20#define _RTEMS_SCORE_THREADQ_H
21
22#include <rtems/score/chain.h>
23#include <rtems/score/isrlock.h>
24#include <rtems/score/object.h>
25#include <rtems/score/priority.h>
26#include <rtems/score/rbtree.h>
27#include <rtems/score/watchdog.h>
28
29#ifdef __cplusplus
30extern "C" {
31#endif
32
33/**
34 *  @defgroup ScoreThreadQueue Thread Queue Handler
35 *
36 *  @ingroup Score
37 *
38 *  This handler provides the capability to have threads block in
39 *  ordered sets. The sets may be ordered using the FIFO or priority
40 *  discipline.
41 */
42/**@{*/
43
44typedef struct _Thread_Control Thread_Control;
45
46typedef struct Thread_queue_Queue Thread_queue_Queue;
47
48typedef struct Thread_queue_Operations Thread_queue_Operations;
49
50typedef struct Thread_queue_Path Thread_queue_Path;
51
52/**
53 * @brief Thread queue deadlock callout.
54 *
55 * @param the_thread The thread that detected the deadlock.
56 *
57 * @see _Thread_queue_Context_set_deadlock_callout().
58 */
59typedef void ( *Thread_queue_Deadlock_callout )(
60  Thread_Control *the_thread
61);
62
63#if defined(RTEMS_MULTIPROCESSING)
64/**
65 * @brief Multiprocessing (MP) support callout for thread queue operations.
66 *
67 * @param the_proxy The thread proxy of the thread queue operation.  A thread
68 *   control is actually a thread proxy if and only if
69 *   _Objects_Is_local_id( the_proxy->Object.id ) is false.
70 * @param mp_id Object identifier of the object containing the thread queue.
71 *
72 * @see _Thread_queue_Context_set_MP_callout().
73 */
74typedef void ( *Thread_queue_MP_callout )(
75  Thread_Control *the_proxy,
76  Objects_Id      mp_id
77);
78#endif
79
80#if defined(RTEMS_SMP)
81/**
82 * @brief The thread queue gate is an SMP synchronization means.
83 *
84 * The gates are added to a list of requests.  A busy wait is performed to make
85 * sure that preceding requests are carried out.  Each predecessor notifies its
86 * successor about on request completion.
87 *
88 * @see _Thread_queue_Gate_add(), _Thread_queue_Gate_wait(), and
89 *   _Thread_queue_Gate_open().
90 */
91typedef struct {
92  Chain_Node Node;
93
94  Atomic_Uint go_ahead;
95} Thread_queue_Gate;
96#endif
97
98/**
99 * @brief Thread queue context for the thread queue methods.
100 *
101 * @see _Thread_queue_Context_initialize().
102 */
103typedef struct {
104  /**
105   * @brief The lock context for the thread queue acquire and release
106   * operations.
107   */
108  ISR_lock_Context Lock_context;
109
110  /**
111   * @brief The expected thread dispatch disable level for
112   * _Thread_queue_Enqueue_critical().
113   *
114   * In case the actual thread dispatch disable level is not equal to the
115   * expected level, then a fatal error occurs.
116   */
117  uint32_t expected_thread_dispatch_disable_level;
118
119  /**
120   * @brief The clock discipline for the interval timeout.
121   * Use WATCHDOG_NO_TIMEOUT to block indefinitely.
122   */
123  Watchdog_Discipline timeout_discipline;
124
125  /**
126   * @brief Interval to wait.
127   */
128  uint64_t timeout;
129
130  /**
131   * @brief Invoked in case of a detected deadlock.
132   *
133   * Must be initialized for _Thread_queue_Enqueue_critical() in case the
134   * thread queue may have an owner, e.g. for mutex objects.
135   *
136   * @see _Thread_queue_Context_set_deadlock_callout().
137   */
138  Thread_queue_Deadlock_callout deadlock_callout;
139
140#if defined(RTEMS_MULTIPROCESSING)
141  /**
142   * @brief Callout to unblock the thread in case it is actually a thread
143   * proxy.
144   *
145   * This field is only used on multiprocessing configurations.  Used by
146   * thread queue extract and unblock methods for objects with multiprocessing
147   * (MP) support.
148   *
149   * @see _Thread_queue_Context_set_MP_callout().
150   */
151  Thread_queue_MP_callout mp_callout;
152#endif
153
154#if defined(RTEMS_SMP)
155  /**
156   * @brief Data to support thread queue enqueue operations.
157   */
158  struct {
159    /**
160     * @brief Gate to synchronize thread wait lock requests.
161     *
162     * @see _Thread_Wait_acquire_critical() and _Thread_Wait_tranquilize().
163     */
164    Thread_queue_Gate Gate;
165
166    /**
167     * @brief The thread queue in case the thread is blocked on a thread queue.
168     */
169    Thread_queue_Queue *queue;
170  } Wait;
171#endif
172} Thread_queue_Context;
173
174#if defined(RTEMS_SMP)
175/**
176 * @brief A thread queue link from one thread to another specified by the
177 * thread queue owner and thread wait queue relationships.
178 */
179typedef struct {
180  /**
181   * @brief Node to register this link in the global thread queue links lookup
182   * tree.
183   */
184  RBTree_Node Registry_node;
185
186  /**
187   * @brief The source thread queue determined by the thread queue owner.
188   */
189  Thread_queue_Queue *source;
190
191  /**
192   * @brief The target thread queue determined by the thread wait queue of the
193   * source owner.
194   */
195  Thread_queue_Queue *target;
196
197  /**
198   * @brief Node to add this link to a thread queue path.
199   */
200  Chain_Node Path_node;
201
202  /**
203   * @brief The owner of this thread queue link.
204   */
205  Thread_Control *owner;
206
207  /**
208   * @brief The queue context used to acquire the thread wait lock of the
209   * owner.
210   */
211  Thread_queue_Context Queue_context;
212} Thread_queue_Link;
213#endif
214
215/**
216 * @brief Thread priority queue.
217 */
218typedef struct {
219#if defined(RTEMS_SMP)
220  /**
221   * @brief Node to enqueue this queue in the FIFO chain of the corresponding
222   * heads structure.
223   *
224   * @see Thread_queue_Heads::Heads::Fifo.
225   */
226  Chain_Node Node;
227#endif
228
229  /**
230   * @brief The actual thread priority queue.
231   */
232  RBTree_Control Queue;
233} Thread_queue_Priority_queue;
234
235/**
236 * @brief Thread queue heads.
237 *
238 * Each thread is equipped with spare thread queue heads in case it is not
239 * enqueued on a thread queue.  The first thread enqueued on a thread queue
240 * will give its spare thread queue heads to that thread queue.  The threads
241 * arriving at the queue will add their thread queue heads to the free chain of
242 * the queue heads provided by the first thread enqueued.  Once a thread is
243 * dequeued it use the free chain to get new spare thread queue heads.
244 *
245 * Uses a leading underscore in the structure name to allow forward
246 * declarations in standard header files provided by Newlib and GCC.
247 */
248typedef struct _Thread_queue_Heads {
249  /** This union contains the data structures used to manage the blocked
250   *  set of tasks which varies based upon the discipline.
251   */
252  union {
253    /**
254     * @brief This is the FIFO discipline list.
255     *
256     * On SMP configurations this FIFO is used to enqueue the per scheduler
257     * instance priority queues of this structure.  This ensures FIFO fairness
258     * among the highest priority thread of each scheduler instance.
259     */
260    Chain_Control Fifo;
261
262#if !defined(RTEMS_SMP)
263    /**
264     * @brief This is the set of threads for priority discipline waiting.
265     */
266    Thread_queue_Priority_queue Priority;
267#endif
268  } Heads;
269
270  /**
271   * @brief A chain with free thread queue heads providing the spare thread
272   * queue heads for a thread once it is dequeued.
273   */
274  Chain_Control Free_chain;
275
276  /**
277   * @brief A chain node to add these thread queue heads to the free chain of
278   * the thread queue heads dedicated to the thread queue of an object.
279   */
280  Chain_Node Free_node;
281
282#if defined(RTEMS_SMP)
283  /**
284   * @brief One priority queue per scheduler instance.
285   */
286  Thread_queue_Priority_queue Priority[ RTEMS_ZERO_LENGTH_ARRAY ];
287#endif
288} Thread_queue_Heads;
289
290#if defined(RTEMS_SMP)
291  #define THREAD_QUEUE_HEADS_SIZE( scheduler_count ) \
292    ( sizeof( Thread_queue_Heads ) \
293      + ( scheduler_count ) * sizeof( Thread_queue_Priority_queue ) )
294#else
295  #define THREAD_QUEUE_HEADS_SIZE( scheduler_count ) \
296    sizeof( Thread_queue_Heads )
297#endif
298
299struct Thread_queue_Queue {
300  /**
301   * @brief Lock to protect this thread queue.
302   *
303   * It may be used to protect additional state of the object embedding this
304   * thread queue.
305   *
306   * Must be the first component of this structure to be able to re-use
307   * implementation parts for structures defined by Newlib <sys/lock.h>.
308   *
309   * @see _Thread_queue_Acquire(), _Thread_queue_Acquire_critical() and
310   * _Thread_queue_Release().
311   */
312#if defined(RTEMS_SMP)
313  SMP_ticket_lock_Control Lock;
314#endif
315
316  /**
317   * @brief The thread queue heads.
318   *
319   * This pointer is NULL, if and only if no threads are enqueued.  The first
320   * thread to enqueue will give its spare thread queue heads to this thread
321   * queue.
322   */
323  Thread_queue_Heads *heads;
324
325  /**
326   * @brief The thread queue owner.
327   */
328  Thread_Control *owner;
329};
330
331/**
332 * @brief Thread queue priority change operation.
333 *
334 * @param[in] queue The actual thread queue.
335 * @param[in] the_thread The thread.
336 * @param[in] new_priority The new priority value.
337 *
338 * @see Thread_queue_Operations.
339 */
340typedef void ( *Thread_queue_Priority_change_operation )(
341  Thread_queue_Queue *queue,
342  Thread_Control     *the_thread,
343  Priority_Control    new_priority
344);
345
346/**
347 * @brief Thread queue enqueue operation.
348 *
349 * A potential thread to update the priority due to priority inheritance is
350 * returned via the thread queue path.  This thread is handed over to
351 * _Thread_Update_priority().
352 *
353 * @param[in] queue The actual thread queue.
354 * @param[in] the_thread The thread to enqueue on the queue.
355 */
356typedef void ( *Thread_queue_Enqueue_operation )(
357  Thread_queue_Queue *queue,
358  Thread_Control     *the_thread,
359  Thread_queue_Path  *path
360);
361
362/**
363 * @brief Thread queue extract operation.
364 *
365 * @param[in] queue The actual thread queue.
366 * @param[in] the_thread The thread to extract from the thread queue.
367 */
368typedef void ( *Thread_queue_Extract_operation )(
369  Thread_queue_Queue *queue,
370  Thread_Control     *the_thread
371);
372
373/**
374 * @brief Thread queue first operation.
375 *
376 * @param[in] heads The thread queue heads.
377 *
378 * @retval NULL No thread is present on the thread queue.
379 * @retval first The first thread of the thread queue according to the insert
380 * order.  This thread remains on the thread queue.
381 */
382typedef Thread_Control *( *Thread_queue_First_operation )(
383  Thread_queue_Heads *heads
384);
385
386/**
387 * @brief Thread queue operations.
388 *
389 * @see _Thread_wait_Set_operations().
390 */
391struct Thread_queue_Operations {
392  /**
393   * @brief Thread queue priority change operation.
394   *
395   * Called by _Thread_Change_priority() to notify a thread about a priority
396   * change.  In case this thread waits currently for a resource the handler
397   * may adjust its data structures according to the new priority value.  This
398   * handler must not be NULL, instead the default handler
399   * _Thread_Do_nothing_priority_change() should be used in case nothing needs
400   * to be done during a priority change.
401   */
402  Thread_queue_Priority_change_operation priority_change;
403
404  /**
405   * @brief Thread queue enqueue operation.
406   *
407   * Called by object routines to enqueue the thread.
408   */
409  Thread_queue_Enqueue_operation enqueue;
410
411  /**
412   * @brief Thread queue extract operation.
413   *
414   * Called by object routines to extract a thread from a thread queue.
415   */
416  Thread_queue_Extract_operation extract;
417
418  /**
419   * @brief Thread queue first operation.
420   */
421  Thread_queue_First_operation first;
422};
423
424/**
425 *  This is the structure used to manage sets of tasks which are blocked
426 *  waiting to acquire a resource.
427 */
428typedef struct {
429#if defined(RTEMS_SMP)
430#if defined(RTEMS_DEBUG)
431  /**
432   * @brief The index of the owning processor of the thread queue lock.
433   *
434   * The thread queue lock may be acquired via the thread lock also.  This path
435   * is not covered by this field.  In case the lock is not owned directly via
436   * _Thread_queue_Acquire(), then the value of this field is
437   * SMP_LOCK_NO_OWNER.
438   *
439   * Must be before the queue component of this structure to be able to re-use
440   * implementation parts for structures defined by Newlib <sys/lock.h>.
441   */
442  uint32_t owner;
443#endif
444
445#if defined(RTEMS_PROFILING)
446  /**
447   * @brief SMP lock statistics in case SMP and profiling are enabled.
448   *
449   * Must be before the queue component of this structure to be able to re-use
450   * implementation parts for structures defined by Newlib <sys/lock.h>.
451   */
452  SMP_lock_Stats Lock_stats;
453#endif
454#endif
455
456  /**
457   * @brief The actual thread queue.
458   */
459  Thread_queue_Queue Queue;
460} Thread_queue_Control;
461
462/**@}*/
463
464#ifdef __cplusplus
465}
466#endif
467
468#endif
469/* end of include file */
Note: See TracBrowser for help on using the repository browser.