source: rtems/cpukit/include/rtems/score/coremuteximpl.h @ 86b05bf6

Last change on this file since 86b05bf6 was 86b05bf6, checked in by Andreas Dachsberger <andreas.dachsberger@…>, on Apr 8, 2019 at 8:09:54 AM

doxygen: score: adjust doc in coremuteximpl.h to doxygen guidelines

Update #3706.

  • Property mode set to 100644
File size: 16.5 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup RTEMSScoreMutex
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 RTEMSScoreMutex
34 *
35 * @{
36 */
37
38#define CORE_MUTEX_TQ_OPERATIONS &_Thread_queue_Operations_priority
39
40#define CORE_MUTEX_TQ_PRIORITY_INHERIT_OPERATIONS \
41  &_Thread_queue_Operations_priority_inherit
42
43/**
44 * @brief Initializes the mutex.
45 *
46 * @param[out] the_mutex The mutex to initialize.
47 */
48RTEMS_INLINE_ROUTINE void _CORE_mutex_Initialize(
49  CORE_mutex_Control *the_mutex
50)
51{
52  _Thread_queue_Object_initialize( &the_mutex->Wait_queue );
53}
54
55/**
56 * @brief Destroys the mutex.
57 *
58 * @param[out] the_mutex the mutex to destroy.
59 */
60RTEMS_INLINE_ROUTINE void _CORE_mutex_Destroy( CORE_mutex_Control *the_mutex )
61{
62  _Thread_queue_Destroy( &the_mutex->Wait_queue );
63}
64
65/**
66 * @brief Acquires the mutex critical.
67 *
68 * @param[in, out] the_mutex The mutex to acquire critical.
69 * @param queue_context The queue context.
70 */
71RTEMS_INLINE_ROUTINE void _CORE_mutex_Acquire_critical(
72  CORE_mutex_Control   *the_mutex,
73  Thread_queue_Context *queue_context
74)
75{
76  _Thread_queue_Acquire_critical( &the_mutex->Wait_queue, queue_context );
77}
78
79/**
80 * @brief Releases the mutex.
81 *
82 * @param[in, out] the_mutex The mutex to release.
83 * @param queue_context The queue context.
84 */
85RTEMS_INLINE_ROUTINE void _CORE_mutex_Release(
86  CORE_mutex_Control   *the_mutex,
87  Thread_queue_Context *queue_context
88)
89{
90  _Thread_queue_Release( &the_mutex->Wait_queue, queue_context );
91}
92
93/**
94 * @brief Gets the owner of the mutex.
95 *
96 * @param the_mutex The mutex to get the owner from.
97 *
98 * @return The owner of the mutex.
99 */
100RTEMS_INLINE_ROUTINE Thread_Control *_CORE_mutex_Get_owner(
101  const CORE_mutex_Control *the_mutex
102)
103{
104  return the_mutex->Wait_queue.Queue.owner;
105}
106
107/**
108 * @brief Checks if the mutex is locked.
109 *
110 * This routine returns true if the specified mutex is locked and false
111 * otherwise.
112 *
113 * @param the_mutex The mutex to check if it is locked.
114 *
115 * @retval true The mutex is locked.
116 * @retval false The mutex is not locked.
117 */
118RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_locked(
119  const CORE_mutex_Control *the_mutex
120)
121{
122  return _CORE_mutex_Get_owner( the_mutex ) != NULL;
123}
124
125/**
126 * @brief Seize the mutex slowly.
127 *
128 * @param[in, out] the_mutex The mutex to seize.
129 * @param operations The thread queue operations.
130 * @param executing The calling thread.
131 * @param wait Indicates whether the calling thread is willing to wait.
132 * @param queue_context The thread queue context.
133 *
134 * @retval _Thread_Wait_get_status The status of the executing thread.
135 * @retval STATUS_UNAVAILABLE The calling thread is not willing to wait.
136 */
137Status_Control _CORE_mutex_Seize_slow(
138  CORE_mutex_Control            *the_mutex,
139  const Thread_queue_Operations *operations,
140  Thread_Control                *executing,
141  bool                           wait,
142  Thread_queue_Context          *queue_context
143);
144
145/**
146 * @brief Sets the owner of the mutex.
147 *
148 * @param[out] the_mutex The mutex to set the owner from.
149 * @param owner The new owner of the mutex.
150 */
151RTEMS_INLINE_ROUTINE void _CORE_mutex_Set_owner(
152  CORE_mutex_Control *the_mutex,
153  Thread_Control     *owner
154)
155{
156  the_mutex->Wait_queue.Queue.owner = owner;
157}
158
159/**
160 * @brief Checks if the the thread is the owner of the mutex.
161 *
162 * @param the_mutex The mutex to check the owner of.
163 * @param the_thread The thread to check if it is the owner of @a the_mutex.
164 *
165 * @retval true @a the_thread is the owner of @a the_mutex.
166 * @retval false @a the_thread is not the owner of @a the_mutex.
167 */
168RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_owner(
169  const CORE_mutex_Control *the_mutex,
170  const Thread_Control     *the_thread
171)
172{
173  return _CORE_mutex_Get_owner( the_mutex ) == the_thread;
174}
175
176/**
177 * @brief Initializes a recursive mutex.
178 *
179 * @param[out] the_mutex The recursive mutex to initialize.
180 */
181RTEMS_INLINE_ROUTINE void _CORE_recursive_mutex_Initialize(
182  CORE_recursive_mutex_Control *the_mutex
183)
184{
185  _CORE_mutex_Initialize( &the_mutex->Mutex );
186  the_mutex->nest_level = 0;
187}
188
189/**
190 * @brief Seizes the recursive mutex nested.
191 *
192 * @param[out] the_mutex The recursive mutex to seize nested.
193 *
194 * @return STATUS_SUCCESSFUL, this method is always successful.
195 */
196RTEMS_INLINE_ROUTINE Status_Control _CORE_recursive_mutex_Seize_nested(
197  CORE_recursive_mutex_Control *the_mutex
198)
199{
200  ++the_mutex->nest_level;
201  return STATUS_SUCCESSFUL;
202}
203
204/**
205 * @brief Seizes the recursive mutex.
206 *
207 * @param[in, out] the_mutex The recursive mutex to seize.
208 * @param operations The thread queue operations.
209 * @param[out] executing The executing thread.
210 * @param wait Indicates whether the calling thread is willing to wait.
211 * @param nested Returns the status of a recursive mutex.
212 * @param queue_context The thread queue context.
213 *
214 * @retval STATUS_SUCCESSFUL The owner of the mutex was NULL, successful
215 *      seizing of the mutex.
216 * @retval _Thread_Wait_get_status The status of the executing thread.
217 * @retval STATUS_UNAVAILABLE The calling thread is not willing to wait.
218 */
219RTEMS_INLINE_ROUTINE Status_Control _CORE_recursive_mutex_Seize(
220  CORE_recursive_mutex_Control  *the_mutex,
221  const Thread_queue_Operations *operations,
222  Thread_Control                *executing,
223  bool                           wait,
224  Status_Control              ( *nested )( CORE_recursive_mutex_Control * ),
225  Thread_queue_Context          *queue_context
226)
227{
228  Thread_Control *owner;
229
230  _CORE_mutex_Acquire_critical( &the_mutex->Mutex, queue_context );
231
232  owner = _CORE_mutex_Get_owner( &the_mutex->Mutex );
233
234  if ( owner == NULL ) {
235    _CORE_mutex_Set_owner( &the_mutex->Mutex, executing );
236    _Thread_Resource_count_increment( executing );
237    _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
238    return STATUS_SUCCESSFUL;
239  }
240
241  if ( owner == executing ) {
242    Status_Control status;
243
244    status = ( *nested )( the_mutex );
245    _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
246    return status;
247  }
248
249  return _CORE_mutex_Seize_slow(
250    &the_mutex->Mutex,
251    operations,
252    executing,
253    wait,
254    queue_context
255  );
256}
257
258/**
259 * @brief Surrenders the recursive mutex.
260 *
261 * @param[in, out] the_mutex The recursive mutex to surrender.
262 * @param operations The thread queue operations.
263 * @param executing The executing thread.
264 * @param queue_context the thread queue context.
265 *
266 * @retval STATUS_SUCCESSFUL @a the_mutex is successfully surrendered.
267 * @retval STATUS_NOT_OWNER The executing thread does not own @a the_mutex.
268 */
269RTEMS_INLINE_ROUTINE Status_Control _CORE_recursive_mutex_Surrender(
270  CORE_recursive_mutex_Control  *the_mutex,
271  const Thread_queue_Operations *operations,
272  Thread_Control                *executing,
273  Thread_queue_Context          *queue_context
274)
275{
276  unsigned int        nest_level;
277  Thread_queue_Heads *heads;
278
279  _CORE_mutex_Acquire_critical( &the_mutex->Mutex, queue_context );
280
281  if ( !_CORE_mutex_Is_owner( &the_mutex->Mutex, executing ) ) {
282    _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
283    return STATUS_NOT_OWNER;
284  }
285
286  nest_level = the_mutex->nest_level;
287
288  if ( nest_level > 0 ) {
289    the_mutex->nest_level = nest_level - 1;
290    _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
291    return STATUS_SUCCESSFUL;
292  }
293
294  _Thread_Resource_count_decrement( executing );
295  _CORE_mutex_Set_owner( &the_mutex->Mutex, NULL );
296
297  heads = the_mutex->Mutex.Wait_queue.Queue.heads;
298
299  if ( heads == NULL ) {
300    _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
301    return STATUS_SUCCESSFUL;
302  }
303
304  _Thread_queue_Surrender(
305    &the_mutex->Mutex.Wait_queue.Queue,
306    heads,
307    executing,
308    queue_context,
309    operations
310  );
311  return STATUS_SUCCESSFUL;
312}
313
314/**
315 * @brief initializes a ceiling mutex.
316 *
317 * @param[out] the_mutex The ceiling mutex to initialize.
318 * @param scheduler The scheduler for the new ceiling mutex.
319 *      Only needed if RTEMS_SMP is defined
320 * @param priority_ceiling The priority ceiling for the initialized mutex.
321 */
322RTEMS_INLINE_ROUTINE void _CORE_ceiling_mutex_Initialize(
323  CORE_ceiling_mutex_Control *the_mutex,
324  const Scheduler_Control    *scheduler,
325  Priority_Control            priority_ceiling
326)
327{
328  _CORE_recursive_mutex_Initialize( &the_mutex->Recursive );
329  _Priority_Node_initialize( &the_mutex->Priority_ceiling, priority_ceiling );
330#if defined(RTEMS_SMP)
331  the_mutex->scheduler = scheduler;
332#endif
333}
334
335/**
336 * @brief Gets the scheduler of the ceiling mutex.
337 *
338 * @param the_mutex The ceiling mutex to get the scheduler from.
339 *
340 * @return The scheduler of the mutex. If RTEMS_SMP is not defined, the first entry of the _Scheduler_Table is returned.
341 */
342RTEMS_INLINE_ROUTINE const Scheduler_Control *
343_CORE_ceiling_mutex_Get_scheduler(
344  const CORE_ceiling_mutex_Control *the_mutex
345)
346{
347#if defined(RTEMS_SMP)
348  return the_mutex->scheduler;
349#else
350  return &_Scheduler_Table[ 0 ];
351#endif
352}
353
354/**
355 * @brief Sets the priority of the ceiling mutex.
356 *
357 * @param[out] the_mutex The ceiling mutex to set the priority of.
358 * @param priority_ceiling The new priority ceiling of the mutex.
359 * @param queue_context The thread queue context.
360 */
361RTEMS_INLINE_ROUTINE void _CORE_ceiling_mutex_Set_priority(
362  CORE_ceiling_mutex_Control *the_mutex,
363  Priority_Control            priority_ceiling,
364  Thread_queue_Context       *queue_context
365)
366{
367  Thread_Control *owner;
368
369  owner = _CORE_mutex_Get_owner( &the_mutex->Recursive.Mutex );
370
371  if ( owner != NULL ) {
372    _Thread_Wait_acquire( owner, queue_context );
373    _Thread_Priority_change(
374      owner,
375      &the_mutex->Priority_ceiling,
376      priority_ceiling,
377      false,
378      queue_context
379    );
380    _Thread_Wait_release( owner, queue_context );
381  } else {
382    the_mutex->Priority_ceiling.priority = priority_ceiling;
383  }
384}
385
386/**
387 * @brief Gets the priority of the ceiling mutex.
388 *
389 * @param the_mutex The mutex to get the priority from.
390 *
391 * @return The priority ceiling of @a the_mutex.
392 */
393RTEMS_INLINE_ROUTINE Priority_Control _CORE_ceiling_mutex_Get_priority(
394  const CORE_ceiling_mutex_Control *the_mutex
395)
396{
397  return the_mutex->Priority_ceiling.priority;
398}
399
400/**
401 * @brief Sets the owner of the ceiling mutex.
402 *
403 * @param[in, out] the_mutex The mutex to set the owner of.
404 * @param owner The new owner of @a the_mutex.
405 * @param queue_context The thread queue context.
406 *
407 * @retval STATUS_SUCCESSFUL The owner of the mutex was changed successfully.
408 * @retval STATUS_MUTEX_CEILING_VIOLATED The owners wait priority
409 *          is smaller than the priority of the ceiling mutex.
410 */
411RTEMS_INLINE_ROUTINE Status_Control _CORE_ceiling_mutex_Set_owner(
412  CORE_ceiling_mutex_Control *the_mutex,
413  Thread_Control             *owner,
414  Thread_queue_Context       *queue_context
415)
416{
417  ISR_lock_Context  lock_context;
418  Scheduler_Node   *scheduler_node;
419  Per_CPU_Control  *cpu_self;
420
421  _Thread_Wait_acquire_default_critical( owner, &lock_context );
422
423  scheduler_node = _Thread_Scheduler_get_home_node( owner );
424
425  if (
426    _Priority_Get_priority( &scheduler_node->Wait.Priority )
427      < the_mutex->Priority_ceiling.priority
428  ) {
429    _Thread_Wait_release_default_critical( owner, &lock_context );
430    _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
431    return STATUS_MUTEX_CEILING_VIOLATED;
432  }
433
434  _CORE_mutex_Set_owner( &the_mutex->Recursive.Mutex, owner );
435  _Thread_Resource_count_increment( owner );
436  _Thread_Priority_add(
437    owner,
438    &the_mutex->Priority_ceiling,
439    queue_context
440  );
441  _Thread_Wait_release_default_critical( owner, &lock_context );
442
443  cpu_self = _Thread_queue_Dispatch_disable( queue_context );
444  _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
445  _Thread_Priority_update( queue_context );
446  _Thread_Dispatch_enable( cpu_self );
447  return STATUS_SUCCESSFUL;
448}
449
450/**
451 * @brief Seizes the ceiling mutex.
452 *
453 * @param[in, out] the_mutex The mutex to seize.
454 * @param executing The executing thread.
455 * @param wait Indicates whether the calling thread is willing to wait.
456 * @param nested Function that returns the status of the recursive mutex
457 * @param queue_context The thread queue context.
458 *
459 * @retval STATUS_SUCCESSFUL The owner of the mutex was changed successfully.
460 * @retval STATUS_NOT_DEFINED If the scheduler of the executing thread is not equal to the owner of @a the_mutex .
461 * @retval STATUS_MUTEX_CEILING_VIOLATED The owners wait priority
462 *          is smaller than the priority of the ceiling mutex.
463 * @retval other Return value of @a nested.
464 */
465RTEMS_INLINE_ROUTINE Status_Control _CORE_ceiling_mutex_Seize(
466  CORE_ceiling_mutex_Control    *the_mutex,
467  Thread_Control                *executing,
468  bool                           wait,
469  Status_Control              ( *nested )( CORE_recursive_mutex_Control * ),
470  Thread_queue_Context          *queue_context
471)
472{
473  Thread_Control *owner;
474
475  _CORE_mutex_Acquire_critical( &the_mutex->Recursive.Mutex, queue_context );
476
477  owner = _CORE_mutex_Get_owner( &the_mutex->Recursive.Mutex );
478
479  if ( owner == NULL ) {
480#if defined(RTEMS_SMP)
481    if (
482      _Thread_Scheduler_get_home( executing )
483        != _CORE_ceiling_mutex_Get_scheduler( the_mutex )
484    ) {
485      _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
486      return STATUS_NOT_DEFINED;
487    }
488#endif
489
490    _Thread_queue_Context_clear_priority_updates( queue_context );
491    return _CORE_ceiling_mutex_Set_owner(
492      the_mutex,
493      executing,
494      queue_context
495    );
496  }
497
498  if ( owner == executing ) {
499    Status_Control status;
500
501    status = ( *nested )( &the_mutex->Recursive );
502    _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
503    return status;
504  }
505
506  return _CORE_mutex_Seize_slow(
507    &the_mutex->Recursive.Mutex,
508    CORE_MUTEX_TQ_OPERATIONS,
509    executing,
510    wait,
511    queue_context
512  );
513}
514
515/**
516 * @brief Surrenders the ceiling mutex.
517 *
518 * @param[in, out] the_mutex The ceiling mutex to surrender.
519 * @param executing The executing thread.
520 * @param queue_context The thread queue context.
521 *
522 * @retval STATUS_SUCCESSFUL The ceiling mutex was successfullysurrendered.
523 * @retval STATUS_NOT_OWNER The executing thread is not the owner of @a the_mutex.
524 */
525RTEMS_INLINE_ROUTINE Status_Control _CORE_ceiling_mutex_Surrender(
526  CORE_ceiling_mutex_Control *the_mutex,
527  Thread_Control             *executing,
528  Thread_queue_Context       *queue_context
529)
530{
531  unsigned int      nest_level;
532  ISR_lock_Context  lock_context;
533  Per_CPU_Control  *cpu_self;
534  Thread_Control   *new_owner;
535
536  _CORE_mutex_Acquire_critical( &the_mutex->Recursive.Mutex, queue_context );
537
538  if ( !_CORE_mutex_Is_owner( &the_mutex->Recursive.Mutex, executing ) ) {
539    _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
540    return STATUS_NOT_OWNER;
541  }
542
543  nest_level = the_mutex->Recursive.nest_level;
544
545  if ( nest_level > 0 ) {
546    the_mutex->Recursive.nest_level = nest_level - 1;
547    _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
548    return STATUS_SUCCESSFUL;
549  }
550
551  _Thread_Resource_count_decrement( executing );
552
553  _Thread_queue_Context_clear_priority_updates( queue_context );
554  _Thread_Wait_acquire_default_critical( executing, &lock_context );
555  _Thread_Priority_remove(
556    executing,
557    &the_mutex->Priority_ceiling,
558    queue_context
559  );
560  _Thread_Wait_release_default_critical( executing, &lock_context );
561
562  new_owner = _Thread_queue_First_locked(
563    &the_mutex->Recursive.Mutex.Wait_queue,
564    CORE_MUTEX_TQ_OPERATIONS
565  );
566  _CORE_mutex_Set_owner( &the_mutex->Recursive.Mutex, new_owner );
567
568  cpu_self = _Thread_Dispatch_disable_critical(
569    &queue_context->Lock_context.Lock_context
570  );
571
572  if ( new_owner != NULL ) {
573#if defined(RTEMS_MULTIPROCESSING)
574    if ( _Objects_Is_local_id( new_owner->Object.id ) )
575#endif
576    {
577      _Thread_Resource_count_increment( new_owner );
578      _Thread_Priority_add(
579        new_owner,
580        &the_mutex->Priority_ceiling,
581        queue_context
582      );
583    }
584
585    _Thread_queue_Extract_critical(
586      &the_mutex->Recursive.Mutex.Wait_queue.Queue,
587      CORE_MUTEX_TQ_OPERATIONS,
588      new_owner,
589      queue_context
590    );
591  } else {
592    _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
593  }
594
595  _Thread_Priority_update( queue_context );
596  _Thread_Dispatch_enable( cpu_self );
597  return STATUS_SUCCESSFUL;
598}
599
600/** @} */
601
602#ifdef __cplusplus
603}
604#endif
605
606#endif
607/* end of include file */
Note: See TracBrowser for help on using the repository browser.