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  * @brief Private Inlined Routines for POSIX Mutex's.
0007  *
0008  * This include file contains the static inline implementation of the private
0009  * inlined routines for POSIX mutex's.
0010  */
0011 
0012 /*  COPYRIGHT (c) 1989-2013.
0013  *  On-Line Applications Research Corporation (OAR).
0014  *
0015  * Redistribution and use in source and binary forms, with or without
0016  * modification, are permitted provided that the following conditions
0017  * are met:
0018  * 1. Redistributions of source code must retain the above copyright
0019  *    notice, this list of conditions and the following disclaimer.
0020  * 2. Redistributions in binary form must reproduce the above copyright
0021  *    notice, this list of conditions and the following disclaimer in the
0022  *    documentation and/or other materials provided with the distribution.
0023  *
0024  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0025  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0026  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0027  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0028  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0029  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0030  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0031  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0032  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0033  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0034  * POSSIBILITY OF SUCH DAMAGE.
0035  */
0036 
0037 #ifndef _RTEMS_POSIX_MUTEXIMPL_H
0038 #define _RTEMS_POSIX_MUTEXIMPL_H
0039 
0040 #include <errno.h>
0041 #include <pthread.h>
0042 
0043 #include <rtems/score/percpu.h>
0044 #include <rtems/score/muteximpl.h>
0045 #include <rtems/score/threadimpl.h>
0046 
0047 #ifdef __cplusplus
0048 extern "C" {
0049 #endif
0050 
0051 typedef struct {
0052   unsigned long flags;
0053   Mutex_recursive_Control Recursive;
0054   Priority_Node Priority_ceiling;
0055   const Scheduler_Control *scheduler;
0056 } POSIX_Mutex_Control;
0057 
0058 #define POSIX_MUTEX_PROTOCOL_MASK 0x3UL
0059 
0060 #define POSIX_MUTEX_RECURSIVE 0x4UL
0061 
0062 #define POSIX_MUTEX_FLAGS_MASK 0x7UL
0063 
0064 #define POSIX_MUTEX_MAGIC 0x961c13b8UL
0065 
0066 #define POSIX_MUTEX_NO_PROTOCOL_TQ_OPERATIONS &_Thread_queue_Operations_FIFO
0067 
0068 #define POSIX_MUTEX_PRIORITY_INHERIT_TQ_OPERATIONS \
0069   &_Thread_queue_Operations_priority_inherit
0070 
0071 #define POSIX_MUTEX_PRIORITY_CEILING_TQ_OPERATIONS \
0072   &_Thread_queue_Operations_priority
0073 
0074 /**
0075  * @brief Supported POSIX mutex protocols.
0076  *
0077  * Must be in synchronization with POSIX_Mutex_Control::protocol.
0078  */
0079 typedef enum {
0080   POSIX_MUTEX_NO_PROTOCOL,
0081   POSIX_MUTEX_PRIORITY_INHERIT,
0082   POSIX_MUTEX_PRIORITY_CEILING
0083 } POSIX_Mutex_Protocol;
0084 
0085 /**
0086  *  The default mutex attributes structure.
0087  */
0088 extern const pthread_mutexattr_t _POSIX_Mutex_Default_attributes;
0089 
0090 static inline Thread_Control *_POSIX_Mutex_Acquire(
0091   POSIX_Mutex_Control  *the_mutex,
0092   Thread_queue_Context *queue_context
0093 )
0094 {
0095   ISR_Level       level;
0096   Thread_Control *executing;
0097 
0098   _Thread_queue_Context_initialize( queue_context );
0099   _Thread_queue_Context_ISR_disable( queue_context, level );
0100   _Thread_queue_Context_set_ISR_level( queue_context, level );
0101   executing = _Thread_Executing;
0102   _Thread_queue_Queue_acquire_critical(
0103     &the_mutex->Recursive.Mutex.Queue.Queue,
0104     &executing->Potpourri_stats,
0105     &queue_context->Lock_context.Lock_context
0106   );
0107 
0108   return executing;
0109 }
0110 
0111 static inline void _POSIX_Mutex_Release(
0112   POSIX_Mutex_Control  *the_mutex,
0113   Thread_queue_Context *queue_context
0114 )
0115 {
0116   _Thread_queue_Queue_release(
0117     &the_mutex->Recursive.Mutex.Queue.Queue,
0118     &queue_context->Lock_context.Lock_context
0119   );
0120 }
0121 
0122 static inline POSIX_Mutex_Protocol _POSIX_Mutex_Get_protocol(
0123   unsigned long flags
0124 )
0125 {
0126   return (POSIX_Mutex_Protocol) (flags & POSIX_MUTEX_PROTOCOL_MASK);
0127 }
0128 
0129 static inline bool _POSIX_Mutex_Is_recursive(
0130   unsigned long flags
0131 )
0132 {
0133   return ( flags & POSIX_MUTEX_RECURSIVE ) != 0;
0134 }
0135 
0136 static inline Thread_Control *_POSIX_Mutex_Get_owner(
0137   const POSIX_Mutex_Control *the_mutex
0138 )
0139 {
0140   return the_mutex->Recursive.Mutex.Queue.Queue.owner;
0141 }
0142 
0143 static inline bool _POSIX_Mutex_Is_locked(
0144   const POSIX_Mutex_Control *the_mutex
0145 )
0146 {
0147   return _POSIX_Mutex_Get_owner( the_mutex ) != NULL;
0148 }
0149 
0150 Status_Control _POSIX_Mutex_Seize_slow(
0151   POSIX_Mutex_Control           *the_mutex,
0152   const Thread_queue_Operations *operations,
0153   Thread_Control                *executing,
0154   const struct timespec         *abstime,
0155   Thread_queue_Context          *queue_context
0156 );
0157 
0158 static inline void _POSIX_Mutex_Set_owner(
0159   POSIX_Mutex_Control *the_mutex,
0160   Thread_Control      *owner
0161 )
0162 {
0163   the_mutex->Recursive.Mutex.Queue.Queue.owner = owner;
0164 }
0165 
0166 static inline bool _POSIX_Mutex_Is_owner(
0167   const POSIX_Mutex_Control *the_mutex,
0168   const Thread_Control      *the_thread
0169 )
0170 {
0171   return _POSIX_Mutex_Get_owner( the_mutex ) == the_thread;
0172 }
0173 
0174 static Status_Control _POSIX_Mutex_Lock_nested(
0175   POSIX_Mutex_Control *the_mutex,
0176   unsigned long        flags
0177 )
0178 {
0179 
0180   if ( _POSIX_Mutex_Is_recursive( flags ) ) {
0181     ++the_mutex->Recursive.nest_level;
0182     return STATUS_SUCCESSFUL;
0183   } else {
0184     return STATUS_NESTING_NOT_ALLOWED;
0185   }
0186 }
0187 
0188 static inline Status_Control _POSIX_Mutex_Seize(
0189   POSIX_Mutex_Control           *the_mutex,
0190   unsigned long                  flags,
0191   const Thread_queue_Operations *operations,
0192   Thread_Control                *executing,
0193   const struct timespec         *abstime,
0194   Thread_queue_Context          *queue_context
0195 )
0196 {
0197   Thread_Control *owner;
0198 
0199   owner = _POSIX_Mutex_Get_owner( the_mutex );
0200 
0201   if ( owner == NULL ) {
0202     _POSIX_Mutex_Set_owner( the_mutex, executing );
0203     _Thread_Resource_count_increment( executing );
0204     _POSIX_Mutex_Release( the_mutex, queue_context );
0205     return STATUS_SUCCESSFUL;
0206   }
0207 
0208   if ( owner == executing ) {
0209     Status_Control status;
0210 
0211     status = _POSIX_Mutex_Lock_nested( the_mutex, flags );
0212     _POSIX_Mutex_Release( the_mutex, queue_context );
0213     return status;
0214   }
0215 
0216   return _POSIX_Mutex_Seize_slow(
0217     the_mutex,
0218     operations,
0219     executing,
0220     abstime,
0221     queue_context
0222   );
0223 }
0224 
0225 static inline Status_Control _POSIX_Mutex_Surrender(
0226   POSIX_Mutex_Control           *the_mutex,
0227   const Thread_queue_Operations *operations,
0228   Thread_Control                *executing,
0229   Thread_queue_Context          *queue_context
0230 )
0231 {
0232   unsigned int        nest_level;
0233   Thread_queue_Heads *heads;
0234 
0235   if ( !_POSIX_Mutex_Is_owner( the_mutex, executing ) ) {
0236     _POSIX_Mutex_Release( the_mutex, queue_context );
0237     return STATUS_NOT_OWNER;
0238   }
0239 
0240   nest_level = the_mutex->Recursive.nest_level;
0241 
0242   if ( nest_level > 0 ) {
0243     the_mutex->Recursive.nest_level = nest_level - 1;
0244     _POSIX_Mutex_Release( the_mutex, queue_context );
0245     return STATUS_SUCCESSFUL;
0246   }
0247 
0248   _Thread_Resource_count_decrement( executing );
0249   _POSIX_Mutex_Set_owner( the_mutex, NULL );
0250 
0251   heads = the_mutex->Recursive.Mutex.Queue.Queue.heads;
0252 
0253   if ( heads == NULL ) {
0254     _POSIX_Mutex_Release( the_mutex, queue_context );
0255     return STATUS_SUCCESSFUL;
0256   }
0257 
0258   _Thread_queue_Surrender(
0259     &the_mutex->Recursive.Mutex.Queue.Queue,
0260     heads,
0261     executing,
0262     queue_context,
0263     operations
0264   );
0265   return STATUS_SUCCESSFUL;
0266 }
0267 
0268 static inline const Scheduler_Control *_POSIX_Mutex_Get_scheduler(
0269   const POSIX_Mutex_Control *the_mutex
0270 )
0271 {
0272 #if defined(RTEMS_SMP)
0273   return the_mutex->scheduler;
0274 #else
0275   return &_Scheduler_Table[ 0 ];
0276 #endif
0277 }
0278 
0279 static inline void _POSIX_Mutex_Set_priority(
0280   POSIX_Mutex_Control  *the_mutex,
0281   Priority_Control      priority_ceiling,
0282   Thread_queue_Context *queue_context
0283 )
0284 {
0285   Thread_Control *owner;
0286 
0287   owner = _POSIX_Mutex_Get_owner( the_mutex );
0288 
0289   if ( owner != NULL ) {
0290     _Thread_Wait_acquire( owner, queue_context );
0291     _Thread_Priority_change(
0292       owner,
0293       &the_mutex->Priority_ceiling,
0294       priority_ceiling,
0295       PRIORITY_GROUP_LAST,
0296       queue_context
0297     );
0298     _Thread_Wait_release( owner, queue_context );
0299   } else {
0300     the_mutex->Priority_ceiling.priority = priority_ceiling;
0301   }
0302 }
0303 
0304 static inline Priority_Control _POSIX_Mutex_Get_priority(
0305   const POSIX_Mutex_Control *the_mutex
0306 )
0307 {
0308   return the_mutex->Priority_ceiling.priority;
0309 }
0310 
0311 static inline Status_Control _POSIX_Mutex_Ceiling_set_owner(
0312   POSIX_Mutex_Control  *the_mutex,
0313   Thread_Control       *owner,
0314   Thread_queue_Context *queue_context
0315 )
0316 {
0317   ISR_lock_Context  lock_context;
0318   Scheduler_Node   *scheduler_node;
0319   Per_CPU_Control  *cpu_self;
0320 
0321   _Thread_Wait_acquire_default_critical( owner, &lock_context );
0322 
0323   scheduler_node = _Thread_Scheduler_get_home_node( owner );
0324 
0325   if (
0326     _Priority_Get_priority( &scheduler_node->Wait.Priority )
0327       < the_mutex->Priority_ceiling.priority
0328   ) {
0329     _Thread_Wait_release_default_critical( owner, &lock_context );
0330     _POSIX_Mutex_Release( the_mutex, queue_context );
0331     return STATUS_MUTEX_CEILING_VIOLATED;
0332   }
0333 
0334   _POSIX_Mutex_Set_owner( the_mutex, owner );
0335   _Thread_Resource_count_increment( owner );
0336   _Thread_Priority_add(
0337     owner,
0338     &the_mutex->Priority_ceiling,
0339     queue_context
0340   );
0341   _Thread_Wait_release_default_critical( owner, &lock_context );
0342 
0343   cpu_self = _Thread_queue_Dispatch_disable( queue_context );
0344   _POSIX_Mutex_Release( the_mutex, queue_context );
0345   _Thread_Priority_update( queue_context );
0346   _Thread_Dispatch_enable( cpu_self );
0347   return STATUS_SUCCESSFUL;
0348 }
0349 
0350 static inline Status_Control _POSIX_Mutex_Ceiling_seize(
0351   POSIX_Mutex_Control   *the_mutex,
0352   unsigned long          flags,
0353   Thread_Control        *executing,
0354   const struct timespec *abstime,
0355   Thread_queue_Context  *queue_context
0356 )
0357 {
0358   Thread_Control *owner;
0359 
0360   owner = _POSIX_Mutex_Get_owner( the_mutex );
0361 
0362   if ( owner == NULL ) {
0363 #if defined(RTEMS_SMP)
0364     if (
0365       _Thread_Scheduler_get_home( executing )
0366         != _POSIX_Mutex_Get_scheduler( the_mutex )
0367     ) {
0368       _POSIX_Mutex_Release( the_mutex, queue_context );
0369       return STATUS_NOT_DEFINED;
0370     }
0371 #endif
0372 
0373     _Thread_queue_Context_clear_priority_updates( queue_context );
0374     return _POSIX_Mutex_Ceiling_set_owner(
0375       the_mutex,
0376       executing,
0377       queue_context
0378     );
0379   }
0380 
0381   if ( owner == executing ) {
0382     Status_Control status;
0383 
0384     status = _POSIX_Mutex_Lock_nested( the_mutex, flags );
0385     _POSIX_Mutex_Release( the_mutex, queue_context );
0386     return status;
0387   }
0388 
0389   return _POSIX_Mutex_Seize_slow(
0390     the_mutex,
0391     POSIX_MUTEX_PRIORITY_CEILING_TQ_OPERATIONS,
0392     executing,
0393     abstime,
0394     queue_context
0395   );
0396 }
0397 
0398 static inline Status_Control _POSIX_Mutex_Ceiling_surrender(
0399   POSIX_Mutex_Control  *the_mutex,
0400   Thread_Control       *executing,
0401   Thread_queue_Context *queue_context
0402 )
0403 {
0404   unsigned int nest_level;
0405 
0406   if ( !_POSIX_Mutex_Is_owner( the_mutex, executing ) ) {
0407     _POSIX_Mutex_Release( the_mutex, queue_context );
0408     return STATUS_NOT_OWNER;
0409   }
0410 
0411   nest_level = the_mutex->Recursive.nest_level;
0412 
0413   if ( nest_level > 0 ) {
0414     the_mutex->Recursive.nest_level = nest_level - 1;
0415     _POSIX_Mutex_Release( the_mutex, queue_context );
0416     return STATUS_SUCCESSFUL;
0417   }
0418 
0419   return _Thread_queue_Surrender_priority_ceiling(
0420     &the_mutex->Recursive.Mutex.Queue.Queue,
0421     executing,
0422     &the_mutex->Priority_ceiling,
0423     queue_context,
0424     POSIX_MUTEX_PRIORITY_CEILING_TQ_OPERATIONS
0425   );
0426 }
0427 
0428 #define POSIX_MUTEX_ABSTIME_TRY_LOCK ((uintptr_t) 1)
0429 
0430 int _POSIX_Mutex_Lock_support(
0431   pthread_mutex_t              *mutex,
0432   const struct timespec        *abstime,
0433   Thread_queue_Enqueue_callout  enqueue_callout
0434 );
0435 
0436 static inline POSIX_Mutex_Control *_POSIX_Mutex_Get(
0437   pthread_mutex_t *mutex
0438 )
0439 {
0440   return (POSIX_Mutex_Control *) mutex;
0441 }
0442 
0443 bool _POSIX_Mutex_Auto_initialization( POSIX_Mutex_Control *the_mutex );
0444 
0445 #define POSIX_MUTEX_VALIDATE_OBJECT( the_mutex, flags ) \
0446   do { \
0447     if ( ( the_mutex ) == NULL ) { \
0448       return EINVAL; \
0449     } \
0450     flags = ( the_mutex )->flags; \
0451     if ( \
0452       ( ( (uintptr_t) ( the_mutex ) ^ POSIX_MUTEX_MAGIC ) \
0453           & ~POSIX_MUTEX_FLAGS_MASK ) \
0454         != ( flags & ~POSIX_MUTEX_FLAGS_MASK ) \
0455     ) { \
0456       if ( !_POSIX_Mutex_Auto_initialization( the_mutex ) ) { \
0457         return EINVAL; \
0458       } \
0459     } \
0460   } while ( 0 )
0461 
0462 #ifdef __cplusplus
0463 }
0464 #endif
0465 
0466 #endif
0467 /*  end of include file */