diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2016-11-16 16:39:43 +0100 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2016-11-23 12:52:06 +0100 |
commit | 125f248231c173a038ed9fc00832e0b3d221ad43 (patch) | |
tree | 3894553badc7582b0c460aec4d34955f23ea3e81 /cpukit/posix | |
parent | score: Robust thread dispatch (diff) | |
download | rtems-125f248231c173a038ed9fc00832e0b3d221ad43.tar.bz2 |
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.
Diffstat (limited to '')
-rw-r--r-- | cpukit/posix/include/rtems/posix/condimpl.h | 4 | ||||
-rw-r--r-- | cpukit/posix/src/condwaitsupp.c | 75 | ||||
-rw-r--r-- | cpukit/posix/src/nanosleep.c | 31 | ||||
-rw-r--r-- | cpukit/posix/src/pthreadjoin.c | 2 | ||||
-rw-r--r-- | cpukit/posix/src/sigtimedwait.c | 2 |
5 files changed, 69 insertions, 45 deletions
diff --git a/cpukit/posix/include/rtems/posix/condimpl.h b/cpukit/posix/include/rtems/posix/condimpl.h index 2ae0a6adf5..f508519c2f 100644 --- a/cpukit/posix/include/rtems/posix/condimpl.h +++ b/cpukit/posix/include/rtems/posix/condimpl.h @@ -35,6 +35,10 @@ extern "C" { #define POSIX_CONDITION_VARIABLES_TQ_OPERATIONS &_Thread_queue_Operations_FIFO +#define POSIX_CONDITION_VARIABLE_OF_THREAD_QUEUE_QUEUE( queue ) \ + RTEMS_CONTAINER_OF( \ + queue, POSIX_Condition_variables_Control, Wait_queue.Queue ) + /** * The following defines the information control block used to manage * this class of objects. 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,34 +128,19 @@ 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, * according to the POSIX standard. It means that pthread_cond_wait @@ -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; diff --git a/cpukit/posix/src/nanosleep.c b/cpukit/posix/src/nanosleep.c index 0fec1e48e1..8addc87c59 100644 --- a/cpukit/posix/src/nanosleep.c +++ b/cpukit/posix/src/nanosleep.c @@ -40,23 +40,34 @@ static inline int nanosleep_helper( Watchdog_Discipline discipline ) { - Thread_Control *executing; - struct timespec stop; - int err = 0; + Thread_queue_Context queue_context; + struct timespec stop; + int err; - executing = _Thread_Get_executing(); + err = 0; + + _Thread_queue_Context_initialize( &queue_context ); + _Thread_queue_Context_set_enqueue_callout( + &queue_context, + _Thread_queue_Enqueue_do_nothing + ); + + if ( discipline == WATCHDOG_ABSOLUTE ) { + _Thread_queue_Context_set_absolute_timeout( &queue_context, ticks ); + } else { + _Thread_queue_Context_set_relative_timeout( &queue_context, ticks ); + } /* * Block for the desired amount of time */ - _Thread_queue_Enqueue( - &_Nanosleep_Pseudo_queue, + _Thread_queue_Acquire( &_Nanosleep_Pseudo_queue, &queue_context ); + _Thread_queue_Enqueue_critical( + &_Nanosleep_Pseudo_queue.Queue, &_Thread_queue_Operations_FIFO, - executing, + _Thread_Executing, STATES_DELAYING | STATES_INTERRUPTIBLE_BY_SIGNAL, - ticks, - discipline, - 1 + &queue_context ); clock_gettime( clock_id, &stop ); diff --git a/cpukit/posix/src/pthreadjoin.c b/cpukit/posix/src/pthreadjoin.c index 5ed01185f1..12f49e55d8 100644 --- a/cpukit/posix/src/pthreadjoin.c +++ b/cpukit/posix/src/pthreadjoin.c @@ -39,7 +39,7 @@ static int _POSIX_Threads_Join( pthread_t thread, void **value_ptr ) void *value; _Thread_queue_Context_initialize( &queue_context ); - _Thread_queue_Context_set_expected_level( &queue_context, 1 ); + _Thread_queue_Context_set_do_nothing_enqueue_callout( &queue_context ); _Thread_queue_Context_set_no_timeout( &queue_context ); the_thread = _Thread_Get( thread, &queue_context.Lock_context.Lock_context ); diff --git a/cpukit/posix/src/sigtimedwait.c b/cpukit/posix/src/sigtimedwait.c index b85d48e909..7853dc007a 100644 --- a/cpukit/posix/src/sigtimedwait.c +++ b/cpukit/posix/src/sigtimedwait.c @@ -156,7 +156,7 @@ int sigtimedwait( executing->Wait.option = *set; executing->Wait.return_argument = the_info; - _Thread_queue_Context_set_expected_level( &queue_context, 1 ); + _Thread_queue_Context_set_do_nothing_enqueue_callout( &queue_context ); _Thread_queue_Enqueue_critical( &_POSIX_signals_Wait_queue.Queue, POSIX_SIGNALS_TQ_OPERATIONS, |