RTEMS 6.1-rc1
muteximpl.h
Go to the documentation of this file.
1/* SPDX-License-Identifier: BSD-2-Clause */
2
12/* COPYRIGHT (c) 1989-2013.
13 * On-Line Applications Research Corporation (OAR).
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
17 * are met:
18 * 1. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in the
22 * documentation and/or other materials provided with the distribution.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 */
36
37#ifndef _RTEMS_POSIX_MUTEXIMPL_H
38#define _RTEMS_POSIX_MUTEXIMPL_H
39
40#include <errno.h>
41#include <pthread.h>
42
43#include <rtems/score/percpu.h>
46
47#ifdef __cplusplus
48extern "C" {
49#endif
50
51typedef struct {
52 unsigned long flags;
54 Priority_Node Priority_ceiling;
55 const Scheduler_Control *scheduler;
57
58#define POSIX_MUTEX_PROTOCOL_MASK 0x3UL
59
60#define POSIX_MUTEX_RECURSIVE 0x4UL
61
62#define POSIX_MUTEX_FLAGS_MASK 0x7UL
63
64#define POSIX_MUTEX_MAGIC 0x961c13b8UL
65
66#define POSIX_MUTEX_NO_PROTOCOL_TQ_OPERATIONS &_Thread_queue_Operations_FIFO
67
68#define POSIX_MUTEX_PRIORITY_INHERIT_TQ_OPERATIONS \
69 &_Thread_queue_Operations_priority_inherit
70
71#define POSIX_MUTEX_PRIORITY_CEILING_TQ_OPERATIONS \
72 &_Thread_queue_Operations_priority
73
79typedef enum {
80 POSIX_MUTEX_NO_PROTOCOL,
81 POSIX_MUTEX_PRIORITY_INHERIT,
82 POSIX_MUTEX_PRIORITY_CEILING
84
88extern const pthread_mutexattr_t _POSIX_Mutex_Default_attributes;
89
90static inline Thread_Control *_POSIX_Mutex_Acquire(
91 POSIX_Mutex_Control *the_mutex,
92 Thread_queue_Context *queue_context
93)
94{
95 ISR_Level level;
96 Thread_Control *executing;
97
98 _Thread_queue_Context_initialize( queue_context );
99 _Thread_queue_Context_ISR_disable( queue_context, level );
100 _Thread_queue_Context_set_ISR_level( queue_context, level );
101 executing = _Thread_Executing;
102 _Thread_queue_Queue_acquire_critical(
103 &the_mutex->Recursive.Mutex.Queue.Queue,
104 &executing->Potpourri_stats,
105 &queue_context->Lock_context.Lock_context
106 );
107
108 return executing;
109}
110
111static inline void _POSIX_Mutex_Release(
112 POSIX_Mutex_Control *the_mutex,
113 Thread_queue_Context *queue_context
114)
115{
116 _Thread_queue_Queue_release(
117 &the_mutex->Recursive.Mutex.Queue.Queue,
118 &queue_context->Lock_context.Lock_context
119 );
120}
121
122static inline POSIX_Mutex_Protocol _POSIX_Mutex_Get_protocol(
123 unsigned long flags
124)
125{
126 return (POSIX_Mutex_Protocol) (flags & POSIX_MUTEX_PROTOCOL_MASK);
127}
128
129static inline bool _POSIX_Mutex_Is_recursive(
130 unsigned long flags
131)
132{
133 return ( flags & POSIX_MUTEX_RECURSIVE ) != 0;
134}
135
136static inline Thread_Control *_POSIX_Mutex_Get_owner(
137 const POSIX_Mutex_Control *the_mutex
138)
139{
140 return the_mutex->Recursive.Mutex.Queue.Queue.owner;
141}
142
143static inline bool _POSIX_Mutex_Is_locked(
144 const POSIX_Mutex_Control *the_mutex
145)
146{
147 return _POSIX_Mutex_Get_owner( the_mutex ) != NULL;
148}
149
150Status_Control _POSIX_Mutex_Seize_slow(
151 POSIX_Mutex_Control *the_mutex,
152 const Thread_queue_Operations *operations,
153 Thread_Control *executing,
154 const struct timespec *abstime,
155 Thread_queue_Context *queue_context
156);
157
158static inline void _POSIX_Mutex_Set_owner(
159 POSIX_Mutex_Control *the_mutex,
160 Thread_Control *owner
161)
162{
163 the_mutex->Recursive.Mutex.Queue.Queue.owner = owner;
164}
165
166static inline bool _POSIX_Mutex_Is_owner(
167 const POSIX_Mutex_Control *the_mutex,
168 const Thread_Control *the_thread
169)
170{
171 return _POSIX_Mutex_Get_owner( the_mutex ) == the_thread;
172}
173
174static Status_Control _POSIX_Mutex_Lock_nested(
175 POSIX_Mutex_Control *the_mutex,
176 unsigned long flags
177)
178{
179
180 if ( _POSIX_Mutex_Is_recursive( flags ) ) {
181 ++the_mutex->Recursive.nest_level;
182 return STATUS_SUCCESSFUL;
183 } else {
184 return STATUS_NESTING_NOT_ALLOWED;
185 }
186}
187
188static inline Status_Control _POSIX_Mutex_Seize(
189 POSIX_Mutex_Control *the_mutex,
190 unsigned long flags,
191 const Thread_queue_Operations *operations,
192 Thread_Control *executing,
193 const struct timespec *abstime,
194 Thread_queue_Context *queue_context
195)
196{
197 Thread_Control *owner;
198
199 owner = _POSIX_Mutex_Get_owner( the_mutex );
200
201 if ( owner == NULL ) {
202 _POSIX_Mutex_Set_owner( the_mutex, executing );
203 _Thread_Resource_count_increment( executing );
204 _POSIX_Mutex_Release( the_mutex, queue_context );
205 return STATUS_SUCCESSFUL;
206 }
207
208 if ( owner == executing ) {
209 Status_Control status;
210
211 status = _POSIX_Mutex_Lock_nested( the_mutex, flags );
212 _POSIX_Mutex_Release( the_mutex, queue_context );
213 return status;
214 }
215
216 return _POSIX_Mutex_Seize_slow(
217 the_mutex,
218 operations,
219 executing,
220 abstime,
221 queue_context
222 );
223}
224
225static inline Status_Control _POSIX_Mutex_Surrender(
226 POSIX_Mutex_Control *the_mutex,
227 const Thread_queue_Operations *operations,
228 Thread_Control *executing,
229 Thread_queue_Context *queue_context
230)
231{
232 unsigned int nest_level;
233 Thread_queue_Heads *heads;
234
235 if ( !_POSIX_Mutex_Is_owner( the_mutex, executing ) ) {
236 _POSIX_Mutex_Release( the_mutex, queue_context );
237 return STATUS_NOT_OWNER;
238 }
239
240 nest_level = the_mutex->Recursive.nest_level;
241
242 if ( nest_level > 0 ) {
243 the_mutex->Recursive.nest_level = nest_level - 1;
244 _POSIX_Mutex_Release( the_mutex, queue_context );
245 return STATUS_SUCCESSFUL;
246 }
247
248 _Thread_Resource_count_decrement( executing );
249 _POSIX_Mutex_Set_owner( the_mutex, NULL );
250
251 heads = the_mutex->Recursive.Mutex.Queue.Queue.heads;
252
253 if ( heads == NULL ) {
254 _POSIX_Mutex_Release( the_mutex, queue_context );
255 return STATUS_SUCCESSFUL;
256 }
257
259 &the_mutex->Recursive.Mutex.Queue.Queue,
260 heads,
261 executing,
262 queue_context,
263 operations
264 );
265 return STATUS_SUCCESSFUL;
266}
267
268static inline const Scheduler_Control *_POSIX_Mutex_Get_scheduler(
269 const POSIX_Mutex_Control *the_mutex
270)
271{
272#if defined(RTEMS_SMP)
273 return the_mutex->scheduler;
274#else
275 return &_Scheduler_Table[ 0 ];
276#endif
277}
278
279static inline void _POSIX_Mutex_Set_priority(
280 POSIX_Mutex_Control *the_mutex,
281 Priority_Control priority_ceiling,
282 Thread_queue_Context *queue_context
283)
284{
285 Thread_Control *owner;
286
287 owner = _POSIX_Mutex_Get_owner( the_mutex );
288
289 if ( owner != NULL ) {
290 _Thread_Wait_acquire( owner, queue_context );
291 _Thread_Priority_change(
292 owner,
293 &the_mutex->Priority_ceiling,
294 priority_ceiling,
296 queue_context
297 );
298 _Thread_Wait_release( owner, queue_context );
299 } else {
300 the_mutex->Priority_ceiling.priority = priority_ceiling;
301 }
302}
303
304static inline Priority_Control _POSIX_Mutex_Get_priority(
305 const POSIX_Mutex_Control *the_mutex
306)
307{
308 return the_mutex->Priority_ceiling.priority;
309}
310
311static inline Status_Control _POSIX_Mutex_Ceiling_set_owner(
312 POSIX_Mutex_Control *the_mutex,
313 Thread_Control *owner,
314 Thread_queue_Context *queue_context
315)
316{
317 ISR_lock_Context lock_context;
318 Scheduler_Node *scheduler_node;
319 Per_CPU_Control *cpu_self;
320
321 _Thread_Wait_acquire_default_critical( owner, &lock_context );
322
323 scheduler_node = _Thread_Scheduler_get_home_node( owner );
324
325 if (
326 _Priority_Get_priority( &scheduler_node->Wait.Priority )
327 < the_mutex->Priority_ceiling.priority
328 ) {
329 _Thread_Wait_release_default_critical( owner, &lock_context );
330 _POSIX_Mutex_Release( the_mutex, queue_context );
331 return STATUS_MUTEX_CEILING_VIOLATED;
332 }
333
334 _POSIX_Mutex_Set_owner( the_mutex, owner );
335 _Thread_Resource_count_increment( owner );
337 owner,
338 &the_mutex->Priority_ceiling,
339 queue_context
340 );
341 _Thread_Wait_release_default_critical( owner, &lock_context );
342
343 cpu_self = _Thread_queue_Dispatch_disable( queue_context );
344 _POSIX_Mutex_Release( the_mutex, queue_context );
345 _Thread_Priority_update( queue_context );
346 _Thread_Dispatch_enable( cpu_self );
347 return STATUS_SUCCESSFUL;
348}
349
350static inline Status_Control _POSIX_Mutex_Ceiling_seize(
351 POSIX_Mutex_Control *the_mutex,
352 unsigned long flags,
353 Thread_Control *executing,
354 const struct timespec *abstime,
355 Thread_queue_Context *queue_context
356)
357{
358 Thread_Control *owner;
359
360 owner = _POSIX_Mutex_Get_owner( the_mutex );
361
362 if ( owner == NULL ) {
363#if defined(RTEMS_SMP)
364 if (
365 _Thread_Scheduler_get_home( executing )
366 != _POSIX_Mutex_Get_scheduler( the_mutex )
367 ) {
368 _POSIX_Mutex_Release( the_mutex, queue_context );
369 return STATUS_NOT_DEFINED;
370 }
371#endif
372
373 _Thread_queue_Context_clear_priority_updates( queue_context );
374 return _POSIX_Mutex_Ceiling_set_owner(
375 the_mutex,
376 executing,
377 queue_context
378 );
379 }
380
381 if ( owner == executing ) {
382 Status_Control status;
383
384 status = _POSIX_Mutex_Lock_nested( the_mutex, flags );
385 _POSIX_Mutex_Release( the_mutex, queue_context );
386 return status;
387 }
388
389 return _POSIX_Mutex_Seize_slow(
390 the_mutex,
391 POSIX_MUTEX_PRIORITY_CEILING_TQ_OPERATIONS,
392 executing,
393 abstime,
394 queue_context
395 );
396}
397
398static inline Status_Control _POSIX_Mutex_Ceiling_surrender(
399 POSIX_Mutex_Control *the_mutex,
400 Thread_Control *executing,
401 Thread_queue_Context *queue_context
402)
403{
404 unsigned int nest_level;
405
406 if ( !_POSIX_Mutex_Is_owner( the_mutex, executing ) ) {
407 _POSIX_Mutex_Release( the_mutex, queue_context );
408 return STATUS_NOT_OWNER;
409 }
410
411 nest_level = the_mutex->Recursive.nest_level;
412
413 if ( nest_level > 0 ) {
414 the_mutex->Recursive.nest_level = nest_level - 1;
415 _POSIX_Mutex_Release( the_mutex, queue_context );
416 return STATUS_SUCCESSFUL;
417 }
418
420 &the_mutex->Recursive.Mutex.Queue.Queue,
421 executing,
422 &the_mutex->Priority_ceiling,
423 queue_context,
424 POSIX_MUTEX_PRIORITY_CEILING_TQ_OPERATIONS
425 );
426}
427
428#define POSIX_MUTEX_ABSTIME_TRY_LOCK ((uintptr_t) 1)
429
430int _POSIX_Mutex_Lock_support(
431 pthread_mutex_t *mutex,
432 const struct timespec *abstime,
433 Thread_queue_Enqueue_callout enqueue_callout
434);
435
436static inline POSIX_Mutex_Control *_POSIX_Mutex_Get(
437 pthread_mutex_t *mutex
438)
439{
440 return (POSIX_Mutex_Control *) mutex;
441}
442
443bool _POSIX_Mutex_Auto_initialization( POSIX_Mutex_Control *the_mutex );
444
445#define POSIX_MUTEX_VALIDATE_OBJECT( the_mutex, flags ) \
446 do { \
447 if ( ( the_mutex ) == NULL ) { \
448 return EINVAL; \
449 } \
450 flags = ( the_mutex )->flags; \
451 if ( \
452 ( ( (uintptr_t) ( the_mutex ) ^ POSIX_MUTEX_MAGIC ) \
453 & ~POSIX_MUTEX_FLAGS_MASK ) \
454 != ( flags & ~POSIX_MUTEX_FLAGS_MASK ) \
455 ) { \
456 if ( !_POSIX_Mutex_Auto_initialization( the_mutex ) ) { \
457 return EINVAL; \
458 } \
459 } \
460 } while ( 0 )
461
462#ifdef __cplusplus
463}
464#endif
465
466#endif
467/* end of include file */
uint32_t ISR_Level
Definition: isrlevel.h:60
uint64_t Priority_Control
The thread priority control.
Definition: priority.h:91
@ PRIORITY_GROUP_LAST
Priority group last option requests that the priority node is inserted as the last node into its prio...
Definition: priorityimpl.h:73
const Scheduler_Control _Scheduler_Table[]
This table contains the configured schedulers.
Status_Control
Status codes.
Definition: status.h:111
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:690
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:90
Status_Control _Thread_queue_Surrender_priority_ceiling(Thread_queue_Queue *queue, Thread_Control *executing, Priority_Node *ceiling_priority, 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:759
void _Thread_Priority_update(Thread_queue_Context *queue_context)
Updates the priority of all threads in the set.
Definition: threadchangepriority.c:381
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:317
void _Thread_Dispatch_enable(Per_CPU_Control *cpu_self)
Enables thread dispatching.
#define NULL
Requests a GPIO pin group configuration.
Definition: xil_types.h:54
POSIX_Mutex_Protocol
Supported POSIX mutex protocols.
Definition: muteximpl.h:79
const pthread_mutexattr_t _POSIX_Mutex_Default_attributes
Definition: mutexinit.c:77
POSIX Threads Private Support.
This header file provides the interfaces of the System Lock Mutex Support.
This header file provides the interfaces of the Per-CPU Information.
Local ISR lock context for acquire and release pairs.
Definition: isrlock.h:81
Definition: muteximpl.h:62
Definition: muteximpl.h:51
Per CPU Core Structure.
Definition: percpu.h:384
The priority node to build up a priority aggregation.
Definition: priority.h:112
Priority_Control priority
The priority value of this node.
Definition: priority.h:124
Scheduler node for per-thread data.
Definition: schedulernode.h:94
struct Scheduler_Node::@4383 Wait
Thread wait support block.
Thread queue context for the thread queue methods.
Definition: threadq.h:216
Thread_queue_Lock_context Lock_context
The lock context for the thread queue acquire and release operations.
Definition: threadq.h:221
ISR_lock_Context Lock_context
The lock context for the thread queue acquire and release operations.
Definition: threadq.h:148
The thread queue operations are used to manage the threads of a thread queue.
Definition: threadq.h:554
Thread_queue_Heads * heads
The thread queue heads.
Definition: threadq.h:451
Thread_Control * owner
The thread queue owner.
Definition: threadq.h:456
Scheduler control.
Definition: scheduler.h:335
Definition: thread.h:812
Thread queue heads.
Definition: threadq.h:385
Definition: mutex.h:6
This header file provides interfaces of the Thread Handler which are only used by the implementation.