source: rtems/cpukit/score/include/rtems/score/coremuteximpl.h @ 09c5ca4

5
Last change on this file since 09c5ca4 was 09c5ca4, checked in by Sebastian Huber <sebastian.huber@…>, on 05/26/16 at 20:29:56

score: Simplify CORE mutex

Remove superfluous support for simple binary semaphores. With this we
can get rid of the CORE_MUTEX_NESTING_BLOCKS variant.

  • Property mode set to 100644
File size: 10.0 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/status.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 Initializes the mutex based on the parameters passed.
38 *
39 *  This routine initializes the mutex based on the parameters passed.
40 *
41 *  @param[in,out] the_mutex is the mutex to initalize
42 *  @param[in,out] executing The currently executing thread.
43 *  @param[in] the_mutex_attributes is the attributes associated with this
44 *         mutex instance
45 *  @param[in] initially_locked If true, then the mutex is initially locked by
46 *  the executing thread.
47 *
48 *  @retval This method returns STATUS_SUCCESSFUL if successful.
49 */
50Status_Control _CORE_mutex_Initialize(
51  CORE_mutex_Control           *the_mutex,
52  Thread_Control               *executing,
53  const CORE_mutex_Attributes  *the_mutex_attributes,
54  bool                          initially_locked
55);
56
57RTEMS_INLINE_ROUTINE void _CORE_mutex_Destroy( CORE_mutex_Control *the_mutex )
58{
59  _Thread_queue_Destroy( &the_mutex->Wait_queue );
60}
61
62RTEMS_INLINE_ROUTINE void _CORE_mutex_Acquire_critical(
63  CORE_mutex_Control   *the_mutex,
64  Thread_queue_Context *queue_context
65)
66{
67  _Thread_queue_Acquire_critical(
68    &the_mutex->Wait_queue,
69    &queue_context->Lock_context
70  );
71}
72
73RTEMS_INLINE_ROUTINE void _CORE_mutex_Release(
74  CORE_mutex_Control   *the_mutex,
75  Thread_queue_Context *queue_context
76)
77{
78  _Thread_queue_Release(
79    &the_mutex->Wait_queue,
80    &queue_context->Lock_context
81  );
82}
83
84/**
85 *  @brief Performs the blocking portion of a mutex obtain.
86 *
87 *  This routine performs the blocking portion of a mutex obtain.
88 *  It is an actual subroutine and is not implemented as something
89 *  that may be inlined.
90 *
91 *  @param[in,out] the_mutex is the mutex to attempt to lock
92 *  @param[in,out] executing The currently executing thread.
93 *  @param[in] timeout is the maximum number of ticks to block
94 *  @param[in] lock_context is the interrupt level
95 */
96Status_Control _CORE_mutex_Seize_interrupt_blocking(
97  CORE_mutex_Control   *the_mutex,
98  Thread_Control       *executing,
99  Watchdog_Interval     timeout,
100  Thread_queue_Context *queue_context
101);
102
103/**
104 * @brief Is mutex locked.
105 *
106 * This routine returns true if the mutex specified is locked and false
107 * otherwise.
108 *
109 * @param[in] the_mutex is the mutex to check.
110 *
111 * @retval true The mutex is locked.
112 * @retval false The mutex is not locked.
113 */
114RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_locked(
115  const CORE_mutex_Control *the_mutex
116)
117{
118  return the_mutex->holder != NULL;
119}
120
121/**
122 * @brief Does mutex use priority inheritance.
123 *
124 * This routine returns true if the mutex's wait discipline is
125 * INHERIT_PRIORITY and false otherwise.
126 *
127 * @param[in] the_attribute is the attribute set of the mutex.
128 *
129 * @retval true The mutex is using priority inheritance.
130 * @retval false The mutex is not using priority inheritance.
131 */
132RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_inherit_priority(
133  const CORE_mutex_Attributes *the_attribute
134)
135{
136  return the_attribute->discipline == CORE_MUTEX_DISCIPLINES_PRIORITY_INHERIT;
137}
138
139/**
140 * @brief Does mutex use priority ceiling.
141 *
142 * This routine returns true if the mutex's wait discipline is
143 * PRIORITY_CEILING and false otherwise.
144 *
145 * @param[in] the_attribute is the attribute set of the mutex.
146 *
147 * @retval true The mutex is using priority ceiling.
148 * @retval false The mutex is not using priority ceiling.
149 */
150RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_priority_ceiling(
151  const CORE_mutex_Attributes *the_attribute
152)
153{
154  return the_attribute->discipline == CORE_MUTEX_DISCIPLINES_PRIORITY_CEILING;
155}
156
157/**
158 *  @brief Attempt to receive a unit from the_mutex.
159 *
160 *  This routine attempts to receive a unit from the_mutex.
161 *  If a unit is available or if the wait flag is false, then the routine
162 *  returns.  Otherwise, the calling task is blocked until a unit becomes
163 *  available.
164 *
165 *  @param[in,out] executing The currently executing thread.
166 *  @param[in,out] the_mutex is the mutex to attempt to lock
167 *  @param[in] queue_context is the interrupt level
168 *
169 *  @retval STATUS_UNAVAILABLE The mutex is already locked.
170 *  @retval other Otherwise.
171 */
172RTEMS_INLINE_ROUTINE Status_Control _CORE_mutex_Seize_interrupt_trylock(
173  CORE_mutex_Control   *the_mutex,
174  Thread_Control       *executing,
175  Thread_queue_Context *queue_context
176)
177{
178  /* disabled when you get here */
179
180  if ( !_CORE_mutex_Is_locked( the_mutex ) ) {
181    the_mutex->holder     = executing;
182    the_mutex->nest_count = 1;
183    if ( _CORE_mutex_Is_inherit_priority( &the_mutex->Attributes ) ||
184         _CORE_mutex_Is_priority_ceiling( &the_mutex->Attributes ) ){
185      executing->resource_count++;
186    }
187
188    if ( !_CORE_mutex_Is_priority_ceiling( &the_mutex->Attributes ) ) {
189      _CORE_mutex_Release( the_mutex, queue_context );
190    } else {
191      /*
192       * must be CORE_MUTEX_DISCIPLINES_PRIORITY_CEILING
193       *
194       * we possibly bump the priority of the current holder -- which
195       * happens to be _Thread_Executing.
196       */
197      Priority_Control  ceiling;
198      Priority_Control  current;
199
200      ceiling = the_mutex->Attributes.priority_ceiling;
201      current = executing->current_priority;
202      if ( current == ceiling ) {
203        _CORE_mutex_Release( the_mutex, queue_context );
204      } else if ( current > ceiling ) {
205        Per_CPU_Control *cpu_self;
206
207        cpu_self = _Thread_Dispatch_disable_critical(
208          &queue_context->Lock_context
209        );
210        _CORE_mutex_Release( the_mutex, queue_context );
211        _Thread_Raise_priority( executing, ceiling );
212        _Thread_Dispatch_enable( cpu_self );
213      } else /* if ( current < ceiling ) */ {
214        the_mutex->holder = NULL;
215        the_mutex->nest_count = 0;     /* undo locking above */
216        executing->resource_count--;   /* undo locking above */
217        _CORE_mutex_Release( the_mutex, queue_context );
218        return STATUS_MUTEX_CEILING_VIOLATED;
219      }
220    }
221
222    return STATUS_SUCCESSFUL;
223  }
224
225  /*
226   *  At this point, we know the mutex was not available.  If this thread
227   *  is the thread that has locked the mutex, let's see if we are allowed
228   *  to nest access.
229   */
230  if ( _Thread_Is_executing( the_mutex->holder ) ) {
231    switch ( the_mutex->Attributes.lock_nesting_behavior ) {
232      case CORE_MUTEX_NESTING_ACQUIRES:
233        the_mutex->nest_count++;
234        _CORE_mutex_Release( the_mutex, queue_context );
235        return STATUS_SUCCESSFUL;
236      #if defined(RTEMS_POSIX_API)
237        case CORE_MUTEX_NESTING_IS_ERROR:
238          _CORE_mutex_Release( the_mutex, queue_context );
239          return STATUS_NESTING_NOT_ALLOWED;
240      #endif
241    }
242  }
243
244  /*
245   *  The mutex is not available and the caller must deal with the possibility
246   *  of blocking.
247   */
248  return STATUS_UNAVAILABLE;
249}
250
251/**
252 *  @brief Attempt to obtain the mutex.
253 *
254 *  This routine attempts to obtain the mutex.  If the mutex is available,
255 *  then it will return immediately.  Otherwise, it will invoke the
256 *  support routine @a _Core_mutex_Seize_interrupt_blocking.
257 *
258 *  @param[in] the_mutex is the mutex to attempt to lock
259 *  @param[in] wait is true if the thread is willing to wait
260 *  @param[in] timeout is the maximum number of ticks to block
261 *  @param[in] queue_context is a temporary variable used to contain the ISR
262 *         disable level cookie
263 *
264 *  @note If the mutex is called from an interrupt service routine,
265 *        with context switching disabled, or before multitasking,
266 *        then a fatal error is generated.
267 *
268 *  The logic on this routine is as follows:
269 *
270 *  * If incorrect system state
271 *      return an error
272 *  * If mutex is available without any contention or blocking
273 *      obtain it with interrupts disabled and returned
274 *  * If the caller is willing to wait
275 *      then they are blocked.
276 */
277RTEMS_INLINE_ROUTINE Status_Control _CORE_mutex_Seize(
278  CORE_mutex_Control   *the_mutex,
279  Thread_Control       *executing,
280  bool                  wait,
281  Watchdog_Interval     timeout,
282  Thread_queue_Context *queue_context
283)
284{
285  Status_Control status;
286
287  _CORE_mutex_Acquire_critical( the_mutex, queue_context );
288
289  status = _CORE_mutex_Seize_interrupt_trylock(
290    the_mutex,
291    executing,
292    queue_context
293  );
294
295  if ( status != STATUS_UNAVAILABLE ) {
296    return status;
297  }
298
299  if ( !wait ) {
300    _CORE_mutex_Release( the_mutex, queue_context );
301    return status;
302  }
303
304  return _CORE_mutex_Seize_interrupt_blocking(
305    the_mutex,
306    executing,
307    timeout,
308    queue_context
309  );
310}
311
312Status_Control _CORE_mutex_Surrender(
313  CORE_mutex_Control   *the_mutex,
314  Thread_queue_Context *queue_context
315);
316
317RTEMS_INLINE_ROUTINE void _CORE_mutex_Flush(
318  CORE_mutex_Control        *the_mutex,
319  Thread_queue_Flush_filter  filter,
320  Thread_queue_Context      *queue_context
321)
322{
323  _Thread_queue_Flush_critical(
324    &the_mutex->Wait_queue.Queue,
325    the_mutex->operations,
326    filter,
327    queue_context
328  );
329}
330
331RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_owner(
332  const CORE_mutex_Control *the_mutex,
333  const Thread_Control     *the_thread
334)
335{
336  return the_mutex->holder == the_thread;
337}
338
339/**
340 * @brief Does core mutex use FIFO blocking.
341 *
342 * This routine returns true if the mutex's wait discipline is FIFO and false
343 * otherwise.
344 *
345 * @param[in] the_attribute is the attribute set of the mutex.
346 *
347 * @retval true The mutex is using FIFO blocking order.
348 * @retval false The mutex is not using FIFO blocking order.
349 */
350RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_fifo(
351  const CORE_mutex_Attributes *the_attribute
352)
353{
354  return the_attribute->discipline == CORE_MUTEX_DISCIPLINES_FIFO;
355}
356
357/** @} */
358
359#ifdef __cplusplus
360}
361#endif
362
363#endif
364/* end of include file */
Note: See TracBrowser for help on using the repository browser.