RTEMS
mutex.c
1 /*
2  * Copyright (c) 2015, 2016 embedded brains GmbH. All rights reserved.
3  *
4  * embedded brains GmbH
5  * Dornierstr. 4
6  * 82178 Puchheim
7  * Germany
8  * <rtems@embedded-brains.de>
9  *
10  * The license and distribution terms for this file may be
11  * found in the file LICENSE in this distribution or at
12  * http://www.rtems.org/license/LICENSE.
13  */
14 
15 #ifdef HAVE_CONFIG_H
16 #include "config.h"
17 #endif
18 
19 #include <sys/lock.h>
20 #include <errno.h>
21 
22 #include <rtems/score/assert.h>
23 #include <rtems/score/muteximpl.h>
24 #include <rtems/score/threadimpl.h>
25 #include <rtems/score/todimpl.h>
26 
27 #define MUTEX_TQ_OPERATIONS &_Thread_queue_Operations_priority_inherit
28 
30  offsetof( Mutex_Control, Queue )
31  == offsetof( struct _Mutex_Control, _Queue ),
32  MUTEX_CONTROL_QUEUE
33 );
34 
36  sizeof( Mutex_Control ) == sizeof( struct _Mutex_Control ),
37  MUTEX_CONTROL_SIZE
38 );
39 
41  offsetof( Mutex_recursive_Control, Mutex )
42  == offsetof( struct _Mutex_recursive_Control, _Mutex ),
43  MUTEX_RECURSIVE_CONTROL_MUTEX
44 );
45 
47  offsetof( Mutex_recursive_Control, nest_level )
48  == offsetof( struct _Mutex_recursive_Control, _nest_level ),
49  MUTEX_RECURSIVE_CONTROL_NEST_LEVEL
50 );
51 
53  sizeof( Mutex_recursive_Control )
54  == sizeof( struct _Mutex_recursive_Control ),
55  MUTEX_RECURSIVE_CONTROL_SIZE
56 );
57 
58 static Mutex_Control *_Mutex_Get( struct _Mutex_Control *_mutex )
59 {
60  return (Mutex_Control *) _mutex;
61 }
62 
63 static Thread_Control *_Mutex_Queue_acquire_critical(
64  Mutex_Control *mutex,
65  Thread_queue_Context *queue_context
66 )
67 {
68  Thread_Control *executing;
69 
70  executing = _Thread_Executing;
71  _Thread_queue_Queue_acquire_critical(
72  &mutex->Queue.Queue,
73  &executing->Potpourri_stats,
74  &queue_context->Lock_context.Lock_context
75  );
76 
77  return executing;
78 }
79 
80 static void _Mutex_Queue_release(
81  Mutex_Control *mutex,
82  ISR_Level level,
83  Thread_queue_Context *queue_context
84 )
85 {
87  &mutex->Queue.Queue,
88  &queue_context->Lock_context.Lock_context
89  );
90  _ISR_Local_enable( level );
91 }
92 
93 static void _Mutex_Acquire_slow(
94  Mutex_Control *mutex,
95  Thread_Control *owner,
96  Thread_Control *executing,
97  ISR_Level level,
98  Thread_queue_Context *queue_context
99 )
100 {
102  queue_context,
104  );
106  queue_context,
108  );
109  _Thread_queue_Context_set_ISR_level( queue_context, level );
111  &mutex->Queue.Queue,
112  MUTEX_TQ_OPERATIONS,
113  executing,
114  queue_context
115  );
116 }
117 
118 static void _Mutex_Release_critical(
119  Mutex_Control *mutex,
120  Thread_Control *executing,
121  ISR_Level level,
122  Thread_queue_Context *queue_context
123 )
124 {
125  Thread_queue_Heads *heads;
126 
127  heads = mutex->Queue.Queue.heads;
128  mutex->Queue.Queue.owner = NULL;
130 
131  if ( RTEMS_PREDICT_TRUE( heads == NULL ) ) {
132  _Mutex_Queue_release( mutex, level, queue_context );
133  } else {
134  _Thread_queue_Context_set_ISR_level( queue_context, level );
136  &mutex->Queue.Queue,
137  heads,
138  executing,
139  queue_context,
140  MUTEX_TQ_OPERATIONS
141  );
142  }
143 }
144 
145 void _Mutex_Acquire( struct _Mutex_Control *_mutex )
146 {
147  Mutex_Control *mutex;
148  Thread_queue_Context queue_context;
149  ISR_Level level;
150  Thread_Control *executing;
151  Thread_Control *owner;
152 
153  mutex = _Mutex_Get( _mutex );
154  _Thread_queue_Context_initialize( &queue_context );
155  _Thread_queue_Context_ISR_disable( &queue_context, level );
156  executing = _Mutex_Queue_acquire_critical( mutex, &queue_context );
157 
158  owner = mutex->Queue.Queue.owner;
159 
160  if ( RTEMS_PREDICT_TRUE( owner == NULL ) ) {
161  mutex->Queue.Queue.owner = executing;
163  _Mutex_Queue_release( mutex, level, &queue_context );
164  } else {
166  _Mutex_Acquire_slow( mutex, owner, executing, level, &queue_context );
167  }
168 }
169 
170 int _Mutex_Acquire_timed(
171  struct _Mutex_Control *_mutex,
172  const struct timespec *abstime
173 )
174 {
175  Mutex_Control *mutex;
176  Thread_queue_Context queue_context;
177  ISR_Level level;
178  Thread_Control *executing;
179  Thread_Control *owner;
180 
181  mutex = _Mutex_Get( _mutex );
182  _Thread_queue_Context_initialize( &queue_context );
183  _Thread_queue_Context_ISR_disable( &queue_context, level );
184  executing = _Mutex_Queue_acquire_critical( mutex, &queue_context );
185 
186  owner = mutex->Queue.Queue.owner;
187 
188  if ( RTEMS_PREDICT_TRUE( owner == NULL ) ) {
189  mutex->Queue.Queue.owner = executing;
191  _Mutex_Queue_release( mutex, level, &queue_context );
192 
193  return 0;
194  } else {
196  &queue_context,
197  abstime
198  );
199  _Mutex_Acquire_slow( mutex, owner, executing, level, &queue_context );
200 
201  return STATUS_GET_POSIX( _Thread_Wait_get_status( executing ) );
202  }
203 }
204 
205 int _Mutex_Try_acquire( struct _Mutex_Control *_mutex )
206 {
207  Mutex_Control *mutex;
208  Thread_queue_Context queue_context;
209  ISR_Level level;
210  Thread_Control *executing;
211  Thread_Control *owner;
212  int eno;
213 
214  mutex = _Mutex_Get( _mutex );
215  _Thread_queue_Context_initialize( &queue_context );
216  _Thread_queue_Context_ISR_disable( &queue_context, level );
217  executing = _Mutex_Queue_acquire_critical( mutex, &queue_context );
218 
219  owner = mutex->Queue.Queue.owner;
220 
221  if ( RTEMS_PREDICT_TRUE( owner == NULL ) ) {
222  mutex->Queue.Queue.owner = executing;
224  eno = 0;
225  } else {
226  eno = EBUSY;
227  }
228 
229  _Mutex_Queue_release( mutex, level, &queue_context );
230 
231  return eno;
232 }
233 
234 void _Mutex_Release( struct _Mutex_Control *_mutex )
235 {
236  Mutex_Control *mutex;
237  Thread_queue_Context queue_context;
238  ISR_Level level;
239  Thread_Control *executing;
240 
241  mutex = _Mutex_Get( _mutex );
242  _Thread_queue_Context_initialize( &queue_context );
243  _Thread_queue_Context_ISR_disable( &queue_context, level );
244  executing = _Mutex_Queue_acquire_critical( mutex, &queue_context );
245 
246  _Assert( mutex->Queue.Queue.owner == executing );
247 
248  _Mutex_Release_critical( mutex, executing, level, &queue_context );
249 }
250 
251 static Mutex_recursive_Control *_Mutex_recursive_Get(
252  struct _Mutex_recursive_Control *_mutex
253 )
254 {
255  return (Mutex_recursive_Control *) _mutex;
256 }
257 
258 void _Mutex_recursive_Acquire( struct _Mutex_recursive_Control *_mutex )
259 {
261  Thread_queue_Context queue_context;
262  ISR_Level level;
263  Thread_Control *executing;
264  Thread_Control *owner;
265 
266  mutex = _Mutex_recursive_Get( _mutex );
267  _Thread_queue_Context_initialize( &queue_context );
268  _Thread_queue_Context_ISR_disable( &queue_context, level );
269  executing = _Mutex_Queue_acquire_critical( &mutex->Mutex, &queue_context );
270 
271  owner = mutex->Mutex.Queue.Queue.owner;
272 
273  if ( RTEMS_PREDICT_TRUE( owner == NULL ) ) {
274  mutex->Mutex.Queue.Queue.owner = executing;
276  _Mutex_Queue_release( &mutex->Mutex, level, &queue_context );
277  } else if ( owner == executing ) {
278  ++mutex->nest_level;
279  _Mutex_Queue_release( &mutex->Mutex, level, &queue_context );
280  } else {
282  _Mutex_Acquire_slow( &mutex->Mutex, owner, executing, level, &queue_context );
283  }
284 }
285 
286 int _Mutex_recursive_Acquire_timed(
287  struct _Mutex_recursive_Control *_mutex,
288  const struct timespec *abstime
289 )
290 {
292  Thread_queue_Context queue_context;
293  ISR_Level level;
294  Thread_Control *executing;
295  Thread_Control *owner;
296 
297  mutex = _Mutex_recursive_Get( _mutex );
298  _Thread_queue_Context_initialize( &queue_context );
299  _Thread_queue_Context_ISR_disable( &queue_context, level );
300  executing = _Mutex_Queue_acquire_critical( &mutex->Mutex, &queue_context );
301 
302  owner = mutex->Mutex.Queue.Queue.owner;
303 
304  if ( RTEMS_PREDICT_TRUE( owner == NULL ) ) {
305  mutex->Mutex.Queue.Queue.owner = executing;
307  _Mutex_Queue_release( &mutex->Mutex, level, &queue_context );
308 
309  return 0;
310  } else if ( owner == executing ) {
311  ++mutex->nest_level;
312  _Mutex_Queue_release( &mutex->Mutex, level, &queue_context );
313 
314  return 0;
315  } else {
317  &queue_context,
318  abstime
319  );
320  _Mutex_Acquire_slow( &mutex->Mutex, owner, executing, level, &queue_context );
321 
322  return STATUS_GET_POSIX( _Thread_Wait_get_status( executing ) );
323  }
324 }
325 
326 int _Mutex_recursive_Try_acquire( struct _Mutex_recursive_Control *_mutex )
327 {
329  Thread_queue_Context queue_context;
330  ISR_Level level;
331  Thread_Control *executing;
332  Thread_Control *owner;
333  int eno;
334 
335  mutex = _Mutex_recursive_Get( _mutex );
336  _Thread_queue_Context_initialize( &queue_context );
337  _Thread_queue_Context_ISR_disable( &queue_context, level );
338  executing = _Mutex_Queue_acquire_critical( &mutex->Mutex, &queue_context );
339 
340  owner = mutex->Mutex.Queue.Queue.owner;
341 
342  if ( RTEMS_PREDICT_TRUE( owner == NULL ) ) {
343  mutex->Mutex.Queue.Queue.owner = executing;
345  eno = 0;
346  } else if ( owner == executing ) {
347  ++mutex->nest_level;
348  eno = 0;
349  } else {
350  eno = EBUSY;
351  }
352 
353  _Mutex_Queue_release( &mutex->Mutex, level, &queue_context );
354 
355  return eno;
356 }
357 
358 void _Mutex_recursive_Release( struct _Mutex_recursive_Control *_mutex )
359 {
361  Thread_queue_Context queue_context;
362  ISR_Level level;
363  Thread_Control *executing;
364  unsigned int nest_level;
365 
366  mutex = _Mutex_recursive_Get( _mutex );
367  _Thread_queue_Context_initialize( &queue_context );
368  _Thread_queue_Context_ISR_disable( &queue_context, level );
369  executing = _Mutex_Queue_acquire_critical( &mutex->Mutex, &queue_context );
370 
371  _Assert( mutex->Mutex.Queue.Queue.owner == executing );
372 
373  nest_level = mutex->nest_level;
374 
375  if ( RTEMS_PREDICT_TRUE( nest_level == 0 ) ) {
376  _Mutex_Release_critical( &mutex->Mutex, executing, level, &queue_context );
377  } else {
378  mutex->nest_level = nest_level - 1;
379 
380  _Mutex_Queue_release( &mutex->Mutex, level, &queue_context );
381  }
382 }
Thread_Control * owner
The thread queue owner.
Definition: threadq.h:431
#define STATES_WAITING_FOR_MUTEX
Definition: statesimpl.h:48
Thread queue context for the thread queue methods.
Definition: threadq.h:198
static __inline__ void _Thread_queue_Context_set_deadlock_callout(Thread_queue_Context *queue_context, Thread_queue_Deadlock_callout deadlock_callout)
Sets the deadlock callout in the thread queue context.
Definition: threadqimpl.h:324
static __inline__ void _Thread_Resource_count_increment(Thread_Control *the_thread)
Increments the thread&#39;s resource count.
Definition: threadimpl.h:1339
static __inline__ void _Thread_queue_Context_initialize(Thread_queue_Context *queue_context)
Initializes a thread queue context.
Definition: threadqimpl.h:152
static __inline__ void _Thread_queue_Context_set_ISR_level(Thread_queue_Context *queue_context, ISR_Level level)
Sets the thread queue context ISR level.
Definition: threadqimpl.h:411
static __inline__ void _Thread_queue_Context_set_enqueue_timeout_realtime_timespec(Thread_queue_Context *queue_context, const struct timespec *abstime)
Sets the enqueue callout to add an absolute realtime timeout in timespec format.
Definition: threadqimpl.h:301
static __inline__ void _Thread_Resource_count_decrement(Thread_Control *the_thread)
Decrements the thread&#39;s resource count.
Definition: threadimpl.h:1355
static __inline__ void _Thread_queue_Queue_release_critical(Thread_queue_Queue *queue, ISR_lock_Context *lock_context)
Releases the thread queue queue in a critical section.
Definition: threadqimpl.h:603
Information for the Assert Handler.
Thread_queue_Heads * heads
The thread queue heads.
Definition: threadq.h:426
Thread queue heads.
Definition: threadq.h:360
static __inline__ void _Thread_queue_Context_set_thread_state(Thread_queue_Context *queue_context, States_Control thread_state)
Sets the thread state for the thread to enqueue in the thread queue context.
Definition: threadqimpl.h:178
static __inline__ void _Thread_queue_Context_set_enqueue_do_nothing_extra(Thread_queue_Context *queue_context)
Sets the do nothing enqueue callout in the thread queue context.
Definition: threadqimpl.h:245
void _Thread_queue_Deadlock_fatal(Thread_Control *the_thread)
Results in an INTERNAL_ERROR_THREAD_QUEUE_DEADLOCK fatal error.
Structures for the implementation of mutexes.
uint32_t ISR_Level
Definition: isrlevel.h:41
Thread_queue_Lock_context Lock_context
The lock context for the thread queue acquire and release operations.
Definition: threadq.h:203
#define _ISR_Local_enable(_level)
Enables interrupts on this processor.
Definition: isrlevel.h:74
#define RTEMS_STATIC_ASSERT(_cond, _msg)
Asserts at compile time that the specified condition is satisfied.
Definition: basedefs.h:838
void _Thread_queue_Surrender(Thread_queue_Queue *queue, Thread_queue_Heads *heads, Thread_Control *previous_owner, Thread_queue_Context *queue_context, const Thread_queue_Operations *operations)
Surrenders the thread queue previously owned by the thread to the first enqueued thread.
Time of Day Handler API.
Inlined Routines from the Thread Handler.
static __inline__ Status_Control _Thread_Wait_get_status(const Thread_Control *the_thread)
Get the status of the wait return code of the thread.
Definition: threadimpl.h:2354
ISR_lock_Context Lock_context
The lock context for the thread queue acquire and release operations.
Definition: threadq.h:130
void _Thread_queue_Enqueue(Thread_queue_Queue *queue, const Thread_queue_Operations *operations, Thread_Control *the_thread, Thread_queue_Context *queue_context)
Blocks the thread and places it on the thread queue.
#define RTEMS_PREDICT_TRUE(_exp)
Returns the value of the specified integral expression and tells the compiler that the predicted valu...
Definition: basedefs.h:765
#define _Assert(_e)
Assertion similar to assert() controlled via RTEMS_DEBUG instead of NDEBUG.
Definition: assert.h:100