summaryrefslogtreecommitdiffstats
path: root/cpukit/posix/src
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2016-11-16 16:39:43 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2016-11-23 12:52:06 +0100
commit125f248231c173a038ed9fc00832e0b3d221ad43 (patch)
tree3894553badc7582b0c460aec4d34955f23ea3e81 /cpukit/posix/src
parentscore: Robust thread dispatch (diff)
downloadrtems-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 'cpukit/posix/src')
-rw-r--r--cpukit/posix/src/condwaitsupp.c75
-rw-r--r--cpukit/posix/src/nanosleep.c31
-rw-r--r--cpukit/posix/src/pthreadjoin.c2
-rw-r--r--cpukit/posix/src/sigtimedwait.c2
4 files changed, 65 insertions, 45 deletions
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,