source: rtems/cpukit/score/include/rtems/score/coremuteximpl.h @ 500a8e9c

5
Last change on this file since 500a8e9c was 500a8e9c, checked in by Sebastian Huber <sebastian.huber@…>, on 04/28/16 at 04:26:01

score: Delete RTEMS_STRICT_ORDER_MUTEX

Remove support for strict order mutexes.

Close #2124.

  • Property mode set to 100644
File size: 16.4 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup ScoreMutex
5 *
6 * @brief CORE Mutex Implementation
7 */
8
9/*
10 *  COPYRIGHT (c) 1989-2009.
11 *  On-Line Applications Research Corporation (OAR).
12 *
13 *  The license and distribution terms for this file may be
14 *  found in the file LICENSE in this distribution or at
15 *  http://www.rtems.org/license/LICENSE.
16 */
17
18#ifndef _RTEMS_SCORE_COREMUTEXIMPL_H
19#define _RTEMS_SCORE_COREMUTEXIMPL_H
20
21#include <rtems/score/coremutex.h>
22#include <rtems/score/chainimpl.h>
23#include <rtems/score/sysstate.h>
24#include <rtems/score/threadimpl.h>
25#include <rtems/score/threadqimpl.h>
26
27#ifdef __cplusplus
28extern "C" {
29#endif
30
31/**
32 * @addtogroup ScoreMutex
33 */
34/**@{**/
35
36/**
37 *  @brief The possible Mutex handler return statuses.
38 *
39 *  This enumerated type defines the possible Mutex handler return statuses.
40 */
41typedef enum {
42  /** This status indicates that the operation completed successfully. */
43  CORE_MUTEX_STATUS_SUCCESSFUL,
44  /** This status indicates that the calling task did not want to block
45   *  and the operation was unable to complete immediately because the
46   *  resource was unavailable.
47   */
48  CORE_MUTEX_STATUS_UNSATISFIED_NOWAIT,
49#if defined(RTEMS_POSIX_API)
50  /** This status indicates that an attempt was made to relock a mutex
51   *  for which nesting is not configured.
52   */
53  CORE_MUTEX_STATUS_NESTING_NOT_ALLOWED,
54#endif
55  /** This status indicates that an attempt was made to release a mutex
56   *  by a thread other than the thread which locked it.
57   */
58  CORE_MUTEX_STATUS_NOT_OWNER_OF_RESOURCE,
59  /** This status indicates that the thread was blocked waiting for an
60   *  operation to complete and the mutex was deleted.
61   */
62  CORE_MUTEX_WAS_DELETED,
63  /** This status indicates that the calling task was willing to block
64   *  but the operation was unable to complete within the time allotted
65   *  because the resource never became available.
66   */
67  CORE_MUTEX_TIMEOUT,
68
69  /** This status indicates that a thread of logically greater importance
70   *  than the ceiling priority attempted to lock this mutex.
71   */
72  CORE_MUTEX_STATUS_CEILING_VIOLATED
73
74}   CORE_mutex_Status;
75
76/**
77 *  @brief The last status value.
78 *
79 *  This is the last status value.
80 */
81#define CORE_MUTEX_STATUS_LAST CORE_MUTEX_STATUS_CEILING_VIOLATED
82
83/**
84 *  @brief Initializes the mutex based on the parameters passed.
85 *
86 *  This routine initializes the mutex based on the parameters passed.
87 *
88 *  @param[in,out] the_mutex is the mutex to initalize
89 *  @param[in,out] executing The currently executing thread.
90 *  @param[in] the_mutex_attributes is the attributes associated with this
91 *         mutex instance
92 *  @param[in] initially_locked If true, then the mutex is initially locked by
93 *  the executing thread.
94 *
95 *  @retval This method returns CORE_MUTEX_STATUS_SUCCESSFUL if successful.
96 */
97CORE_mutex_Status _CORE_mutex_Initialize(
98  CORE_mutex_Control           *the_mutex,
99  Thread_Control               *executing,
100  const CORE_mutex_Attributes  *the_mutex_attributes,
101  bool                          initially_locked
102);
103
104RTEMS_INLINE_ROUTINE void _CORE_mutex_Destroy( CORE_mutex_Control *the_mutex )
105{
106  _Thread_queue_Destroy( &the_mutex->Wait_queue );
107}
108
109RTEMS_INLINE_ROUTINE void _CORE_mutex_Acquire_critical(
110  CORE_mutex_Control *the_mutex,
111  ISR_lock_Context   *lock_context
112)
113{
114  _Thread_queue_Acquire_critical( &the_mutex->Wait_queue, lock_context );
115}
116
117RTEMS_INLINE_ROUTINE void _CORE_mutex_Release(
118  CORE_mutex_Control *the_mutex,
119  ISR_lock_Context   *lock_context
120)
121{
122  _Thread_queue_Release( &the_mutex->Wait_queue, lock_context );
123}
124
125/**
126 *  @brief Attempt to receive a unit from the_mutex.
127 *
128 *  This routine attempts to receive a unit from the_mutex.
129 *  If a unit is available or if the wait flag is false, then the routine
130 *  returns.  Otherwise, the calling task is blocked until a unit becomes
131 *  available.
132 *
133 *  @param[in,out] executing The currently executing thread.
134 *  @param[in,out] the_mutex is the mutex to attempt to lock
135 *  @param[in] lock_context is the interrupt level
136 *
137 *  @retval This routine returns 0 if "trylock" can resolve whether or not
138 *  the mutex is immediately obtained or there was an error attempting to
139 *  get it.  It returns 1 to indicate that the caller cannot obtain
140 *  the mutex and will have to block to do so.
141 *
142 *  @note  For performance reasons, this routine is implemented as
143 *         a macro that uses two support routines.
144 */
145
146RTEMS_INLINE_ROUTINE int _CORE_mutex_Seize_interrupt_trylock_body(
147  CORE_mutex_Control  *the_mutex,
148  Thread_Control      *executing,
149  ISR_lock_Context    *lock_context
150);
151
152#if defined(__RTEMS_DO_NOT_INLINE_CORE_MUTEX_SEIZE__)
153  /**
154   *  @brief Interrupt trylock CORE mutex seize.
155   *
156   *  When doing test coverage analysis or trying to minimize the code
157   *  space for RTEMS, it is often helpful to not inline this method
158   *  multiple times.  It is fairly large and has a high branch complexity
159   *  which makes it harder to get full binary test coverage.
160   *
161   *  @param[in] the_mutex will attempt to lock
162   *  @param[in] _executing points to the executing thread
163   *  @param[in] level_p is the interrupt level
164   */
165  int _CORE_mutex_Seize_interrupt_trylock(
166    CORE_mutex_Control  *the_mutex,
167    Thread_Control      *executing,
168    ISR_lock_Context    *lock_context
169  );
170#else
171  /**
172   *  The default is to favor speed and inlining this definitely saves
173   *  a few instructions.  This is very important for mutex performance.
174   *
175   *  @param[in] _mutex will attempt to lock
176   *  @param[in] _executing points to the executing thread
177   *  @param[in] _lock_context is the interrupt level
178   */
179  #define _CORE_mutex_Seize_interrupt_trylock( _mutex, _executing, _lock_context ) \
180     _CORE_mutex_Seize_interrupt_trylock_body( _mutex, _executing, _lock_context )
181#endif
182
183/**
184 *  @brief Performs the blocking portion of a mutex obtain.
185 *
186 *  This routine performs the blocking portion of a mutex obtain.
187 *  It is an actual subroutine and is not implemented as something
188 *  that may be inlined.
189 *
190 *  @param[in,out] the_mutex is the mutex to attempt to lock
191 *  @param[in,out] executing The currently executing thread.
192 *  @param[in] timeout is the maximum number of ticks to block
193 *  @param[in] lock_context is the interrupt level
194 */
195void _CORE_mutex_Seize_interrupt_blocking(
196  CORE_mutex_Control  *the_mutex,
197  Thread_Control      *executing,
198  Watchdog_Interval    timeout,
199  ISR_lock_Context    *lock_context
200);
201
202/**
203 *  @brief Verifies that a mutex blocking seize is performed safely.
204 *
205 *  This macro is to verify that a mutex blocking seize is
206 *  performed from a safe system state.  For example, one
207 *  cannot block inside an isr.
208 *
209 *  @retval this method returns true if dispatch is in an unsafe state.
210 */
211#define _CORE_mutex_Check_dispatch_for_seize(_wait) \
212  (!_Thread_Dispatch_is_enabled() \
213    && (_wait) \
214    && (_System_state_Get() >= SYSTEM_STATE_UP))
215
216/**
217 *  @brief Attempt to obtain the mutex.
218 *
219 *  This routine attempts to obtain the mutex.  If the mutex is available,
220 *  then it will return immediately.  Otherwise, it will invoke the
221 *  support routine @a _Core_mutex_Seize_interrupt_blocking.
222 *
223 *  @param[in] the_mutex is the mutex to attempt to lock
224 *  @param[in] wait is true if the thread is willing to wait
225 *  @param[in] timeout is the maximum number of ticks to block
226 *  @param[in] lock_context is a temporary variable used to contain the ISR
227 *         disable level cookie
228 *
229 *  @note If the mutex is called from an interrupt service routine,
230 *        with context switching disabled, or before multitasking,
231 *        then a fatal error is generated.
232 *
233 *  The logic on this routine is as follows:
234 *
235 *  * If incorrect system state
236 *      return an error
237 *  * If mutex is available without any contention or blocking
238 *      obtain it with interrupts disabled and returned
239 *  * If the caller is willing to wait
240 *      then they are blocked.
241 */
242RTEMS_INLINE_ROUTINE void _CORE_mutex_Seize_body(
243  CORE_mutex_Control  *the_mutex,
244  Thread_Control      *executing,
245  bool                 wait,
246  Watchdog_Interval    timeout,
247  ISR_lock_Context    *lock_context
248)
249{
250  if ( _CORE_mutex_Check_dispatch_for_seize( wait ) ) {
251    _Terminate(
252      INTERNAL_ERROR_CORE,
253      false,
254      INTERNAL_ERROR_MUTEX_OBTAIN_FROM_BAD_STATE
255    );
256  }
257  _CORE_mutex_Acquire_critical( the_mutex, lock_context );
258  if ( _CORE_mutex_Seize_interrupt_trylock( the_mutex, executing, lock_context ) ) {
259    if ( !wait ) {
260      _CORE_mutex_Release( the_mutex, lock_context );
261      executing->Wait.return_code =
262        CORE_MUTEX_STATUS_UNSATISFIED_NOWAIT;
263    } else {
264      _CORE_mutex_Seize_interrupt_blocking(
265        the_mutex,
266        executing,
267        timeout,
268        lock_context
269      );
270    }
271  }
272}
273
274/**
275 *  This method is used to obtain a core mutex.
276 *
277 *  @param[in] _the_mutex is the mutex to attempt to lock
278 *  @param[in] _executing The currently executing thread.
279 *  @param[in] _wait is true if the thread is willing to wait
280 *  @param[in] _timeout is the maximum number of ticks to block
281 *  @param[in] _lock_context is a temporary variable used to contain the ISR
282 *         disable level cookie
283 */
284#if defined(__RTEMS_DO_NOT_INLINE_CORE_MUTEX_SEIZE__)
285  void _CORE_mutex_Seize(
286    CORE_mutex_Control  *_the_mutex,
287    Thread_Control      *_executing,
288    bool                 _wait,
289    Watchdog_Interval    _timeout,
290    ISR_lock_Context    *_lock_context
291  );
292#else
293  #define _CORE_mutex_Seize( \
294      _the_mutex, _executing, _wait, _timeout, _lock_context ) \
295       _CORE_mutex_Seize_body( \
296         _the_mutex, _executing, _wait, _timeout, _lock_context )
297#endif
298
299CORE_mutex_Status _CORE_mutex_Do_surrender(
300  CORE_mutex_Control      *the_mutex,
301#if defined(RTEMS_MULTIPROCESSING)
302  Thread_queue_MP_callout  mp_callout,
303  Objects_Id               mp_id,
304#endif
305  ISR_lock_Context        *lock_context
306);
307
308#if defined(RTEMS_MULTIPROCESSING)
309  #define _CORE_mutex_Surrender( \
310    the_mutex, \
311    mp_callout, \
312    mp_id, \
313    lock_context \
314  ) \
315    _CORE_mutex_Do_surrender( \
316      the_mutex, \
317      mp_callout, \
318      mp_id, \
319      lock_context \
320    )
321#else
322  #define _CORE_mutex_Surrender( \
323    the_mutex, \
324    mp_callout, \
325    mp_id, \
326    lock_context \
327  ) \
328    _CORE_mutex_Do_surrender( \
329      the_mutex, \
330      lock_context \
331    )
332#endif
333
334Thread_Control *_CORE_mutex_Was_deleted(
335  Thread_Control     *the_thread,
336  Thread_queue_Queue *queue,
337  ISR_lock_Context   *lock_context
338);
339
340Thread_Control *_CORE_mutex_Unsatisfied_nowait(
341  Thread_Control     *the_thread,
342  Thread_queue_Queue *queue,
343  ISR_lock_Context   *lock_context
344);
345
346/* Must be a macro due to the multiprocessing dependent parameters */
347#define _CORE_mutex_Flush( \
348  the_mutex, \
349  filter, \
350  mp_callout, \
351  mp_id, \
352  lock_context \
353) \
354  _Thread_queue_Flush_critical( \
355    &( the_mutex )->Wait_queue.Queue, \
356    ( the_mutex )->operations, \
357    filter, \
358    mp_callout, \
359    mp_id, \
360    lock_context \
361  )
362
363/**
364 * @brief Is mutex locked.
365 *
366 * This routine returns true if the mutex specified is locked and false
367 * otherwise.
368 *
369 * @param[in] the_mutex is the mutex to check.
370 *
371 * @retval true The mutex is locked.
372 * @retval false The mutex is not locked.
373 */
374RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_locked(
375  const CORE_mutex_Control *the_mutex
376)
377{
378  return the_mutex->holder != NULL;
379}
380
381RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_owner(
382  const CORE_mutex_Control *the_mutex,
383  const Thread_Control     *the_thread
384)
385{
386  return the_mutex->holder == the_thread;
387}
388
389/**
390 * @brief Does core mutex use FIFO blocking.
391 *
392 * This routine returns true if the mutex's wait discipline is FIFO and false
393 * otherwise.
394 *
395 * @param[in] the_attribute is the attribute set of the mutex.
396 *
397 * @retval true The mutex is using FIFO blocking order.
398 * @retval false The mutex is not using FIFO blocking order.
399 */
400RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_fifo(
401  const CORE_mutex_Attributes *the_attribute
402)
403{
404  return the_attribute->discipline == CORE_MUTEX_DISCIPLINES_FIFO;
405}
406
407/**
408 * @brief Doex core mutex use priority blocking.
409 *
410 * This routine returns true if the mutex's wait discipline is PRIORITY and
411 * false otherwise.
412 *
413 * @param[in] the_attribute is the attribute set of the mutex.
414 *
415 * @retval true The mutex is using priority blocking order.
416 * @retval false The mutex is not using priority blocking order.
417 *
418 */
419RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_priority(
420  const CORE_mutex_Attributes *the_attribute
421)
422{
423  return the_attribute->discipline == CORE_MUTEX_DISCIPLINES_PRIORITY;
424}
425
426/**
427 * @brief Does mutex use priority inheritance.
428 *
429 * This routine returns true if the mutex's wait discipline is
430 * INHERIT_PRIORITY and false otherwise.
431 *
432 * @param[in] the_attribute is the attribute set of the mutex.
433 *
434 * @retval true The mutex is using priority inheritance.
435 * @retval false The mutex is not using priority inheritance.
436 */
437RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_inherit_priority(
438  const CORE_mutex_Attributes *the_attribute
439)
440{
441  return the_attribute->discipline == CORE_MUTEX_DISCIPLINES_PRIORITY_INHERIT;
442}
443
444/**
445 * @brief Does mutex use priority ceiling.
446 *
447 * This routine returns true if the mutex's wait discipline is
448 * PRIORITY_CEILING and false otherwise.
449 *
450 * @param[in] the_attribute is the attribute set of the mutex.
451 *
452 * @retval true The mutex is using priority ceiling.
453 * @retval false The mutex is not using priority ceiling.
454 */
455RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_priority_ceiling(
456  const CORE_mutex_Attributes *the_attribute
457)
458{
459  return the_attribute->discipline == CORE_MUTEX_DISCIPLINES_PRIORITY_CEILING;
460}
461
462/*
463 *  Seize Mutex with Quick Success Path
464 *
465 *  NOTE: There is no MACRO version of this routine.  A body is in
466 *  coremutexseize.c that is duplicated from the .inl by hand.
467 *
468 *  NOTE: The Doxygen for this routine is in the .h file.
469 */
470
471RTEMS_INLINE_ROUTINE int _CORE_mutex_Seize_interrupt_trylock_body(
472  CORE_mutex_Control  *the_mutex,
473  Thread_Control      *executing,
474  ISR_lock_Context    *lock_context
475)
476{
477  /* disabled when you get here */
478
479  executing->Wait.return_code = CORE_MUTEX_STATUS_SUCCESSFUL;
480  if ( !_CORE_mutex_Is_locked( the_mutex ) ) {
481    the_mutex->holder     = executing;
482    the_mutex->nest_count = 1;
483    if ( _CORE_mutex_Is_inherit_priority( &the_mutex->Attributes ) ||
484         _CORE_mutex_Is_priority_ceiling( &the_mutex->Attributes ) ){
485      executing->resource_count++;
486    }
487
488    if ( !_CORE_mutex_Is_priority_ceiling( &the_mutex->Attributes ) ) {
489      _CORE_mutex_Release( the_mutex, lock_context );
490      return 0;
491    } /* else must be CORE_MUTEX_DISCIPLINES_PRIORITY_CEILING
492       *
493       * we possibly bump the priority of the current holder -- which
494       * happens to be _Thread_Executing.
495       */
496    {
497      Priority_Control  ceiling;
498      Priority_Control  current;
499
500      ceiling = the_mutex->Attributes.priority_ceiling;
501      current = executing->current_priority;
502      if ( current == ceiling ) {
503        _CORE_mutex_Release( the_mutex, lock_context );
504        return 0;
505      }
506
507      if ( current > ceiling ) {
508        Per_CPU_Control *cpu_self;
509
510        cpu_self = _Thread_Dispatch_disable_critical( lock_context );
511        _CORE_mutex_Release( the_mutex, lock_context );
512        _Thread_Raise_priority( executing, ceiling );
513        _Thread_Dispatch_enable( cpu_self );
514        return 0;
515      }
516      /* if ( current < ceiling ) */ {
517        executing->Wait.return_code = CORE_MUTEX_STATUS_CEILING_VIOLATED;
518        the_mutex->holder = NULL;
519        the_mutex->nest_count = 0;     /* undo locking above */
520        executing->resource_count--;   /* undo locking above */
521        _CORE_mutex_Release( the_mutex, lock_context );
522        return 0;
523      }
524    }
525    return 0;
526  }
527
528  /*
529   *  At this point, we know the mutex was not available.  If this thread
530   *  is the thread that has locked the mutex, let's see if we are allowed
531   *  to nest access.
532   */
533  if ( _Thread_Is_executing( the_mutex->holder ) ) {
534    switch ( the_mutex->Attributes.lock_nesting_behavior ) {
535      case CORE_MUTEX_NESTING_ACQUIRES:
536        the_mutex->nest_count++;
537        _CORE_mutex_Release( the_mutex, lock_context );
538        return 0;
539      #if defined(RTEMS_POSIX_API)
540        case CORE_MUTEX_NESTING_IS_ERROR:
541          executing->Wait.return_code = CORE_MUTEX_STATUS_NESTING_NOT_ALLOWED;
542          _CORE_mutex_Release( the_mutex, lock_context );
543          return 0;
544      #endif
545      case CORE_MUTEX_NESTING_BLOCKS:
546        break;
547    }
548  }
549
550  /*
551   *  The mutex is not available and the caller must deal with the possibility
552   *  of blocking.
553   */
554  return 1;
555}
556
557/** @} */
558
559#ifdef __cplusplus
560}
561#endif
562
563#endif
564/* end of include file */
Note: See TracBrowser for help on using the repository browser.