From 125f248231c173a038ed9fc00832e0b3d221ad43 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Wed, 16 Nov 2016 16:39:43 +0100 Subject: score: Add thread queue enqueue callout Replace the expected thread dispatch disable level with a thread queue enqueue callout. This enables the use of _Thread_Dispatch_direct() in the thread queue enqueue procedure. This avoids impossible exection paths, e.g. Per_CPU_Control::dispatch_necessary is always true. --- cpukit/posix/src/condwaitsupp.c | 75 +++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 33 deletions(-) (limited to 'cpukit/posix/src/condwaitsupp.c') diff --git a/cpukit/posix/src/condwaitsupp.c b/cpukit/posix/src/condwaitsupp.c index 52367f6364..49352382db 100644 --- a/cpukit/posix/src/condwaitsupp.c +++ b/cpukit/posix/src/condwaitsupp.c @@ -27,6 +27,30 @@ THREAD_QUEUE_OBJECT_ASSERT( POSIX_Condition_variables_Control, Wait_queue ); +static void _POSIX_Condition_variables_Enqueue_callout( + Thread_queue_Queue *queue, + Thread_Control *the_thread, + Thread_queue_Context *queue_context +) +{ + POSIX_Condition_variables_Control *the_cond; + int mutex_error; + + the_cond = POSIX_CONDITION_VARIABLE_OF_THREAD_QUEUE_QUEUE( queue ); + + mutex_error = pthread_mutex_unlock( &the_cond->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( the_thread ); + the_thread->Wait.return_code= STATUS_NOT_OWNER; + } +} + int _POSIX_Condition_variables_Wait_support( pthread_cond_t *cond, pthread_mutex_t *mutex, @@ -37,7 +61,6 @@ int _POSIX_Condition_variables_Wait_support( Thread_queue_Context queue_context; int error; int mutex_error; - Per_CPU_Control *cpu_self; Thread_Control *executing; Watchdog_Interval timeout; bool already_timedout; @@ -91,14 +114,13 @@ int _POSIX_Condition_variables_Wait_support( } the_cond->mutex = *mutex; - - cpu_self = _Thread_Dispatch_disable_critical( - &queue_context.Lock_context.Lock_context - ); - executing = _Per_CPU_Get_executing( cpu_self ); + executing = _Thread_Executing; if ( !already_timedout ) { - _Thread_queue_Context_set_expected_level( &queue_context, 2 ); + _Thread_queue_Context_set_enqueue_callout( + &queue_context, + _POSIX_Condition_variables_Enqueue_callout + ); _Thread_queue_Enqueue_critical( &the_cond->Wait_queue.Queue, POSIX_CONDITION_VARIABLES_TQ_OPERATIONS, @@ -106,33 +128,18 @@ int _POSIX_Condition_variables_Wait_support( STATES_WAITING_FOR_CONDITION_VARIABLE, &queue_context ); + error = _POSIX_Get_error_after_wait( executing ); } 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; + mutex_error = pthread_mutex_unlock( &the_cond->mutex ); + if ( mutex_error != 0 ) { + error = EPERM; + } else { + error = ETIMEDOUT; + } } - /* - * 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, @@ -149,10 +156,12 @@ int _POSIX_Condition_variables_Wait_support( * 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; + if ( error != EPERM ) { + mutex_error = pthread_mutex_lock( mutex ); + if ( mutex_error != 0 ) { + _Assert( mutex_error == EINVAL ); + error = EINVAL; + } } return error; -- cgit v1.2.3