source: rtems/cpukit/score/src/coremutexsurrender.c @ 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: 4.9 KB
Line 
1/**
2 * @file
3 *
4 * @brief Surrender the Mutex
5 * @ingroup ScoreMutex
6 */
7
8/*
9 *  COPYRIGHT (c) 1989-2006.
10 *  On-Line Applications Research Corporation (OAR).
11 *
12 *  The license and distribution terms for this file may be
13 *  found in the file LICENSE in this distribution or at
14 *  http://www.rtems.org/license/LICENSE.
15 */
16
17#if HAVE_CONFIG_H
18#include "config.h"
19#endif
20
21#include <rtems/system.h>
22#include <rtems/score/isr.h>
23#include <rtems/score/coremuteximpl.h>
24#include <rtems/score/thread.h>
25
26Status_Control _CORE_mutex_Surrender(
27  CORE_mutex_Control   *the_mutex,
28  Thread_queue_Context *queue_context
29)
30{
31  Thread_Control *the_thread;
32  Thread_Control *holder;
33
34  holder = the_mutex->holder;
35
36  /*
37   *  The following code allows a thread (or ISR) other than the thread
38   *  which acquired the mutex to release that mutex.  This is only
39   *  allowed when the mutex in quetion is FIFO or simple Priority
40   *  discipline.  But Priority Ceiling or Priority Inheritance mutexes
41   *  must be released by the thread which acquired them.
42   */
43
44  if ( the_mutex->Attributes.only_owner_release ) {
45    if ( !_Thread_Is_executing( holder ) ) {
46      _ISR_lock_ISR_enable( &queue_context->Lock_context );
47      return STATUS_NOT_OWNER;
48    }
49  }
50
51  _CORE_mutex_Acquire_critical( the_mutex, queue_context );
52
53  /* XXX already unlocked -- not right status */
54
55  if ( !the_mutex->nest_count ) {
56    _CORE_mutex_Release( the_mutex, queue_context );
57    return STATUS_SUCCESSFUL;
58  }
59
60  the_mutex->nest_count--;
61
62  if ( the_mutex->nest_count != 0 ) {
63    /*
64     *  All error checking is on the locking side, so if the lock was
65     *  allowed to acquired multiple times, then we should just deal with
66     *  that.  The RTEMS_DEBUG is just a validation.
67     */
68    #if defined(RTEMS_DEBUG)
69      switch ( the_mutex->Attributes.lock_nesting_behavior ) {
70        case CORE_MUTEX_NESTING_ACQUIRES:
71          _CORE_mutex_Release( the_mutex, queue_context );
72          return STATUS_SUCCESSFUL;
73        #if defined(RTEMS_POSIX_API)
74          case CORE_MUTEX_NESTING_IS_ERROR:
75            /* should never occur */
76            _CORE_mutex_Release( the_mutex, queue_context );
77            return STATUS_NESTING_NOT_ALLOWED;
78        #endif
79      }
80    #else
81      _CORE_mutex_Release( the_mutex, queue_context );
82      /* must be CORE_MUTEX_NESTING_ACQUIRES or we wouldn't be here */
83      return STATUS_SUCCESSFUL;
84    #endif
85  }
86
87  /*
88   *  Formally release the mutex before possibly transferring it to a
89   *  blocked thread.
90   */
91  if ( _CORE_mutex_Is_inherit_priority( &the_mutex->Attributes ) ||
92       _CORE_mutex_Is_priority_ceiling( &the_mutex->Attributes ) ) {
93    holder->resource_count--;
94  }
95  the_mutex->holder = NULL;
96
97  /*
98   *  Now we check if another thread was waiting for this mutex.  If so,
99   *  transfer the mutex to that thread.
100   */
101  if (
102    ( the_thread = _Thread_queue_First_locked(
103        &the_mutex->Wait_queue,
104        the_mutex->operations
105      )
106    )
107  ) {
108    bool unblock;
109
110    the_mutex->holder     = the_thread;
111    the_mutex->nest_count = 1;
112
113    /*
114     * We must extract the thread now since this will restore its default
115     * thread lock.  This is necessary to avoid a deadlock in the
116     * _Thread_Change_priority() below due to a recursive thread queue lock
117     * acquire.
118     */
119    unblock = _Thread_queue_Extract_locked(
120      &the_mutex->Wait_queue.Queue,
121      the_mutex->operations,
122      the_thread,
123      queue_context
124    );
125
126#if defined(RTEMS_MULTIPROCESSING)
127    if ( _Objects_Is_local_id( the_thread->Object.id ) )
128#endif
129    {
130      switch ( the_mutex->Attributes.discipline ) {
131        case CORE_MUTEX_DISCIPLINES_FIFO:
132        case CORE_MUTEX_DISCIPLINES_PRIORITY:
133          break;
134        case CORE_MUTEX_DISCIPLINES_PRIORITY_INHERIT:
135          the_thread->resource_count++;
136          _Thread_queue_Boost_priority( &the_mutex->Wait_queue.Queue, the_thread );
137          break;
138        case CORE_MUTEX_DISCIPLINES_PRIORITY_CEILING:
139          the_thread->resource_count++;
140          _Thread_Raise_priority(
141            the_thread,
142            the_mutex->Attributes.priority_ceiling
143          );
144          break;
145      }
146    }
147
148    _Thread_queue_Unblock_critical(
149      unblock,
150      &the_mutex->Wait_queue.Queue,
151      the_thread,
152      &queue_context->Lock_context
153    );
154  } else {
155    _CORE_mutex_Release( the_mutex, queue_context );
156  }
157
158  /*
159   *  Whether or not someone is waiting for the mutex, an
160   *  inherited priority must be lowered if this is the last
161   *  mutex (i.e. resource) this task has.
162   */
163  if ( !_Thread_Owns_resources( holder ) ) {
164    /*
165     * Ensure that the holder resource count is visible to all other processors
166     * and that we read the latest priority restore hint.
167     */
168    _Atomic_Fence( ATOMIC_ORDER_ACQ_REL );
169
170    if ( holder->priority_restore_hint ) {
171      Per_CPU_Control *cpu_self;
172
173      cpu_self = _Thread_Dispatch_disable();
174      _Thread_Restore_priority( holder );
175      _Thread_Dispatch_enable( cpu_self );
176    }
177  }
178
179  return STATUS_SUCCESSFUL;
180}
Note: See TracBrowser for help on using the repository browser.