Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup POSIXAPI
0007  *
0008  * @brief Initialize a Mutex
0009  */
0010 
0011 /*
0012  *  COPYRIGHT (c) 1989-2009.
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 #ifdef HAVE_CONFIG_H
0038 #include "config.h"
0039 #endif
0040 
0041 #include <rtems/posix/muteximpl.h>
0042 #include <rtems/posix/posixapi.h>
0043 #include <rtems/posix/priorityimpl.h>
0044 #include <rtems/score/schedulerimpl.h>
0045 
0046 #include <limits.h>
0047 
0048 RTEMS_STATIC_ASSERT(
0049   offsetof( POSIX_Mutex_Control, flags )
0050     == offsetof( pthread_mutex_t, _flags ),
0051   POSIX_MUTEX_CONTROL_FLAGS
0052 );
0053 
0054 RTEMS_STATIC_ASSERT(
0055   offsetof( POSIX_Mutex_Control, Recursive )
0056     == offsetof( pthread_mutex_t, _Recursive ),
0057   POSIX_MUTEX_CONTROL_RECURSIVE
0058 );
0059 
0060 RTEMS_STATIC_ASSERT(
0061   offsetof( POSIX_Mutex_Control, Priority_ceiling )
0062     == offsetof( pthread_mutex_t, _Priority_ceiling ),
0063   POSIX_MUTEX_CONTROL_PRIORITY_CEILING
0064 );
0065 
0066 RTEMS_STATIC_ASSERT(
0067   offsetof( POSIX_Mutex_Control, scheduler )
0068     == offsetof( pthread_mutex_t, _scheduler ),
0069   POSIX_MUTEX_CONTROL_SCHEDULER
0070 );
0071 
0072 RTEMS_STATIC_ASSERT(
0073   sizeof( POSIX_Mutex_Control ) == sizeof( pthread_mutex_t ),
0074   POSIX_MUTEX_CONTROL_SIZE
0075 );
0076 
0077 const pthread_mutexattr_t _POSIX_Mutex_Default_attributes = {
0078 #if defined(_UNIX98_THREAD_MUTEX_ATTRIBUTES)
0079   .type           = PTHREAD_MUTEX_DEFAULT,
0080 #endif
0081   .is_initialized = true,
0082   .process_shared = PTHREAD_PROCESS_PRIVATE,
0083   .prio_ceiling   = INT_MAX,
0084   .protocol       = PTHREAD_PRIO_NONE,
0085   .recursive      = false
0086 };
0087 
0088 /**
0089  * 11.3.2 Initializing and Destroying a Mutex, P1003.1c/Draft 10, p. 87
0090  *
0091  * NOTE:  XXX Could be optimized so all the attribute error checking
0092  *            is not performed when attr is NULL.
0093  */
0094 
0095 int pthread_mutex_init(
0096   pthread_mutex_t           *mutex,
0097   const pthread_mutexattr_t *attr
0098 )
0099 {
0100   POSIX_Mutex_Control       *the_mutex;
0101   const pthread_mutexattr_t *the_attr;
0102   POSIX_Mutex_Protocol       protocol;
0103   unsigned long              flags;
0104   Priority_Control           priority;
0105   const Scheduler_Control   *scheduler;
0106 
0107   if ( attr ) the_attr = attr;
0108   else        the_attr = &_POSIX_Mutex_Default_attributes;
0109 
0110   /* Check for NULL mutex */
0111   if ( !mutex )
0112     return EINVAL;
0113 
0114   /*
0115    *  The POSIX specification says:
0116    *
0117    *  "Attempting to initialize an already initialized mutex results
0118    *  in undefined behavior."
0119    *
0120    *  Trying to keep the caller from doing the create when *mutex
0121    *  is actually a valid ID causes grief.  All it takes is the wrong
0122    *  value in an uninitialized variable to make this fail.
0123    *
0124    *  Thus, we do not look at *mutex.
0125    */
0126 
0127   if ( !the_attr->is_initialized )
0128     return EINVAL;
0129 
0130   if ( !_POSIX_Is_valid_pshared( the_attr->process_shared ) ) {
0131     return EINVAL;
0132   }
0133 
0134   /*
0135    *  Determine the discipline of the mutex
0136    */
0137   switch ( the_attr->protocol ) {
0138     case PTHREAD_PRIO_NONE:
0139       protocol = POSIX_MUTEX_NO_PROTOCOL;
0140       break;
0141     case PTHREAD_PRIO_INHERIT:
0142       protocol = POSIX_MUTEX_PRIORITY_INHERIT;
0143       break;
0144     case PTHREAD_PRIO_PROTECT:
0145       protocol = POSIX_MUTEX_PRIORITY_CEILING;
0146       break;
0147     default:
0148       return EINVAL;
0149   }
0150 
0151 #if defined(_UNIX98_THREAD_MUTEX_ATTRIBUTES)
0152   /*
0153    *  Validate the mutex type and set appropriate SuperCore mutex
0154    *  attributes.
0155    */
0156   switch ( the_attr->type ) {
0157     case PTHREAD_MUTEX_NORMAL:
0158     case PTHREAD_MUTEX_RECURSIVE:
0159     case PTHREAD_MUTEX_ERRORCHECK:
0160     case PTHREAD_MUTEX_DEFAULT:
0161       break;
0162 
0163     default:
0164       return EINVAL;
0165   }
0166 #endif
0167 
0168   the_mutex = _POSIX_Mutex_Get( mutex );
0169 
0170   flags = (uintptr_t) the_mutex ^ POSIX_MUTEX_MAGIC;
0171   flags &= ~POSIX_MUTEX_FLAGS_MASK;
0172   flags |= protocol;
0173 
0174   if ( the_attr->type == PTHREAD_MUTEX_RECURSIVE ) {
0175     flags |= POSIX_MUTEX_RECURSIVE;
0176   }
0177 
0178   the_mutex->flags = flags;
0179 
0180   if ( protocol == POSIX_MUTEX_PRIORITY_CEILING ) {
0181     int  prio_ceiling;
0182     bool valid;
0183 
0184     scheduler = _Thread_Scheduler_get_home( _Thread_Get_executing() );
0185     prio_ceiling = the_attr->prio_ceiling;
0186 
0187     if ( prio_ceiling == INT_MAX ) {
0188       prio_ceiling = _POSIX_Priority_Get_maximum( scheduler );
0189     }
0190 
0191     priority = _POSIX_Priority_To_core( scheduler, prio_ceiling, &valid );
0192     if ( !valid ) {
0193       return EINVAL;
0194     }
0195   } else {
0196     priority = 0;
0197     scheduler = NULL;
0198   }
0199 
0200   _Thread_queue_Queue_initialize(
0201     &the_mutex->Recursive.Mutex.Queue.Queue,
0202     NULL
0203   );
0204   the_mutex->Recursive.nest_level = 0;
0205   _Priority_Node_initialize( &the_mutex->Priority_ceiling, priority );
0206   the_mutex->scheduler = scheduler;
0207   return 0;
0208 }