Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:12

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSScoreMutex
0007  *
0008  * @brief This header file provides interfaces of the
0009  *   @ref RTEMSScoreMutex which are only used by the implementation.
0010  */
0011 
0012 /*
0013  *  COPYRIGHT (c) 1989-2009.
0014  *  On-Line Applications Research Corporation (OAR).
0015  *
0016  * Redistribution and use in source and binary forms, with or without
0017  * modification, are permitted provided that the following conditions
0018  * are met:
0019  * 1. Redistributions of source code must retain the above copyright
0020  *    notice, this list of conditions and the following disclaimer.
0021  * 2. Redistributions in binary form must reproduce the above copyright
0022  *    notice, this list of conditions and the following disclaimer in the
0023  *    documentation and/or other materials provided with the distribution.
0024  *
0025  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0026  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0027  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0028  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0029  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0030  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0031  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0032  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0033  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0034  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0035  * POSSIBILITY OF SUCH DAMAGE.
0036  */
0037 
0038 #ifndef _RTEMS_SCORE_COREMUTEXIMPL_H
0039 #define _RTEMS_SCORE_COREMUTEXIMPL_H
0040 
0041 #include <rtems/score/coremutex.h>
0042 #include <rtems/score/chainimpl.h>
0043 #include <rtems/score/schedulerimpl.h>
0044 #include <rtems/score/status.h>
0045 #include <rtems/score/threadimpl.h>
0046 #include <rtems/score/threadqimpl.h>
0047 
0048 #ifdef __cplusplus
0049 extern "C" {
0050 #endif
0051 
0052 /**
0053  * @addtogroup RTEMSScoreMutex
0054  *
0055  * @{
0056  */
0057 
0058 #define CORE_MUTEX_TQ_OPERATIONS &_Thread_queue_Operations_priority
0059 
0060 #define CORE_MUTEX_TQ_PRIORITY_INHERIT_OPERATIONS \
0061   &_Thread_queue_Operations_priority_inherit
0062 
0063 /**
0064  * @brief Initializes the mutex.
0065  *
0066  * @param[out] the_mutex The mutex to initialize.
0067  */
0068 static inline void _CORE_mutex_Initialize(
0069   CORE_mutex_Control *the_mutex
0070 )
0071 {
0072   _Thread_queue_Object_initialize( &the_mutex->Wait_queue );
0073 }
0074 
0075 /**
0076  * @brief Destroys the mutex.
0077  *
0078  * @param[out] the_mutex the mutex to destroy.
0079  */
0080 static inline void _CORE_mutex_Destroy( CORE_mutex_Control *the_mutex )
0081 {
0082   _Thread_queue_Destroy( &the_mutex->Wait_queue );
0083 }
0084 
0085 /**
0086  * @brief Acquires the mutex critical.
0087  *
0088  * @param[in, out] the_mutex The mutex to acquire critical.
0089  * @param queue_context The queue context.
0090  */
0091 static inline void _CORE_mutex_Acquire_critical(
0092   CORE_mutex_Control   *the_mutex,
0093   Thread_queue_Context *queue_context
0094 )
0095 {
0096   _Thread_queue_Acquire_critical( &the_mutex->Wait_queue, queue_context );
0097 }
0098 
0099 /**
0100  * @brief Releases the mutex.
0101  *
0102  * @param[in, out] the_mutex The mutex to release.
0103  * @param queue_context The queue context.
0104  */
0105 static inline void _CORE_mutex_Release(
0106   CORE_mutex_Control   *the_mutex,
0107   Thread_queue_Context *queue_context
0108 )
0109 {
0110   _Thread_queue_Release( &the_mutex->Wait_queue, queue_context );
0111 }
0112 
0113 /**
0114  * @brief Gets the owner of the mutex.
0115  *
0116  * @param the_mutex The mutex to get the owner from.
0117  *
0118  * @return The owner of the mutex.
0119  */
0120 static inline Thread_Control *_CORE_mutex_Get_owner(
0121   const CORE_mutex_Control *the_mutex
0122 )
0123 {
0124   return the_mutex->Wait_queue.Queue.owner;
0125 }
0126 
0127 /**
0128  * @brief Checks if the mutex is locked.
0129  *
0130  * This routine returns true if the specified mutex is locked and false
0131  * otherwise.
0132  *
0133  * @param the_mutex The mutex to check if it is locked.
0134  *
0135  * @retval true The mutex is locked.
0136  * @retval false The mutex is not locked.
0137  */
0138 static inline bool _CORE_mutex_Is_locked(
0139   const CORE_mutex_Control *the_mutex
0140 )
0141 {
0142   return _CORE_mutex_Get_owner( the_mutex ) != NULL;
0143 }
0144 
0145 /**
0146  * @brief Seize the mutex slowly.
0147  *
0148  * @param[in, out] the_mutex The mutex to seize.
0149  * @param operations The thread queue operations.
0150  * @param executing The calling thread.
0151  * @param wait Indicates whether the calling thread is willing to wait.
0152  * @param queue_context The thread queue context.
0153  *
0154  * @retval _Thread_Wait_get_status The status of the executing thread.
0155  * @retval STATUS_UNAVAILABLE The calling thread is not willing to wait.
0156  */
0157 Status_Control _CORE_mutex_Seize_slow(
0158   CORE_mutex_Control            *the_mutex,
0159   const Thread_queue_Operations *operations,
0160   Thread_Control                *executing,
0161   bool                           wait,
0162   Thread_queue_Context          *queue_context
0163 );
0164 
0165 /**
0166  * @brief Sets the owner of the mutex.
0167  *
0168  * @param[out] the_mutex The mutex to set the owner from.
0169  * @param owner The new owner of the mutex.
0170  */
0171 static inline void _CORE_mutex_Set_owner(
0172   CORE_mutex_Control *the_mutex,
0173   Thread_Control     *owner
0174 )
0175 {
0176   the_mutex->Wait_queue.Queue.owner = owner;
0177 }
0178 
0179 /**
0180  * @brief Checks if the the thread is the owner of the mutex.
0181  *
0182  * @param the_mutex The mutex to check the owner of.
0183  * @param the_thread The thread to check if it is the owner of @a the_mutex.
0184  *
0185  * @retval true @a the_thread is the owner of @a the_mutex.
0186  * @retval false @a the_thread is not the owner of @a the_mutex.
0187  */
0188 static inline bool _CORE_mutex_Is_owner(
0189   const CORE_mutex_Control *the_mutex,
0190   const Thread_Control     *the_thread
0191 )
0192 {
0193   return _CORE_mutex_Get_owner( the_mutex ) == the_thread;
0194 }
0195 
0196 /**
0197  * @brief Initializes a recursive mutex.
0198  *
0199  * @param[out] the_mutex The recursive mutex to initialize.
0200  */
0201 static inline void _CORE_recursive_mutex_Initialize(
0202   CORE_recursive_mutex_Control *the_mutex
0203 )
0204 {
0205   _CORE_mutex_Initialize( &the_mutex->Mutex );
0206   the_mutex->nest_level = 0;
0207 }
0208 
0209 /**
0210  * @brief Seizes the recursive mutex nested.
0211  *
0212  * @param[out] the_mutex The recursive mutex to seize nested.
0213  *
0214  * @return STATUS_SUCCESSFUL, this method is always successful.
0215  */
0216 static inline Status_Control _CORE_recursive_mutex_Seize_nested(
0217   CORE_recursive_mutex_Control *the_mutex
0218 )
0219 {
0220   ++the_mutex->nest_level;
0221   return STATUS_SUCCESSFUL;
0222 }
0223 
0224 /**
0225  * @brief Seizes the recursive mutex.
0226  *
0227  * @param[in, out] the_mutex The recursive mutex to seize.
0228  * @param operations The thread queue operations.
0229  * @param[out] executing The executing thread.
0230  * @param wait Indicates whether the calling thread is willing to wait.
0231  * @param nested Returns the status of a recursive mutex.
0232  * @param queue_context The thread queue context.
0233  *
0234  * @retval STATUS_SUCCESSFUL The owner of the mutex was NULL, successful
0235  *      seizing of the mutex.
0236  * @retval _Thread_Wait_get_status The status of the executing thread.
0237  * @retval STATUS_UNAVAILABLE The calling thread is not willing to wait.
0238  */
0239 static inline Status_Control _CORE_recursive_mutex_Seize(
0240   CORE_recursive_mutex_Control  *the_mutex,
0241   const Thread_queue_Operations *operations,
0242   Thread_Control                *executing,
0243   bool                           wait,
0244   Status_Control              ( *nested )( CORE_recursive_mutex_Control * ),
0245   Thread_queue_Context          *queue_context
0246 )
0247 {
0248   Thread_Control *owner;
0249 
0250   _CORE_mutex_Acquire_critical( &the_mutex->Mutex, queue_context );
0251 
0252   owner = _CORE_mutex_Get_owner( &the_mutex->Mutex );
0253 
0254   if ( owner == NULL ) {
0255     _CORE_mutex_Set_owner( &the_mutex->Mutex, executing );
0256     _Thread_Resource_count_increment( executing );
0257     _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
0258     return STATUS_SUCCESSFUL;
0259   }
0260 
0261   if ( owner == executing ) {
0262     Status_Control status;
0263 
0264     status = ( *nested )( the_mutex );
0265     _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
0266     return status;
0267   }
0268 
0269   return _CORE_mutex_Seize_slow(
0270     &the_mutex->Mutex,
0271     operations,
0272     executing,
0273     wait,
0274     queue_context
0275   );
0276 }
0277 
0278 /**
0279  * @brief Surrenders the recursive mutex.
0280  *
0281  * @param[in, out] the_mutex The recursive mutex to surrender.
0282  * @param operations The thread queue operations.
0283  * @param executing The executing thread.
0284  * @param queue_context the thread queue context.
0285  *
0286  * @retval STATUS_SUCCESSFUL @a the_mutex is successfully surrendered.
0287  * @retval STATUS_NOT_OWNER The executing thread does not own @a the_mutex.
0288  */
0289 static inline Status_Control _CORE_recursive_mutex_Surrender(
0290   CORE_recursive_mutex_Control  *the_mutex,
0291   const Thread_queue_Operations *operations,
0292   Thread_Control                *executing,
0293   Thread_queue_Context          *queue_context
0294 )
0295 {
0296   unsigned int        nest_level;
0297   Thread_queue_Heads *heads;
0298 
0299   _CORE_mutex_Acquire_critical( &the_mutex->Mutex, queue_context );
0300 
0301   if ( !_CORE_mutex_Is_owner( &the_mutex->Mutex, executing ) ) {
0302     _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
0303     return STATUS_NOT_OWNER;
0304   }
0305 
0306   nest_level = the_mutex->nest_level;
0307 
0308   if ( nest_level > 0 ) {
0309     the_mutex->nest_level = nest_level - 1;
0310     _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
0311     return STATUS_SUCCESSFUL;
0312   }
0313 
0314   _Thread_Resource_count_decrement( executing );
0315   _CORE_mutex_Set_owner( &the_mutex->Mutex, NULL );
0316 
0317   heads = the_mutex->Mutex.Wait_queue.Queue.heads;
0318 
0319   if ( heads == NULL ) {
0320     _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
0321     return STATUS_SUCCESSFUL;
0322   }
0323 
0324   _Thread_queue_Surrender(
0325     &the_mutex->Mutex.Wait_queue.Queue,
0326     heads,
0327     executing,
0328     queue_context,
0329     operations
0330   );
0331   return STATUS_SUCCESSFUL;
0332 }
0333 
0334 /**
0335  * @brief initializes a ceiling mutex.
0336  *
0337  * @param[out] the_mutex The ceiling mutex to initialize.
0338  * @param scheduler The scheduler for the new ceiling mutex.
0339  *      Only needed if RTEMS_SMP is defined
0340  * @param priority_ceiling The priority ceiling for the initialized mutex.
0341  */
0342 static inline void _CORE_ceiling_mutex_Initialize(
0343   CORE_ceiling_mutex_Control *the_mutex,
0344   const Scheduler_Control    *scheduler,
0345   Priority_Control            priority_ceiling
0346 )
0347 {
0348   _CORE_recursive_mutex_Initialize( &the_mutex->Recursive );
0349   _Priority_Node_initialize( &the_mutex->Priority_ceiling, priority_ceiling );
0350 #if defined(RTEMS_SMP)
0351   the_mutex->scheduler = scheduler;
0352 #endif
0353 }
0354 
0355 /**
0356  * @brief Gets the scheduler of the ceiling mutex.
0357  *
0358  * @param the_mutex The ceiling mutex to get the scheduler from.
0359  *
0360  * @return The scheduler of the mutex. If RTEMS_SMP is not defined, the first entry of the _Scheduler_Table is returned.
0361  */
0362 static inline const Scheduler_Control *
0363 _CORE_ceiling_mutex_Get_scheduler(
0364   const CORE_ceiling_mutex_Control *the_mutex
0365 )
0366 {
0367 #if defined(RTEMS_SMP)
0368   return the_mutex->scheduler;
0369 #else
0370   return &_Scheduler_Table[ 0 ];
0371 #endif
0372 }
0373 
0374 /**
0375  * @brief Sets the priority of the ceiling mutex.
0376  *
0377  * @param[out] the_mutex The ceiling mutex to set the priority of.
0378  * @param priority_ceiling The new priority ceiling of the mutex.
0379  */
0380 static inline void _CORE_ceiling_mutex_Set_priority(
0381   CORE_ceiling_mutex_Control *the_mutex,
0382   Priority_Control            priority_ceiling
0383 )
0384 {
0385   Thread_Control *owner;
0386 
0387   owner = _CORE_mutex_Get_owner( &the_mutex->Recursive.Mutex );
0388 
0389   if ( owner != NULL ) {
0390     Thread_queue_Context queue_context;
0391 
0392     _Thread_queue_Context_initialize( &queue_context );
0393     _Thread_queue_Context_clear_priority_updates( &queue_context );
0394     _Thread_Wait_acquire_critical( owner, &queue_context );
0395     _Thread_Priority_change(
0396       owner,
0397       &the_mutex->Priority_ceiling,
0398       priority_ceiling,
0399       PRIORITY_GROUP_LAST,
0400       &queue_context
0401     );
0402     _Thread_Wait_release_critical( owner, &queue_context );
0403   } else {
0404     the_mutex->Priority_ceiling.priority = priority_ceiling;
0405   }
0406 }
0407 
0408 /**
0409  * @brief Gets the priority of the ceiling mutex.
0410  *
0411  * @param the_mutex The mutex to get the priority from.
0412  *
0413  * @return The priority ceiling of @a the_mutex.
0414  */
0415 static inline Priority_Control _CORE_ceiling_mutex_Get_priority(
0416   const CORE_ceiling_mutex_Control *the_mutex
0417 )
0418 {
0419   return the_mutex->Priority_ceiling.priority;
0420 }
0421 
0422 /**
0423  * @brief Sets the owner of the ceiling mutex.
0424  *
0425  * @param[in, out] the_mutex The mutex to set the owner of.
0426  * @param owner The new owner of @a the_mutex.
0427  * @param queue_context The thread queue context.
0428  *
0429  * @retval STATUS_SUCCESSFUL The owner of the mutex was changed successfully.
0430  * @retval STATUS_MUTEX_CEILING_VIOLATED The owners wait priority
0431  *          is smaller than the priority of the ceiling mutex.
0432  */
0433 static inline Status_Control _CORE_ceiling_mutex_Set_owner(
0434   CORE_ceiling_mutex_Control *the_mutex,
0435   Thread_Control             *owner,
0436   Thread_queue_Context       *queue_context
0437 )
0438 {
0439   ISR_lock_Context  lock_context;
0440   Scheduler_Node   *scheduler_node;
0441   Per_CPU_Control  *cpu_self;
0442 
0443   _Thread_Wait_acquire_default_critical( owner, &lock_context );
0444 
0445   scheduler_node = _Thread_Scheduler_get_home_node( owner );
0446 
0447   if (
0448     _Priority_Get_priority( &scheduler_node->Wait.Priority )
0449       < the_mutex->Priority_ceiling.priority
0450   ) {
0451     _Thread_Wait_release_default_critical( owner, &lock_context );
0452     _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
0453     return STATUS_MUTEX_CEILING_VIOLATED;
0454   }
0455 
0456   _CORE_mutex_Set_owner( &the_mutex->Recursive.Mutex, owner );
0457   _Thread_Resource_count_increment( owner );
0458   _Thread_Priority_add(
0459     owner,
0460     &the_mutex->Priority_ceiling,
0461     queue_context
0462   );
0463   _Thread_Wait_release_default_critical( owner, &lock_context );
0464 
0465   cpu_self = _Thread_queue_Dispatch_disable( queue_context );
0466   _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
0467   _Thread_Priority_update( queue_context );
0468   _Thread_Dispatch_enable( cpu_self );
0469   return STATUS_SUCCESSFUL;
0470 }
0471 
0472 /**
0473  * @brief Seizes the ceiling mutex.
0474  *
0475  * @param[in, out] the_mutex The mutex to seize.
0476  * @param executing The executing thread.
0477  * @param wait Indicates whether the calling thread is willing to wait.
0478  * @param nested Function that returns the status of the recursive mutex
0479  * @param queue_context The thread queue context.
0480  *
0481  * @retval STATUS_SUCCESSFUL The owner of the mutex was changed successfully.
0482  * @retval STATUS_NOT_DEFINED If the scheduler of the executing thread is not equal to the owner of @a the_mutex .
0483  * @retval STATUS_MUTEX_CEILING_VIOLATED The owners wait priority
0484  *          is smaller than the priority of the ceiling mutex.
0485  * @retval other Return value of @a nested.
0486  */
0487 static inline Status_Control _CORE_ceiling_mutex_Seize(
0488   CORE_ceiling_mutex_Control    *the_mutex,
0489   Thread_Control                *executing,
0490   bool                           wait,
0491   Status_Control              ( *nested )( CORE_recursive_mutex_Control * ),
0492   Thread_queue_Context          *queue_context
0493 )
0494 {
0495   Thread_Control *owner;
0496 
0497   _CORE_mutex_Acquire_critical( &the_mutex->Recursive.Mutex, queue_context );
0498 
0499 #if defined(RTEMS_SMP)
0500   if (
0501     _Thread_Scheduler_get_home( executing )
0502       != _CORE_ceiling_mutex_Get_scheduler( the_mutex )
0503   ) {
0504     _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
0505     return STATUS_NOT_DEFINED;
0506   }
0507 #endif
0508 
0509   owner = _CORE_mutex_Get_owner( &the_mutex->Recursive.Mutex );
0510 
0511   if ( owner == NULL ) {
0512     _Thread_queue_Context_clear_priority_updates( queue_context );
0513     return _CORE_ceiling_mutex_Set_owner(
0514       the_mutex,
0515       executing,
0516       queue_context
0517     );
0518   }
0519 
0520   if ( owner == executing ) {
0521     Status_Control status;
0522 
0523     status = ( *nested )( &the_mutex->Recursive );
0524     _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
0525     return status;
0526   }
0527 
0528   return _CORE_mutex_Seize_slow(
0529     &the_mutex->Recursive.Mutex,
0530     CORE_MUTEX_TQ_OPERATIONS,
0531     executing,
0532     wait,
0533     queue_context
0534   );
0535 }
0536 
0537 /**
0538  * @brief Surrenders the ceiling mutex.
0539  *
0540  * @param[in, out] the_mutex The ceiling mutex to surrender.
0541  * @param executing The executing thread.
0542  * @param queue_context The thread queue context.
0543  *
0544  * @retval STATUS_SUCCESSFUL The ceiling mutex was successfullysurrendered.
0545  * @retval STATUS_NOT_OWNER The executing thread is not the owner of @a the_mutex.
0546  */
0547 static inline Status_Control _CORE_ceiling_mutex_Surrender(
0548   CORE_ceiling_mutex_Control *the_mutex,
0549   Thread_Control             *executing,
0550   Thread_queue_Context       *queue_context
0551 )
0552 {
0553   unsigned int nest_level;
0554 
0555   _CORE_mutex_Acquire_critical( &the_mutex->Recursive.Mutex, queue_context );
0556 
0557   if ( !_CORE_mutex_Is_owner( &the_mutex->Recursive.Mutex, executing ) ) {
0558     _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
0559     return STATUS_NOT_OWNER;
0560   }
0561 
0562   nest_level = the_mutex->Recursive.nest_level;
0563 
0564   if ( nest_level > 0 ) {
0565     the_mutex->Recursive.nest_level = nest_level - 1;
0566     _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
0567     return STATUS_SUCCESSFUL;
0568   }
0569 
0570   return _Thread_queue_Surrender_priority_ceiling(
0571     &the_mutex->Recursive.Mutex.Wait_queue.Queue,
0572     executing,
0573     &the_mutex->Priority_ceiling,
0574     queue_context,
0575     CORE_MUTEX_TQ_OPERATIONS
0576   );
0577 }
0578 
0579 /** @} */
0580 
0581 #ifdef __cplusplus
0582 }
0583 #endif
0584 
0585 #endif
0586 /* end of include file */