RTEMS 5.2
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
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>
27
28#ifdef __cplusplus
29extern "C" {
30#endif
31
32typedef struct {
33 unsigned long flags;
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
60typedef enum {
61 POSIX_MUTEX_NO_PROTOCOL,
62 POSIX_MUTEX_PRIORITY_INHERIT,
63 POSIX_MUTEX_PRIORITY_CEILING
65
69extern const pthread_mutexattr_t _POSIX_Mutex_Default_attributes;
70
71RTEMS_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
92RTEMS_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
103RTEMS_INLINE_ROUTINE POSIX_Mutex_Protocol _POSIX_Mutex_Get_protocol(
104 unsigned long flags
105)
106{
107 return (POSIX_Mutex_Protocol) (flags & POSIX_MUTEX_PROTOCOL_MASK);
108}
109
110RTEMS_INLINE_ROUTINE bool _POSIX_Mutex_Is_recursive(
111 unsigned long flags
112)
113{
114 return ( flags & POSIX_MUTEX_RECURSIVE ) != 0;
115}
116
117RTEMS_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
124RTEMS_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
131Status_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
139RTEMS_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
147RTEMS_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
155static 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
169RTEMS_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
206RTEMS_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
249RTEMS_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
260RTEMS_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
285RTEMS_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
292RTEMS_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
331RTEMS_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
379RTEMS_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
449int _POSIX_Mutex_Lock_support(
450 pthread_mutex_t *mutex,
451 const struct timespec *abstime,
452 Thread_queue_Enqueue_callout enqueue_callout
453);
454
455static inline POSIX_Mutex_Control *_POSIX_Mutex_Get(
456 pthread_mutex_t *mutex
457)
458{
459 return (POSIX_Mutex_Control *) mutex;
460}
461
462bool _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 */
#define NULL
Requests a GPIO pin group configuration.
Definition: bestcomm_api.h:77
#define RTEMS_INLINE_ROUTINE
Definition: basedefs.h:66
uint32_t ISR_Level
Definition: isrlevel.h:41
uint64_t Priority_Control
The thread priority control.
Definition: priority.h:70
RTEMS_INLINE_ROUTINE Priority_Control _Priority_Get_priority(const Priority_Aggregation *aggregation)
Gets the priority aggregation's priority.
Definition: priorityimpl.h:270
const Scheduler_Control _Scheduler_Table[]
Registered schedulers.
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
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 Per_CPU_Control * _Thread_queue_Dispatch_disable(Thread_queue_Context *queue_context)
Disables dispatching in a critical section.
Definition: threadqimpl.h:429
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
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
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
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
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
void _Thread_Priority_update(Thread_queue_Context *queue_context)
Updates the priority of all threads in the set.
Definition: threadchangepriority.c:339
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
RTEMS_INLINE_ROUTINE void _Thread_Resource_count_decrement(Thread_Control *the_thread)
Decrements the thread's resource count.
Definition: threadimpl.h:1329
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
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
void _Thread_Dispatch_enable(Per_CPU_Control *cpu_self)
Enables thread dispatching.
Definition: threaddispatch.c:362
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
RTEMS_INLINE_ROUTINE void _Thread_Resource_count_increment(Thread_Control *the_thread)
Increments the thread's resource count.
Definition: threadimpl.h:1313
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
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
POSIX_Mutex_Protocol
Supported POSIX mutex protocols.
Definition: muteximpl.h:60
const pthread_mutexattr_t _POSIX_Mutex_Default_attributes
Definition: mutexinit.c:58
POSIX Threads Private Support.
Structures for the implementation of mutexes.
Local ISR lock context for acquire and release pairs.
Definition: isrlock.h:65
Definition: muteximpl.h:42
Definition: muteximpl.h:32
Per CPU Core Structure.
Definition: percpu.h:347
The priority node to build up a priority aggregation.
Definition: priority.h:98
Priority_Control priority
The priority value of this node.
Definition: priority.h:110
Scheduler node for per-thread data.
Definition: schedulernode.h:79
struct Scheduler_Node::@3981 Wait
Thread wait support block.
Thread queue context for the thread queue methods.
Definition: threadq.h:198
Thread_queue_Lock_context Lock_context
The lock context for the thread queue acquire and release operations.
Definition: threadq.h:203
ISR_lock_Context Lock_context
The lock context for the thread queue acquire and release operations.
Definition: threadq.h:130
Thread queue operations.
Definition: threadq.h:518
Thread_queue_First_operation first
Thread queue first operation.
Definition: threadq.h:546
Thread_queue_Heads * heads
Lock to protect this thread queue.
Definition: threadq.h:426
Thread_Control * owner
The thread queue owner.
Definition: threadq.h:431
Scheduler control.
Definition: scheduler.h:269
Definition: thread.h:732
Thread queue heads.
Definition: threadq.h:360
Definition: mutex.h:4
Inlined Routines from the Thread Handler.