int pthread_mutex_unlock( pthread_mutex_t *mutex ) { register POSIX_Mutex_Control *the_mutex; Objects_Locations location; CORE_mutex_Status status; the_mutex = _POSIX_Mutex_Get( mutex, &location ); switch ( location ) { case OBJECTS_LOCAL: status = _CORE_mutex_Surrender( &the_mutex->Mutex, the_mutex->Object.id, NULL ); _Thread_Enable_dispatch(); return _POSIX_Mutex_Translate_core_mutex_return_code( status ); #if defined(RTEMS_MULTIPROCESSING) case OBJECTS_REMOTE: #endif case OBJECTS_ERROR: break; } return EINVAL; }
int pthread_mutex_getprioceiling( pthread_mutex_t *mutex, int *prioceiling ) { register POSIX_Mutex_Control *the_mutex; Objects_Locations location; if ( !prioceiling ) return EINVAL; the_mutex = _POSIX_Mutex_Get( mutex, &location ); switch ( location ) { case OBJECTS_LOCAL: *prioceiling = _POSIX_Priority_From_core( the_mutex->Mutex.Attributes.priority_ceiling ); _Thread_Enable_dispatch(); return 0; #if defined(RTEMS_MULTIPROCESSING) case OBJECTS_REMOTE: #endif case OBJECTS_ERROR: break; } return EINVAL; }
int pthread_mutex_setprioceiling( pthread_mutex_t *mutex, int prioceiling, int *old_ceiling ) { register POSIX_Mutex_Control *the_mutex; Objects_Locations location; Priority_Control the_priority; int status; if ( !old_ceiling ) return EINVAL; if ( !_POSIX_Priority_Is_valid( prioceiling ) ) return EINVAL; the_priority = _POSIX_Priority_To_core( prioceiling ); /* * Must acquire the mutex before we can change it's ceiling */ status = pthread_mutex_lock( mutex ); if ( status ) return status; the_mutex = _POSIX_Mutex_Get( mutex, &location ); switch ( location ) { case OBJECTS_REMOTE: #if defined(RTEMS_MULTIPROCESSING) /* XXX It feels questionable to set the ceiling on a remote mutex. */ return EINVAL; #endif case OBJECTS_ERROR: return EINVAL; /* impossible to get here */ case OBJECTS_LOCAL: *old_ceiling = _POSIX_Priority_From_core( the_mutex->Mutex.Attributes.priority_ceiling ); the_mutex->Mutex.Attributes.priority_ceiling = the_priority; _CORE_mutex_Surrender( &the_mutex->Mutex, the_mutex->Object.id, #if defined(RTEMS_MULTIPROCESSING) _POSIX_Threads_mutex_MP_support #else NULL #endif ); _Thread_Enable_dispatch(); return 0; } return POSIX_BOTTOM_REACHED(); }
int _POSIX_Mutex_Lock_support( pthread_mutex_t *mutex, bool wait, Watchdog_Interval timeout ) { POSIX_Mutex_Control *the_mutex; Thread_queue_Context queue_context; Thread_Control *executing; Status_Control status; the_mutex = _POSIX_Mutex_Get( mutex, &queue_context ); if ( the_mutex == NULL ) { return EINVAL; } executing = _Thread_Executing; _Thread_queue_Context_set_relative_timeout( &queue_context, timeout ); switch ( the_mutex->protocol ) { case POSIX_MUTEX_PRIORITY_CEILING: status = _CORE_ceiling_mutex_Seize( &the_mutex->Mutex, executing, wait, _POSIX_Mutex_Lock_nested, &queue_context ); break; case POSIX_MUTEX_NO_PROTOCOL: status = _CORE_recursive_mutex_Seize( &the_mutex->Mutex.Recursive, POSIX_MUTEX_NO_PROTOCOL_TQ_OPERATIONS, executing, wait, _POSIX_Mutex_Lock_nested, &queue_context ); break; default: _Assert( the_mutex->protocol == POSIX_MUTEX_PRIORITY_INHERIT ); status = _CORE_recursive_mutex_Seize( &the_mutex->Mutex.Recursive, CORE_MUTEX_TQ_PRIORITY_INHERIT_OPERATIONS, executing, wait, _POSIX_Mutex_Lock_nested, &queue_context ); break; } return _POSIX_Get_error( status ); }
int pthread_mutex_destroy( pthread_mutex_t *mutex ) { register POSIX_Mutex_Control *the_mutex; Objects_Locations location; the_mutex = _POSIX_Mutex_Get( mutex, &location ); switch ( location ) { case OBJECTS_LOCAL: /* * XXX: There is an error for the mutex being locked * or being in use by a condition variable. */ if ( _CORE_mutex_Is_locked( &the_mutex->Mutex ) ) { _Thread_Enable_dispatch(); return EBUSY; } _Objects_Close( &_POSIX_Mutex_Information, &the_mutex->Object ); _CORE_mutex_Flush( &the_mutex->Mutex, NULL, EINVAL ); _POSIX_Mutex_Free( the_mutex ); _Thread_Enable_dispatch(); return 0; #if defined(RTEMS_MULTIPROCESSING) case OBJECTS_REMOTE: #endif case OBJECTS_ERROR: break; } return EINVAL; }
int _POSIX_Condition_variables_Wait_support( pthread_cond_t *cond, pthread_mutex_t *mutex, Watchdog_Interval timeout, bool already_timedout ) { POSIX_Condition_variables_Control *the_cond; POSIX_Mutex_Control *the_mutex; Objects_Locations location; int status; int mutex_status; Thread_Control *executing; the_mutex = _POSIX_Mutex_Get( mutex, &location ); if ( !the_mutex ) { return EINVAL; } _Objects_Put_without_thread_dispatch( &the_mutex->Object ); the_cond = _POSIX_Condition_variables_Get( cond, &location ); switch ( location ) { case OBJECTS_LOCAL: if ( the_cond->Mutex && ( the_cond->Mutex != *mutex ) ) { _Objects_Put( &the_cond->Object ); return EINVAL; } mutex_status = pthread_mutex_unlock( mutex ); /* * Historically, we ignored the return code since the behavior * is undefined by POSIX. But GNU/Linux returns EPERM in this * case, so we follow their lead. */ if ( mutex_status ) { _Objects_Put( &the_cond->Object ); return EPERM; } if ( !already_timedout ) { the_cond->Mutex = *mutex; executing = _Thread_Executing; executing->Wait.return_code = 0; executing->Wait.id = *cond; _Thread_queue_Enqueue( &the_cond->Wait_queue, executing, STATES_WAITING_FOR_CONDITION_VARIABLE | STATES_INTERRUPTIBLE_BY_SIGNAL, timeout, ETIMEDOUT ); _Objects_Put( &the_cond->Object ); /* * Switch ourself out because we blocked as a result of the * _Thread_queue_Enqueue. */ /* * If the thread is interrupted, while in the thread queue, by * a POSIX signal, then pthread_cond_wait returns spuriously, * according to the POSIX standard. It means that pthread_cond_wait * returns a success status, except for the fact that it was not * woken up a pthread_cond_signal or a pthread_cond_broadcast. */ status = executing->Wait.return_code; if ( status == EINTR ) status = 0; } else { _Objects_Put( &the_cond->Object ); status = ETIMEDOUT; } /* * When we get here the dispatch disable level is 0. */ mutex_status = pthread_mutex_lock( mutex ); if ( mutex_status ) return EINVAL; return status; #if defined(RTEMS_MULTIPROCESSING) case OBJECTS_REMOTE: #endif case OBJECTS_ERROR: break; } return EINVAL; }
int _POSIX_Condition_variables_Wait_support( pthread_cond_t *cond, pthread_mutex_t *mutex, Watchdog_Interval timeout, bool already_timedout ) { register POSIX_Condition_variables_Control *the_cond; Objects_Locations location; int status; int mutex_status; if ( !_POSIX_Mutex_Get( mutex, &location ) ) { return EINVAL; } _Thread_Unnest_dispatch(); the_cond = _POSIX_Condition_variables_Get( cond, &location ); switch ( location ) { case OBJECTS_LOCAL: if ( the_cond->Mutex && ( the_cond->Mutex != *mutex ) ) { _Thread_Enable_dispatch(); return EINVAL; } (void) pthread_mutex_unlock( mutex ); /* XXX ignore this for now since behavior is undefined if ( mutex_status ) { _Thread_Enable_dispatch(); return EINVAL; } */ if ( !already_timedout ) { the_cond->Mutex = *mutex; _Thread_queue_Enter_critical_section( &the_cond->Wait_queue ); _Thread_Executing->Wait.return_code = 0; _Thread_Executing->Wait.queue = &the_cond->Wait_queue; _Thread_Executing->Wait.id = *cond; _Thread_queue_Enqueue( &the_cond->Wait_queue, timeout ); _Thread_Enable_dispatch(); /* * Switch ourself out because we blocked as a result of the * _Thread_queue_Enqueue. */ /* * If the thread is interrupted, while in the thread queue, by * a POSIX signal, then pthread_cond_wait returns spuriously, * according to the POSIX standard. It means that pthread_cond_wait * returns a success status, except for the fact that it was not * woken up a pthread_cond_signal or a pthread_cond_broadcast. */ status = _Thread_Executing->Wait.return_code; if ( status == EINTR ) status = 0; } else { _Thread_Enable_dispatch(); status = ETIMEDOUT; } /* * When we get here the dispatch disable level is 0. */ mutex_status = pthread_mutex_lock( mutex ); if ( mutex_status ) return EINVAL; return status; #if defined(RTEMS_MULTIPROCESSING) case OBJECTS_REMOTE: #endif case OBJECTS_ERROR: break; } return EINVAL; }
int pthread_mutex_init( pthread_mutex_t *mutex, const pthread_mutexattr_t *attr ) { POSIX_Mutex_Control *the_mutex; CORE_mutex_Attributes *the_mutex_attr; const pthread_mutexattr_t *the_attr; CORE_mutex_Disciplines the_discipline; if ( attr ) the_attr = attr; else the_attr = &_POSIX_Mutex_Default_attributes; /* Check for NULL mutex */ if ( !mutex ) return EINVAL; /* * This code should eventually be removed. * * Although the POSIX specification says: * * "Attempting to initialize an already initialized mutex results * in undefined behavior." * * Trying to keep the caller from doing the create when *mutex * is actually a valid ID causes grief. All it takes is the wrong * value in an uninitialized variable to make this fail. As best * I can tell, RTEMS was the only pthread implementation to choose * this option for "undefined behavior" and doing so has created * portability problems. In particular, Rosimildo DaSilva * <*****@*****.**> saw seemingly random failures in the * RTEMS port of omniORB2 when this code was enabled. * * Joel Sherrill <*****@*****.**> 14 May 1999 * NOTE: Be careful to avoid infinite recursion on call to this * routine in _POSIX_Mutex_Get. */ #if 0 { POSIX_Mutex_Control *mutex_in_use; Objects_Locations location; if ( *mutex != PTHREAD_MUTEX_INITIALIZER ) { /* EBUSY if *mutex is a valid id */ mutex_in_use = _POSIX_Mutex_Get( mutex, &location ); switch ( location ) { case OBJECTS_LOCAL: _Objects_Put( &mutex_in_use->Object ); return EBUSY; #if defined(RTEMS_MULTIPROCESSING) case OBJECTS_REMOTE: #endif case OBJECTS_ERROR: break; } } } #endif if ( !the_attr->is_initialized ) return EINVAL; /* * We only support process private mutexes. */ if ( the_attr->process_shared == PTHREAD_PROCESS_SHARED ) return ENOSYS; if ( the_attr->process_shared != PTHREAD_PROCESS_PRIVATE ) return EINVAL; /* * Determine the discipline of the mutex */ switch ( the_attr->protocol ) { case PTHREAD_PRIO_NONE: the_discipline = CORE_MUTEX_DISCIPLINES_FIFO; break; case PTHREAD_PRIO_INHERIT: the_discipline = CORE_MUTEX_DISCIPLINES_PRIORITY_INHERIT; break; case PTHREAD_PRIO_PROTECT: the_discipline = CORE_MUTEX_DISCIPLINES_PRIORITY_CEILING; break; default: return EINVAL; } /* * Validate the priority ceiling field -- should always be valid. */ if ( !_POSIX_Priority_Is_valid( the_attr->prio_ceiling ) ) return EINVAL; #if defined(_UNIX98_THREAD_MUTEX_ATTRIBUTES) /* * Validate the mutex type and set appropriate SuperCore mutex * attributes. */ switch ( the_attr->type ) { case PTHREAD_MUTEX_NORMAL: case PTHREAD_MUTEX_RECURSIVE: case PTHREAD_MUTEX_ERRORCHECK: case PTHREAD_MUTEX_DEFAULT: break; default: return EINVAL; } #endif the_mutex = _POSIX_Mutex_Allocate(); if ( !the_mutex ) { _Objects_Allocator_unlock(); return EAGAIN; } the_mutex->process_shared = the_attr->process_shared; the_mutex_attr = &the_mutex->Mutex.Attributes; if ( the_attr->type == PTHREAD_MUTEX_RECURSIVE ) the_mutex_attr->lock_nesting_behavior = CORE_MUTEX_NESTING_ACQUIRES; else the_mutex_attr->lock_nesting_behavior = CORE_MUTEX_NESTING_IS_ERROR; the_mutex_attr->only_owner_release = true; the_mutex_attr->priority_ceiling = _POSIX_Priority_To_core( the_attr->prio_ceiling ); the_mutex_attr->discipline = the_discipline; /* * Must be initialized to unlocked. */ _CORE_mutex_Initialize( &the_mutex->Mutex, NULL, the_mutex_attr, false ); _Objects_Open_u32( &_POSIX_Mutex_Information, &the_mutex->Object, 0 ); *mutex = the_mutex->Object.id; _Objects_Allocator_unlock(); return 0; }
int pthread_mutex_setprioceiling( pthread_mutex_t *mutex, int prioceiling, int *old_ceiling ) { register POSIX_Mutex_Control *the_mutex; Objects_Locations location; Priority_Control the_priority; if ( !old_ceiling ) return EINVAL; if ( !_POSIX_Priority_Is_valid( prioceiling ) ) return EINVAL; the_priority = _POSIX_Priority_To_core( prioceiling ); /* * Must acquire the mutex before we can change it's ceiling. * POSIX says block until we acquire it. */ (void) pthread_mutex_lock( mutex ); /* * Do not worry about the return code from this. The Get operation * will also fail if it is a bad id or was deleted between the two * operations. * * NOTE: This makes it easier to get 100% binary coverage since the * bad Id case is handled by the switch. */ the_mutex = _POSIX_Mutex_Get( mutex, &location ); switch ( location ) { case OBJECTS_LOCAL: *old_ceiling = _POSIX_Priority_From_core( the_mutex->Mutex.Attributes.priority_ceiling ); the_mutex->Mutex.Attributes.priority_ceiling = the_priority; /* * We are required to unlock the mutex before we return. */ _CORE_mutex_Surrender( &the_mutex->Mutex, the_mutex->Object.id, NULL ); _Thread_Enable_dispatch(); return 0; #if defined(RTEMS_MULTIPROCESSING) case OBJECTS_REMOTE: /* impossible to get here */ #endif case OBJECTS_ERROR: break; } return EINVAL; }