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

5
Last change on this file since d79df38 was d79df38, checked in by Sebastian Huber <sebastian.huber@…>, on 07/26/16 at 08:34:21

score: Add deadlock detection

The mutex objects use the owner field of the thread queues for the mutex
owner. Use this and add a deadlock detection to
_Thread_queue_Enqueue_critical() for thread queues with an owner.

Update #2412.
Update #2556.
Close #2765.

  • Property mode set to 100644
File size: 13.1 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 lock in case the thread is blocked on a thread
168     * queue at thread wait lock acquire time.
169     */
170    SMP_ticket_lock_Control *queue_lock;
171
172    /**
173     * @brief The thread queue after thread wait lock acquire.
174     *
175     * In case the thread queue is NULL and the thread queue lock is non-NULL
176     * in this context, then we have a stale thread queue.  This happens in
177     * case the thread wait default is restored while we wait on the thread
178     * queue lock, e.g. during a mutex ownership transfer.
179     *
180     * @see _Thread_Wait_restore_default().
181     */
182    Thread_queue_Queue *queue;
183
184    /**
185     * @brief The thread queue operations after thread wait lock acquire.
186     */
187    const Thread_queue_Operations *operations;
188  } Wait;
189#endif
190} Thread_queue_Context;
191
192#if defined(RTEMS_SMP)
193/**
194 * @brief A thread queue link from one thread to another specified by the
195 * thread queue owner and thread wait queue relationships.
196 */
197typedef struct {
198  /**
199   * @brief Node to register this link in the global thread queue links lookup
200   * tree.
201   */
202  RBTree_Node Registry_node;
203
204  /**
205   * @brief The source thread queue determined by the thread queue owner.
206   */
207  Thread_queue_Queue *source;
208
209  /**
210   * @brief The target thread queue determined by the thread wait queue of the
211   * source owner.
212   */
213  Thread_queue_Queue *target;
214
215  /**
216   * @brief Node to add this link to a thread queue path.
217   */
218  Chain_Node Path_node;
219
220  /**
221   * @brief The owner of this thread queue link.
222   */
223  Thread_Control *owner;
224
225  /**
226   * @brief The queue context used to acquire the thread wait lock of the
227   * owner.
228   */
229  Thread_queue_Context Queue_context;
230} Thread_queue_Link;
231#endif
232
233/**
234 * @brief Thread priority queue.
235 */
236typedef struct {
237#if defined(RTEMS_SMP)
238  /**
239   * @brief Node to enqueue this queue in the FIFO chain of the corresponding
240   * heads structure.
241   *
242   * @see Thread_queue_Heads::Heads::Fifo.
243   */
244  Chain_Node Node;
245#endif
246
247  /**
248   * @brief The actual thread priority queue.
249   */
250  RBTree_Control Queue;
251} Thread_queue_Priority_queue;
252
253/**
254 * @brief Thread queue heads.
255 *
256 * Each thread is equipped with spare thread queue heads in case it is not
257 * enqueued on a thread queue.  The first thread enqueued on a thread queue
258 * will give its spare thread queue heads to that thread queue.  The threads
259 * arriving at the queue will add their thread queue heads to the free chain of
260 * the queue heads provided by the first thread enqueued.  Once a thread is
261 * dequeued it use the free chain to get new spare thread queue heads.
262 *
263 * Uses a leading underscore in the structure name to allow forward
264 * declarations in standard header files provided by Newlib and GCC.
265 */
266typedef struct _Thread_queue_Heads {
267  /** This union contains the data structures used to manage the blocked
268   *  set of tasks which varies based upon the discipline.
269   */
270  union {
271    /**
272     * @brief This is the FIFO discipline list.
273     *
274     * On SMP configurations this FIFO is used to enqueue the per scheduler
275     * instance priority queues of this structure.  This ensures FIFO fairness
276     * among the highest priority thread of each scheduler instance.
277     */
278    Chain_Control Fifo;
279
280#if !defined(RTEMS_SMP)
281    /**
282     * @brief This is the set of threads for priority discipline waiting.
283     */
284    Thread_queue_Priority_queue Priority;
285#endif
286  } Heads;
287
288  /**
289   * @brief A chain with free thread queue heads providing the spare thread
290   * queue heads for a thread once it is dequeued.
291   */
292  Chain_Control Free_chain;
293
294  /**
295   * @brief A chain node to add these thread queue heads to the free chain of
296   * the thread queue heads dedicated to the thread queue of an object.
297   */
298  Chain_Node Free_node;
299
300#if defined(RTEMS_SMP)
301  /**
302   * @brief One priority queue per scheduler instance.
303   */
304  Thread_queue_Priority_queue Priority[ RTEMS_ZERO_LENGTH_ARRAY ];
305#endif
306} Thread_queue_Heads;
307
308#if defined(RTEMS_SMP)
309  #define THREAD_QUEUE_HEADS_SIZE( scheduler_count ) \
310    ( sizeof( Thread_queue_Heads ) \
311      + ( scheduler_count ) * sizeof( Thread_queue_Priority_queue ) )
312#else
313  #define THREAD_QUEUE_HEADS_SIZE( scheduler_count ) \
314    sizeof( Thread_queue_Heads )
315#endif
316
317struct Thread_queue_Queue {
318  /**
319   * @brief Lock to protect this thread queue.
320   *
321   * It may be used to protect additional state of the object embedding this
322   * thread queue.
323   *
324   * Must be the first component of this structure to be able to re-use
325   * implementation parts for structures defined by Newlib <sys/lock.h>.
326   *
327   * @see _Thread_queue_Acquire(), _Thread_queue_Acquire_critical() and
328   * _Thread_queue_Release().
329   */
330#if defined(RTEMS_SMP)
331  SMP_ticket_lock_Control Lock;
332#endif
333
334  /**
335   * @brief The thread queue heads.
336   *
337   * This pointer is NULL, if and only if no threads are enqueued.  The first
338   * thread to enqueue will give its spare thread queue heads to this thread
339   * queue.
340   */
341  Thread_queue_Heads *heads;
342
343  /**
344   * @brief The thread queue owner.
345   */
346  Thread_Control *owner;
347};
348
349/**
350 * @brief Thread queue priority change operation.
351 *
352 * @param[in] the_thread The thread.
353 * @param[in] new_priority The new priority value.
354 * @param[in] prepend_it In case this is true, then the thread is prepended to
355 *   its priority group in its scheduler instance, otherwise it is appended.
356 * @param[in] queue The actual thread queue.
357 *
358 * @see Thread_queue_Operations.
359 */
360typedef void ( *Thread_queue_Priority_change_operation )(
361  Thread_Control     *the_thread,
362  Priority_Control    new_priority,
363  bool                prepend_it,
364  Thread_queue_Queue *queue
365);
366
367/**
368 * @brief Thread queue enqueue operation.
369 *
370 * A potential thread to update the priority due to priority inheritance is
371 * returned via the thread queue path.  This thread is handed over to
372 * _Thread_Update_priority().
373 *
374 * @param[in] queue The actual thread queue.
375 * @param[in] the_thread The thread to enqueue on the queue.
376 */
377typedef void ( *Thread_queue_Enqueue_operation )(
378  Thread_queue_Queue *queue,
379  Thread_Control     *the_thread,
380  Thread_queue_Path  *path
381);
382
383/**
384 * @brief Thread queue extract operation.
385 *
386 * @param[in] queue The actual thread queue.
387 * @param[in] the_thread The thread to extract from the thread queue.
388 */
389typedef void ( *Thread_queue_Extract_operation )(
390  Thread_queue_Queue *queue,
391  Thread_Control     *the_thread
392);
393
394/**
395 * @brief Thread queue first operation.
396 *
397 * @param[in] heads The thread queue heads.
398 *
399 * @retval NULL No thread is present on the thread queue.
400 * @retval first The first thread of the thread queue according to the insert
401 * order.  This thread remains on the thread queue.
402 */
403typedef Thread_Control *( *Thread_queue_First_operation )(
404  Thread_queue_Heads *heads
405);
406
407/**
408 * @brief Thread queue operations.
409 *
410 * @see _Thread_wait_Set_operations().
411 */
412struct Thread_queue_Operations {
413  /**
414   * @brief Thread queue priority change operation.
415   *
416   * Called by _Thread_Change_priority() to notify a thread about a priority
417   * change.  In case this thread waits currently for a resource the handler
418   * may adjust its data structures according to the new priority value.  This
419   * handler must not be NULL, instead the default handler
420   * _Thread_Do_nothing_priority_change() should be used in case nothing needs
421   * to be done during a priority change.
422   */
423  Thread_queue_Priority_change_operation priority_change;
424
425  /**
426   * @brief Thread queue enqueue operation.
427   *
428   * Called by object routines to enqueue the thread.
429   */
430  Thread_queue_Enqueue_operation enqueue;
431
432  /**
433   * @brief Thread queue extract operation.
434   *
435   * Called by object routines to extract a thread from a thread queue.
436   */
437  Thread_queue_Extract_operation extract;
438
439  /**
440   * @brief Thread queue first operation.
441   */
442  Thread_queue_First_operation first;
443};
444
445/**
446 *  This is the structure used to manage sets of tasks which are blocked
447 *  waiting to acquire a resource.
448 */
449typedef struct {
450#if defined(RTEMS_SMP)
451#if defined(RTEMS_DEBUG)
452  /**
453   * @brief The index of the owning processor of the thread queue lock.
454   *
455   * The thread queue lock may be acquired via the thread lock also.  This path
456   * is not covered by this field.  In case the lock is not owned directly via
457   * _Thread_queue_Acquire(), then the value of this field is
458   * SMP_LOCK_NO_OWNER.
459   *
460   * Must be before the queue component of this structure to be able to re-use
461   * implementation parts for structures defined by Newlib <sys/lock.h>.
462   */
463  uint32_t owner;
464#endif
465
466#if defined(RTEMS_PROFILING)
467  /**
468   * @brief SMP lock statistics in case SMP and profiling are enabled.
469   *
470   * Must be before the queue component of this structure to be able to re-use
471   * implementation parts for structures defined by Newlib <sys/lock.h>.
472   */
473  SMP_lock_Stats Lock_stats;
474#endif
475#endif
476
477  /**
478   * @brief The actual thread queue.
479   */
480  Thread_queue_Queue Queue;
481} Thread_queue_Control;
482
483/**@}*/
484
485#ifdef __cplusplus
486}
487#endif
488
489#endif
490/* end of include file */
Note: See TracBrowser for help on using the repository browser.