source: rtems/cpukit/include/rtems/posix/muteximpl.h @ a660e9dc

Last change on this file since a660e9dc was a660e9dc, checked in by Sebastian Huber <sebastian.huber@…>, on 09/08/22 at 08:37:05

Do not use RTEMS_INLINE_ROUTINE

Directly use "static inline" which is available in C99 and later. This brings
the RTEMS implementation closer to standard C.

Close #3935.

  • Property mode set to 100644
File size: 11.9 KB
Line 
1/* SPDX-License-Identifier: BSD-2-Clause */
2
3/**
4 * @file
5 *
6 * @brief Private Inlined Routines for POSIX Mutex's.
7 *
8 * This include file contains the static inline implementation of the private
9 * inlined routines for POSIX mutex's.
10 */
11
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>
44#include <rtems/score/muteximpl.h>
45#include <rtems/score/threadimpl.h>
46
47#ifdef __cplusplus
48extern "C" {
49#endif
50
51typedef struct {
52  unsigned long flags;
53  Mutex_recursive_Control Recursive;
54  Priority_Node Priority_ceiling;
55  const Scheduler_Control *scheduler;
56} POSIX_Mutex_Control;
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
74/**
75 * @brief Supported POSIX mutex protocols.
76 *
77 * Must be in synchronization with POSIX_Mutex_Control::protocol.
78 */
79typedef enum {
80  POSIX_MUTEX_NO_PROTOCOL,
81  POSIX_MUTEX_PRIORITY_INHERIT,
82  POSIX_MUTEX_PRIORITY_CEILING
83} POSIX_Mutex_Protocol;
84
85/**
86 *  The default mutex attributes structure.
87 */
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
258  _Thread_queue_Surrender(
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,
295      PRIORITY_GROUP_LAST,
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 );
336  _Thread_Priority_add(
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
419  return _Thread_queue_Surrender_priority_ceiling(
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 */
Note: See TracBrowser for help on using the repository browser.