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

5
Last change on this file since c09db57 was c09db57, checked in by Sebastian Huber <sebastian.huber@…>, on 11/28/16 at 12:28:32

score: Fix thread queue context initialization

Initialize the thread queue context with invalid data in debug
configurations to catch missing set up steps.

  • Property mode set to 100644
File size: 11.3 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    _Thread_Resource_count_increment( executing );
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  _Thread_Resource_count_decrement( executing );
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_Table[ 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_queue_Context_clear_priority_updates( queue_context );
257    _Thread_Priority_change(
258      owner,
259      &the_mutex->Priority_ceiling,
260      priority_ceiling,
261      false,
262      queue_context
263    );
264    _Thread_Wait_release( owner, queue_context );
265  } else {
266    the_mutex->Priority_ceiling.priority = priority_ceiling;
267  }
268}
269
270RTEMS_INLINE_ROUTINE Priority_Control _CORE_ceiling_mutex_Get_priority(
271  const CORE_ceiling_mutex_Control *the_mutex
272)
273{
274  return the_mutex->Priority_ceiling.priority;
275}
276
277RTEMS_INLINE_ROUTINE Status_Control _CORE_ceiling_mutex_Set_owner(
278  CORE_ceiling_mutex_Control *the_mutex,
279  Thread_Control             *owner,
280  Thread_queue_Context       *queue_context
281)
282{
283  ISR_lock_Context  lock_context;
284  Scheduler_Node   *scheduler_node;
285  Per_CPU_Control  *cpu_self;
286
287  _Thread_queue_Context_clear_priority_updates( queue_context );
288  _Thread_Wait_acquire_default_critical( owner, &lock_context );
289
290  scheduler_node = _Thread_Scheduler_get_home_node( owner );
291
292  if (
293    _Priority_Get_priority( &scheduler_node->Wait.Priority )
294      < the_mutex->Priority_ceiling.priority
295  ) {
296    _Thread_Wait_release_default_critical( owner, &lock_context );
297    _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
298    return STATUS_MUTEX_CEILING_VIOLATED;
299  }
300
301  _CORE_mutex_Set_owner( &the_mutex->Recursive.Mutex, owner );
302  _Thread_Resource_count_increment( owner );
303  _Thread_Priority_add(
304    owner,
305    &the_mutex->Priority_ceiling,
306    queue_context
307  );
308  _Thread_Wait_release_default_critical( owner, &lock_context );
309
310  cpu_self = _Thread_Dispatch_disable_critical(
311    &queue_context->Lock_context.Lock_context
312  );
313  _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
314  _Thread_Priority_update( queue_context );
315  _Thread_Dispatch_enable( cpu_self );
316  return STATUS_SUCCESSFUL;
317}
318
319RTEMS_INLINE_ROUTINE Status_Control _CORE_ceiling_mutex_Seize(
320  CORE_ceiling_mutex_Control    *the_mutex,
321  Thread_Control                *executing,
322  bool                           wait,
323  Status_Control              ( *nested )( CORE_recursive_mutex_Control * ),
324  Thread_queue_Context          *queue_context
325)
326{
327  Thread_Control *owner;
328
329  _CORE_mutex_Acquire_critical( &the_mutex->Recursive.Mutex, queue_context );
330
331  owner = _CORE_mutex_Get_owner( &the_mutex->Recursive.Mutex );
332
333  if ( owner == NULL ) {
334#if defined(RTEMS_SMP)
335    if (
336      _Thread_Scheduler_get_home( executing )
337        != _CORE_ceiling_mutex_Get_scheduler( the_mutex )
338    ) {
339      _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
340      return STATUS_NOT_DEFINED;
341    }
342#endif
343
344    return _CORE_ceiling_mutex_Set_owner(
345      the_mutex,
346      executing,
347      queue_context
348    );
349  }
350
351  if ( owner == executing ) {
352    Status_Control status;
353
354    status = ( *nested )( &the_mutex->Recursive );
355    _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
356    return status;
357  }
358
359  return _CORE_mutex_Seize_slow(
360    &the_mutex->Recursive.Mutex,
361    CORE_MUTEX_TQ_OPERATIONS,
362    executing,
363    wait,
364    queue_context
365  );
366}
367
368RTEMS_INLINE_ROUTINE Status_Control _CORE_ceiling_mutex_Surrender(
369  CORE_ceiling_mutex_Control *the_mutex,
370  Thread_Control             *executing,
371  Thread_queue_Context       *queue_context
372)
373{
374  unsigned int      nest_level;
375  ISR_lock_Context  lock_context;
376  Per_CPU_Control  *cpu_self;
377  Thread_Control   *new_owner;
378
379  _CORE_mutex_Acquire_critical( &the_mutex->Recursive.Mutex, queue_context );
380
381  if ( !_CORE_mutex_Is_owner( &the_mutex->Recursive.Mutex, executing ) ) {
382    _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
383    return STATUS_NOT_OWNER;
384  }
385
386  nest_level = the_mutex->Recursive.nest_level;
387
388  if ( nest_level > 0 ) {
389    the_mutex->Recursive.nest_level = nest_level - 1;
390    _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
391    return STATUS_SUCCESSFUL;
392  }
393
394  _Thread_Resource_count_decrement( executing );
395
396  _Thread_queue_Context_clear_priority_updates( queue_context );
397  _Thread_Wait_acquire_default_critical( executing, &lock_context );
398  _Thread_Priority_remove(
399    executing,
400    &the_mutex->Priority_ceiling,
401    queue_context
402  );
403  _Thread_Wait_release_default_critical( executing, &lock_context );
404
405  new_owner = _Thread_queue_First_locked(
406    &the_mutex->Recursive.Mutex.Wait_queue,
407    CORE_MUTEX_TQ_OPERATIONS
408  );
409  _CORE_mutex_Set_owner( &the_mutex->Recursive.Mutex, new_owner );
410
411  cpu_self = _Thread_Dispatch_disable_critical(
412    &queue_context->Lock_context.Lock_context
413  );
414
415  if ( new_owner != NULL ) {
416#if defined(RTEMS_MULTIPROCESSING)
417    if ( _Objects_Is_local_id( new_owner->Object.id ) )
418#endif
419    {
420      _Thread_Resource_count_increment( new_owner );
421      _Thread_Priority_add(
422        new_owner,
423        &the_mutex->Priority_ceiling,
424        queue_context
425      );
426    }
427
428    _Thread_queue_Extract_critical(
429      &the_mutex->Recursive.Mutex.Wait_queue.Queue,
430      CORE_MUTEX_TQ_OPERATIONS,
431      new_owner,
432      queue_context
433    );
434  } else {
435    _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
436  }
437
438  _Thread_Priority_update( queue_context );
439  _Thread_Dispatch_enable( cpu_self );
440  return STATUS_SUCCESSFUL;
441}
442
443/** @} */
444
445#ifdef __cplusplus
446}
447#endif
448
449#endif
450/* end of include file */
Note: See TracBrowser for help on using the repository browser.