int _POSIX_Condition_variables_Signal_support( pthread_cond_t *cond, bool is_broadcast ) { register POSIX_Condition_variables_Control *the_cond; Objects_Locations location; Thread_Control *the_thread; the_cond = _POSIX_Condition_variables_Get( cond, &location ); switch ( location ) { case OBJECTS_LOCAL: do { the_thread = _Thread_queue_Dequeue( &the_cond->Wait_queue ); if ( !the_thread ) the_cond->Mutex = POSIX_CONDITION_VARIABLES_NO_MUTEX; } while ( is_broadcast && the_thread ); _Thread_Enable_dispatch(); return 0; #if defined(RTEMS_MULTIPROCESSING) case OBJECTS_REMOTE: #endif case OBJECTS_ERROR: break; } return EINVAL; }
/** * 11.4.2 Initializing and Destroying a Condition Variable, * P1003.1c/Draft 10, p. 87 */ int pthread_cond_destroy( pthread_cond_t *cond ) { POSIX_Condition_variables_Control *the_cond; Objects_Locations location; the_cond = _POSIX_Condition_variables_Get( cond, &location ); switch ( location ) { case OBJECTS_LOCAL: if ( _Thread_queue_First( &the_cond->Wait_queue ) ) { _Thread_Enable_dispatch(); return EBUSY; } _Objects_Close( &_POSIX_Condition_variables_Information, &the_cond->Object ); _POSIX_Condition_variables_Free( the_cond ); _Thread_Enable_dispatch(); return 0; #if defined(RTEMS_MULTIPROCESSING) case OBJECTS_REMOTE: #endif case OBJECTS_ERROR: break; } return EINVAL; }
/** * 11.4.2 Initializing and Destroying a Condition Variable, * P1003.1c/Draft 10, p. 87 */ int pthread_cond_destroy( pthread_cond_t *cond ) { POSIX_Condition_variables_Control *the_cond; Objects_Locations location; _Objects_Allocator_lock(); the_cond = _POSIX_Condition_variables_Get( cond, &location ); switch ( location ) { case OBJECTS_LOCAL: if ( _Thread_queue_First( &the_cond->Wait_queue, POSIX_CONDITION_VARIABLES_TQ_OPERATIONS ) ) { _Objects_Put( &the_cond->Object ); _Objects_Allocator_unlock(); return EBUSY; } _Objects_Close( &_POSIX_Condition_variables_Information, &the_cond->Object ); _Objects_Put( &the_cond->Object ); _POSIX_Condition_variables_Free( the_cond ); _Objects_Allocator_unlock(); return 0; #if defined(RTEMS_MULTIPROCESSING) case OBJECTS_REMOTE: #endif case OBJECTS_ERROR: break; } _Objects_Allocator_unlock(); return EINVAL; }
int _POSIX_Condition_variables_Wait_support( pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime ) { POSIX_Condition_variables_Control *the_cond; Thread_queue_Context queue_context; int error; int mutex_error; Per_CPU_Control *cpu_self; Thread_Control *executing; Watchdog_Interval timeout; bool already_timedout; TOD_Absolute_timeout_conversion_results status; if ( mutex == NULL ) { return EINVAL; } the_cond = _POSIX_Condition_variables_Get( cond, &queue_context ); if ( the_cond == NULL ) { return EINVAL; } already_timedout = false; if ( abstime != NULL ) { /* * POSIX requires that blocking calls with timeouts that take * an absolute timeout must ignore issues with the absolute * time provided if the operation would otherwise succeed. * So we check the abstime provided, and hold on to whether it * is valid or not. If it isn't correct and in the future, * then we do a polling operation and convert the UNSATISFIED * status into the appropriate error. */ _Assert( the_cond->clock ); status = _TOD_Absolute_timeout_to_ticks(abstime, the_cond->clock, &timeout); if ( status == TOD_ABSOLUTE_TIMEOUT_INVALID ) return EINVAL; if ( status == TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST || status == TOD_ABSOLUTE_TIMEOUT_IS_NOW ) { already_timedout = true; } else { _Thread_queue_Context_set_relative_timeout( &queue_context, timeout ); } } else { _Thread_queue_Context_set_no_timeout( &queue_context ); } _POSIX_Condition_variables_Acquire_critical( the_cond, &queue_context ); if ( the_cond->mutex != POSIX_CONDITION_VARIABLES_NO_MUTEX && the_cond->mutex != *mutex ) { _POSIX_Condition_variables_Release( the_cond, &queue_context ); return EINVAL; } the_cond->mutex = *mutex; cpu_self = _Thread_Dispatch_disable_critical( &queue_context.Lock_context ); executing = _Per_CPU_Get_executing( cpu_self ); if ( !already_timedout ) { _Thread_queue_Context_set_expected_level( &queue_context, 2 ); _Thread_queue_Enqueue_critical( &the_cond->Wait_queue.Queue, POSIX_CONDITION_VARIABLES_TQ_OPERATIONS, executing, STATES_WAITING_FOR_CONDITION_VARIABLE, &queue_context ); } else { _POSIX_Condition_variables_Release( the_cond, &queue_context ); executing->Wait.return_code = STATUS_TIMEOUT; } mutex_error = pthread_mutex_unlock( mutex ); if ( mutex_error != 0 ) { /* * Historically, we ignored the unlock status since the behavior * is undefined by POSIX. But GNU/Linux returns EPERM in this * case, so we follow their lead. */ _Assert( mutex_error == EINVAL || mutex_error == EPERM ); _Thread_queue_Extract( executing ); _Thread_Dispatch_enable( cpu_self ); return EPERM; } /* * Switch ourself out because we blocked as a result of the * _Thread_queue_Enqueue_critical(). */ _Thread_Dispatch_enable( cpu_self ); error = _POSIX_Get_error_after_wait( executing ); /* * 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(). */ if ( error == EINTR ) { error = 0; } /* * When we get here the dispatch disable level is 0. */ mutex_error = pthread_mutex_lock( mutex ); if ( mutex_error != 0 ) { _Assert( mutex_error == EINVAL ); return EINVAL; } return error; }
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; }