source: rtems/cpukit/score/src/mutex.c @ 2548d14

5
Last change on this file since 2548d14 was a1f7d7d, checked in by Sebastian Huber <sebastian.huber@…>, on 07/24/18 at 07:00:18

score: RTEMS_PREDICT_TRUE(), RTEMS_PREDICT_FALSE()

Add RTEMS_PREDICT_TRUE() and RTEMS_PREDICT_FALSE() for static branch
prediction hints.

Close #3475.

  • Property mode set to 100644
File size: 10.5 KB
Line 
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#if 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
29RTEMS_STATIC_ASSERT(
30  offsetof( Mutex_Control, Queue )
31    == offsetof( struct _Mutex_Control, _Queue ),
32  MUTEX_CONTROL_QUEUE
33);
34
35RTEMS_STATIC_ASSERT(
36  sizeof( Mutex_Control ) == sizeof( struct _Mutex_Control ),
37  MUTEX_CONTROL_SIZE
38);
39
40RTEMS_STATIC_ASSERT(
41  offsetof( Mutex_recursive_Control, Mutex )
42    == offsetof( struct _Mutex_recursive_Control, _Mutex ),
43  MUTEX_RECURSIVE_CONTROL_MUTEX
44);
45
46RTEMS_STATIC_ASSERT(
47  offsetof( Mutex_recursive_Control, nest_level )
48    == offsetof( struct _Mutex_recursive_Control, _nest_level ),
49  MUTEX_RECURSIVE_CONTROL_NEST_LEVEL
50);
51
52RTEMS_STATIC_ASSERT(
53  sizeof( Mutex_recursive_Control )
54    == sizeof( struct _Mutex_recursive_Control ),
55  MUTEX_RECURSIVE_CONTROL_SIZE
56);
57
58static Mutex_Control *_Mutex_Get( struct _Mutex_Control *_mutex )
59{
60  return (Mutex_Control *) _mutex;
61}
62
63static 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
80static void _Mutex_Queue_release(
81  Mutex_Control        *mutex,
82  ISR_Level             level,
83  Thread_queue_Context *queue_context
84)
85{
86  _Thread_queue_Queue_release_critical(
87    &mutex->Queue.Queue,
88    &queue_context->Lock_context.Lock_context
89  );
90  _ISR_Local_enable( level );
91}
92
93static 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{
101  _Thread_queue_Context_set_thread_state(
102    queue_context,
103    STATES_WAITING_FOR_MUTEX
104  );
105  _Thread_queue_Context_set_deadlock_callout(
106    queue_context,
107    _Thread_queue_Deadlock_fatal
108  );
109  _Thread_queue_Context_set_ISR_level( queue_context, level );
110  _Thread_queue_Enqueue(
111    &mutex->Queue.Queue,
112    MUTEX_TQ_OPERATIONS,
113    executing,
114    queue_context
115  );
116}
117
118static 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;
129  _Thread_Resource_count_decrement( executing );
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 );
135    _Thread_queue_Surrender(
136      &mutex->Queue.Queue,
137      heads,
138      executing,
139      queue_context,
140      MUTEX_TQ_OPERATIONS
141    );
142  }
143}
144
145void _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;
162    _Thread_Resource_count_increment( executing );
163    _Mutex_Queue_release( mutex, level, &queue_context );
164  } else {
165    _Thread_queue_Context_set_enqueue_do_nothing_extra( &queue_context );
166    _Mutex_Acquire_slow( mutex, owner, executing, level, &queue_context );
167  }
168}
169
170int _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;
190    _Thread_Resource_count_increment( executing );
191    _Mutex_Queue_release( mutex, level, &queue_context );
192
193    return 0;
194  } else {
195    _Thread_queue_Context_set_enqueue_timeout_realtime_timespec(
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
205int _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;
223    _Thread_Resource_count_increment( 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
234void _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
251static Mutex_recursive_Control *_Mutex_recursive_Get(
252  struct _Mutex_recursive_Control *_mutex
253)
254{
255  return (Mutex_recursive_Control *) _mutex;
256}
257
258void _Mutex_recursive_Acquire( struct _Mutex_recursive_Control *_mutex )
259{
260  Mutex_recursive_Control *mutex;
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;
275    _Thread_Resource_count_increment( 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 {
281    _Thread_queue_Context_set_enqueue_do_nothing_extra( &queue_context );
282    _Mutex_Acquire_slow( &mutex->Mutex, owner, executing, level, &queue_context );
283  }
284}
285
286int _Mutex_recursive_Acquire_timed(
287  struct _Mutex_recursive_Control *_mutex,
288  const struct timespec           *abstime
289)
290{
291  Mutex_recursive_Control *mutex;
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;
306    _Thread_Resource_count_increment( 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 {
316    _Thread_queue_Context_set_enqueue_timeout_realtime_timespec(
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
326int _Mutex_recursive_Try_acquire( struct _Mutex_recursive_Control *_mutex )
327{
328  Mutex_recursive_Control *mutex;
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;
344    _Thread_Resource_count_increment( 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
358void _Mutex_recursive_Release( struct _Mutex_recursive_Control *_mutex )
359{
360  Mutex_recursive_Control *mutex;
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}
Note: See TracBrowser for help on using the repository browser.