RTEMS  5.1
muteximpl.h
Go to the documentation of this file.
1 
10 /* COPYRIGHT (c) 1989-2013.
11  * On-Line Applications Research Corporation (OAR).
12  *
13  * The license and distribution terms for this file may be
14  * found in the file LICENSE in this distribution or at
15  * http://www.rtems.org/license/LICENSE.
16  */
17 
18 #ifndef _RTEMS_POSIX_MUTEXIMPL_H
19 #define _RTEMS_POSIX_MUTEXIMPL_H
20 
21 #include <errno.h>
22 #include <pthread.h>
23 
24 #include <rtems/score/percpu.h>
25 #include <rtems/score/muteximpl.h>
26 #include <rtems/score/threadimpl.h>
27 
28 #ifdef __cplusplus
29 extern "C" {
30 #endif
31 
32 typedef struct {
33  unsigned long flags;
34  Mutex_recursive_Control Recursive;
35  Priority_Node Priority_ceiling;
36  const Scheduler_Control *scheduler;
38 
39 #define POSIX_MUTEX_PROTOCOL_MASK 0x3UL
40 
41 #define POSIX_MUTEX_RECURSIVE 0x4UL
42 
43 #define POSIX_MUTEX_FLAGS_MASK 0x7UL
44 
45 #define POSIX_MUTEX_MAGIC 0x961c13b8UL
46 
47 #define POSIX_MUTEX_NO_PROTOCOL_TQ_OPERATIONS &_Thread_queue_Operations_FIFO
48 
49 #define POSIX_MUTEX_PRIORITY_INHERIT_TQ_OPERATIONS \
50  &_Thread_queue_Operations_priority_inherit
51 
52 #define POSIX_MUTEX_PRIORITY_CEILING_TQ_OPERATIONS \
53  &_Thread_queue_Operations_priority
54 
60 typedef enum {
61  POSIX_MUTEX_NO_PROTOCOL,
62  POSIX_MUTEX_PRIORITY_INHERIT,
63  POSIX_MUTEX_PRIORITY_CEILING
65 
69 extern const pthread_mutexattr_t _POSIX_Mutex_Default_attributes;
70 
71 RTEMS_INLINE_ROUTINE Thread_Control *_POSIX_Mutex_Acquire(
72  POSIX_Mutex_Control *the_mutex,
73  Thread_queue_Context *queue_context
74 )
75 {
76  ISR_Level level;
77  Thread_Control *executing;
78 
79  _Thread_queue_Context_initialize( queue_context );
80  _Thread_queue_Context_ISR_disable( queue_context, level );
81  _Thread_queue_Context_set_ISR_level( queue_context, level );
82  executing = _Thread_Executing;
83  _Thread_queue_Queue_acquire_critical(
84  &the_mutex->Recursive.Mutex.Queue.Queue,
85  &executing->Potpourri_stats,
86  &queue_context->Lock_context.Lock_context
87  );
88 
89  return executing;
90 }
91 
92 RTEMS_INLINE_ROUTINE void _POSIX_Mutex_Release(
93  POSIX_Mutex_Control *the_mutex,
94  Thread_queue_Context *queue_context
95 )
96 {
98  &the_mutex->Recursive.Mutex.Queue.Queue,
99  &queue_context->Lock_context.Lock_context
100  );
101 }
102 
103 RTEMS_INLINE_ROUTINE POSIX_Mutex_Protocol _POSIX_Mutex_Get_protocol(
104  unsigned long flags
105 )
106 {
107  return flags & POSIX_MUTEX_PROTOCOL_MASK;
108 }
109 
110 RTEMS_INLINE_ROUTINE bool _POSIX_Mutex_Is_recursive(
111  unsigned long flags
112 )
113 {
114  return ( flags & POSIX_MUTEX_RECURSIVE ) != 0;
115 }
116 
117 RTEMS_INLINE_ROUTINE Thread_Control *_POSIX_Mutex_Get_owner(
118  const POSIX_Mutex_Control *the_mutex
119 )
120 {
121  return the_mutex->Recursive.Mutex.Queue.Queue.owner;
122 }
123 
124 RTEMS_INLINE_ROUTINE bool _POSIX_Mutex_Is_locked(
125  const POSIX_Mutex_Control *the_mutex
126 )
127 {
128  return _POSIX_Mutex_Get_owner( the_mutex ) != NULL;
129 }
130 
131 Status_Control _POSIX_Mutex_Seize_slow(
132  POSIX_Mutex_Control *the_mutex,
133  const Thread_queue_Operations *operations,
134  Thread_Control *executing,
135  const struct timespec *abstime,
136  Thread_queue_Context *queue_context
137 );
138 
139 RTEMS_INLINE_ROUTINE void _POSIX_Mutex_Set_owner(
140  POSIX_Mutex_Control *the_mutex,
141  Thread_Control *owner
142 )
143 {
144  the_mutex->Recursive.Mutex.Queue.Queue.owner = owner;
145 }
146 
147 RTEMS_INLINE_ROUTINE bool _POSIX_Mutex_Is_owner(
148  const POSIX_Mutex_Control *the_mutex,
149  const Thread_Control *the_thread
150 )
151 {
152  return _POSIX_Mutex_Get_owner( the_mutex ) == the_thread;
153 }
154 
155 static Status_Control _POSIX_Mutex_Lock_nested(
156  POSIX_Mutex_Control *the_mutex,
157  unsigned long flags
158 )
159 {
160 
161  if ( _POSIX_Mutex_Is_recursive( flags ) ) {
162  ++the_mutex->Recursive.nest_level;
163  return STATUS_SUCCESSFUL;
164  } else {
165  return STATUS_NESTING_NOT_ALLOWED;
166  }
167 }
168 
169 RTEMS_INLINE_ROUTINE Status_Control _POSIX_Mutex_Seize(
170  POSIX_Mutex_Control *the_mutex,
171  unsigned long flags,
172  const Thread_queue_Operations *operations,
173  Thread_Control *executing,
174  const struct timespec *abstime,
175  Thread_queue_Context *queue_context
176 )
177 {
178  Thread_Control *owner;
179 
180  owner = _POSIX_Mutex_Get_owner( the_mutex );
181 
182  if ( owner == NULL ) {
183  _POSIX_Mutex_Set_owner( the_mutex, executing );
185  _POSIX_Mutex_Release( the_mutex, queue_context );
186  return STATUS_SUCCESSFUL;
187  }
188 
189  if ( owner == executing ) {
190  Status_Control status;
191 
192  status = _POSIX_Mutex_Lock_nested( the_mutex, flags );
193  _POSIX_Mutex_Release( the_mutex, queue_context );
194  return status;
195  }
196 
197  return _POSIX_Mutex_Seize_slow(
198  the_mutex,
199  operations,
200  executing,
201  abstime,
202  queue_context
203  );
204 }
205 
206 RTEMS_INLINE_ROUTINE Status_Control _POSIX_Mutex_Surrender(
207  POSIX_Mutex_Control *the_mutex,
208  const Thread_queue_Operations *operations,
209  Thread_Control *executing,
210  Thread_queue_Context *queue_context
211 )
212 {
213  unsigned int nest_level;
214  Thread_queue_Heads *heads;
215 
216  if ( !_POSIX_Mutex_Is_owner( the_mutex, executing ) ) {
217  _POSIX_Mutex_Release( the_mutex, queue_context );
218  return STATUS_NOT_OWNER;
219  }
220 
221  nest_level = the_mutex->Recursive.nest_level;
222 
223  if ( nest_level > 0 ) {
224  the_mutex->Recursive.nest_level = nest_level - 1;
225  _POSIX_Mutex_Release( the_mutex, queue_context );
226  return STATUS_SUCCESSFUL;
227  }
228 
230  _POSIX_Mutex_Set_owner( the_mutex, NULL );
231 
232  heads = the_mutex->Recursive.Mutex.Queue.Queue.heads;
233 
234  if ( heads == NULL ) {
235  _POSIX_Mutex_Release( the_mutex, queue_context );
236  return STATUS_SUCCESSFUL;
237  }
238 
240  &the_mutex->Recursive.Mutex.Queue.Queue,
241  heads,
242  executing,
243  queue_context,
244  operations
245  );
246  return STATUS_SUCCESSFUL;
247 }
248 
249 RTEMS_INLINE_ROUTINE const Scheduler_Control *_POSIX_Mutex_Get_scheduler(
250  const POSIX_Mutex_Control *the_mutex
251 )
252 {
253 #if defined(RTEMS_SMP)
254  return the_mutex->scheduler;
255 #else
256  return &_Scheduler_Table[ 0 ];
257 #endif
258 }
259 
260 RTEMS_INLINE_ROUTINE void _POSIX_Mutex_Set_priority(
261  POSIX_Mutex_Control *the_mutex,
262  Priority_Control priority_ceiling,
263  Thread_queue_Context *queue_context
264 )
265 {
266  Thread_Control *owner;
267 
268  owner = _POSIX_Mutex_Get_owner( the_mutex );
269 
270  if ( owner != NULL ) {
271  _Thread_Wait_acquire( owner, queue_context );
273  owner,
274  &the_mutex->Priority_ceiling,
275  priority_ceiling,
276  false,
277  queue_context
278  );
279  _Thread_Wait_release( owner, queue_context );
280  } else {
281  the_mutex->Priority_ceiling.priority = priority_ceiling;
282  }
283 }
284 
285 RTEMS_INLINE_ROUTINE Priority_Control _POSIX_Mutex_Get_priority(
286  const POSIX_Mutex_Control *the_mutex
287 )
288 {
289  return the_mutex->Priority_ceiling.priority;
290 }
291 
292 RTEMS_INLINE_ROUTINE Status_Control _POSIX_Mutex_Ceiling_set_owner(
293  POSIX_Mutex_Control *the_mutex,
294  Thread_Control *owner,
295  Thread_queue_Context *queue_context
296 )
297 {
298  ISR_lock_Context lock_context;
299  Scheduler_Node *scheduler_node;
300  Per_CPU_Control *cpu_self;
301 
302  _Thread_Wait_acquire_default_critical( owner, &lock_context );
303 
304  scheduler_node = _Thread_Scheduler_get_home_node( owner );
305 
306  if (
307  _Priority_Get_priority( &scheduler_node->Wait.Priority )
308  < the_mutex->Priority_ceiling.priority
309  ) {
310  _Thread_Wait_release_default_critical( owner, &lock_context );
311  _POSIX_Mutex_Release( the_mutex, queue_context );
312  return STATUS_MUTEX_CEILING_VIOLATED;
313  }
314 
315  _POSIX_Mutex_Set_owner( the_mutex, owner );
318  owner,
319  &the_mutex->Priority_ceiling,
320  queue_context
321  );
322  _Thread_Wait_release_default_critical( owner, &lock_context );
323 
324  cpu_self = _Thread_queue_Dispatch_disable( queue_context );
325  _POSIX_Mutex_Release( the_mutex, queue_context );
326  _Thread_Priority_update( queue_context );
327  _Thread_Dispatch_enable( cpu_self );
328  return STATUS_SUCCESSFUL;
329 }
330 
331 RTEMS_INLINE_ROUTINE Status_Control _POSIX_Mutex_Ceiling_seize(
332  POSIX_Mutex_Control *the_mutex,
333  unsigned long flags,
334  Thread_Control *executing,
335  const struct timespec *abstime,
336  Thread_queue_Context *queue_context
337 )
338 {
339  Thread_Control *owner;
340 
341  owner = _POSIX_Mutex_Get_owner( the_mutex );
342 
343  if ( owner == NULL ) {
344 #if defined(RTEMS_SMP)
345  if (
346  _Thread_Scheduler_get_home( executing )
347  != _POSIX_Mutex_Get_scheduler( the_mutex )
348  ) {
349  _POSIX_Mutex_Release( the_mutex, queue_context );
350  return STATUS_NOT_DEFINED;
351  }
352 #endif
353 
355  return _POSIX_Mutex_Ceiling_set_owner(
356  the_mutex,
357  executing,
358  queue_context
359  );
360  }
361 
362  if ( owner == executing ) {
363  Status_Control status;
364 
365  status = _POSIX_Mutex_Lock_nested( the_mutex, flags );
366  _POSIX_Mutex_Release( the_mutex, queue_context );
367  return status;
368  }
369 
370  return _POSIX_Mutex_Seize_slow(
371  the_mutex,
372  POSIX_MUTEX_PRIORITY_CEILING_TQ_OPERATIONS,
373  executing,
374  abstime,
375  queue_context
376  );
377 }
378 
379 RTEMS_INLINE_ROUTINE Status_Control _POSIX_Mutex_Ceiling_surrender(
380  POSIX_Mutex_Control *the_mutex,
381  Thread_Control *executing,
382  Thread_queue_Context *queue_context
383 )
384 {
385  unsigned int nest_level;
386  ISR_lock_Context lock_context;
387  Per_CPU_Control *cpu_self;
388  Thread_queue_Heads *heads;
389 
390  if ( !_POSIX_Mutex_Is_owner( the_mutex, executing ) ) {
391  _POSIX_Mutex_Release( the_mutex, queue_context );
392  return STATUS_NOT_OWNER;
393  }
394 
395  nest_level = the_mutex->Recursive.nest_level;
396 
397  if ( nest_level > 0 ) {
398  the_mutex->Recursive.nest_level = nest_level - 1;
399  _POSIX_Mutex_Release( the_mutex, queue_context );
400  return STATUS_SUCCESSFUL;
401  }
402 
404 
406  _Thread_Wait_acquire_default_critical( executing, &lock_context );
408  executing,
409  &the_mutex->Priority_ceiling,
410  queue_context
411  );
412  _Thread_Wait_release_default_critical( executing, &lock_context );
413 
414  cpu_self = _Thread_queue_Dispatch_disable( queue_context );
415 
416  heads = the_mutex->Recursive.Mutex.Queue.Queue.heads;
417 
418  if ( heads != NULL ) {
419  const Thread_queue_Operations *operations;
420  Thread_Control *new_owner;
421 
422  operations = POSIX_MUTEX_PRIORITY_CEILING_TQ_OPERATIONS;
423  new_owner = ( *operations->first )( heads );
424  _POSIX_Mutex_Set_owner( the_mutex, new_owner );
427  new_owner,
428  &the_mutex->Priority_ceiling,
429  queue_context
430  );
432  &the_mutex->Recursive.Mutex.Queue.Queue,
433  operations,
434  new_owner,
435  queue_context
436  );
437  } else {
438  _POSIX_Mutex_Set_owner( the_mutex, NULL );
439  _POSIX_Mutex_Release( the_mutex, queue_context );
440  }
441 
442  _Thread_Priority_update( queue_context );
443  _Thread_Dispatch_enable( cpu_self );
444  return STATUS_SUCCESSFUL;
445 }
446 
447 #define POSIX_MUTEX_ABSTIME_TRY_LOCK ((uintptr_t) 1)
448 
449 int _POSIX_Mutex_Lock_support(
450  pthread_mutex_t *mutex,
451  const struct timespec *abstime,
452  Thread_queue_Enqueue_callout enqueue_callout
453 );
454 
455 static inline POSIX_Mutex_Control *_POSIX_Mutex_Get(
456  pthread_mutex_t *mutex
457 )
458 {
459  return (POSIX_Mutex_Control *) mutex;
460 }
461 
462 bool _POSIX_Mutex_Auto_initialization( POSIX_Mutex_Control *the_mutex );
463 
464 #define POSIX_MUTEX_VALIDATE_OBJECT( the_mutex, flags ) \
465  do { \
466  if ( ( the_mutex ) == NULL ) { \
467  return EINVAL; \
468  } \
469  flags = ( the_mutex )->flags; \
470  if ( \
471  ( ( (uintptr_t) ( the_mutex ) ^ POSIX_MUTEX_MAGIC ) \
472  & ~POSIX_MUTEX_FLAGS_MASK ) \
473  != ( flags & ~POSIX_MUTEX_FLAGS_MASK ) \
474  ) { \
475  if ( !_POSIX_Mutex_Auto_initialization( the_mutex ) ) { \
476  return EINVAL; \
477  } \
478  } \
479  } while ( 0 )
480 
481 #ifdef __cplusplus
482 }
483 #endif
484 
485 #endif
486 /* end of include file */
487 
Thread_Control * owner
The thread queue owner.
Definition: threadq.h:431
RTEMS_INLINE_ROUTINE void _Thread_Wait_acquire_default_critical(Thread_Control *the_thread, ISR_lock_Context *lock_context)
Acquires the thread wait default lock inside a critical section (interrupts disabled).
Definition: threadimpl.h:1632
RTEMS_INLINE_ROUTINE Per_CPU_Control * _Thread_queue_Dispatch_disable(Thread_queue_Context *queue_context)
Disables dispatching in a critical section.
Definition: threadqimpl.h:429
POSIX_Mutex_Protocol
Supported POSIX mutex protocols.
Definition: muteximpl.h:60
uint64_t Priority_Control
The thread priority control.
Definition: priority.h:70
Thread queue context for the thread queue methods.
Definition: threadq.h:198
The priority node to build up a priority aggregation.
Definition: priority.h:98
RTEMS_INLINE_ROUTINE void _Thread_Resource_count_decrement(Thread_Control *the_thread)
Decrements the thread's resource count.
Definition: threadimpl.h:1329
Definition: muteximpl.h:32
POSIX Threads Private Support.
Priority_Control priority
The priority value of this node.
Definition: priority.h:110
Thread_queue_First_operation first
Thread queue first operation.
Definition: threadq.h:545
Structures for the implementation of mutexes.
RTEMS_INLINE_ROUTINE void _Thread_Wait_acquire(Thread_Control *the_thread, Thread_queue_Context *queue_context)
Acquires the thread wait default lock and disables interrupts.
Definition: threadimpl.h:1842
Thread queue operations.
Definition: threadq.h:517
Thread_queue_Heads * heads
Lock to protect this thread queue.
Definition: threadq.h:426
Thread queue heads.
Definition: threadq.h:360
RTEMS_INLINE_ROUTINE void _Thread_Resource_count_increment(Thread_Control *the_thread)
Increments the thread's resource count.
Definition: threadimpl.h:1313
Definition: thread.h:732
Per CPU Core Structure.
Definition: percpu.h:347
RTEMS_INLINE_ROUTINE void _Thread_Wait_release(Thread_Control *the_thread, Thread_queue_Context *queue_context)
Releases the thread wait lock and restores the previous interrupt status.
Definition: threadimpl.h:1903
uint32_t ISR_Level
Definition: isrlevel.h:41
void(* Thread_queue_Enqueue_callout)(Thread_queue_Queue *queue, Thread_Control *the_thread, struct Per_CPU_Control *cpu_self, Thread_queue_Context *queue_context)
Thread queue enqueue callout.
Definition: threadq.h:72
Thread_queue_Lock_context Lock_context
The lock context for the thread queue acquire and release operations.
Definition: threadq.h:203
RTEMS_INLINE_ROUTINE 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
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.
Definition: threadqenqueue.c:660
const Scheduler_Control _Scheduler_Table[]
Registered schedulers.
void _Thread_Priority_update(Thread_queue_Context *queue_context)
Updates the priority of all threads in the set.
Definition: threadchangepriority.c:339
void _Thread_Dispatch_enable(Per_CPU_Control *cpu_self)
Enables thread dispatching.
Definition: threaddispatch.c:362
RTEMS_INLINE_ROUTINE void _Thread_Wait_release_default_critical(Thread_Control *the_thread, ISR_lock_Context *lock_context)
Releases the thread wait default lock inside a critical section (interrupts disabled).
Definition: threadimpl.h:1692
const pthread_mutexattr_t _POSIX_Mutex_Default_attributes
Definition: mutexinit.c:58
Definition: muteximpl.h:42
RTEMS_INLINE_ROUTINE void _Thread_queue_Context_clear_priority_updates(Thread_queue_Context *queue_context)
Clears the priority update count of the thread queue context.
Definition: threadqimpl.h:338
RTEMS_INLINE_ROUTINE void _Thread_queue_Context_initialize(Thread_queue_Context *queue_context)
Initializes a thread queue context.
Definition: threadqimpl.h:152
RTEMS_INLINE_ROUTINE const Scheduler_Control * _Thread_Scheduler_get_home(const Thread_Control *the_thread)
Gets the home scheduler of the thread.
Definition: threadimpl.h:1393
Scheduler control.
Definition: scheduler.h:269
Scheduler node for per-thread data.
Definition: schedulernode.h:79
Inlined Routines from the Thread Handler.
void _Thread_Priority_remove(Thread_Control *the_thread, Priority_Node *priority_node, Thread_queue_Context *queue_context)
Removes the specified thread priority node from the corresponding thread priority aggregation.
Definition: threadchangepriority.c:292
struct Scheduler_Node::@3980 Wait
Thread wait support block.
RTEMS_INLINE_ROUTINE Priority_Control _Priority_Get_priority(const Priority_Aggregation *aggregation)
Gets the priority aggregation's priority.
Definition: priorityimpl.h:270
Local ISR lock context for acquire and release pairs.
Definition: isrlock.h:65
ISR_lock_Context Lock_context
The lock context for the thread queue acquire and release operations.
Definition: threadq.h:130
void _Thread_Priority_add(Thread_Control *the_thread, Priority_Node *priority_node, Thread_queue_Context *queue_context)
Adds the specified thread priority node to the corresponding thread priority aggregation.
Definition: threadchangepriority.c:277
RTEMS_INLINE_ROUTINE void _Thread_Priority_change(Thread_Control *the_thread, Priority_Node *priority_node, Priority_Control new_priority, bool prepend_it, Thread_queue_Context *queue_context)
Changes the thread priority value of the specified thread priority node in the corresponding thread p...
Definition: threadimpl.h:696
void _Thread_queue_Extract_critical(Thread_queue_Queue *queue, const Thread_queue_Operations *operations, Thread_Control *the_thread, Thread_queue_Context *queue_context)
Extracts the thread from the thread queue and unblocks it.
Definition: threadqenqueue.c:600
#define RTEMS_INLINE_ROUTINE
Definition: basedefs.h:66
Definition: mutex.h:4
RTEMS_INLINE_ROUTINE void _Thread_queue_Queue_release(Thread_queue_Queue *queue, ISR_lock_Context *lock_context)
Releases the thread queue queue and enables interrupts.
Definition: threadqimpl.h:625
RTEMS_INLINE_ROUTINE Scheduler_Node * _Thread_Scheduler_get_home_node(const Thread_Control *the_thread)
Gets the scheduler's home node.
Definition: threadimpl.h:1412
#define NULL
Requests a GPIO pin group configuration.
Definition: bestcomm_api.h:77