RTEMS  5.1
smplockmcs.h
Go to the documentation of this file.
1 
9 /*
10  * Copyright (c) 2016 embedded brains GmbH
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 #ifndef _RTEMS_SCORE_SMPLOCKMCS_H
18 #define _RTEMS_SCORE_SMPLOCKMCS_H
19 
20 #include <rtems/score/cpuopts.h>
21 
22 #if defined(RTEMS_SMP)
23 
24 #include <rtems/score/atomic.h>
26 
27 #ifdef __cplusplus
28 extern "C" {
29 #endif /* __cplusplus */
30 
40 typedef struct SMP_MCS_lock_Context {
44  union {
48  Atomic_Uintptr atomic;
49 
55  struct SMP_MCS_lock_Context *normal;
56  } next;
57 
66  Atomic_Uint locked;
67 
68 #if defined(RTEMS_PROFILING)
69  SMP_lock_Stats_context Stats_context;
70 
71  unsigned int queue_length;
72 #endif
73 } SMP_MCS_lock_Context;
74 
78 typedef struct {
85  union {
90  Atomic_Uintptr atomic;
91 
97  struct SMP_MCS_lock_Context *normal;
98  } queue;
99 } SMP_MCS_lock_Control;
100 
104 #define SMP_MCS_LOCK_INITIALIZER { { ATOMIC_INITIALIZER_UINTPTR( 0 ) } }
105 
113 static inline void _SMP_MCS_lock_Initialize( SMP_MCS_lock_Control *lock )
114 {
115  _Atomic_Init_uintptr( &lock->queue.atomic, 0 );
116 }
117 
125 static inline void _SMP_MCS_lock_Destroy( SMP_MCS_lock_Control *lock )
126 {
127  (void) lock;
128 }
129 
137 static inline void _SMP_MCS_lock_Do_acquire(
138  SMP_MCS_lock_Control *lock,
139  SMP_MCS_lock_Context *context
140 #if defined(RTEMS_PROFILING)
141  ,
142  SMP_lock_Stats *stats
143 #endif
144 )
145 {
146  SMP_MCS_lock_Context *previous;
147 #if defined(RTEMS_PROFILING)
148  SMP_lock_Stats_acquire_context acquire_context;
149 
150  _SMP_lock_Stats_acquire_begin( &acquire_context );
151  context->queue_length = 0;
152 #endif
153 
154  _Atomic_Store_uintptr( &context->next.atomic, 0, ATOMIC_ORDER_RELAXED );
155  _Atomic_Store_uint( &context->locked, 1, ATOMIC_ORDER_RELAXED );
156 
157  previous = (SMP_MCS_lock_Context *) _Atomic_Exchange_uintptr(
158  &lock->queue.atomic,
159  (uintptr_t) context,
160  ATOMIC_ORDER_ACQ_REL
161  );
162 
163  if ( previous != NULL ) {
164  unsigned int locked;
165 
166  _Atomic_Store_uintptr(
167  &previous->next.atomic,
168  (uintptr_t) context,
169  ATOMIC_ORDER_RELAXED
170  );
171 
172  do {
173  locked = _Atomic_Load_uint( &context->locked, ATOMIC_ORDER_ACQUIRE );
174  } while ( locked != 0 );
175  }
176 
177 #if defined(RTEMS_PROFILING)
178  _SMP_lock_Stats_acquire_end(
179  &acquire_context,
180  stats,
181  &context->Stats_context,
182  context->queue_length
183  );
184 #endif
185 }
186 
198 #if defined(RTEMS_PROFILING)
199  #define _SMP_MCS_lock_Acquire( lock, context, stats ) \
200  _SMP_MCS_lock_Do_acquire( lock, context, stats )
201 #else
202  #define _SMP_MCS_lock_Acquire( lock, context, stats ) \
203  _SMP_MCS_lock_Do_acquire( lock, context )
204 #endif
205 
212 static inline void _SMP_MCS_lock_Release(
213  SMP_MCS_lock_Control *lock,
214  SMP_MCS_lock_Context *context
215 )
216 {
217  SMP_MCS_lock_Context *next;
218 
219  next = (SMP_MCS_lock_Context *) _Atomic_Load_uintptr(
220  &context->next.atomic,
221  ATOMIC_ORDER_RELAXED
222  );
223 
224  if ( next == NULL ) {
225  uintptr_t expected;
226  bool success;
227 
228  expected = (uintptr_t) context;
229  success = _Atomic_Compare_exchange_uintptr(
230  &lock->queue.atomic,
231  &expected,
232  0,
233  ATOMIC_ORDER_RELEASE,
234  ATOMIC_ORDER_RELAXED
235  );
236 
237  if ( success ) {
238 #if defined(RTEMS_PROFILING)
239  _SMP_lock_Stats_release_update( &context->Stats_context );
240 #endif
241  /* Nobody waits. So, we are done */
242  return;
243  }
244 
245  do {
246  next = (SMP_MCS_lock_Context *) _Atomic_Load_uintptr(
247  &context->next.atomic,
248  ATOMIC_ORDER_RELAXED
249  );
250  } while ( next == NULL );
251  }
252 
253 #if defined(RTEMS_PROFILING)
254  next->queue_length = context->queue_length + 1;
255  _SMP_lock_Stats_release_update( &context->Stats_context );
256 #endif
257 
258  _Atomic_Store_uint( &next->locked, 0, ATOMIC_ORDER_RELEASE );
259 }
260 
263 #ifdef __cplusplus
264 }
265 #endif /* __cplusplus */
266 
267 #endif /* RTEMS_SMP */
268 
269 #endif /* _RTEMS_SCORE_SMPLOCKMCS_H */
Atomic Operations API.
unsigned context
Definition: tlb.h:108
SMP Lock API.
#define NULL
Requests a GPIO pin group configuration.
Definition: bestcomm_api.h:77