summaryrefslogtreecommitdiffstats
path: root/cpukit/score/src/threadqenqueue.c
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2016-08-02 11:26:56 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2016-08-03 13:57:30 +0200
commitff2e6c647d166fa54769f3c300855ef7f8020668 (patch)
tree2fe5ea9069fc561d1344e54e0524950aefd86e21 /cpukit/score/src/threadqenqueue.c
parentposix: Fix for RTEMS_DEBUG (diff)
downloadrtems-ff2e6c647d166fa54769f3c300855ef7f8020668.tar.bz2
score: Fix and simplify thread wait locks
There was a subtile race condition in _Thread_queue_Do_extract_locked(). It must first update the thread wait flags and then restore the default thread wait state. In the previous implementation this could lead under rare timing conditions to an ineffective _Thread_Wait_tranquilize() resulting to a corrupt system state. Update #2556.
Diffstat (limited to 'cpukit/score/src/threadqenqueue.c')
-rw-r--r--cpukit/score/src/threadqenqueue.c44
1 files changed, 24 insertions, 20 deletions
diff --git a/cpukit/score/src/threadqenqueue.c b/cpukit/score/src/threadqenqueue.c
index a9b2c35af5..9ac57d05b4 100644
--- a/cpukit/score/src/threadqenqueue.c
+++ b/cpukit/score/src/threadqenqueue.c
@@ -176,7 +176,7 @@ static void _Thread_queue_Path_release( Thread_queue_Path *path )
link = RTEMS_CONTAINER_OF( node, Thread_queue_Link, Path_node );
- if ( link->Queue_context.Wait.queue_lock != NULL ) {
+ if ( link->Queue_context.Wait.queue != NULL ) {
_Thread_queue_Link_remove( link );
}
@@ -213,8 +213,6 @@ static bool _Thread_queue_Path_acquire(
*/
_Chain_Initialize_empty( &path->Links );
- _Chain_Initialize_node( &path->Start.Path_node );
- _Thread_queue_Context_initialize( &path->Start.Queue_context );
owner = queue->owner;
@@ -226,6 +224,8 @@ static bool _Thread_queue_Path_acquire(
return false;
}
+ _Chain_Initialize_node( &path->Start.Path_node );
+ _Thread_queue_Context_initialize( &path->Start.Queue_context );
link = &path->Start;
do {
@@ -239,34 +239,36 @@ static bool _Thread_queue_Path_acquire(
target = owner->Wait.queue;
link->Queue_context.Wait.queue = target;
- link->Queue_context.Wait.operations = owner->Wait.operations;
if ( target != NULL ) {
if ( _Thread_queue_Link_add( link, queue, target ) ) {
- link->Queue_context.Wait.queue_lock = &target->Lock;
- _Chain_Append_unprotected(
+ _Thread_queue_Gate_add(
&owner->Wait.Lock.Pending_requests,
- &link->Queue_context.Wait.Gate.Node
+ &link->Queue_context.Wait.Gate
);
_Thread_Wait_release_default_critical(
owner,
&link->Queue_context.Lock_context
);
- _Thread_Wait_acquire_queue_critical(
- &target->Lock,
- &link->Queue_context
- );
+ _Thread_Wait_acquire_queue_critical( target, &link->Queue_context );
if ( link->Queue_context.Wait.queue == NULL ) {
+ _Thread_queue_Link_remove( link );
+ _Thread_Wait_release_queue_critical( target, &link->Queue_context );
+ _Thread_Wait_acquire_default_critical(
+ owner,
+ &link->Queue_context.Lock_context
+ );
+ _Thread_Wait_remove_request_locked( owner, &link->Queue_context );
+ _Assert( owner->Wait.queue == NULL );
return true;
}
} else {
- link->Queue_context.Wait.queue_lock = NULL;
+ link->Queue_context.Wait.queue = NULL;
_Thread_queue_Path_release( path );
return false;
}
} else {
- link->Queue_context.Wait.queue_lock = NULL;
return true;
}
@@ -330,6 +332,7 @@ void _Thread_queue_Enqueue_critical(
if ( !_Thread_queue_Path_acquire( the_thread, queue, &path ) ) {
_Thread_Wait_restore_default( the_thread );
_Thread_queue_Queue_release( queue, &queue_context->Lock_context );
+ _Thread_Wait_tranquilize( the_thread );
( *queue_context->deadlock_callout )( the_thread );
return;
}
@@ -504,14 +507,15 @@ void _Thread_queue_Extract_critical(
void _Thread_queue_Extract( Thread_Control *the_thread )
{
- Thread_queue_Context queue_context;
+ Thread_queue_Context queue_context;
+ Thread_queue_Queue *queue;
_Thread_queue_Context_initialize( &queue_context );
_Thread_Wait_acquire( the_thread, &queue_context );
- if (
- _Thread_queue_Context_get_queue( &queue_context, the_thread ) != NULL
- ) {
+ queue = the_thread->Wait.queue;
+
+ if ( queue != NULL ) {
bool unblock;
_Thread_Wait_remove_request( the_thread, &queue_context );
@@ -520,14 +524,14 @@ void _Thread_queue_Extract( Thread_Control *the_thread )
_Thread_queue_MP_callout_do_nothing
);
unblock = _Thread_queue_Extract_locked(
- _Thread_queue_Context_get_queue( &queue_context, the_thread ),
- _Thread_queue_Context_get_operations( &queue_context, the_thread ),
+ queue,
+ the_thread->Wait.operations,
the_thread,
&queue_context.Lock_context
);
_Thread_queue_Unblock_critical(
unblock,
- _Thread_queue_Context_get_queue( &queue_context, the_thread ),
+ queue,
the_thread,
&queue_context.Lock_context
);