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

Last change on this file since a660e9dc was a660e9dc, checked in by Sebastian Huber <sebastian.huber@…>, on 09/08/22 at 08:37:05

Do not use RTEMS_INLINE_ROUTINE

Directly use "static inline" which is available in C99 and later. This brings
the RTEMS implementation closer to standard C.

Close #3935.

  • Property mode set to 100644
File size: 16.5 KB
Line 
1/* SPDX-License-Identifier: BSD-2-Clause */
2
3/**
4 * @file
5 *
6 * @ingroup RTEMSScoreMutex
7 *
8 * @brief This header file provides interfaces of the
9 *   @ref RTEMSScoreMutex which are only used by the implementation.
10 */
11
12/*
13 *  COPYRIGHT (c) 1989-2009.
14 *  On-Line Applications Research Corporation (OAR).
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 *    notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 *    notice, this list of conditions and the following disclaimer in the
23 *    documentation and/or other materials provided with the distribution.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
29 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38#ifndef _RTEMS_SCORE_COREMUTEXIMPL_H
39#define _RTEMS_SCORE_COREMUTEXIMPL_H
40
41#include <rtems/score/coremutex.h>
42#include <rtems/score/chainimpl.h>
43#include <rtems/score/schedulerimpl.h>
44#include <rtems/score/status.h>
45#include <rtems/score/threadimpl.h>
46#include <rtems/score/threadqimpl.h>
47
48#ifdef __cplusplus
49extern "C" {
50#endif
51
52/**
53 * @addtogroup RTEMSScoreMutex
54 *
55 * @{
56 */
57
58#define CORE_MUTEX_TQ_OPERATIONS &_Thread_queue_Operations_priority
59
60#define CORE_MUTEX_TQ_PRIORITY_INHERIT_OPERATIONS \
61  &_Thread_queue_Operations_priority_inherit
62
63/**
64 * @brief Initializes the mutex.
65 *
66 * @param[out] the_mutex The mutex to initialize.
67 */
68static inline void _CORE_mutex_Initialize(
69  CORE_mutex_Control *the_mutex
70)
71{
72  _Thread_queue_Object_initialize( &the_mutex->Wait_queue );
73}
74
75/**
76 * @brief Destroys the mutex.
77 *
78 * @param[out] the_mutex the mutex to destroy.
79 */
80static inline void _CORE_mutex_Destroy( CORE_mutex_Control *the_mutex )
81{
82  _Thread_queue_Destroy( &the_mutex->Wait_queue );
83}
84
85/**
86 * @brief Acquires the mutex critical.
87 *
88 * @param[in, out] the_mutex The mutex to acquire critical.
89 * @param queue_context The queue context.
90 */
91static inline void _CORE_mutex_Acquire_critical(
92  CORE_mutex_Control   *the_mutex,
93  Thread_queue_Context *queue_context
94)
95{
96  _Thread_queue_Acquire_critical( &the_mutex->Wait_queue, queue_context );
97}
98
99/**
100 * @brief Releases the mutex.
101 *
102 * @param[in, out] the_mutex The mutex to release.
103 * @param queue_context The queue context.
104 */
105static inline void _CORE_mutex_Release(
106  CORE_mutex_Control   *the_mutex,
107  Thread_queue_Context *queue_context
108)
109{
110  _Thread_queue_Release( &the_mutex->Wait_queue, queue_context );
111}
112
113/**
114 * @brief Gets the owner of the mutex.
115 *
116 * @param the_mutex The mutex to get the owner from.
117 *
118 * @return The owner of the mutex.
119 */
120static inline Thread_Control *_CORE_mutex_Get_owner(
121  const CORE_mutex_Control *the_mutex
122)
123{
124  return the_mutex->Wait_queue.Queue.owner;
125}
126
127/**
128 * @brief Checks if the mutex is locked.
129 *
130 * This routine returns true if the specified mutex is locked and false
131 * otherwise.
132 *
133 * @param the_mutex The mutex to check if it is locked.
134 *
135 * @retval true The mutex is locked.
136 * @retval false The mutex is not locked.
137 */
138static inline bool _CORE_mutex_Is_locked(
139  const CORE_mutex_Control *the_mutex
140)
141{
142  return _CORE_mutex_Get_owner( the_mutex ) != NULL;
143}
144
145/**
146 * @brief Seize the mutex slowly.
147 *
148 * @param[in, out] the_mutex The mutex to seize.
149 * @param operations The thread queue operations.
150 * @param executing The calling thread.
151 * @param wait Indicates whether the calling thread is willing to wait.
152 * @param queue_context The thread queue context.
153 *
154 * @retval _Thread_Wait_get_status The status of the executing thread.
155 * @retval STATUS_UNAVAILABLE The calling thread is not willing to wait.
156 */
157Status_Control _CORE_mutex_Seize_slow(
158  CORE_mutex_Control            *the_mutex,
159  const Thread_queue_Operations *operations,
160  Thread_Control                *executing,
161  bool                           wait,
162  Thread_queue_Context          *queue_context
163);
164
165/**
166 * @brief Sets the owner of the mutex.
167 *
168 * @param[out] the_mutex The mutex to set the owner from.
169 * @param owner The new owner of the mutex.
170 */
171static inline void _CORE_mutex_Set_owner(
172  CORE_mutex_Control *the_mutex,
173  Thread_Control     *owner
174)
175{
176  the_mutex->Wait_queue.Queue.owner = owner;
177}
178
179/**
180 * @brief Checks if the the thread is the owner of the mutex.
181 *
182 * @param the_mutex The mutex to check the owner of.
183 * @param the_thread The thread to check if it is the owner of @a the_mutex.
184 *
185 * @retval true @a the_thread is the owner of @a the_mutex.
186 * @retval false @a the_thread is not the owner of @a the_mutex.
187 */
188static inline bool _CORE_mutex_Is_owner(
189  const CORE_mutex_Control *the_mutex,
190  const Thread_Control     *the_thread
191)
192{
193  return _CORE_mutex_Get_owner( the_mutex ) == the_thread;
194}
195
196/**
197 * @brief Initializes a recursive mutex.
198 *
199 * @param[out] the_mutex The recursive mutex to initialize.
200 */
201static inline void _CORE_recursive_mutex_Initialize(
202  CORE_recursive_mutex_Control *the_mutex
203)
204{
205  _CORE_mutex_Initialize( &the_mutex->Mutex );
206  the_mutex->nest_level = 0;
207}
208
209/**
210 * @brief Seizes the recursive mutex nested.
211 *
212 * @param[out] the_mutex The recursive mutex to seize nested.
213 *
214 * @return STATUS_SUCCESSFUL, this method is always successful.
215 */
216static inline Status_Control _CORE_recursive_mutex_Seize_nested(
217  CORE_recursive_mutex_Control *the_mutex
218)
219{
220  ++the_mutex->nest_level;
221  return STATUS_SUCCESSFUL;
222}
223
224/**
225 * @brief Seizes the recursive mutex.
226 *
227 * @param[in, out] the_mutex The recursive mutex to seize.
228 * @param operations The thread queue operations.
229 * @param[out] executing The executing thread.
230 * @param wait Indicates whether the calling thread is willing to wait.
231 * @param nested Returns the status of a recursive mutex.
232 * @param queue_context The thread queue context.
233 *
234 * @retval STATUS_SUCCESSFUL The owner of the mutex was NULL, successful
235 *      seizing of the mutex.
236 * @retval _Thread_Wait_get_status The status of the executing thread.
237 * @retval STATUS_UNAVAILABLE The calling thread is not willing to wait.
238 */
239static inline Status_Control _CORE_recursive_mutex_Seize(
240  CORE_recursive_mutex_Control  *the_mutex,
241  const Thread_queue_Operations *operations,
242  Thread_Control                *executing,
243  bool                           wait,
244  Status_Control              ( *nested )( CORE_recursive_mutex_Control * ),
245  Thread_queue_Context          *queue_context
246)
247{
248  Thread_Control *owner;
249
250  _CORE_mutex_Acquire_critical( &the_mutex->Mutex, queue_context );
251
252  owner = _CORE_mutex_Get_owner( &the_mutex->Mutex );
253
254  if ( owner == NULL ) {
255    _CORE_mutex_Set_owner( &the_mutex->Mutex, executing );
256    _Thread_Resource_count_increment( executing );
257    _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
258    return STATUS_SUCCESSFUL;
259  }
260
261  if ( owner == executing ) {
262    Status_Control status;
263
264    status = ( *nested )( the_mutex );
265    _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
266    return status;
267  }
268
269  return _CORE_mutex_Seize_slow(
270    &the_mutex->Mutex,
271    operations,
272    executing,
273    wait,
274    queue_context
275  );
276}
277
278/**
279 * @brief Surrenders the recursive mutex.
280 *
281 * @param[in, out] the_mutex The recursive mutex to surrender.
282 * @param operations The thread queue operations.
283 * @param executing The executing thread.
284 * @param queue_context the thread queue context.
285 *
286 * @retval STATUS_SUCCESSFUL @a the_mutex is successfully surrendered.
287 * @retval STATUS_NOT_OWNER The executing thread does not own @a the_mutex.
288 */
289static inline Status_Control _CORE_recursive_mutex_Surrender(
290  CORE_recursive_mutex_Control  *the_mutex,
291  const Thread_queue_Operations *operations,
292  Thread_Control                *executing,
293  Thread_queue_Context          *queue_context
294)
295{
296  unsigned int        nest_level;
297  Thread_queue_Heads *heads;
298
299  _CORE_mutex_Acquire_critical( &the_mutex->Mutex, queue_context );
300
301  if ( !_CORE_mutex_Is_owner( &the_mutex->Mutex, executing ) ) {
302    _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
303    return STATUS_NOT_OWNER;
304  }
305
306  nest_level = the_mutex->nest_level;
307
308  if ( nest_level > 0 ) {
309    the_mutex->nest_level = nest_level - 1;
310    _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
311    return STATUS_SUCCESSFUL;
312  }
313
314  _Thread_Resource_count_decrement( executing );
315  _CORE_mutex_Set_owner( &the_mutex->Mutex, NULL );
316
317  heads = the_mutex->Mutex.Wait_queue.Queue.heads;
318
319  if ( heads == NULL ) {
320    _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
321    return STATUS_SUCCESSFUL;
322  }
323
324  _Thread_queue_Surrender(
325    &the_mutex->Mutex.Wait_queue.Queue,
326    heads,
327    executing,
328    queue_context,
329    operations
330  );
331  return STATUS_SUCCESSFUL;
332}
333
334/**
335 * @brief initializes a ceiling mutex.
336 *
337 * @param[out] the_mutex The ceiling mutex to initialize.
338 * @param scheduler The scheduler for the new ceiling mutex.
339 *      Only needed if RTEMS_SMP is defined
340 * @param priority_ceiling The priority ceiling for the initialized mutex.
341 */
342static inline void _CORE_ceiling_mutex_Initialize(
343  CORE_ceiling_mutex_Control *the_mutex,
344  const Scheduler_Control    *scheduler,
345  Priority_Control            priority_ceiling
346)
347{
348  _CORE_recursive_mutex_Initialize( &the_mutex->Recursive );
349  _Priority_Node_initialize( &the_mutex->Priority_ceiling, priority_ceiling );
350#if defined(RTEMS_SMP)
351  the_mutex->scheduler = scheduler;
352#endif
353}
354
355/**
356 * @brief Gets the scheduler of the ceiling mutex.
357 *
358 * @param the_mutex The ceiling mutex to get the scheduler from.
359 *
360 * @return The scheduler of the mutex. If RTEMS_SMP is not defined, the first entry of the _Scheduler_Table is returned.
361 */
362static inline const Scheduler_Control *
363_CORE_ceiling_mutex_Get_scheduler(
364  const CORE_ceiling_mutex_Control *the_mutex
365)
366{
367#if defined(RTEMS_SMP)
368  return the_mutex->scheduler;
369#else
370  return &_Scheduler_Table[ 0 ];
371#endif
372}
373
374/**
375 * @brief Sets the priority of the ceiling mutex.
376 *
377 * @param[out] the_mutex The ceiling mutex to set the priority of.
378 * @param priority_ceiling The new priority ceiling of the mutex.
379 */
380static inline void _CORE_ceiling_mutex_Set_priority(
381  CORE_ceiling_mutex_Control *the_mutex,
382  Priority_Control            priority_ceiling
383)
384{
385  Thread_Control *owner;
386
387  owner = _CORE_mutex_Get_owner( &the_mutex->Recursive.Mutex );
388
389  if ( owner != NULL ) {
390    Thread_queue_Context queue_context;
391
392    _Thread_queue_Context_initialize( &queue_context );
393    _Thread_queue_Context_clear_priority_updates( &queue_context );
394    _Thread_Wait_acquire_critical( owner, &queue_context );
395    _Thread_Priority_change(
396      owner,
397      &the_mutex->Priority_ceiling,
398      priority_ceiling,
399      PRIORITY_GROUP_LAST,
400      &queue_context
401    );
402    _Thread_Wait_release_critical( owner, &queue_context );
403  } else {
404    the_mutex->Priority_ceiling.priority = priority_ceiling;
405  }
406}
407
408/**
409 * @brief Gets the priority of the ceiling mutex.
410 *
411 * @param the_mutex The mutex to get the priority from.
412 *
413 * @return The priority ceiling of @a the_mutex.
414 */
415static inline Priority_Control _CORE_ceiling_mutex_Get_priority(
416  const CORE_ceiling_mutex_Control *the_mutex
417)
418{
419  return the_mutex->Priority_ceiling.priority;
420}
421
422/**
423 * @brief Sets the owner of the ceiling mutex.
424 *
425 * @param[in, out] the_mutex The mutex to set the owner of.
426 * @param owner The new owner of @a the_mutex.
427 * @param queue_context The thread queue context.
428 *
429 * @retval STATUS_SUCCESSFUL The owner of the mutex was changed successfully.
430 * @retval STATUS_MUTEX_CEILING_VIOLATED The owners wait priority
431 *          is smaller than the priority of the ceiling mutex.
432 */
433static inline Status_Control _CORE_ceiling_mutex_Set_owner(
434  CORE_ceiling_mutex_Control *the_mutex,
435  Thread_Control             *owner,
436  Thread_queue_Context       *queue_context
437)
438{
439  ISR_lock_Context  lock_context;
440  Scheduler_Node   *scheduler_node;
441  Per_CPU_Control  *cpu_self;
442
443  _Thread_Wait_acquire_default_critical( owner, &lock_context );
444
445  scheduler_node = _Thread_Scheduler_get_home_node( owner );
446
447  if (
448    _Priority_Get_priority( &scheduler_node->Wait.Priority )
449      < the_mutex->Priority_ceiling.priority
450  ) {
451    _Thread_Wait_release_default_critical( owner, &lock_context );
452    _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
453    return STATUS_MUTEX_CEILING_VIOLATED;
454  }
455
456  _CORE_mutex_Set_owner( &the_mutex->Recursive.Mutex, owner );
457  _Thread_Resource_count_increment( owner );
458  _Thread_Priority_add(
459    owner,
460    &the_mutex->Priority_ceiling,
461    queue_context
462  );
463  _Thread_Wait_release_default_critical( owner, &lock_context );
464
465  cpu_self = _Thread_queue_Dispatch_disable( queue_context );
466  _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
467  _Thread_Priority_update( queue_context );
468  _Thread_Dispatch_enable( cpu_self );
469  return STATUS_SUCCESSFUL;
470}
471
472/**
473 * @brief Seizes the ceiling mutex.
474 *
475 * @param[in, out] the_mutex The mutex to seize.
476 * @param executing The executing thread.
477 * @param wait Indicates whether the calling thread is willing to wait.
478 * @param nested Function that returns the status of the recursive mutex
479 * @param queue_context The thread queue context.
480 *
481 * @retval STATUS_SUCCESSFUL The owner of the mutex was changed successfully.
482 * @retval STATUS_NOT_DEFINED If the scheduler of the executing thread is not equal to the owner of @a the_mutex .
483 * @retval STATUS_MUTEX_CEILING_VIOLATED The owners wait priority
484 *          is smaller than the priority of the ceiling mutex.
485 * @retval other Return value of @a nested.
486 */
487static inline Status_Control _CORE_ceiling_mutex_Seize(
488  CORE_ceiling_mutex_Control    *the_mutex,
489  Thread_Control                *executing,
490  bool                           wait,
491  Status_Control              ( *nested )( CORE_recursive_mutex_Control * ),
492  Thread_queue_Context          *queue_context
493)
494{
495  Thread_Control *owner;
496
497  _CORE_mutex_Acquire_critical( &the_mutex->Recursive.Mutex, queue_context );
498
499#if defined(RTEMS_SMP)
500  if (
501    _Thread_Scheduler_get_home( executing )
502      != _CORE_ceiling_mutex_Get_scheduler( the_mutex )
503  ) {
504    _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
505    return STATUS_NOT_DEFINED;
506  }
507#endif
508
509  owner = _CORE_mutex_Get_owner( &the_mutex->Recursive.Mutex );
510
511  if ( owner == NULL ) {
512    _Thread_queue_Context_clear_priority_updates( queue_context );
513    return _CORE_ceiling_mutex_Set_owner(
514      the_mutex,
515      executing,
516      queue_context
517    );
518  }
519
520  if ( owner == executing ) {
521    Status_Control status;
522
523    status = ( *nested )( &the_mutex->Recursive );
524    _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
525    return status;
526  }
527
528  return _CORE_mutex_Seize_slow(
529    &the_mutex->Recursive.Mutex,
530    CORE_MUTEX_TQ_OPERATIONS,
531    executing,
532    wait,
533    queue_context
534  );
535}
536
537/**
538 * @brief Surrenders the ceiling mutex.
539 *
540 * @param[in, out] the_mutex The ceiling mutex to surrender.
541 * @param executing The executing thread.
542 * @param queue_context The thread queue context.
543 *
544 * @retval STATUS_SUCCESSFUL The ceiling mutex was successfullysurrendered.
545 * @retval STATUS_NOT_OWNER The executing thread is not the owner of @a the_mutex.
546 */
547static inline Status_Control _CORE_ceiling_mutex_Surrender(
548  CORE_ceiling_mutex_Control *the_mutex,
549  Thread_Control             *executing,
550  Thread_queue_Context       *queue_context
551)
552{
553  unsigned int nest_level;
554
555  _CORE_mutex_Acquire_critical( &the_mutex->Recursive.Mutex, queue_context );
556
557  if ( !_CORE_mutex_Is_owner( &the_mutex->Recursive.Mutex, executing ) ) {
558    _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
559    return STATUS_NOT_OWNER;
560  }
561
562  nest_level = the_mutex->Recursive.nest_level;
563
564  if ( nest_level > 0 ) {
565    the_mutex->Recursive.nest_level = nest_level - 1;
566    _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
567    return STATUS_SUCCESSFUL;
568  }
569
570  return _Thread_queue_Surrender_priority_ceiling(
571    &the_mutex->Recursive.Mutex.Wait_queue.Queue,
572    executing,
573    &the_mutex->Priority_ceiling,
574    queue_context,
575    CORE_MUTEX_TQ_OPERATIONS
576  );
577}
578
579/** @} */
580
581#ifdef __cplusplus
582}
583#endif
584
585#endif
586/* end of include file */
Note: See TracBrowser for help on using the repository browser.