source: rtems/cpukit/score/include/rtems/score/coremuteximpl.h @ 7e119990

4.115
Last change on this file since 7e119990 was 03e89287, checked in by Sebastian Huber <sebastian.huber@…>, on 03/27/14 at 13:46:31

score: Delete CORE_mutex_Control::lock

The holder field is enough to determine if a mutex is locked or not.

This leads also to better error status codes in case a
rtems_semaphore_release() is done for a mutex without having the
ownership.

  • 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 Callout which provides to support global/multiprocessor operations.
38 *
39 *  The following type defines the callout which the API provides
40 *  to support global/multiprocessor operations on mutexes.
41 */
42typedef void ( *CORE_mutex_API_mp_support_callout )(
43                 Thread_Control *,
44                 Objects_Id
45             );
46
47/**
48 *  @brief The possible Mutex handler return statuses.
49 *
50 *  This enumerated type defines the possible Mutex handler return statuses.
51 */
52typedef enum {
53  /** This status indicates that the operation completed successfully. */
54  CORE_MUTEX_STATUS_SUCCESSFUL,
55  /** This status indicates that the calling task did not want to block
56   *  and the operation was unable to complete immediately because the
57   *  resource was unavailable.
58   */
59  CORE_MUTEX_STATUS_UNSATISFIED_NOWAIT,
60#if defined(RTEMS_POSIX_API)
61  /** This status indicates that an attempt was made to relock a mutex
62   *  for which nesting is not configured.
63   */
64  CORE_MUTEX_STATUS_NESTING_NOT_ALLOWED,
65#endif
66  /** This status indicates that an attempt was made to release a mutex
67   *  by a thread other than the thread which locked it.
68   */
69  CORE_MUTEX_STATUS_NOT_OWNER_OF_RESOURCE,
70  /** This status indicates that the thread was blocked waiting for an
71   *  operation to complete and the mutex was deleted.
72   */
73  CORE_MUTEX_WAS_DELETED,
74  /** This status indicates that the calling task was willing to block
75   *  but the operation was unable to complete within the time allotted
76   *  because the resource never became available.
77   */
78  CORE_MUTEX_TIMEOUT,
79
80#if defined(__RTEMS_STRICT_ORDER_MUTEX__)
81  /** This status indicates that a thread not release the mutex which has
82   *  the priority inheritance property in a right order.
83   */
84  CORE_MUTEX_RELEASE_NOT_ORDER,
85#endif
86
87  /** This status indicates that a thread of logically greater importance
88   *  than the ceiling priority attempted to lock this mutex.
89   */
90  CORE_MUTEX_STATUS_CEILING_VIOLATED
91
92}   CORE_mutex_Status;
93
94/**
95 *  @brief The last status value.
96 *
97 *  This is the last status value.
98 */
99#define CORE_MUTEX_STATUS_LAST CORE_MUTEX_STATUS_CEILING_VIOLATED
100
101/**
102 *  @brief Initializes the mutex based on the parameters passed.
103 *
104 *  This routine initializes the mutex based on the parameters passed.
105 *
106 *  @param[in,out] the_mutex is the mutex to initalize
107 *  @param[in,out] executing The currently executing thread.
108 *  @param[in] the_mutex_attributes is the attributes associated with this
109 *         mutex instance
110 *  @param[in] initially_locked If true, then the mutex is initially locked by
111 *  the executing thread.
112 *
113 *  @retval This method returns CORE_MUTEX_STATUS_SUCCESSFUL if successful.
114 */
115CORE_mutex_Status _CORE_mutex_Initialize(
116  CORE_mutex_Control           *the_mutex,
117  Thread_Control               *executing,
118  const CORE_mutex_Attributes  *the_mutex_attributes,
119  bool                          initially_locked
120);
121
122/**
123 *  @brief Attempt to receive a unit from the_mutex.
124 *
125 *  This routine attempts to receive a unit from the_mutex.
126 *  If a unit is available or if the wait flag is false, then the routine
127 *  returns.  Otherwise, the calling task is blocked until a unit becomes
128 *  available.
129 *
130 *  @param[in,out] executing The currently executing thread.
131 *  @param[in,out] the_mutex is the mutex to attempt to lock
132 *  @param[in] level is the interrupt level
133 *
134 *  @retval This routine returns 0 if "trylock" can resolve whether or not
135 *  the mutex is immediately obtained or there was an error attempting to
136 *  get it.  It returns 1 to indicate that the caller cannot obtain
137 *  the mutex and will have to block to do so.
138 *
139 *  @note  For performance reasons, this routine is implemented as
140 *         a macro that uses two support routines.
141 */
142
143RTEMS_INLINE_ROUTINE int _CORE_mutex_Seize_interrupt_trylock_body(
144  CORE_mutex_Control  *the_mutex,
145  Thread_Control      *executing,
146  ISR_Level            level
147);
148
149#if defined(__RTEMS_DO_NOT_INLINE_CORE_MUTEX_SEIZE__)
150  /**
151   *  @brief Interrupt trylock CORE mutex seize.
152   *
153   *  When doing test coverage analysis or trying to minimize the code
154   *  space for RTEMS, it is often helpful to not inline this method
155   *  multiple times.  It is fairly large and has a high branch complexity
156   *  which makes it harder to get full binary test coverage.
157   *
158   *  @param[in] the_mutex will attempt to lock
159   *  @param[in] level_p is the interrupt level
160   */
161  int _CORE_mutex_Seize_interrupt_trylock(
162    CORE_mutex_Control  *the_mutex,
163    Thread_Control      *executing,
164    ISR_Level            level
165  );
166#else
167  /**
168   *  The default is to favor speed and inlining this definitely saves
169   *  a few instructions.  This is very important for mutex performance.
170   *
171   *  @param[in] _mutex will attempt to lock
172   *  @param[in] _level is the interrupt level
173   */
174  #define _CORE_mutex_Seize_interrupt_trylock( _mutex, _executing, _level ) \
175     _CORE_mutex_Seize_interrupt_trylock_body( _mutex, _executing, _level )
176#endif
177
178/**
179 *  @brief Performs the blocking portion of a mutex obtain.
180 *
181 *  This routine performs the blocking portion of a mutex obtain.
182 *  It is an actual subroutine and is not implemented as something
183 *  that may be inlined.
184 *
185 *  @param[in,out] the_mutex is the mutex to attempt to lock
186 *  @param[in,out] executing The currently executing thread.
187 *  @param[in] timeout is the maximum number of ticks to block
188 */
189void _CORE_mutex_Seize_interrupt_blocking(
190  CORE_mutex_Control  *the_mutex,
191  Thread_Control      *executing,
192  Watchdog_Interval    timeout
193);
194/**
195 *  @brief Verifies that a mutex blocking seize is performed safely.
196 *
197 *  This macro is to verify that a mutex blocking seize is
198 *  performed from a safe system state.  For example, one
199 *  cannot block inside an isr.
200 *
201 *  @retval this method returns true if dispatch is in an unsafe state.
202 */
203#ifdef RTEMS_SMP
204  #define _CORE_mutex_Check_dispatch_for_seize(_wait) \
205      (_Thread_Dispatch_get_disable_level() != 1 \
206        && (_wait) \
207        && (_System_state_Get() >= SYSTEM_STATE_UP))
208#else
209  #define _CORE_mutex_Check_dispatch_for_seize(_wait) \
210      (!_Thread_Dispatch_is_enabled() \
211        && (_wait) \
212        && (_System_state_Get() >= SYSTEM_STATE_UP))
213#endif
214
215/**
216 *  @brief Attempt to obtain the mutex.
217 *
218 *  This routine attempts to obtain the mutex.  If the mutex is available,
219 *  then it will return immediately.  Otherwise, it will invoke the
220 *  support routine @a _Core_mutex_Seize_interrupt_blocking.
221 *
222 *  @param[in] _the_mutex is the mutex to attempt to lock
223 *  @param[in] _id is the Id of the owning API level Semaphore object
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] _level 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  Objects_Id           id,
246  bool                 wait,
247  Watchdog_Interval    timeout,
248  ISR_Level            level
249)
250{
251  if ( _CORE_mutex_Check_dispatch_for_seize( wait ) ) {
252    _Terminate(
253      INTERNAL_ERROR_CORE,
254      false,
255      INTERNAL_ERROR_MUTEX_OBTAIN_FROM_BAD_STATE
256    );
257  }
258  if ( _CORE_mutex_Seize_interrupt_trylock( the_mutex, executing, level ) ) {
259    if ( !wait ) {
260      _ISR_Enable( level );
261      executing->Wait.return_code =
262        CORE_MUTEX_STATUS_UNSATISFIED_NOWAIT;
263    } else {
264      _Thread_queue_Enter_critical_section( &the_mutex->Wait_queue );
265      executing->Wait.queue = &the_mutex->Wait_queue;
266      executing->Wait.id = id;
267      _Thread_Disable_dispatch();
268      _ISR_Enable( level );
269      _CORE_mutex_Seize_interrupt_blocking( the_mutex, executing, timeout );
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] _id is the Id of the owning API level Semaphore object
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] _level 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    Objects_Id           _id,
289    bool                 _wait,
290    Watchdog_Interval    _timeout,
291    ISR_Level            _level
292  );
293#else
294  #define _CORE_mutex_Seize( _executing, _mtx, _id, _wait, _timeout, _level ) \
295     _CORE_mutex_Seize_body( _executing, _mtx, _id, _wait, _timeout, _level )
296#endif
297
298/**
299 *  @brief Frees a unit to the mutex.
300 *
301 *  This routine frees a unit to the mutex.  If a task was blocked waiting for
302 *  a unit from this mutex, then that task will be readied and the unit
303 *  given to that task.  Otherwise, the unit will be returned to the mutex.
304 *
305 *  @param[in] the_mutex is the mutex to surrender
306 *  @param[in] id is the id of the RTEMS Object associated with this mutex
307 *  @param[in] api_mutex_mp_support is the routine that will be called when
308 *         unblocking a remote mutex
309 *
310 *  @retval an indication of whether the routine succeeded or failed
311 */
312CORE_mutex_Status _CORE_mutex_Surrender(
313  CORE_mutex_Control                *the_mutex,
314  Objects_Id                         id,
315  CORE_mutex_API_mp_support_callout  api_mutex_mp_support
316);
317
318/**
319 *  @brief Flush all waiting threads.
320 *
321 *  This routine assists in the deletion of a mutex by flushing the associated
322 *  wait queue.
323 *
324 *  @param[in] the_mutex is the mutex to flush
325 *  @param[in] remote_extract_callout is the routine to invoke when a remote
326 *         thread is extracted
327 *  @param[in] status is the status value which each unblocked thread will
328 *         return to its caller.
329 */
330void _CORE_mutex_Flush(
331  CORE_mutex_Control         *the_mutex,
332  Thread_queue_Flush_callout  remote_extract_callout,
333  uint32_t                    status
334);
335
336/**
337 * @brief Is mutex locked.
338 *
339 * This routine returns true if the mutex specified is locked and false
340 * otherwise.
341 *
342 * @param[in] the_mutex is the mutex to check.
343 *
344 * @retval true The mutex is locked.
345 * @retval false The mutex is not locked.
346 */
347RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_locked(
348  CORE_mutex_Control  *the_mutex
349)
350{
351  return the_mutex->holder != NULL;
352}
353
354/**
355 * @brief Does core mutex use FIFO blocking.
356 *
357 * This routine returns true if the mutex's wait discipline is FIFO and false
358 * otherwise.
359 *
360 * @param[in] the_attribute is the attribute set of the mutex.
361 *
362 * @retval true The mutex is using FIFO blocking order.
363 * @retval false The mutex is not using FIFO blocking order.
364 */
365RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_fifo(
366  const CORE_mutex_Attributes *the_attribute
367)
368{
369  return the_attribute->discipline == CORE_MUTEX_DISCIPLINES_FIFO;
370}
371
372/**
373 * @brief Doex core mutex use priority blocking.
374 *
375 * This routine returns true if the mutex's wait discipline is PRIORITY and
376 * false otherwise.
377 *
378 * @param[in] the_attribute is the attribute set of the mutex.
379 *
380 * @retval true The mutex is using priority blocking order.
381 * @retval false The mutex is not using priority blocking order.
382 *
383 */
384RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_priority(
385  CORE_mutex_Attributes *the_attribute
386)
387{
388  return the_attribute->discipline == CORE_MUTEX_DISCIPLINES_PRIORITY;
389}
390
391/**
392 * @brief Does mutex use priority inheritance.
393 *
394 * This routine returns true if the mutex's wait discipline is
395 * INHERIT_PRIORITY and false otherwise.
396 *
397 * @param[in] the_attribute is the attribute set of the mutex.
398 *
399 * @retval true The mutex is using priority inheritance.
400 * @retval false The mutex is not using priority inheritance.
401 */
402RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_inherit_priority(
403  CORE_mutex_Attributes *the_attribute
404)
405{
406  return the_attribute->discipline == CORE_MUTEX_DISCIPLINES_PRIORITY_INHERIT;
407}
408
409/**
410 * @brief Does mutex use priority ceiling.
411 *
412 * This routine returns true if the mutex's wait discipline is
413 * PRIORITY_CEILING and false otherwise.
414 *
415 * @param[in] the_attribute is the attribute set of the mutex.
416 *
417 * @retval true The mutex is using priority ceiling.
418 * @retval false The mutex is not using priority ceiling.
419 */
420RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_priority_ceiling(
421  CORE_mutex_Attributes *the_attribute
422)
423{
424  return the_attribute->discipline == CORE_MUTEX_DISCIPLINES_PRIORITY_CEILING;
425}
426
427/*
428 *  Seize Mutex with Quick Success Path
429 *
430 *  NOTE: There is no MACRO version of this routine.  A body is in
431 *  coremutexseize.c that is duplicated from the .inl by hand.
432 *
433 *  NOTE: The Doxygen for this routine is in the .h file.
434 */
435
436RTEMS_INLINE_ROUTINE int _CORE_mutex_Seize_interrupt_trylock_body(
437  CORE_mutex_Control  *the_mutex,
438  Thread_Control      *executing,
439  ISR_Level            level
440)
441{
442  /* disabled when you get here */
443
444  executing->Wait.return_code = CORE_MUTEX_STATUS_SUCCESSFUL;
445  if ( !_CORE_mutex_Is_locked( the_mutex ) ) {
446    the_mutex->holder     = executing;
447    the_mutex->nest_count = 1;
448    if ( _CORE_mutex_Is_inherit_priority( &the_mutex->Attributes ) ||
449         _CORE_mutex_Is_priority_ceiling( &the_mutex->Attributes ) ){
450
451#ifdef __RTEMS_STRICT_ORDER_MUTEX__
452       _Chain_Prepend_unprotected( &executing->lock_mutex,
453                                   &the_mutex->queue.lock_queue );
454       the_mutex->queue.priority_before = executing->current_priority;
455#endif
456
457      executing->resource_count++;
458    }
459
460    if ( !_CORE_mutex_Is_priority_ceiling( &the_mutex->Attributes ) ) {
461      _ISR_Enable( level );
462      return 0;
463    } /* else must be CORE_MUTEX_DISCIPLINES_PRIORITY_CEILING
464       *
465       * we possibly bump the priority of the current holder -- which
466       * happens to be _Thread_Executing.
467       */
468    {
469      Priority_Control  ceiling;
470      Priority_Control  current;
471
472      ceiling = the_mutex->Attributes.priority_ceiling;
473      current = executing->current_priority;
474      if ( current == ceiling ) {
475        _ISR_Enable( level );
476        return 0;
477      }
478
479      if ( current > ceiling ) {
480        _Thread_Disable_dispatch();
481        _ISR_Enable( level );
482        _Thread_Change_priority(
483          executing,
484          ceiling,
485          false
486        );
487        _Thread_Enable_dispatch();
488        return 0;
489      }
490      /* if ( current < ceiling ) */ {
491        executing->Wait.return_code = CORE_MUTEX_STATUS_CEILING_VIOLATED;
492        the_mutex->holder = NULL;
493        the_mutex->nest_count = 0;     /* undo locking above */
494        executing->resource_count--;   /* undo locking above */
495        _ISR_Enable( level );
496        return 0;
497      }
498    }
499    return 0;
500  }
501
502  /*
503   *  At this point, we know the mutex was not available.  If this thread
504   *  is the thread that has locked the mutex, let's see if we are allowed
505   *  to nest access.
506   */
507  if ( _Thread_Is_executing( the_mutex->holder ) ) {
508    switch ( the_mutex->Attributes.lock_nesting_behavior ) {
509      case CORE_MUTEX_NESTING_ACQUIRES:
510        the_mutex->nest_count++;
511        _ISR_Enable( level );
512        return 0;
513      #if defined(RTEMS_POSIX_API)
514        case CORE_MUTEX_NESTING_IS_ERROR:
515          executing->Wait.return_code = CORE_MUTEX_STATUS_NESTING_NOT_ALLOWED;
516          _ISR_Enable( level );
517          return 0;
518      #endif
519      case CORE_MUTEX_NESTING_BLOCKS:
520        break;
521    }
522  }
523
524  /*
525   *  The mutex is not available and the caller must deal with the possibility
526   *  of blocking.
527   */
528  return 1;
529}
530
531/** @} */
532
533#ifdef __cplusplus
534}
535#endif
536
537#endif
538/* end of include file */
Note: See TracBrowser for help on using the repository browser.