[8396c18e] | 1 | /** |
---|
| 2 | * @file |
---|
[7cc8d6c] | 3 | * |
---|
[8396c18e] | 4 | * @brief Surrender the Mutex |
---|
| 5 | * @ingroup ScoreMutex |
---|
| 6 | */ |
---|
| 7 | |
---|
| 8 | /* |
---|
[96d0b64] | 9 | * COPYRIGHT (c) 1989-2006. |
---|
[7cc8d6c] | 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 |
---|
[c499856] | 14 | * http://www.rtems.org/license/LICENSE. |
---|
[7cc8d6c] | 15 | */ |
---|
| 16 | |
---|
[a8eed23] | 17 | #if HAVE_CONFIG_H |
---|
| 18 | #include "config.h" |
---|
| 19 | #endif |
---|
| 20 | |
---|
[7cc8d6c] | 21 | #include <rtems/system.h> |
---|
| 22 | #include <rtems/score/isr.h> |
---|
[20e239c2] | 23 | #include <rtems/score/coremuteximpl.h> |
---|
[7cc8d6c] | 24 | #include <rtems/score/thread.h> |
---|
| 25 | |
---|
[bbe6a5fe] | 26 | #ifdef __RTEMS_STRICT_ORDER_MUTEX__ |
---|
| 27 | static inline void _CORE_mutex_Push_priority( |
---|
| 28 | CORE_mutex_Control *mutex, |
---|
| 29 | Thread_Control *thread |
---|
| 30 | ) |
---|
| 31 | { |
---|
| 32 | _Chain_Prepend_unprotected( |
---|
| 33 | &thread->lock_mutex, |
---|
| 34 | &mutex->queue.lock_queue |
---|
| 35 | ); |
---|
| 36 | mutex->queue.priority_before = thread->current_priority; |
---|
| 37 | } |
---|
| 38 | |
---|
| 39 | static inline CORE_mutex_Status _CORE_mutex_Pop_priority( |
---|
| 40 | CORE_mutex_Control *mutex, |
---|
| 41 | Thread_Control *holder |
---|
| 42 | ) |
---|
| 43 | { |
---|
| 44 | /* |
---|
| 45 | * Check whether the holder release the mutex in LIFO order if not return |
---|
| 46 | * error code. |
---|
| 47 | */ |
---|
[36a6f58a] | 48 | if ( _Chain_First( &holder->lock_mutex ) != &mutex->queue.lock_queue ) { |
---|
[bbe6a5fe] | 49 | mutex->nest_count++; |
---|
| 50 | |
---|
| 51 | return CORE_MUTEX_RELEASE_NOT_ORDER; |
---|
| 52 | } |
---|
| 53 | |
---|
| 54 | /* |
---|
| 55 | * This pops the first node from the list. |
---|
| 56 | */ |
---|
| 57 | _Chain_Get_first_unprotected( &holder->lock_mutex ); |
---|
| 58 | |
---|
| 59 | if ( mutex->queue.priority_before != holder->current_priority ) |
---|
| 60 | _Thread_Change_priority( holder, mutex->queue.priority_before, true ); |
---|
| 61 | |
---|
| 62 | return CORE_MUTEX_STATUS_SUCCESSFUL; |
---|
| 63 | } |
---|
| 64 | #else |
---|
| 65 | #define _CORE_mutex_Push_priority( mutex, thread ) ((void) 0) |
---|
| 66 | |
---|
| 67 | #define _CORE_mutex_Pop_priority( mutex, thread ) \ |
---|
| 68 | CORE_MUTEX_STATUS_SUCCESSFUL |
---|
| 69 | #endif |
---|
| 70 | |
---|
[7cc8d6c] | 71 | /* |
---|
| 72 | * _CORE_mutex_Surrender |
---|
| 73 | * |
---|
| 74 | * DESCRIPTION: |
---|
| 75 | * |
---|
| 76 | * This routine frees a unit to the mutex. If a task was blocked waiting for |
---|
| 77 | * a unit from this mutex, then that task will be readied and the unit |
---|
| 78 | * given to that task. Otherwise, the unit will be returned to the mutex. |
---|
| 79 | * |
---|
| 80 | * Input parameters: |
---|
| 81 | * the_mutex - the mutex to be flushed |
---|
| 82 | * id - id of parent mutex |
---|
| 83 | * api_mutex_mp_support - api dependent MP support actions |
---|
| 84 | * |
---|
| 85 | * Output parameters: |
---|
| 86 | * CORE_MUTEX_STATUS_SUCCESSFUL - if successful |
---|
| 87 | * core error code - if unsuccessful |
---|
| 88 | */ |
---|
| 89 | |
---|
| 90 | CORE_mutex_Status _CORE_mutex_Surrender( |
---|
| 91 | CORE_mutex_Control *the_mutex, |
---|
[f0b14cf2] | 92 | #if defined(RTEMS_MULTIPROCESSING) |
---|
[7cc8d6c] | 93 | Objects_Id id, |
---|
| 94 | CORE_mutex_API_mp_support_callout api_mutex_mp_support |
---|
[f0b14cf2] | 95 | #else |
---|
| 96 | Objects_Id id __attribute__((unused)), |
---|
| 97 | CORE_mutex_API_mp_support_callout api_mutex_mp_support __attribute__((unused)) |
---|
| 98 | #endif |
---|
[7cc8d6c] | 99 | ) |
---|
| 100 | { |
---|
| 101 | Thread_Control *the_thread; |
---|
[5870ac55] | 102 | Thread_Control *holder; |
---|
[bbe6a5fe] | 103 | |
---|
| 104 | holder = the_mutex->holder; |
---|
[7cc8d6c] | 105 | |
---|
| 106 | /* |
---|
| 107 | * The following code allows a thread (or ISR) other than the thread |
---|
| 108 | * which acquired the mutex to release that mutex. This is only |
---|
| 109 | * allowed when the mutex in quetion is FIFO or simple Priority |
---|
| 110 | * discipline. But Priority Ceiling or Priority Inheritance mutexes |
---|
| 111 | * must be released by the thread which acquired them. |
---|
[a0ed4ed] | 112 | */ |
---|
[7cc8d6c] | 113 | |
---|
[5870ac55] | 114 | if ( the_mutex->Attributes.only_owner_release ) { |
---|
| 115 | if ( !_Thread_Is_executing( holder ) ) |
---|
[42ed3004] | 116 | return CORE_MUTEX_STATUS_NOT_OWNER_OF_RESOURCE; |
---|
[7cc8d6c] | 117 | } |
---|
| 118 | |
---|
[7d91d72] | 119 | /* XXX already unlocked -- not right status */ |
---|
| 120 | |
---|
[a0ed4ed] | 121 | if ( !the_mutex->nest_count ) |
---|
[42ed3004] | 122 | return CORE_MUTEX_STATUS_SUCCESSFUL; |
---|
[7d91d72] | 123 | |
---|
[7cc8d6c] | 124 | the_mutex->nest_count--; |
---|
| 125 | |
---|
[28352fae] | 126 | if ( the_mutex->nest_count != 0 ) { |
---|
[06f5ec9] | 127 | /* |
---|
| 128 | * All error checking is on the locking side, so if the lock was |
---|
| 129 | * allowed to acquired multiple times, then we should just deal with |
---|
| 130 | * that. The RTEMS_DEBUG is just a validation. |
---|
| 131 | */ |
---|
| 132 | #if defined(RTEMS_DEBUG) |
---|
| 133 | switch ( the_mutex->Attributes.lock_nesting_behavior ) { |
---|
| 134 | case CORE_MUTEX_NESTING_ACQUIRES: |
---|
| 135 | return CORE_MUTEX_STATUS_SUCCESSFUL; |
---|
[2610747] | 136 | #if defined(RTEMS_POSIX_API) |
---|
[2af90ff] | 137 | case CORE_MUTEX_NESTING_IS_ERROR: |
---|
| 138 | /* should never occur */ |
---|
| 139 | return CORE_MUTEX_STATUS_NESTING_NOT_ALLOWED; |
---|
| 140 | #endif |
---|
[06f5ec9] | 141 | case CORE_MUTEX_NESTING_BLOCKS: |
---|
| 142 | /* Currently no API exercises this behavior. */ |
---|
| 143 | break; |
---|
| 144 | } |
---|
| 145 | #else |
---|
| 146 | /* must be CORE_MUTEX_NESTING_ACQUIRES or we wouldn't be here */ |
---|
| 147 | return CORE_MUTEX_STATUS_SUCCESSFUL; |
---|
| 148 | #endif |
---|
[db6ec79e] | 149 | } |
---|
[7cc8d6c] | 150 | |
---|
[96d0b64] | 151 | /* |
---|
| 152 | * Formally release the mutex before possibly transferring it to a |
---|
| 153 | * blocked thread. |
---|
| 154 | */ |
---|
[fb1d8f81] | 155 | if ( _CORE_mutex_Is_inherit_priority( &the_mutex->Attributes ) || |
---|
[bbe6a5fe] | 156 | _CORE_mutex_Is_priority_ceiling( &the_mutex->Attributes ) ) { |
---|
| 157 | CORE_mutex_Status pop_status = |
---|
| 158 | _CORE_mutex_Pop_priority( the_mutex, holder ); |
---|
| 159 | |
---|
| 160 | if ( pop_status != CORE_MUTEX_STATUS_SUCCESSFUL ) |
---|
| 161 | return pop_status; |
---|
| 162 | |
---|
[fb1d8f81] | 163 | holder->resource_count--; |
---|
[7cc8d6c] | 164 | |
---|
[bbe6a5fe] | 165 | /* |
---|
| 166 | * Whether or not someone is waiting for the mutex, an |
---|
| 167 | * inherited priority must be lowered if this is the last |
---|
| 168 | * mutex (i.e. resource) this task has. |
---|
| 169 | */ |
---|
[a0ed4ed] | 170 | if ( holder->resource_count == 0 && |
---|
[fb1d8f81] | 171 | holder->real_priority != holder->current_priority ) { |
---|
[aae7f1a1] | 172 | _Thread_Change_priority( holder, holder->real_priority, true ); |
---|
[fb1d8f81] | 173 | } |
---|
[7cc8d6c] | 174 | } |
---|
[b1ce1161] | 175 | the_mutex->holder = NULL; |
---|
[7cc8d6c] | 176 | |
---|
[96d0b64] | 177 | /* |
---|
| 178 | * Now we check if another thread was waiting for this mutex. If so, |
---|
| 179 | * transfer the mutex to that thread. |
---|
| 180 | */ |
---|
[7cc8d6c] | 181 | if ( ( the_thread = _Thread_queue_Dequeue( &the_mutex->Wait_queue ) ) ) { |
---|
| 182 | |
---|
| 183 | #if defined(RTEMS_MULTIPROCESSING) |
---|
| 184 | if ( !_Objects_Is_local_id( the_thread->Object.id ) ) { |
---|
[05279b84] | 185 | |
---|
[7cc8d6c] | 186 | the_mutex->holder = NULL; |
---|
| 187 | the_mutex->nest_count = 1; |
---|
| 188 | |
---|
| 189 | ( *api_mutex_mp_support)( the_thread, id ); |
---|
| 190 | |
---|
[a0ed4ed] | 191 | } else |
---|
[7cc8d6c] | 192 | #endif |
---|
| 193 | { |
---|
| 194 | |
---|
| 195 | the_mutex->holder = the_thread; |
---|
| 196 | the_mutex->nest_count = 1; |
---|
| 197 | |
---|
[83df49f] | 198 | switch ( the_mutex->Attributes.discipline ) { |
---|
| 199 | case CORE_MUTEX_DISCIPLINES_FIFO: |
---|
| 200 | case CORE_MUTEX_DISCIPLINES_PRIORITY: |
---|
| 201 | break; |
---|
| 202 | case CORE_MUTEX_DISCIPLINES_PRIORITY_INHERIT: |
---|
[bbe6a5fe] | 203 | _CORE_mutex_Push_priority( the_mutex, the_thread ); |
---|
[83df49f] | 204 | the_thread->resource_count++; |
---|
| 205 | break; |
---|
| 206 | case CORE_MUTEX_DISCIPLINES_PRIORITY_CEILING: |
---|
[bbe6a5fe] | 207 | _CORE_mutex_Push_priority( the_mutex, the_thread ); |
---|
[83df49f] | 208 | the_thread->resource_count++; |
---|
| 209 | if (the_mutex->Attributes.priority_ceiling < |
---|
| 210 | the_thread->current_priority){ |
---|
| 211 | _Thread_Change_priority( |
---|
| 212 | the_thread, |
---|
| 213 | the_mutex->Attributes.priority_ceiling, |
---|
[aae7f1a1] | 214 | false |
---|
[83df49f] | 215 | ); |
---|
| 216 | } |
---|
| 217 | break; |
---|
| 218 | } |
---|
[7cc8d6c] | 219 | } |
---|
[03e89287] | 220 | } |
---|
[7cc8d6c] | 221 | |
---|
[42ed3004] | 222 | return CORE_MUTEX_STATUS_SUCCESSFUL; |
---|
[7cc8d6c] | 223 | } |
---|