source: rtems/cpukit/score/include/rtems/score/coremutex.h @ b50468c

4.10
Last change on this file since b50468c was b50468c, checked in by Gedare Bloom <gedare@…>, on 12/21/17 at 18:04:50

score: add Inherited_priorities priority queue and functions

Adds enqueue, dequeue, requeue, evaluate, and release functions
for the thread priority node priority queue of inherited priorities.
Add calls to these functions as needed to maintain the priority
queue due to blocking, unblocking, and priority changes.

Closes #3359.

  • Property mode set to 100644
File size: 14.8 KB
Line 
1/**
2 *  @file  rtems/score/coremutex.h
3 *
4 *  This include file contains all the constants and structures associated
5 *  with the Mutex Handler.  A mutex is an enhanced version of the standard
6 *  Dijkstra binary semaphore used to provide synchronization and mutual
7 *  exclusion capabilities.
8 */
9
10/*
11 *  COPYRIGHT (c) 1989-2009.
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.com/license/LICENSE.
17 *
18 *  $Id$
19 */
20
21#ifndef _RTEMS_SCORE_COREMUTEX_H
22#define _RTEMS_SCORE_COREMUTEX_H
23
24
25/**
26 *  @defgroup ScoreMutex Mutex Handler
27 *
28 *  This handler encapsulates functionality which provides the foundation
29 *  Mutex services used in all of the APIs supported by RTEMS.
30 */
31/**@{*/
32
33#ifdef __cplusplus
34extern "C" {
35#endif
36
37#include <rtems/score/thread.h>
38#include <rtems/score/threadq.h>
39#include <rtems/score/priority.h>
40#include <rtems/score/watchdog.h>
41#include <rtems/score/interr.h>
42#include <rtems/score/sysstate.h>
43
44/**
45 *  @brief MP Support Callback Prototype
46 *
47 *  The following type defines the callout which the API provides
48 *  to support global/multiprocessor operations on mutexes.
49 */
50typedef void ( *CORE_mutex_API_mp_support_callout )(
51                 Thread_Control *,
52                 Objects_Id
53             );
54
55/**
56 *  @brief Blocking Disciplines Enumerated Type
57 *
58 *  This enumerated type defines the blocking disciplines for a mutex.
59 */
60typedef enum {
61  /** This specifies that threads will wait for the mutex in FIFO order. */
62  CORE_MUTEX_DISCIPLINES_FIFO,
63  /** This specifies that threads will wait for the mutex in priority order.  */
64  CORE_MUTEX_DISCIPLINES_PRIORITY,
65  /** This specifies that threads will wait for the mutex in priority order.
66   *  Additionally, the Priority Inheritance Protocol will be in effect.
67   */
68  CORE_MUTEX_DISCIPLINES_PRIORITY_INHERIT,
69  /** This specifies that threads will wait for the mutex in priority order.
70   *  Additionally, the Priority Ceiling Protocol will be in effect.
71   */
72  CORE_MUTEX_DISCIPLINES_PRIORITY_CEILING
73}   CORE_mutex_Disciplines;
74
75/**
76 *  @brief Mutex method return statuses
77 *
78 *  This enumerated type defines the possible Mutex handler return statuses.
79 */
80typedef enum {
81  /** This status indicates that the operation completed successfully. */
82  CORE_MUTEX_STATUS_SUCCESSFUL,
83  /** This status indicates that the calling task did not want to block
84   *  and the operation was unable to complete immediately because the
85   *  resource was unavailable.
86   */
87  CORE_MUTEX_STATUS_UNSATISFIED_NOWAIT,
88  /** This status indicates that an attempt was made to relock a mutex
89   *  for which nesting is not configured.
90   */
91  CORE_MUTEX_STATUS_NESTING_NOT_ALLOWED,
92  /** This status indicates that an attempt was made to release a mutex
93   *  by a thread other than the thread which locked it.
94   */
95  CORE_MUTEX_STATUS_NOT_OWNER_OF_RESOURCE,
96  /** This status indicates that the thread was blocked waiting for an
97   *  operation to complete and the mutex was deleted.
98   */
99  CORE_MUTEX_WAS_DELETED,
100  /** This status indicates that the calling task was willing to block
101   *  but the operation was unable to complete within the time allotted
102   *  because the resource never became available.
103   */
104  CORE_MUTEX_TIMEOUT,
105
106#ifdef __RTEMS_STRICT_ORDER_MUTEX__
107  /** This status indicates that a thread not release the mutex which has
108   *  the priority inheritance property in a right order.
109   */
110  CORE_MUTEX_RELEASE_NOT_ORDER,
111#endif
112
113  /** This status indicates that a thread of logically greater importance
114   *  than the ceiling priority attempted to lock this mutex.
115   */
116  CORE_MUTEX_STATUS_CEILING_VIOLATED
117
118}   CORE_mutex_Status;
119
120/**
121 *  @brief Core Mutex Last Status
122 *
123 *  This is the last status value.
124 */
125#define CORE_MUTEX_STATUS_LAST CORE_MUTEX_STATUS_CEILING_VIOLATED
126
127/**
128 *  @brief Mutex Lock Nesting Behavior Enumeration
129 *
130 *  This enumerated type defines the possible behaviors for
131 *  lock nesting.
132 */
133typedef enum {
134  /**
135   *    This sequence has no blocking or errors:
136   *
137   *         + lock(m)
138   *         + lock(m)
139   *         + unlock(m)
140   *         + unlock(m)
141   */
142  CORE_MUTEX_NESTING_ACQUIRES,
143  /**
144   *    This sequence returns an error at the indicated point:
145   *
146   *        + lock(m)
147   *        + lock(m)   - already locked error
148   *        + unlock(m)
149   */
150  CORE_MUTEX_NESTING_IS_ERROR,
151  /**
152   *    This sequence performs as indicated:
153   *        + lock(m)
154   *        + lock(m)   - deadlocks or timeouts
155   *        + unlock(m) - releases
156   */
157  CORE_MUTEX_NESTING_BLOCKS
158}  CORE_mutex_Nesting_behaviors;
159
160/**
161 *  This is the value of a mutex when it is unlocked.
162 */
163#define CORE_MUTEX_UNLOCKED 1
164
165/**
166 *  This is the value of a mutex when it is locked.
167 */
168#define CORE_MUTEX_LOCKED   0
169
170/**
171 *  @brief Core Mutex Attributes
172 *
173 *  The following defines the control block used to manage the
174 *  attributes of each mutex.
175 */
176typedef struct {
177  /** This field determines what the behavior of this mutex instance will
178   *  be when attempting to acquire the mutex when it is already locked.
179   */
180  CORE_mutex_Nesting_behaviors lock_nesting_behavior;
181  /** When this field is true, then only the thread that locked the mutex
182   *  is allowed to unlock it.
183   */
184  bool                         only_owner_release;
185  /** This field indicates whether threads waiting on the mutex block in
186   *  FIFO or priority order.
187   */
188  CORE_mutex_Disciplines       discipline;
189  /** This field contains the ceiling priority to be used if that protocol
190   *  is selected.
191   */
192  Priority_Control             priority_ceiling;
193}   CORE_mutex_Attributes;
194
195#ifdef __RTEMS_STRICT_ORDER_MUTEX__
196/*@brief Core Mutex Lock_Chain Struct
197 *
198 * The following defines the control block used to manage lock chain of
199 * priority inheritance mutex.
200 */
201  typedef struct{
202    /** This field is a chian of locked mutex by a thread,new mutex will
203     *  be added to the head of queue, and the mutex which will be released
204     *  must be the head of queue.
205     */
206    Chain_Node                lock_queue;
207    /** This field is the priority of thread before locking this mutex
208     *
209     */
210    Priority_Control          priority_before;
211  }  CORE_mutex_order_list;
212#endif
213
214/**
215 *  @brief Core Mutex Control Structure
216 *
217 *  The following defines the control block used to manage each mutex.
218 */
219typedef struct CORE_mutex_Control {
220  /** This field is the Waiting Queue used to manage the set of tasks
221   *  which are blocked waiting to lock the mutex.
222   */
223  Thread_queue_Control    Wait_queue;
224  /** This element is the set of attributes which define this instance's
225   *  behavior.
226   */
227  CORE_mutex_Attributes   Attributes;
228  /** This element contains the current state of the mutex.
229   */
230  uint32_t                lock;
231  /** This element contains the number of times the mutex has been acquired
232   *  nested.  This must be zero (0) before the mutex is actually unlocked.
233   */
234  uint32_t                nest_count;
235  /** This is the number of waiting threads. */
236  uint32_t                blocked_count;
237  /** This element points to the thread which is currently holding this mutex.
238   *  The holder is the last thread to successfully lock the mutex and which
239   *  has not unlocked it.  If the thread is not locked, there is no holder.
240   */
241  Thread_Control         *holder;
242  /** This element contains the object Id of the holding thread.  */
243  Objects_Id              holder_id;
244#ifdef __RTEMS_STRICT_ORDER_MUTEX__
245  /** This field is used to manipulate the priority inheritance mutex queue*/
246  CORE_mutex_order_list   queue;
247#endif
248
249}   CORE_mutex_Control;
250
251/**
252 *  @brief Initialize a Core Mutex
253 *
254 *  This routine initializes the mutex based on the parameters passed.
255 *
256 *  @param[in] the_mutex is the mutex to initalize
257 *  @param[in] the_mutex_attributes is the attributes associated with this
258 *         mutex instance
259 *  @param[in] initial_lock is the initial value of the mutex
260 *
261 *  @return This method returns CORE_MUTEX_STATUS_SUCCESSFUL if successful.
262 */
263CORE_mutex_Status _CORE_mutex_Initialize(
264  CORE_mutex_Control           *the_mutex,
265  CORE_mutex_Attributes        *the_mutex_attributes,
266  uint32_t                      initial_lock
267);
268
269#ifndef __RTEMS_APPLICATION__
270/**
271 *  @brief Seize Mutex with Quick Success Path
272 *
273 *  This routine attempts to receive a unit from the_mutex.
274 *  If a unit is available or if the wait flag is false, then the routine
275 *  returns.  Otherwise, the calling task is blocked until a unit becomes
276 *  available.
277 *
278 *  @param[in] the_mutex is the mutex to attempt to lock
279 *  @param[in] level_p is the interrupt level holder
280 *
281 *  @return This routine returns 0 if "trylock" can resolve whether or not
282 *  the mutex is immediately obtained or there was an error attempting to
283 *  get it.  It returns 1 to indicate that the caller cannot obtain
284 *  the mutex and will have to block to do so.
285 *
286 *  @note  For performance reasons, this routine is implemented as
287 *         a macro that uses two support routines.
288 */
289
290RTEMS_INLINE_ROUTINE int _CORE_mutex_Seize_interrupt_trylock_body(
291  CORE_mutex_Control  *the_mutex,
292  ISR_Level           *level_p
293);
294
295#if defined(__RTEMS_DO_NOT_INLINE_CORE_MUTEX_SEIZE__)
296  /**
297   *  When doing test coverage analysis or trying to minimize the code
298   *  space for RTEMS, it is often helpful to not inline this method
299   *  multiple times.  It is fairly large and has a high branch complexity
300   *  which makes it harder to get full binary test coverage.
301   *
302   *  @param[in] the_mutex will attempt to lock
303   *  @param[in] level_p is the interrupt level holder
304   */
305  int _CORE_mutex_Seize_interrupt_trylock(
306    CORE_mutex_Control  *the_mutex,
307    ISR_Level           *level_p
308  );
309#else
310  /**
311   *  The default is to favor speed and inlining this definitely saves
312   *  a few instructions.  This is very important for mutex performance.
313   *
314   *  @param[in] _mutex will attempt to lock
315   *  @param[in] _level_p is the interrupt level holder
316   */
317  #define _CORE_mutex_Seize_interrupt_trylock( _mutex, _level_p ) \
318     _CORE_mutex_Seize_interrupt_trylock_body( _mutex, _level_p )
319#endif
320
321/**
322 *  @brief Seize Mutex with Blocking
323 *
324 *  This routine performs the blocking portion of a mutex obtain.
325 *  It is an actual subroutine and is not implemented as something
326 *  that may be inlined.
327 *
328 *  @param[in] the_mutex is the mutex to attempt to lock
329 *  @param[in] timeout is the maximum number of ticks to block
330 */
331void _CORE_mutex_Seize_interrupt_blocking(
332  CORE_mutex_Control  *the_mutex,
333  Watchdog_Interval    timeout
334);
335
336/**
337 *  @brief Sieze Interrupt Wrapper
338 *
339 *  This routine attempts to obtain the mutex.  If the mutex is available,
340 *  then it will return immediately.  Otherwise, it will invoke the
341 *  support routine @a _Core_mutex_Seize_interrupt_blocking.
342 *
343 *  @param[in] _the_mutex is the mutex to attempt to lock
344 *  @param[in] _id is the Id of the owning API level Semaphore object
345 *  @param[in] _wait is true if the thread is willing to wait
346 *  @param[in] _timeout is the maximum number of ticks to block
347 *  @param[in] _level is a temporary variable used to contain the ISR
348 *         disable level cookie
349 *
350 *  @note If the mutex is called from an interrupt service routine,
351 *        with context switching disabled, or before multitasking,
352 *        then a fatal error is generated.
353 *
354 *  The logic on this routine is as follows:
355 *
356 *  * If incorrect system state
357 *      return an error
358 *  * If mutex is available without any contention or blocking
359 *      obtain it with interrupts disabled and returned
360 *  * If the caller is willing to wait
361 *      then they are blocked.
362 */
363
364#define _CORE_mutex_Seize_body( \
365  _the_mutex, _id, _wait, _timeout, _level ) \
366  do { \
367    if ( _Thread_Dispatch_disable_level \
368        && (_wait) \
369        && (_System_state_Get() >= SYSTEM_STATE_BEGIN_MULTITASKING ) \
370       ) { \
371        _Internal_error_Occurred( \
372           INTERNAL_ERROR_CORE, \
373           false, \
374           INTERNAL_ERROR_MUTEX_OBTAIN_FROM_BAD_STATE \
375           ); \
376    } \
377    if ( _CORE_mutex_Seize_interrupt_trylock( _the_mutex, &(_level) ) ) {  \
378      if ( !(_wait) ) { \
379        _ISR_Enable( _level ); \
380        _Thread_Executing->Wait.return_code = \
381          CORE_MUTEX_STATUS_UNSATISFIED_NOWAIT; \
382      } else { \
383        _Thread_queue_Enter_critical_section( &(_the_mutex)->Wait_queue ); \
384        _Thread_Executing->Wait.queue = &(_the_mutex)->Wait_queue; \
385        _Thread_Executing->Wait.id    = _id; \
386        _Thread_Disable_dispatch(); \
387        _ISR_Enable( _level ); \
388       _CORE_mutex_Seize_interrupt_blocking( _the_mutex, _timeout ); \
389      } \
390    } \
391  } while (0)
392
393/**
394 *  This method is used to obtain a core mutex.
395 *
396 *  @param[in] _the_mutex is the mutex to attempt to lock
397 *  @param[in] _id is the Id of the owning API level Semaphore object
398 *  @param[in] _wait is true if the thread is willing to wait
399 *  @param[in] _timeout is the maximum number of ticks to block
400 *  @param[in] _level is a temporary variable used to contain the ISR
401 *         disable level cookie
402 */
403#if defined(__RTEMS_DO_NOT_INLINE_CORE_MUTEX_SEIZE__)
404  void _CORE_mutex_Seize(
405    CORE_mutex_Control  *_the_mutex,
406    Objects_Id           _id,
407    bool                 _wait,
408    Watchdog_Interval    _timeout,
409    ISR_Level            _level
410  );
411#else
412  #define _CORE_mutex_Seize( _the_mutex, _id, _wait, _timeout, _level ) \
413     _CORE_mutex_Seize_body( _the_mutex, _id, _wait, _timeout, _level )
414#endif
415
416/**
417 *  @brief Surrender the Mutex
418 *
419 *  This routine frees a unit to the mutex.  If a task was blocked waiting for
420 *  a unit from this mutex, then that task will be readied and the unit
421 *  given to that task.  Otherwise, the unit will be returned to the mutex.
422 *
423 *  @param[in] the_mutex is the mutex to surrender
424 *  @param[in] id is the id of the RTEMS Object associated with this mutex
425 *  @param[in] api_mutex_mp_support is the routine that will be called when
426 *         unblocking a remote mutex
427 *
428 *  @return an indication of whether the routine succeeded or failed
429 */
430CORE_mutex_Status _CORE_mutex_Surrender(
431  CORE_mutex_Control                *the_mutex,
432  Objects_Id                         id,
433  CORE_mutex_API_mp_support_callout  api_mutex_mp_support
434);
435
436/**
437 *  @brief Flush all waiting threads
438 *
439 *  This routine assists in the deletion of a mutex by flushing the associated
440 *  wait queue.
441 *
442 *  @param[in] the_mutex is the mutex to flush
443 *  @param[in] remote_extract_callout is the routine to invoke when a remote
444 *         thread is extracted
445 *  @param[in] status is the status value which each unblocked thread will
446 *         return to its caller.
447 */
448void _CORE_mutex_Flush(
449  CORE_mutex_Control         *the_mutex,
450  Thread_queue_Flush_callout  remote_extract_callout,
451  uint32_t                    status
452);
453
454#include <rtems/score/coremutex.inl>
455#endif
456
457#ifdef __cplusplus
458}
459#endif
460
461/**@}*/
462
463#endif
464/*  end of include file */
Note: See TracBrowser for help on using the repository browser.