source: rtems/cpukit/score/include/rtems/score/coremuteximpl.h @ 2dd098a

5
Last change on this file since 2dd098a was 2dd098a, checked in by Sebastian Huber <sebastian.huber@…>, on Oct 31, 2016 at 7:33:11 AM

score: Introduce Thread_Scheduler_control::home

Replace Thread_Scheduler_control::control and
Thread_Scheduler_control::own_control with new
Thread_Scheduler_control::home.

Update #2556.

  • Property mode set to 100644
File size: 11.2 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  const Thread_queue_Operations *operations,
98  Thread_Control                *executing,
99  bool                           wait,
100  Thread_queue_Context          *queue_context
101);
102
103RTEMS_INLINE_ROUTINE void _CORE_mutex_Set_owner(
104  CORE_mutex_Control *the_mutex,
105  Thread_Control     *owner
106)
107{
108  the_mutex->Wait_queue.Queue.owner = owner;
109}
110
111RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_owner(
112  const CORE_mutex_Control *the_mutex,
113  const Thread_Control     *the_thread
114)
115{
116  return _CORE_mutex_Get_owner( the_mutex ) == the_thread;
117}
118
119RTEMS_INLINE_ROUTINE void _CORE_recursive_mutex_Initialize(
120  CORE_recursive_mutex_Control *the_mutex
121)
122{
123  _CORE_mutex_Initialize( &the_mutex->Mutex );
124  the_mutex->nest_level = 0;
125}
126
127RTEMS_INLINE_ROUTINE Status_Control _CORE_recursive_mutex_Seize_nested(
128  CORE_recursive_mutex_Control *the_mutex
129)
130{
131  ++the_mutex->nest_level;
132  return STATUS_SUCCESSFUL;
133}
134
135RTEMS_INLINE_ROUTINE Status_Control _CORE_recursive_mutex_Seize(
136  CORE_recursive_mutex_Control  *the_mutex,
137  const Thread_queue_Operations *operations,
138  Thread_Control                *executing,
139  bool                           wait,
140  Status_Control              ( *nested )( CORE_recursive_mutex_Control * ),
141  Thread_queue_Context          *queue_context
142)
143{
144  Thread_Control *owner;
145
146  _CORE_mutex_Acquire_critical( &the_mutex->Mutex, queue_context );
147
148  owner = _CORE_mutex_Get_owner( &the_mutex->Mutex );
149
150  if ( owner == NULL ) {
151    _CORE_mutex_Set_owner( &the_mutex->Mutex, executing );
152    ++executing->resource_count;
153    _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
154    return STATUS_SUCCESSFUL;
155  }
156
157  if ( owner == executing ) {
158    Status_Control status;
159
160    status = ( *nested )( the_mutex );
161    _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
162    return status;
163  }
164
165  return _CORE_mutex_Seize_slow(
166    &the_mutex->Mutex,
167    operations,
168    executing,
169    wait,
170    queue_context
171  );
172}
173
174RTEMS_INLINE_ROUTINE Status_Control _CORE_recursive_mutex_Surrender(
175  CORE_recursive_mutex_Control  *the_mutex,
176  const Thread_queue_Operations *operations,
177  Thread_Control                *executing,
178  Thread_queue_Context          *queue_context
179)
180{
181  unsigned int        nest_level;
182  Thread_queue_Heads *heads;
183
184  _CORE_mutex_Acquire_critical( &the_mutex->Mutex, queue_context );
185
186  if ( !_CORE_mutex_Is_owner( &the_mutex->Mutex, executing ) ) {
187    _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
188    return STATUS_NOT_OWNER;
189  }
190
191  nest_level = the_mutex->nest_level;
192
193  if ( nest_level > 0 ) {
194    the_mutex->nest_level = nest_level - 1;
195    _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
196    return STATUS_SUCCESSFUL;
197  }
198
199  --executing->resource_count;
200  _CORE_mutex_Set_owner( &the_mutex->Mutex, NULL );
201
202  heads = the_mutex->Mutex.Wait_queue.Queue.heads;
203
204  if ( heads == NULL ) {
205    _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
206    return STATUS_SUCCESSFUL;
207  }
208
209  _Thread_queue_Surrender(
210    &the_mutex->Mutex.Wait_queue.Queue,
211    heads,
212    executing,
213    queue_context,
214    operations
215  );
216  return STATUS_SUCCESSFUL;
217}
218
219RTEMS_INLINE_ROUTINE void _CORE_ceiling_mutex_Initialize(
220  CORE_ceiling_mutex_Control *the_mutex,
221  const Scheduler_Control    *scheduler,
222  Priority_Control            priority_ceiling
223)
224{
225  _CORE_recursive_mutex_Initialize( &the_mutex->Recursive );
226  _Priority_Node_initialize( &the_mutex->Priority_ceiling, priority_ceiling );
227#if defined(RTEMS_SMP)
228  the_mutex->scheduler = scheduler;
229#endif
230}
231
232RTEMS_INLINE_ROUTINE const Scheduler_Control *
233_CORE_ceiling_mutex_Get_scheduler(
234  const CORE_ceiling_mutex_Control *the_mutex
235)
236{
237#if defined(RTEMS_SMP)
238  return the_mutex->scheduler;
239#else
240  return _Scheduler_Get_by_CPU_index( 0 );
241#endif
242}
243
244RTEMS_INLINE_ROUTINE void _CORE_ceiling_mutex_Set_priority(
245  CORE_ceiling_mutex_Control *the_mutex,
246  Priority_Control            priority_ceiling,
247  Thread_queue_Context       *queue_context
248)
249{
250  Thread_Control *owner;
251
252  owner = _CORE_mutex_Get_owner( &the_mutex->Recursive.Mutex );
253
254  if ( owner != NULL ) {
255    _Thread_Wait_acquire( owner, queue_context );
256    _Thread_Priority_change(
257      owner,
258      &the_mutex->Priority_ceiling,
259      priority_ceiling,
260      false,
261      queue_context
262    );
263    _Thread_Wait_release( owner, queue_context );
264  } else {
265    the_mutex->Priority_ceiling.priority = priority_ceiling;
266  }
267}
268
269RTEMS_INLINE_ROUTINE Priority_Control _CORE_ceiling_mutex_Get_priority(
270  const CORE_ceiling_mutex_Control *the_mutex
271)
272{
273  return the_mutex->Priority_ceiling.priority;
274}
275
276RTEMS_INLINE_ROUTINE Status_Control _CORE_ceiling_mutex_Set_owner(
277  CORE_ceiling_mutex_Control *the_mutex,
278  Thread_Control             *owner,
279  Thread_queue_Context       *queue_context
280)
281{
282  ISR_lock_Context  lock_context;
283  Scheduler_Node   *scheduler_node;
284  Per_CPU_Control  *cpu_self;
285
286  _Thread_queue_Context_clear_priority_updates( queue_context );
287  _Thread_Wait_acquire_default_critical( owner, &lock_context );
288
289  scheduler_node = _Thread_Scheduler_get_home_node( owner );
290
291  if (
292    _Priority_Get_priority( &scheduler_node->Wait.Priority )
293      < the_mutex->Priority_ceiling.priority
294  ) {
295    _Thread_Wait_release_default_critical( owner, &lock_context );
296    _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
297    return STATUS_MUTEX_CEILING_VIOLATED;
298  }
299
300  _CORE_mutex_Set_owner( &the_mutex->Recursive.Mutex, owner );
301  ++owner->resource_count;
302  _Thread_Priority_add(
303    owner,
304    &the_mutex->Priority_ceiling,
305    queue_context
306  );
307  _Thread_Wait_release_default_critical( owner, &lock_context );
308
309  cpu_self = _Thread_Dispatch_disable_critical(
310    &queue_context->Lock_context.Lock_context
311  );
312  _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
313  _Thread_Priority_update( queue_context );
314  _Thread_Dispatch_enable( cpu_self );
315  return STATUS_SUCCESSFUL;
316}
317
318RTEMS_INLINE_ROUTINE Status_Control _CORE_ceiling_mutex_Seize(
319  CORE_ceiling_mutex_Control    *the_mutex,
320  Thread_Control                *executing,
321  bool                           wait,
322  Status_Control              ( *nested )( CORE_recursive_mutex_Control * ),
323  Thread_queue_Context          *queue_context
324)
325{
326  Thread_Control *owner;
327
328  _CORE_mutex_Acquire_critical( &the_mutex->Recursive.Mutex, queue_context );
329
330  owner = _CORE_mutex_Get_owner( &the_mutex->Recursive.Mutex );
331
332  if ( owner == NULL ) {
333#if defined(RTEMS_SMP)
334    if (
335      _Thread_Scheduler_get_home( executing )
336        != _CORE_ceiling_mutex_Get_scheduler( the_mutex )
337    ) {
338      _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
339      return STATUS_NOT_DEFINED;
340    }
341#endif
342
343    return _CORE_ceiling_mutex_Set_owner(
344      the_mutex,
345      executing,
346      queue_context
347    );
348  }
349
350  if ( owner == executing ) {
351    Status_Control status;
352
353    status = ( *nested )( &the_mutex->Recursive );
354    _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
355    return status;
356  }
357
358  return _CORE_mutex_Seize_slow(
359    &the_mutex->Recursive.Mutex,
360    CORE_MUTEX_TQ_OPERATIONS,
361    executing,
362    wait,
363    queue_context
364  );
365}
366
367RTEMS_INLINE_ROUTINE Status_Control _CORE_ceiling_mutex_Surrender(
368  CORE_ceiling_mutex_Control *the_mutex,
369  Thread_Control             *executing,
370  Thread_queue_Context       *queue_context
371)
372{
373  unsigned int      nest_level;
374  ISR_lock_Context  lock_context;
375  Per_CPU_Control  *cpu_self;
376  Thread_Control   *new_owner;
377
378  _CORE_mutex_Acquire_critical( &the_mutex->Recursive.Mutex, queue_context );
379
380  if ( !_CORE_mutex_Is_owner( &the_mutex->Recursive.Mutex, executing ) ) {
381    _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
382    return STATUS_NOT_OWNER;
383  }
384
385  nest_level = the_mutex->Recursive.nest_level;
386
387  if ( nest_level > 0 ) {
388    the_mutex->Recursive.nest_level = nest_level - 1;
389    _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
390    return STATUS_SUCCESSFUL;
391  }
392
393  --executing->resource_count;
394
395  _Thread_queue_Context_clear_priority_updates( queue_context );
396  _Thread_Wait_acquire_default_critical( executing, &lock_context );
397  _Thread_Priority_remove(
398    executing,
399    &the_mutex->Priority_ceiling,
400    queue_context
401  );
402  _Thread_Wait_release_default_critical( executing, &lock_context );
403
404  new_owner = _Thread_queue_First_locked(
405    &the_mutex->Recursive.Mutex.Wait_queue,
406    CORE_MUTEX_TQ_OPERATIONS
407  );
408  _CORE_mutex_Set_owner( &the_mutex->Recursive.Mutex, new_owner );
409
410  cpu_self = _Thread_Dispatch_disable_critical(
411    &queue_context->Lock_context.Lock_context
412  );
413
414  if ( new_owner != NULL ) {
415#if defined(RTEMS_MULTIPROCESSING)
416    if ( _Objects_Is_local_id( new_owner->Object.id ) )
417#endif
418    {
419      ++new_owner->resource_count;
420      _Thread_Priority_add(
421        new_owner,
422        &the_mutex->Priority_ceiling,
423        queue_context
424      );
425    }
426
427    _Thread_queue_Extract_critical(
428      &the_mutex->Recursive.Mutex.Wait_queue.Queue,
429      CORE_MUTEX_TQ_OPERATIONS,
430      new_owner,
431      queue_context
432    );
433  } else {
434    _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
435  }
436
437  _Thread_Priority_update( queue_context );
438  _Thread_Dispatch_enable( cpu_self );
439  return STATUS_SUCCESSFUL;
440}
441
442/** @} */
443
444#ifdef __cplusplus
445}
446#endif
447
448#endif
449/* end of include file */
Note: See TracBrowser for help on using the repository browser.