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

5
Last change on this file since db3a3de was db3a3de, checked in by Sebastian Huber <sebastian.huber@…>, on 10/10/17 at 08:03:48

score: Add _Thread_queue_Dispatch_disable()

  • Property mode set to 100644
File size: 12.0 KB
Line 
1/**
2 * @file
3 *
4 * @brief Private Inlined Routines for POSIX Mutex's.
5 *
6 * This include file contains the static inline implementation of the private
7 * inlined routines for POSIX mutex's.
8 */
9
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
29extern "C" {
30#endif
31
32typedef struct {
33  unsigned long flags;
34  Mutex_recursive_Control Recursive;
35  Priority_Node Priority_ceiling;
36  const Scheduler_Control *scheduler;
37} POSIX_Mutex_Control;
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
55/**
56 * @brief Supported POSIX mutex protocols.
57 *
58 * Must be in synchronization with POSIX_Mutex_Control::protocol.
59 */
60typedef enum {
61  POSIX_MUTEX_NO_PROTOCOL,
62  POSIX_MUTEX_PRIORITY_INHERIT,
63  POSIX_MUTEX_PRIORITY_CEILING
64} POSIX_Mutex_Protocol;
65
66/**
67 *  The default mutex attributes structure.
68 */
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{
97  _Thread_queue_Queue_release(
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 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  bool                           wait,
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  bool                           wait,
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 );
184    _Thread_Resource_count_increment( 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    wait,
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
229  _Thread_Resource_count_decrement( executing );
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
239  _Thread_queue_Surrender(
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 );
272    _Thread_Priority_change(
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 );
316  _Thread_Resource_count_increment( owner );
317  _Thread_Priority_add(
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  bool                  wait,
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
354    _Thread_queue_Context_clear_priority_updates( queue_context );
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    wait,
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
403  _Thread_Resource_count_decrement( executing );
404
405  _Thread_queue_Context_clear_priority_updates( queue_context );
406  _Thread_Wait_acquire_default_critical( executing, &lock_context );
407  _Thread_Priority_remove(
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 );
425    _Thread_Resource_count_increment( new_owner );
426    _Thread_Priority_add(
427      new_owner,
428      &the_mutex->Priority_ceiling,
429      queue_context
430    );
431    _Thread_queue_Extract_critical(
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/**
448 *  @brief POSIX Mutex Lock Support Method
449 *
450 *  A support routine which implements guts of the blocking, non-blocking, and
451 *  timed wait version of mutex lock.
452 */
453int _POSIX_Mutex_Lock_support(
454  pthread_mutex_t           *mutex,
455  bool                       blocking,
456  Watchdog_Interval          timeout
457);
458
459static inline POSIX_Mutex_Control *_POSIX_Mutex_Get(
460  pthread_mutex_t *mutex
461)
462{
463  return (POSIX_Mutex_Control *) mutex;
464}
465
466bool _POSIX_Mutex_Auto_initialization( POSIX_Mutex_Control *the_mutex );
467
468#define POSIX_MUTEX_VALIDATE_OBJECT( the_mutex, flags ) \
469  do { \
470    if ( ( the_mutex ) == NULL ) { \
471      return EINVAL; \
472    } \
473    flags = ( the_mutex )->flags; \
474    if ( \
475      ( ( (uintptr_t) ( the_mutex ) ^ POSIX_MUTEX_MAGIC ) \
476          & ~POSIX_MUTEX_FLAGS_MASK ) \
477        != ( flags & ~POSIX_MUTEX_FLAGS_MASK ) \
478    ) { \
479      if ( !_POSIX_Mutex_Auto_initialization( the_mutex ) ) { \
480        return EINVAL; \
481      } \
482    } \
483  } while ( 0 )
484
485#ifdef __cplusplus
486}
487#endif
488
489#endif
490/*  end of include file */
491
Note: See TracBrowser for help on using the repository browser.