source: rtems/cpukit/score/include/rtems/score/coremuteximpl.h @ e41308ea

5
Last change on this file since e41308ea was e41308ea, checked in by Sebastian Huber <sebastian.huber@…>, on 08/22/16 at 08:58:34

score: Introduce Thread_queue_Lock_context

Introduce Thread_queue_Lock_context to contain the context necessary for
thread queue lock and thread wait lock acquire/release operations to
reduce the Thread_Control size.

  • Property mode set to 100644
File size: 13.8 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup ScoreMutex
5 *
6 * @brief CORE Mutex Implementation
7 */
8
9/*
10 *  COPYRIGHT (c) 1989-2009.
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_SCORE_COREMUTEXIMPL_H
19#define _RTEMS_SCORE_COREMUTEXIMPL_H
20
21#include <rtems/score/coremutex.h>
22#include <rtems/score/chainimpl.h>
23#include <rtems/score/schedulerimpl.h>
24#include <rtems/score/status.h>
25#include <rtems/score/threadimpl.h>
26#include <rtems/score/threadqimpl.h>
27
28#ifdef __cplusplus
29extern "C" {
30#endif
31
32/**
33 * @addtogroup ScoreMutex
34 */
35/**@{**/
36
37#define CORE_MUTEX_TQ_OPERATIONS &_Thread_queue_Operations_priority
38
39#define CORE_MUTEX_TQ_PRIORITY_INHERIT_OPERATIONS \
40  &_Thread_queue_Operations_priority_inherit
41
42RTEMS_INLINE_ROUTINE void _CORE_mutex_Initialize(
43  CORE_mutex_Control *the_mutex
44)
45{
46  _Thread_queue_Initialize( &the_mutex->Wait_queue );
47}
48
49RTEMS_INLINE_ROUTINE void _CORE_mutex_Destroy( CORE_mutex_Control *the_mutex )
50{
51  _Thread_queue_Destroy( &the_mutex->Wait_queue );
52}
53
54RTEMS_INLINE_ROUTINE void _CORE_mutex_Acquire_critical(
55  CORE_mutex_Control   *the_mutex,
56  Thread_queue_Context *queue_context
57)
58{
59  _Thread_queue_Acquire_critical( &the_mutex->Wait_queue, queue_context );
60}
61
62RTEMS_INLINE_ROUTINE void _CORE_mutex_Release(
63  CORE_mutex_Control   *the_mutex,
64  Thread_queue_Context *queue_context
65)
66{
67  _Thread_queue_Release( &the_mutex->Wait_queue, queue_context );
68}
69
70RTEMS_INLINE_ROUTINE Thread_Control *_CORE_mutex_Get_owner(
71  const CORE_mutex_Control *the_mutex
72)
73{
74  return the_mutex->Wait_queue.Queue.owner;
75}
76
77/**
78 * @brief Is mutex locked.
79 *
80 * This routine returns true if the mutex specified is locked and false
81 * otherwise.
82 *
83 * @param[in] the_mutex is the mutex to check.
84 *
85 * @retval true The mutex is locked.
86 * @retval false The mutex is not locked.
87 */
88RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_locked(
89  const CORE_mutex_Control *the_mutex
90)
91{
92  return _CORE_mutex_Get_owner( the_mutex ) != NULL;
93}
94
95Status_Control _CORE_mutex_Seize_slow(
96  CORE_mutex_Control   *the_mutex,
97  Thread_Control       *executing,
98  Thread_Control       *owner,
99  bool                  wait,
100  Thread_queue_Context *queue_context
101);
102
103Status_Control _CORE_mutex_Seize_no_protocol_slow(
104  CORE_mutex_Control            *the_mutex,
105  const Thread_queue_Operations *operations,
106  Thread_Control                *executing,
107  bool                           wait,
108  Thread_queue_Context          *queue_context
109);
110
111RTEMS_INLINE_ROUTINE void _CORE_mutex_Set_owner(
112  CORE_mutex_Control *the_mutex,
113  Thread_Control     *owner
114)
115{
116  the_mutex->Wait_queue.Queue.owner = owner;
117}
118
119RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_owner(
120  const CORE_mutex_Control *the_mutex,
121  const Thread_Control     *the_thread
122)
123{
124  return _CORE_mutex_Get_owner( the_mutex ) == the_thread;
125}
126
127RTEMS_INLINE_ROUTINE void _CORE_mutex_Restore_priority(
128  Thread_Control *executing
129)
130{
131  /*
132   *  Whether or not someone is waiting for the mutex, an
133   *  inherited priority must be lowered if this is the last
134   *  mutex (i.e. resource) this task has.
135   */
136  if ( !_Thread_Owns_resources( executing ) ) {
137    /*
138     * Ensure that the executing resource count is visible to all other
139     * processors and that we read the latest priority restore hint.
140     */
141    _Atomic_Fence( ATOMIC_ORDER_ACQ_REL );
142
143    if ( executing->priority_restore_hint ) {
144      Per_CPU_Control *cpu_self;
145
146      cpu_self = _Thread_Dispatch_disable();
147      _Thread_Restore_priority( executing );
148      _Thread_Dispatch_enable( cpu_self );
149    }
150  }
151}
152
153RTEMS_INLINE_ROUTINE void _CORE_recursive_mutex_Initialize(
154  CORE_recursive_mutex_Control *the_mutex
155)
156{
157  _CORE_mutex_Initialize( &the_mutex->Mutex );
158  the_mutex->nest_level = 0;
159}
160
161RTEMS_INLINE_ROUTINE Status_Control _CORE_recursive_mutex_Seize_nested(
162  CORE_recursive_mutex_Control *the_mutex
163)
164{
165  ++the_mutex->nest_level;
166  return STATUS_SUCCESSFUL;
167}
168
169RTEMS_INLINE_ROUTINE Status_Control _CORE_recursive_mutex_Seize(
170  CORE_recursive_mutex_Control  *the_mutex,
171  Thread_Control                *executing,
172  bool                           wait,
173  Status_Control              ( *nested )( CORE_recursive_mutex_Control * ),
174  Thread_queue_Context          *queue_context
175)
176{
177  Thread_Control *owner;
178
179  _CORE_mutex_Acquire_critical( &the_mutex->Mutex, queue_context );
180
181  owner = _CORE_mutex_Get_owner( &the_mutex->Mutex );
182
183  if ( owner == NULL ) {
184    _CORE_mutex_Set_owner( &the_mutex->Mutex, executing );
185    ++executing->resource_count;
186    _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
187    return STATUS_SUCCESSFUL;
188  }
189
190  if ( owner == executing ) {
191    Status_Control status;
192
193    status = ( *nested )( the_mutex );
194    _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
195    return status;
196  }
197
198  return _CORE_mutex_Seize_slow(
199    &the_mutex->Mutex,
200    executing,
201    owner,
202    wait,
203    queue_context
204  );
205}
206
207RTEMS_INLINE_ROUTINE Status_Control _CORE_recursive_mutex_Surrender(
208  CORE_recursive_mutex_Control *the_mutex,
209  Thread_Control               *executing,
210  Thread_queue_Context         *queue_context
211)
212{
213  unsigned int        nest_level;
214  Thread_queue_Heads *heads;
215  bool                keep_priority;
216
217  _CORE_mutex_Acquire_critical( &the_mutex->Mutex, queue_context );
218
219  if ( !_CORE_mutex_Is_owner( &the_mutex->Mutex, executing ) ) {
220    _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
221    return STATUS_NOT_OWNER;
222  }
223
224  nest_level = the_mutex->nest_level;
225
226  if ( nest_level > 0 ) {
227    the_mutex->nest_level = nest_level - 1;
228    _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
229    return STATUS_SUCCESSFUL;
230  }
231
232  --executing->resource_count;
233  _CORE_mutex_Set_owner( &the_mutex->Mutex, NULL );
234
235  /*
236   * Ensure that the owner resource count is visible to all other
237   * processors and that we read the latest priority restore
238   * hint.
239   */
240  _Atomic_Fence( ATOMIC_ORDER_ACQ_REL );
241
242  heads = the_mutex->Mutex.Wait_queue.Queue.heads;
243  keep_priority = _Thread_Owns_resources( executing )
244    || !executing->priority_restore_hint;
245
246  if ( heads == NULL && keep_priority ) {
247    _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
248    return STATUS_SUCCESSFUL;
249  }
250
251  _Thread_queue_Surrender(
252    &the_mutex->Mutex.Wait_queue.Queue,
253    CORE_MUTEX_TQ_PRIORITY_INHERIT_OPERATIONS,
254    heads,
255    executing,
256    keep_priority,
257    queue_context
258  );
259  return STATUS_SUCCESSFUL;
260}
261
262RTEMS_INLINE_ROUTINE Status_Control _CORE_recursive_mutex_Seize_no_protocol(
263  CORE_recursive_mutex_Control  *the_mutex,
264  const Thread_queue_Operations *operations,
265  Thread_Control                *executing,
266  bool                           wait,
267  Status_Control              ( *nested )( CORE_recursive_mutex_Control * ),
268  Thread_queue_Context          *queue_context
269)
270{
271  Thread_Control *owner;
272
273  _CORE_mutex_Acquire_critical( &the_mutex->Mutex, queue_context );
274
275  owner = _CORE_mutex_Get_owner( &the_mutex->Mutex );
276
277  if ( owner == NULL ) {
278    _CORE_mutex_Set_owner( &the_mutex->Mutex, executing );
279    _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
280    return STATUS_SUCCESSFUL;
281  }
282
283  if ( owner == executing ) {
284    Status_Control status;
285
286    status = ( *nested )( the_mutex );
287    _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
288    return status;
289  }
290
291  return _CORE_mutex_Seize_no_protocol_slow(
292    &the_mutex->Mutex,
293    operations,
294    executing,
295    wait,
296    queue_context
297  );
298}
299
300RTEMS_INLINE_ROUTINE Status_Control _CORE_recursive_mutex_Surrender_no_protocol(
301  CORE_recursive_mutex_Control  *the_mutex,
302  const Thread_queue_Operations *operations,
303  Thread_Control                *executing,
304  Thread_queue_Context          *queue_context
305)
306{
307  unsigned int    nest_level;
308  Thread_Control *new_owner;
309
310  _CORE_mutex_Acquire_critical( &the_mutex->Mutex, queue_context );
311
312  if ( !_CORE_mutex_Is_owner( &the_mutex->Mutex, executing ) ) {
313    _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
314    return STATUS_NOT_OWNER;
315  }
316
317  nest_level = the_mutex->nest_level;
318
319  if ( nest_level > 0 ) {
320    the_mutex->nest_level = nest_level - 1;
321    _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
322    return STATUS_SUCCESSFUL;
323  }
324
325  new_owner = _Thread_queue_First_locked(
326    &the_mutex->Mutex.Wait_queue,
327    operations
328  );
329  _CORE_mutex_Set_owner( &the_mutex->Mutex, new_owner );
330
331  if ( new_owner == NULL ) {
332    _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
333    return STATUS_SUCCESSFUL;
334  }
335
336  _Thread_queue_Extract_critical(
337    &the_mutex->Mutex.Wait_queue.Queue,
338    operations,
339    new_owner,
340    queue_context
341  );
342  return STATUS_SUCCESSFUL;
343}
344
345RTEMS_INLINE_ROUTINE void _CORE_ceiling_mutex_Initialize(
346  CORE_ceiling_mutex_Control *the_mutex,
347  const Scheduler_Control    *scheduler,
348  Priority_Control            priority_ceiling
349)
350{
351  _CORE_recursive_mutex_Initialize( &the_mutex->Recursive );
352  the_mutex->priority_ceiling = priority_ceiling;
353#if defined(RTEMS_SMP)
354  the_mutex->scheduler = scheduler;
355#endif
356}
357
358RTEMS_INLINE_ROUTINE const Scheduler_Control *
359_CORE_ceiling_mutex_Get_scheduler(
360  const CORE_ceiling_mutex_Control *the_mutex
361)
362{
363#if defined(RTEMS_SMP)
364  return the_mutex->scheduler;
365#else
366  return _Scheduler_Get_by_CPU_index( 0 );
367#endif
368}
369
370RTEMS_INLINE_ROUTINE void _CORE_ceiling_mutex_Set_priority(
371  CORE_ceiling_mutex_Control *the_mutex,
372  Priority_Control            priority_ceiling
373)
374{
375  the_mutex->priority_ceiling = priority_ceiling;
376}
377
378RTEMS_INLINE_ROUTINE Priority_Control _CORE_ceiling_mutex_Get_priority(
379  const CORE_ceiling_mutex_Control *the_mutex
380)
381{
382  return the_mutex->priority_ceiling;
383}
384
385RTEMS_INLINE_ROUTINE Status_Control _CORE_ceiling_mutex_Set_owner(
386  CORE_ceiling_mutex_Control *the_mutex,
387  Thread_Control             *owner,
388  Thread_queue_Context       *queue_context
389)
390{
391  Priority_Control  priority_ceiling;
392  Priority_Control  current_priority;
393  Per_CPU_Control  *cpu_self;
394
395  priority_ceiling = the_mutex->priority_ceiling;
396  current_priority = owner->current_priority;
397
398  if ( current_priority < priority_ceiling ) {
399    _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
400    return STATUS_MUTEX_CEILING_VIOLATED;
401  }
402
403  _CORE_mutex_Set_owner( &the_mutex->Recursive.Mutex, owner );
404  ++owner->resource_count;
405
406  if ( current_priority == priority_ceiling ) {
407    _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
408    return STATUS_SUCCESSFUL;
409  }
410
411  cpu_self = _Thread_Dispatch_disable_critical(
412    &queue_context->Lock_context.Lock_context
413  );
414  _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
415  _Thread_Raise_priority( owner, priority_ceiling );
416  _Thread_Dispatch_enable( cpu_self );
417  return STATUS_SUCCESSFUL;
418}
419
420RTEMS_INLINE_ROUTINE Status_Control _CORE_ceiling_mutex_Seize(
421  CORE_ceiling_mutex_Control    *the_mutex,
422  Thread_Control                *executing,
423  bool                           wait,
424  Status_Control              ( *nested )( CORE_recursive_mutex_Control * ),
425  Thread_queue_Context          *queue_context
426)
427{
428  Thread_Control *owner;
429
430  _CORE_mutex_Acquire_critical( &the_mutex->Recursive.Mutex, queue_context );
431
432  owner = _CORE_mutex_Get_owner( &the_mutex->Recursive.Mutex );
433
434  if ( owner == NULL ) {
435#if defined(RTEMS_SMP)
436    if (
437      _Scheduler_Get_own( executing )
438        != _CORE_ceiling_mutex_Get_scheduler( the_mutex )
439    ) {
440      _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
441      return STATUS_NOT_DEFINED;
442    }
443#endif
444
445    return _CORE_ceiling_mutex_Set_owner(
446      the_mutex,
447      executing,
448      queue_context
449    );
450  }
451
452  if ( owner == executing ) {
453    Status_Control status;
454
455    status = ( *nested )( &the_mutex->Recursive );
456    _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
457    return status;
458  }
459
460  return _CORE_mutex_Seize_no_protocol_slow(
461    &the_mutex->Recursive.Mutex,
462    CORE_MUTEX_TQ_OPERATIONS,
463    executing,
464    wait,
465    queue_context
466  );
467}
468
469RTEMS_INLINE_ROUTINE Status_Control _CORE_ceiling_mutex_Surrender(
470  CORE_ceiling_mutex_Control *the_mutex,
471  Thread_Control             *executing,
472  Thread_queue_Context       *queue_context
473)
474{
475  unsigned int    nest_level;
476  Thread_Control *new_owner;
477
478  _CORE_mutex_Acquire_critical( &the_mutex->Recursive.Mutex, queue_context );
479
480  if ( !_CORE_mutex_Is_owner( &the_mutex->Recursive.Mutex, executing ) ) {
481    _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
482    return STATUS_NOT_OWNER;
483  }
484
485  nest_level = the_mutex->Recursive.nest_level;
486
487  if ( nest_level > 0 ) {
488    the_mutex->Recursive.nest_level = nest_level - 1;
489    _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
490    return STATUS_SUCCESSFUL;
491  }
492
493  --executing->resource_count;
494
495  new_owner = _Thread_queue_First_locked(
496    &the_mutex->Recursive.Mutex.Wait_queue,
497    CORE_MUTEX_TQ_OPERATIONS
498  );
499  _CORE_mutex_Set_owner( &the_mutex->Recursive.Mutex, new_owner );
500
501  if ( new_owner != NULL ) {
502    bool unblock;
503
504    /*
505     * We must extract the thread now since this will restore its default
506     * thread lock.  This is necessary to avoid a deadlock in the
507     * _Thread_Change_priority() below due to a recursive thread queue lock
508     * acquire.
509     */
510    unblock = _Thread_queue_Extract_locked(
511      &the_mutex->Recursive.Mutex.Wait_queue.Queue,
512      CORE_MUTEX_TQ_OPERATIONS,
513      new_owner,
514      queue_context
515    );
516
517#if defined(RTEMS_MULTIPROCESSING)
518    if ( _Objects_Is_local_id( new_owner->Object.id ) )
519#endif
520    {
521      ++new_owner->resource_count;
522      _Thread_Raise_priority( new_owner, the_mutex->priority_ceiling );
523    }
524
525    _Thread_queue_Unblock_critical(
526      unblock,
527      &the_mutex->Recursive.Mutex.Wait_queue.Queue,
528      new_owner,
529      &queue_context->Lock_context.Lock_context
530    );
531  } else {
532    _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
533  }
534
535  _CORE_mutex_Restore_priority( executing );
536  return STATUS_SUCCESSFUL;
537}
538
539/** @} */
540
541#ifdef __cplusplus
542}
543#endif
544
545#endif
546/* end of include file */
Note: See TracBrowser for help on using the repository browser.