source: rtems/cpukit/score/include/rtems/score/coremuteximpl.h @ 631b3c8

Last change on this file since 631b3c8 was 631b3c8, checked in by Sebastian Huber <sebastian.huber@…>, on May 23, 2016 at 9:40:18 AM

score: Move thread queue MP callout to context

Drop the multiprocessing (MP) dependent callout parameter from the
thread queue extract, dequeue, flush and unblock methods. Merge this
parameter with the lock context into new structure Thread_queue_Context.
This helps to gets rid of the conditionally compiled method call
helpers.

  • Property mode set to 100644
File size: 12.8 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  Thread_queue_Context *queue_context
112)
113{
114  _Thread_queue_Acquire_critical(
115    &the_mutex->Wait_queue,
116    &queue_context->Lock_context
117  );
118}
119
120RTEMS_INLINE_ROUTINE void _CORE_mutex_Release(
121  CORE_mutex_Control   *the_mutex,
122  Thread_queue_Context *queue_context
123)
124{
125  _Thread_queue_Release(
126    &the_mutex->Wait_queue,
127    &queue_context->Lock_context
128  );
129}
130
131/**
132 *  @brief Performs the blocking portion of a mutex obtain.
133 *
134 *  This routine performs the blocking portion of a mutex obtain.
135 *  It is an actual subroutine and is not implemented as something
136 *  that may be inlined.
137 *
138 *  @param[in,out] the_mutex is the mutex to attempt to lock
139 *  @param[in,out] executing The currently executing thread.
140 *  @param[in] timeout is the maximum number of ticks to block
141 *  @param[in] lock_context is the interrupt level
142 */
143void _CORE_mutex_Seize_interrupt_blocking(
144  CORE_mutex_Control  *the_mutex,
145  Thread_Control      *executing,
146  Watchdog_Interval    timeout,
147  ISR_lock_Context    *lock_context
148);
149
150/**
151 *  @brief Verifies that a mutex blocking seize is performed safely.
152 *
153 *  This macro is to verify that a mutex blocking seize is
154 *  performed from a safe system state.  For example, one
155 *  cannot block inside an isr.
156 *
157 *  @retval this method returns true if dispatch is in an unsafe state.
158 */
159#define _CORE_mutex_Check_dispatch_for_seize(_wait) \
160  (!_Thread_Dispatch_is_enabled() \
161    && (_wait) \
162    && (_System_state_Get() >= SYSTEM_STATE_UP))
163
164/**
165 * @brief Is mutex locked.
166 *
167 * This routine returns true if the mutex specified is locked and false
168 * otherwise.
169 *
170 * @param[in] the_mutex is the mutex to check.
171 *
172 * @retval true The mutex is locked.
173 * @retval false The mutex is not locked.
174 */
175RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_locked(
176  const CORE_mutex_Control *the_mutex
177)
178{
179  return the_mutex->holder != NULL;
180}
181
182/**
183 * @brief Does mutex use priority inheritance.
184 *
185 * This routine returns true if the mutex's wait discipline is
186 * INHERIT_PRIORITY and false otherwise.
187 *
188 * @param[in] the_attribute is the attribute set of the mutex.
189 *
190 * @retval true The mutex is using priority inheritance.
191 * @retval false The mutex is not using priority inheritance.
192 */
193RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_inherit_priority(
194  const CORE_mutex_Attributes *the_attribute
195)
196{
197  return the_attribute->discipline == CORE_MUTEX_DISCIPLINES_PRIORITY_INHERIT;
198}
199
200/**
201 * @brief Does mutex use priority ceiling.
202 *
203 * This routine returns true if the mutex's wait discipline is
204 * PRIORITY_CEILING and false otherwise.
205 *
206 * @param[in] the_attribute is the attribute set of the mutex.
207 *
208 * @retval true The mutex is using priority ceiling.
209 * @retval false The mutex is not using priority ceiling.
210 */
211RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_priority_ceiling(
212  const CORE_mutex_Attributes *the_attribute
213)
214{
215  return the_attribute->discipline == CORE_MUTEX_DISCIPLINES_PRIORITY_CEILING;
216}
217
218/**
219 *  @brief Attempt to receive a unit from the_mutex.
220 *
221 *  This routine attempts to receive a unit from the_mutex.
222 *  If a unit is available or if the wait flag is false, then the routine
223 *  returns.  Otherwise, the calling task is blocked until a unit becomes
224 *  available.
225 *
226 *  @param[in,out] executing The currently executing thread.
227 *  @param[in,out] the_mutex is the mutex to attempt to lock
228 *  @param[in] queue_context is the interrupt level
229 *
230 *  @retval This routine returns 0 if "trylock" can resolve whether or not
231 *  the mutex is immediately obtained or there was an error attempting to
232 *  get it.  It returns 1 to indicate that the caller cannot obtain
233 *  the mutex and will have to block to do so.
234 */
235RTEMS_INLINE_ROUTINE int _CORE_mutex_Seize_interrupt_trylock(
236  CORE_mutex_Control   *the_mutex,
237  Thread_Control       *executing,
238  Thread_queue_Context *queue_context
239)
240{
241  /* disabled when you get here */
242
243  executing->Wait.return_code = CORE_MUTEX_STATUS_SUCCESSFUL;
244  if ( !_CORE_mutex_Is_locked( the_mutex ) ) {
245    the_mutex->holder     = executing;
246    the_mutex->nest_count = 1;
247    if ( _CORE_mutex_Is_inherit_priority( &the_mutex->Attributes ) ||
248         _CORE_mutex_Is_priority_ceiling( &the_mutex->Attributes ) ){
249      executing->resource_count++;
250    }
251
252    if ( !_CORE_mutex_Is_priority_ceiling( &the_mutex->Attributes ) ) {
253      _CORE_mutex_Release( the_mutex, queue_context );
254      return 0;
255    } /* else must be CORE_MUTEX_DISCIPLINES_PRIORITY_CEILING
256       *
257       * we possibly bump the priority of the current holder -- which
258       * happens to be _Thread_Executing.
259       */
260    {
261      Priority_Control  ceiling;
262      Priority_Control  current;
263
264      ceiling = the_mutex->Attributes.priority_ceiling;
265      current = executing->current_priority;
266      if ( current == ceiling ) {
267        _CORE_mutex_Release( the_mutex, queue_context );
268        return 0;
269      }
270
271      if ( current > ceiling ) {
272        Per_CPU_Control *cpu_self;
273
274        cpu_self = _Thread_Dispatch_disable_critical(
275          &queue_context->Lock_context
276        );
277        _CORE_mutex_Release( the_mutex, queue_context );
278        _Thread_Raise_priority( executing, ceiling );
279        _Thread_Dispatch_enable( cpu_self );
280        return 0;
281      }
282      /* if ( current < ceiling ) */ {
283        executing->Wait.return_code = CORE_MUTEX_STATUS_CEILING_VIOLATED;
284        the_mutex->holder = NULL;
285        the_mutex->nest_count = 0;     /* undo locking above */
286        executing->resource_count--;   /* undo locking above */
287        _CORE_mutex_Release( the_mutex, queue_context );
288        return 0;
289      }
290    }
291    return 0;
292  }
293
294  /*
295   *  At this point, we know the mutex was not available.  If this thread
296   *  is the thread that has locked the mutex, let's see if we are allowed
297   *  to nest access.
298   */
299  if ( _Thread_Is_executing( the_mutex->holder ) ) {
300    switch ( the_mutex->Attributes.lock_nesting_behavior ) {
301      case CORE_MUTEX_NESTING_ACQUIRES:
302        the_mutex->nest_count++;
303        _CORE_mutex_Release( the_mutex, queue_context );
304        return 0;
305      #if defined(RTEMS_POSIX_API)
306        case CORE_MUTEX_NESTING_IS_ERROR:
307          executing->Wait.return_code = CORE_MUTEX_STATUS_NESTING_NOT_ALLOWED;
308          _CORE_mutex_Release( the_mutex, queue_context );
309          return 0;
310      #endif
311      case CORE_MUTEX_NESTING_BLOCKS:
312        break;
313    }
314  }
315
316  /*
317   *  The mutex is not available and the caller must deal with the possibility
318   *  of blocking.
319   */
320  return 1;
321}
322
323/**
324 *  @brief Attempt to obtain the mutex.
325 *
326 *  This routine attempts to obtain the mutex.  If the mutex is available,
327 *  then it will return immediately.  Otherwise, it will invoke the
328 *  support routine @a _Core_mutex_Seize_interrupt_blocking.
329 *
330 *  @param[in] the_mutex is the mutex to attempt to lock
331 *  @param[in] wait is true if the thread is willing to wait
332 *  @param[in] timeout is the maximum number of ticks to block
333 *  @param[in] queue_context is a temporary variable used to contain the ISR
334 *         disable level cookie
335 *
336 *  @note If the mutex is called from an interrupt service routine,
337 *        with context switching disabled, or before multitasking,
338 *        then a fatal error is generated.
339 *
340 *  The logic on this routine is as follows:
341 *
342 *  * If incorrect system state
343 *      return an error
344 *  * If mutex is available without any contention or blocking
345 *      obtain it with interrupts disabled and returned
346 *  * If the caller is willing to wait
347 *      then they are blocked.
348 */
349RTEMS_INLINE_ROUTINE void _CORE_mutex_Seize(
350  CORE_mutex_Control   *the_mutex,
351  Thread_Control       *executing,
352  bool                  wait,
353  Watchdog_Interval     timeout,
354  Thread_queue_Context *queue_context
355)
356{
357  if ( _CORE_mutex_Check_dispatch_for_seize( wait ) ) {
358    _Terminate(
359      INTERNAL_ERROR_CORE,
360      false,
361      INTERNAL_ERROR_MUTEX_OBTAIN_FROM_BAD_STATE
362    );
363  }
364  _CORE_mutex_Acquire_critical( the_mutex, queue_context );
365  if (
366    _CORE_mutex_Seize_interrupt_trylock( the_mutex, executing, queue_context )
367  ) {
368    if ( !wait ) {
369      _CORE_mutex_Release( the_mutex, queue_context );
370      executing->Wait.return_code =
371        CORE_MUTEX_STATUS_UNSATISFIED_NOWAIT;
372    } else {
373      _CORE_mutex_Seize_interrupt_blocking(
374        the_mutex,
375        executing,
376        timeout,
377        &queue_context->Lock_context
378      );
379    }
380  }
381}
382
383CORE_mutex_Status _CORE_mutex_Surrender(
384  CORE_mutex_Control   *the_mutex,
385  Thread_queue_Context *queue_context
386);
387
388Thread_Control *_CORE_mutex_Was_deleted(
389  Thread_Control       *the_thread,
390  Thread_queue_Queue   *queue,
391  Thread_queue_Context *queue_context
392);
393
394Thread_Control *_CORE_mutex_Unsatisfied_nowait(
395  Thread_Control       *the_thread,
396  Thread_queue_Queue   *queue,
397  Thread_queue_Context *queue_context
398);
399
400RTEMS_INLINE_ROUTINE void _CORE_mutex_Flush(
401  CORE_mutex_Control        *the_mutex,
402  Thread_queue_Flush_filter  filter,
403  Thread_queue_Context      *queue_context
404)
405{
406  _Thread_queue_Flush_critical(
407    &the_mutex->Wait_queue.Queue,
408    the_mutex->operations,
409    filter,
410    queue_context
411  );
412}
413
414RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_owner(
415  const CORE_mutex_Control *the_mutex,
416  const Thread_Control     *the_thread
417)
418{
419  return the_mutex->holder == the_thread;
420}
421
422/**
423 * @brief Does core mutex use FIFO blocking.
424 *
425 * This routine returns true if the mutex's wait discipline is FIFO and false
426 * otherwise.
427 *
428 * @param[in] the_attribute is the attribute set of the mutex.
429 *
430 * @retval true The mutex is using FIFO blocking order.
431 * @retval false The mutex is not using FIFO blocking order.
432 */
433RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_fifo(
434  const CORE_mutex_Attributes *the_attribute
435)
436{
437  return the_attribute->discipline == CORE_MUTEX_DISCIPLINES_FIFO;
438}
439
440/** @} */
441
442#ifdef __cplusplus
443}
444#endif
445
446#endif
447/* end of include file */
Note: See TracBrowser for help on using the repository browser.