Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSScoreSysLockMutex
0007  *
0008  * @brief This source file contains the implementation of
0009  *   _Mutex_Acquire(), _Mutex_Acquire_timed(), _Mutex_Acquire_timed_ticks(),
0010  *   _Mutex_Try_acquire(), _Mutex_Release(), _Mutex_recursive_Acquire(),
0011  *   _Mutex_recursive_Acquire_timed(), _Mutex_recursive_Try_acquire(), and
0012  *   _Mutex_recursive_Release().
0013  */
0014 
0015 /*
0016  * Copyright (C) 2015, 2016 embedded brains GmbH & Co. KG
0017  *
0018  * Redistribution and use in source and binary forms, with or without
0019  * modification, are permitted provided that the following conditions
0020  * are met:
0021  * 1. Redistributions of source code must retain the above copyright
0022  *    notice, this list of conditions and the following disclaimer.
0023  * 2. Redistributions in binary form must reproduce the above copyright
0024  *    notice, this list of conditions and the following disclaimer in the
0025  *    documentation and/or other materials provided with the distribution.
0026  *
0027  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0028  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0029  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0030  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0031  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0032  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0033  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0034  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0035  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0036  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0037  * POSSIBILITY OF SUCH DAMAGE.
0038  */
0039 
0040 #ifdef HAVE_CONFIG_H
0041 #include "config.h"
0042 #endif
0043 
0044 #include <sys/lock.h>
0045 #include <errno.h>
0046 
0047 #include <rtems/score/assert.h>
0048 #include <rtems/score/muteximpl.h>
0049 #include <rtems/score/threadimpl.h>
0050 #include <rtems/score/todimpl.h>
0051 
0052 /**
0053  * @defgroup RTEMSScoreSysLockMutex System Lock Mutex Handler
0054  *
0055  * @ingroup RTEMSScore
0056  *
0057  * @brief This group contains the System Lock Mutex Handler implementation.
0058  *
0059  * The interfaces are defined by Newlib in <sys/lock.h>.  The system lock
0060  * mutexes are used for Newlib internal locking, the C++ standard library
0061  * provided by GCC, the OpenMP support provided by GCC, the self-contained
0062  * objects API provided by RTEMS, and the SuperCore internal mutexes such as
0063  * the objects allocator lock (see ::API_Mutex_Control).
0064  */
0065 
0066 #define MUTEX_TQ_OPERATIONS &_Thread_queue_Operations_priority_inherit
0067 
0068 RTEMS_STATIC_ASSERT(
0069   offsetof( Mutex_Control, Queue )
0070     == offsetof( struct _Mutex_Control, _Queue ),
0071   MUTEX_CONTROL_QUEUE
0072 );
0073 
0074 RTEMS_STATIC_ASSERT(
0075   sizeof( Mutex_Control ) == sizeof( struct _Mutex_Control ),
0076   MUTEX_CONTROL_SIZE
0077 );
0078 
0079 RTEMS_STATIC_ASSERT(
0080   offsetof( Mutex_recursive_Control, Mutex )
0081     == offsetof( struct _Mutex_recursive_Control, _Mutex ),
0082   MUTEX_RECURSIVE_CONTROL_MUTEX
0083 );
0084 
0085 RTEMS_STATIC_ASSERT(
0086   offsetof( Mutex_recursive_Control, nest_level )
0087     == offsetof( struct _Mutex_recursive_Control, _nest_level ),
0088   MUTEX_RECURSIVE_CONTROL_NEST_LEVEL
0089 );
0090 
0091 RTEMS_STATIC_ASSERT(
0092   sizeof( Mutex_recursive_Control )
0093     == sizeof( struct _Mutex_recursive_Control ),
0094   MUTEX_RECURSIVE_CONTROL_SIZE
0095 );
0096 
0097 static Mutex_Control *_Mutex_Get( struct _Mutex_Control *_mutex )
0098 {
0099   return (Mutex_Control *) _mutex;
0100 }
0101 
0102 static Thread_Control *_Mutex_Queue_acquire_critical(
0103   Mutex_Control        *mutex,
0104   Thread_queue_Context *queue_context
0105 )
0106 {
0107   Thread_Control *executing;
0108 
0109   executing = _Thread_Executing;
0110   _Thread_queue_Queue_acquire_critical(
0111     &mutex->Queue.Queue,
0112     &executing->Potpourri_stats,
0113     &queue_context->Lock_context.Lock_context
0114   );
0115 
0116   return executing;
0117 }
0118 
0119 static void _Mutex_Queue_release(
0120   Mutex_Control        *mutex,
0121   ISR_Level             level,
0122   Thread_queue_Context *queue_context
0123 )
0124 {
0125   _Thread_queue_Queue_release_critical(
0126     &mutex->Queue.Queue,
0127     &queue_context->Lock_context.Lock_context
0128   );
0129   _ISR_Local_enable( level );
0130 }
0131 
0132 static void _Mutex_Acquire_slow(
0133   Mutex_Control        *mutex,
0134   Thread_Control       *owner,
0135   Thread_Control       *executing,
0136   ISR_Level             level,
0137   Thread_queue_Context *queue_context
0138 )
0139 {
0140   _Thread_queue_Context_set_thread_state(
0141     queue_context,
0142     STATES_WAITING_FOR_MUTEX
0143   );
0144   _Thread_queue_Context_set_deadlock_callout(
0145     queue_context,
0146     _Thread_queue_Deadlock_fatal
0147   );
0148   _Thread_queue_Context_set_ISR_level( queue_context, level );
0149   _Thread_queue_Enqueue(
0150     &mutex->Queue.Queue,
0151     MUTEX_TQ_OPERATIONS,
0152     executing,
0153     queue_context
0154   );
0155 }
0156 
0157 static void _Mutex_Release_critical(
0158   Mutex_Control        *mutex,
0159   Thread_Control       *executing,
0160   ISR_Level             level,
0161   Thread_queue_Context *queue_context
0162 )
0163 {
0164   Thread_queue_Heads *heads;
0165 
0166   heads = mutex->Queue.Queue.heads;
0167   mutex->Queue.Queue.owner = NULL;
0168   _Thread_Resource_count_decrement( executing );
0169 
0170   if ( RTEMS_PREDICT_TRUE( heads == NULL ) ) {
0171     _Mutex_Queue_release( mutex, level, queue_context );
0172   } else {
0173     _Thread_queue_Context_set_ISR_level( queue_context, level );
0174     _Thread_queue_Surrender(
0175       &mutex->Queue.Queue,
0176       heads,
0177       executing,
0178       queue_context,
0179       MUTEX_TQ_OPERATIONS
0180     );
0181   }
0182 }
0183 
0184 void _Mutex_Acquire( struct _Mutex_Control *_mutex )
0185 {
0186   Mutex_Control        *mutex;
0187   Thread_queue_Context  queue_context;
0188   ISR_Level             level;
0189   Thread_Control       *executing;
0190   Thread_Control       *owner;
0191 
0192   mutex = _Mutex_Get( _mutex );
0193   _Thread_queue_Context_initialize( &queue_context );
0194   _Thread_queue_Context_ISR_disable( &queue_context, level );
0195   executing = _Mutex_Queue_acquire_critical( mutex, &queue_context );
0196 
0197   owner = mutex->Queue.Queue.owner;
0198 
0199   if ( RTEMS_PREDICT_TRUE( owner == NULL ) ) {
0200     mutex->Queue.Queue.owner = executing;
0201     _Thread_Resource_count_increment( executing );
0202     _Mutex_Queue_release( mutex, level, &queue_context );
0203   } else {
0204     _Thread_queue_Context_set_enqueue_do_nothing_extra( &queue_context );
0205     _Mutex_Acquire_slow( mutex, owner, executing, level, &queue_context );
0206   }
0207 }
0208 
0209 int _Mutex_Acquire_timed(
0210   struct _Mutex_Control *_mutex,
0211   const struct timespec *abstime
0212 )
0213 {
0214   Mutex_Control        *mutex;
0215   Thread_queue_Context  queue_context;
0216   ISR_Level             level;
0217   Thread_Control       *executing;
0218   Thread_Control       *owner;
0219 
0220   mutex = _Mutex_Get( _mutex );
0221   _Thread_queue_Context_initialize( &queue_context );
0222   _Thread_queue_Context_ISR_disable( &queue_context, level );
0223   executing = _Mutex_Queue_acquire_critical( mutex, &queue_context );
0224 
0225   owner = mutex->Queue.Queue.owner;
0226 
0227   if ( RTEMS_PREDICT_TRUE( owner == NULL ) ) {
0228     mutex->Queue.Queue.owner = executing;
0229     _Thread_Resource_count_increment( executing );
0230     _Mutex_Queue_release( mutex, level, &queue_context );
0231 
0232     return 0;
0233   } else {
0234     _Thread_queue_Context_set_enqueue_timeout_realtime_timespec(
0235       &queue_context,
0236       abstime,
0237       true
0238     );
0239     _Mutex_Acquire_slow( mutex, owner, executing, level, &queue_context );
0240 
0241     return STATUS_GET_POSIX( _Thread_Wait_get_status( executing ) );
0242   }
0243 }
0244 
0245 int _Mutex_Try_acquire( struct _Mutex_Control *_mutex )
0246 {
0247   Mutex_Control        *mutex;
0248   Thread_queue_Context  queue_context;
0249   ISR_Level             level;
0250   Thread_Control       *executing;
0251   Thread_Control       *owner;
0252   int                   eno;
0253 
0254   mutex = _Mutex_Get( _mutex );
0255   _Thread_queue_Context_initialize( &queue_context );
0256   _Thread_queue_Context_ISR_disable( &queue_context, level );
0257   executing = _Mutex_Queue_acquire_critical( mutex, &queue_context );
0258 
0259   owner = mutex->Queue.Queue.owner;
0260 
0261   if ( RTEMS_PREDICT_TRUE( owner == NULL ) ) {
0262     mutex->Queue.Queue.owner = executing;
0263     _Thread_Resource_count_increment( executing );
0264     eno = 0;
0265   } else {
0266     eno = EBUSY;
0267   }
0268 
0269   _Mutex_Queue_release( mutex, level, &queue_context );
0270 
0271   return eno;
0272 }
0273 
0274 void _Mutex_Release( struct _Mutex_Control *_mutex )
0275 {
0276   Mutex_Control        *mutex;
0277   Thread_queue_Context  queue_context;
0278   ISR_Level             level;
0279   Thread_Control       *executing;
0280 
0281   mutex = _Mutex_Get( _mutex );
0282   _Thread_queue_Context_initialize( &queue_context );
0283   _Thread_queue_Context_ISR_disable( &queue_context, level );
0284   executing = _Mutex_Queue_acquire_critical( mutex, &queue_context );
0285 
0286   _Assert( mutex->Queue.Queue.owner == executing );
0287 
0288   _Mutex_Release_critical( mutex, executing, level, &queue_context );
0289 }
0290 
0291 static Mutex_recursive_Control *_Mutex_recursive_Get(
0292   struct _Mutex_recursive_Control *_mutex
0293 )
0294 {
0295   return (Mutex_recursive_Control *) _mutex;
0296 }
0297 
0298 void _Mutex_recursive_Acquire( struct _Mutex_recursive_Control *_mutex )
0299 {
0300   Mutex_recursive_Control *mutex;
0301   Thread_queue_Context     queue_context;
0302   ISR_Level             level;
0303   Thread_Control          *executing;
0304   Thread_Control          *owner;
0305 
0306   mutex = _Mutex_recursive_Get( _mutex );
0307   _Thread_queue_Context_initialize( &queue_context );
0308   _Thread_queue_Context_ISR_disable( &queue_context, level );
0309   executing = _Mutex_Queue_acquire_critical( &mutex->Mutex, &queue_context );
0310 
0311   owner = mutex->Mutex.Queue.Queue.owner;
0312 
0313   if ( RTEMS_PREDICT_TRUE( owner == NULL ) ) {
0314     mutex->Mutex.Queue.Queue.owner = executing;
0315     _Thread_Resource_count_increment( executing );
0316     _Mutex_Queue_release( &mutex->Mutex, level, &queue_context );
0317   } else if ( owner == executing ) {
0318     ++mutex->nest_level;
0319     _Mutex_Queue_release( &mutex->Mutex, level, &queue_context );
0320   } else {
0321     _Thread_queue_Context_set_enqueue_do_nothing_extra( &queue_context );
0322     _Mutex_Acquire_slow( &mutex->Mutex, owner, executing, level, &queue_context );
0323   }
0324 }
0325 
0326 int _Mutex_recursive_Acquire_timed(
0327   struct _Mutex_recursive_Control *_mutex,
0328   const struct timespec           *abstime
0329 )
0330 {
0331   Mutex_recursive_Control *mutex;
0332   Thread_queue_Context     queue_context;
0333   ISR_Level                level;
0334   Thread_Control          *executing;
0335   Thread_Control          *owner;
0336 
0337   mutex = _Mutex_recursive_Get( _mutex );
0338   _Thread_queue_Context_initialize( &queue_context );
0339   _Thread_queue_Context_ISR_disable( &queue_context, level );
0340   executing = _Mutex_Queue_acquire_critical( &mutex->Mutex, &queue_context );
0341 
0342   owner = mutex->Mutex.Queue.Queue.owner;
0343 
0344   if ( RTEMS_PREDICT_TRUE( owner == NULL ) ) {
0345     mutex->Mutex.Queue.Queue.owner = executing;
0346     _Thread_Resource_count_increment( executing );
0347     _Mutex_Queue_release( &mutex->Mutex, level, &queue_context );
0348 
0349     return 0;
0350   } else if ( owner == executing ) {
0351     ++mutex->nest_level;
0352     _Mutex_Queue_release( &mutex->Mutex, level, &queue_context );
0353 
0354     return 0;
0355   } else {
0356     _Thread_queue_Context_set_enqueue_timeout_realtime_timespec(
0357       &queue_context,
0358       abstime,
0359       true
0360     );
0361     _Mutex_Acquire_slow( &mutex->Mutex, owner, executing, level, &queue_context );
0362 
0363     return STATUS_GET_POSIX( _Thread_Wait_get_status( executing ) );
0364   }
0365 }
0366 
0367 int _Mutex_recursive_Try_acquire( struct _Mutex_recursive_Control *_mutex )
0368 {
0369   Mutex_recursive_Control *mutex;
0370   Thread_queue_Context     queue_context;
0371   ISR_Level                level;
0372   Thread_Control          *executing;
0373   Thread_Control          *owner;
0374   int                      eno;
0375 
0376   mutex = _Mutex_recursive_Get( _mutex );
0377   _Thread_queue_Context_initialize( &queue_context );
0378   _Thread_queue_Context_ISR_disable( &queue_context, level );
0379   executing = _Mutex_Queue_acquire_critical( &mutex->Mutex, &queue_context );
0380 
0381   owner = mutex->Mutex.Queue.Queue.owner;
0382 
0383   if ( RTEMS_PREDICT_TRUE( owner == NULL ) ) {
0384     mutex->Mutex.Queue.Queue.owner = executing;
0385     _Thread_Resource_count_increment( executing );
0386     eno = 0;
0387   } else if ( owner == executing ) {
0388     ++mutex->nest_level;
0389     eno = 0;
0390   } else {
0391     eno = EBUSY;
0392   }
0393 
0394   _Mutex_Queue_release( &mutex->Mutex, level, &queue_context );
0395 
0396   return eno;
0397 }
0398 
0399 void _Mutex_recursive_Release( struct _Mutex_recursive_Control *_mutex )
0400 {
0401   Mutex_recursive_Control *mutex;
0402   Thread_queue_Context     queue_context;
0403   ISR_Level                level;
0404   Thread_Control          *executing;
0405   unsigned int             nest_level;
0406 
0407   mutex = _Mutex_recursive_Get( _mutex );
0408   _Thread_queue_Context_initialize( &queue_context );
0409   _Thread_queue_Context_ISR_disable( &queue_context, level );
0410   executing = _Mutex_Queue_acquire_critical( &mutex->Mutex, &queue_context );
0411 
0412   _Assert( mutex->Mutex.Queue.Queue.owner == executing );
0413 
0414   nest_level = mutex->nest_level;
0415 
0416   if ( RTEMS_PREDICT_TRUE( nest_level == 0 ) ) {
0417     _Mutex_Release_critical( &mutex->Mutex, executing, level, &queue_context );
0418   } else {
0419     mutex->nest_level = nest_level - 1;
0420 
0421     _Mutex_Queue_release( &mutex->Mutex, level, &queue_context );
0422   }
0423 }