forked from Imagelibrary/rtems
score: Add Thread_queue_Deadlock_status
Replace the boolen return value with the new enum Thread_queue_Deadlock_status. This improves the code readability. Improve documentation. Shorten function names.
This commit is contained in:
@@ -1339,28 +1339,56 @@ void _Thread_queue_Unblock_proxy(
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Acquires the thread queue path in a critical section.
|
* @brief This is a status code to indicate if a deadlock was detected or not.
|
||||||
*
|
|
||||||
* @param queue The thread queue queue.
|
|
||||||
* @param the_thread The thread for the operation.
|
|
||||||
* @param queue_context The thread queue context.
|
|
||||||
*
|
|
||||||
* @retval true The operation was successful.
|
|
||||||
* @retval false The operation failed.
|
|
||||||
*/
|
*/
|
||||||
|
typedef enum {
|
||||||
|
/**
|
||||||
|
* @brief The operation did not detect a deadlock.
|
||||||
|
*/
|
||||||
|
THREAD_QUEUE_NO_DEADLOCK,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The operation detected a deadlock.
|
||||||
|
*/
|
||||||
|
THREAD_QUEUE_DEADLOCK_DETECTED
|
||||||
|
} Thread_queue_Deadlock_status;
|
||||||
|
|
||||||
#if defined(RTEMS_SMP)
|
#if defined(RTEMS_SMP)
|
||||||
bool _Thread_queue_Path_acquire_critical(
|
/**
|
||||||
|
* @brief Acquires the thread queue path.
|
||||||
|
*
|
||||||
|
* The caller must own the thread queue lock.
|
||||||
|
*
|
||||||
|
* An acquired thread queue path must be released by calling
|
||||||
|
* _Thread_queue_Path_release() with the same thread queue context.
|
||||||
|
*
|
||||||
|
* @param queue is the thread queue queue.
|
||||||
|
*
|
||||||
|
* @param the_thread is the thread for the operation.
|
||||||
|
*
|
||||||
|
* @param queue_context is the thread queue context.
|
||||||
|
*
|
||||||
|
* @retval THREAD_QUEUE_NO_DEADLOCK No deadlock was detected.
|
||||||
|
*
|
||||||
|
* @retval THREAD_QUEUE_DEADLOCK_DETECTED A deadlock was detected while
|
||||||
|
* acquiring the thread queue path. The thread queue path must still be
|
||||||
|
* released by _Thread_queue_Path_release() in this case.
|
||||||
|
*/
|
||||||
|
Thread_queue_Deadlock_status _Thread_queue_Path_acquire(
|
||||||
Thread_queue_Queue *queue,
|
Thread_queue_Queue *queue,
|
||||||
Thread_Control *the_thread,
|
Thread_Control *the_thread,
|
||||||
Thread_queue_Context *queue_context
|
Thread_queue_Context *queue_context
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Releases the thread queue path in a critical section.
|
* @brief Releases the thread queue path.
|
||||||
*
|
*
|
||||||
* @param queue_context The thread queue context.
|
* The caller must have acquired the thread queue path with a corresponding
|
||||||
|
* _Thread_queue_Path_acquire().
|
||||||
|
*
|
||||||
|
* @param queue_context is the thread queue context.
|
||||||
*/
|
*/
|
||||||
void _Thread_queue_Path_release_critical(
|
void _Thread_queue_Path_release(
|
||||||
Thread_queue_Context *queue_context
|
Thread_queue_Context *queue_context
|
||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -278,11 +278,11 @@ static void _Thread_Priority_apply(
|
|||||||
|
|
||||||
if ( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) {
|
if ( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) {
|
||||||
#if defined(RTEMS_SMP)
|
#if defined(RTEMS_SMP)
|
||||||
_Thread_queue_Path_acquire_critical( queue, the_thread, queue_context );
|
(void) _Thread_queue_Path_acquire( queue, the_thread, queue_context );
|
||||||
#endif
|
#endif
|
||||||
_Thread_Priority_perform_actions( queue->owner, queue_context );
|
_Thread_Priority_perform_actions( queue->owner, queue_context );
|
||||||
#if defined(RTEMS_SMP)
|
#if defined(RTEMS_SMP)
|
||||||
_Thread_queue_Path_release_critical( queue_context );
|
_Thread_queue_Path_release( queue_context );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,10 +8,9 @@
|
|||||||
* _Thread_queue_Do_dequeue(), _Thread_queue_Enqueue(),
|
* _Thread_queue_Do_dequeue(), _Thread_queue_Enqueue(),
|
||||||
* _Thread_queue_Enqueue_do_nothing_extra(), _Thread_queue_Enqueue_sticky(),
|
* _Thread_queue_Enqueue_do_nothing_extra(), _Thread_queue_Enqueue_sticky(),
|
||||||
* _Thread_queue_Extract(), _Thread_queue_Extract_locked(),
|
* _Thread_queue_Extract(), _Thread_queue_Extract_locked(),
|
||||||
* _Thread_queue_Path_acquire_critical(),
|
* _Thread_queue_Path_acquire(), _Thread_queue_Path_release(),
|
||||||
* _Thread_queue_Path_release_critical(),
|
|
||||||
* _Thread_queue_Resume(),_Thread_queue_Surrender(),
|
* _Thread_queue_Resume(),_Thread_queue_Surrender(),
|
||||||
* _Thread_queue_Surrender_sticky().
|
* _Thread_queue_Surrender_no_priority(), _Thread_queue_Surrender_sticky().
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -113,7 +112,7 @@ static Thread_queue_Link *_Thread_queue_Link_find(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _Thread_queue_Link_add(
|
static Thread_queue_Deadlock_status _Thread_queue_Link_add(
|
||||||
Thread_queue_Link *link,
|
Thread_queue_Link *link,
|
||||||
Thread_queue_Queue *source,
|
Thread_queue_Queue *source,
|
||||||
Thread_queue_Queue *target
|
Thread_queue_Queue *target
|
||||||
@@ -144,7 +143,7 @@ static bool _Thread_queue_Link_add(
|
|||||||
|
|
||||||
if ( recursive_target == source ) {
|
if ( recursive_target == source ) {
|
||||||
_ISR_lock_Release( &links->Lock, &lock_context );
|
_ISR_lock_Release( &links->Lock, &lock_context );
|
||||||
return false;
|
return THREAD_QUEUE_DEADLOCK_DETECTED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,7 +155,7 @@ static bool _Thread_queue_Link_add(
|
|||||||
);
|
);
|
||||||
|
|
||||||
_ISR_lock_Release( &links->Lock, &lock_context );
|
_ISR_lock_Release( &links->Lock, &lock_context );
|
||||||
return true;
|
return THREAD_QUEUE_NO_DEADLOCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _Thread_queue_Link_remove( Thread_queue_Link *link )
|
static void _Thread_queue_Link_remove( Thread_queue_Link *link )
|
||||||
@@ -175,9 +174,7 @@ static void _Thread_queue_Link_remove( Thread_queue_Link *link )
|
|||||||
#if !defined(RTEMS_SMP)
|
#if !defined(RTEMS_SMP)
|
||||||
static
|
static
|
||||||
#endif
|
#endif
|
||||||
void _Thread_queue_Path_release_critical(
|
void _Thread_queue_Path_release( Thread_queue_Context *queue_context )
|
||||||
Thread_queue_Context *queue_context
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
#if defined(RTEMS_SMP)
|
#if defined(RTEMS_SMP)
|
||||||
Chain_Node *head;
|
Chain_Node *head;
|
||||||
@@ -260,7 +257,7 @@ static void _Thread_queue_Path_append_deadlock_thread(
|
|||||||
#if !defined(RTEMS_SMP)
|
#if !defined(RTEMS_SMP)
|
||||||
static
|
static
|
||||||
#endif
|
#endif
|
||||||
bool _Thread_queue_Path_acquire_critical(
|
Thread_queue_Deadlock_status _Thread_queue_Path_acquire(
|
||||||
Thread_queue_Queue *queue,
|
Thread_queue_Queue *queue,
|
||||||
Thread_Control *the_thread,
|
Thread_Control *the_thread,
|
||||||
Thread_queue_Context *queue_context
|
Thread_queue_Context *queue_context
|
||||||
@@ -272,11 +269,12 @@ bool _Thread_queue_Path_acquire_critical(
|
|||||||
Thread_queue_Queue *target;
|
Thread_queue_Queue *target;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For an overview please look at the non-SMP part below. We basically do
|
* For an overview please look at the non-SMP part below. In SMP
|
||||||
* the same on SMP configurations. The fact that we may have more than one
|
* configurations, we basically do the same. The fact that we may have more
|
||||||
* executing thread and each thread queue has its own SMP lock makes the task
|
* than one executing thread and each thread queue has its own SMP lock makes
|
||||||
* a bit more difficult. We have to avoid deadlocks at SMP lock level, since
|
* the procedure a bit more difficult. We have to avoid deadlocks at SMP
|
||||||
* this would result in an unrecoverable deadlock of the overall system.
|
* lock level, since this would result in an unrecoverable deadlock of the
|
||||||
|
* overall system.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
_Chain_Initialize_empty( &queue_context->Path.Links );
|
_Chain_Initialize_empty( &queue_context->Path.Links );
|
||||||
@@ -284,11 +282,11 @@ bool _Thread_queue_Path_acquire_critical(
|
|||||||
owner = queue->owner;
|
owner = queue->owner;
|
||||||
|
|
||||||
if ( owner == NULL ) {
|
if ( owner == NULL ) {
|
||||||
return true;
|
return THREAD_QUEUE_NO_DEADLOCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( owner == the_thread ) {
|
if ( owner == the_thread ) {
|
||||||
return false;
|
return THREAD_QUEUE_DEADLOCK_DETECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
_Chain_Initialize_node(
|
_Chain_Initialize_node(
|
||||||
@@ -311,7 +309,11 @@ bool _Thread_queue_Path_acquire_critical(
|
|||||||
link->Lock_context.Wait.queue = target;
|
link->Lock_context.Wait.queue = target;
|
||||||
|
|
||||||
if ( target != NULL ) {
|
if ( target != NULL ) {
|
||||||
if ( _Thread_queue_Link_add( link, queue, target ) ) {
|
Thread_queue_Deadlock_status deadlock_status;
|
||||||
|
|
||||||
|
deadlock_status = _Thread_queue_Link_add( link, queue, target );
|
||||||
|
|
||||||
|
if ( deadlock_status == THREAD_QUEUE_NO_DEADLOCK ) {
|
||||||
_Thread_queue_Gate_add(
|
_Thread_queue_Gate_add(
|
||||||
&owner->Wait.Lock.Pending_requests,
|
&owner->Wait.Lock.Pending_requests,
|
||||||
&link->Lock_context.Wait.Gate
|
&link->Lock_context.Wait.Gate
|
||||||
@@ -331,15 +333,15 @@ bool _Thread_queue_Path_acquire_critical(
|
|||||||
);
|
);
|
||||||
_Thread_Wait_remove_request_locked( owner, &link->Lock_context );
|
_Thread_Wait_remove_request_locked( owner, &link->Lock_context );
|
||||||
_Assert( owner->Wait.queue == NULL );
|
_Assert( owner->Wait.queue == NULL );
|
||||||
return true;
|
return THREAD_QUEUE_NO_DEADLOCK;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
link->Lock_context.Wait.queue = NULL;
|
link->Lock_context.Wait.queue = NULL;
|
||||||
_Thread_queue_Path_append_deadlock_thread( owner, queue_context );
|
_Thread_queue_Path_append_deadlock_thread( owner, queue_context );
|
||||||
return false;
|
return THREAD_QUEUE_DEADLOCK_DETECTED;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return THREAD_QUEUE_NO_DEADLOCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
link = &owner->Wait.Link;
|
link = &owner->Wait.Link;
|
||||||
@@ -351,18 +353,18 @@ bool _Thread_queue_Path_acquire_critical(
|
|||||||
owner = queue->owner;
|
owner = queue->owner;
|
||||||
|
|
||||||
if ( owner == NULL ) {
|
if ( owner == NULL ) {
|
||||||
return true;
|
return THREAD_QUEUE_NO_DEADLOCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( owner == the_thread ) {
|
if ( owner == the_thread ) {
|
||||||
return false;
|
return THREAD_QUEUE_DEADLOCK_DETECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
queue = owner->Wait.queue;
|
queue = owner->Wait.queue;
|
||||||
} while ( queue != NULL );
|
} while ( queue != NULL );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return true;
|
return THREAD_QUEUE_NO_DEADLOCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _Thread_queue_Enqueue_do_nothing_extra(
|
void _Thread_queue_Enqueue_do_nothing_extra(
|
||||||
@@ -392,8 +394,9 @@ void _Thread_queue_Enqueue(
|
|||||||
Thread_queue_Context *queue_context
|
Thread_queue_Context *queue_context
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Per_CPU_Control *cpu_self;
|
Thread_queue_Deadlock_status deadlock_status;
|
||||||
bool success;
|
Per_CPU_Control *cpu_self;
|
||||||
|
bool success;
|
||||||
|
|
||||||
_Assert( queue_context->enqueue_callout != NULL );
|
_Assert( queue_context->enqueue_callout != NULL );
|
||||||
|
|
||||||
@@ -405,8 +408,11 @@ void _Thread_queue_Enqueue(
|
|||||||
|
|
||||||
_Thread_Wait_claim( the_thread, queue );
|
_Thread_Wait_claim( the_thread, queue );
|
||||||
|
|
||||||
if ( !_Thread_queue_Path_acquire_critical( queue, the_thread, queue_context ) ) {
|
deadlock_status =
|
||||||
_Thread_queue_Path_release_critical( queue_context );
|
_Thread_queue_Path_acquire( queue, the_thread, queue_context );
|
||||||
|
|
||||||
|
if ( deadlock_status == THREAD_QUEUE_DEADLOCK_DETECTED ) {
|
||||||
|
_Thread_queue_Path_release( queue_context );
|
||||||
_Thread_Wait_restore_default( the_thread );
|
_Thread_Wait_restore_default( the_thread );
|
||||||
_Thread_queue_Queue_release( queue, &queue_context->Lock_context.Lock_context );
|
_Thread_queue_Queue_release( queue, &queue_context->Lock_context.Lock_context );
|
||||||
_Thread_Wait_tranquilize( the_thread );
|
_Thread_Wait_tranquilize( the_thread );
|
||||||
@@ -419,7 +425,7 @@ void _Thread_queue_Enqueue(
|
|||||||
_Thread_Wait_claim_finalize( the_thread, operations );
|
_Thread_Wait_claim_finalize( the_thread, operations );
|
||||||
( *operations->enqueue )( queue, the_thread, queue_context );
|
( *operations->enqueue )( queue, the_thread, queue_context );
|
||||||
|
|
||||||
_Thread_queue_Path_release_critical( queue_context );
|
_Thread_queue_Path_release( queue_context );
|
||||||
|
|
||||||
the_thread->Wait.return_code = STATUS_SUCCESSFUL;
|
the_thread->Wait.return_code = STATUS_SUCCESSFUL;
|
||||||
_Thread_Wait_flags_set( the_thread, THREAD_QUEUE_INTEND_TO_BLOCK );
|
_Thread_Wait_flags_set( the_thread, THREAD_QUEUE_INTEND_TO_BLOCK );
|
||||||
@@ -468,14 +474,18 @@ Status_Control _Thread_queue_Enqueue_sticky(
|
|||||||
Thread_queue_Context *queue_context
|
Thread_queue_Context *queue_context
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Per_CPU_Control *cpu_self;
|
Thread_queue_Deadlock_status deadlock_status;
|
||||||
|
Per_CPU_Control *cpu_self;
|
||||||
|
|
||||||
_Assert( queue_context->enqueue_callout != NULL );
|
_Assert( queue_context->enqueue_callout != NULL );
|
||||||
|
|
||||||
_Thread_Wait_claim( the_thread, queue );
|
_Thread_Wait_claim( the_thread, queue );
|
||||||
|
|
||||||
if ( !_Thread_queue_Path_acquire_critical( queue, the_thread, queue_context ) ) {
|
deadlock_status =
|
||||||
_Thread_queue_Path_release_critical( queue_context );
|
_Thread_queue_Path_acquire( queue, the_thread, queue_context );
|
||||||
|
|
||||||
|
if ( deadlock_status == THREAD_QUEUE_DEADLOCK_DETECTED ) {
|
||||||
|
_Thread_queue_Path_release( queue_context );
|
||||||
_Thread_Wait_restore_default( the_thread );
|
_Thread_Wait_restore_default( the_thread );
|
||||||
_Thread_queue_Queue_release( queue, &queue_context->Lock_context.Lock_context );
|
_Thread_queue_Queue_release( queue, &queue_context->Lock_context.Lock_context );
|
||||||
_Thread_Wait_tranquilize( the_thread );
|
_Thread_Wait_tranquilize( the_thread );
|
||||||
@@ -487,7 +497,7 @@ Status_Control _Thread_queue_Enqueue_sticky(
|
|||||||
_Thread_Wait_claim_finalize( the_thread, operations );
|
_Thread_Wait_claim_finalize( the_thread, operations );
|
||||||
( *operations->enqueue )( queue, the_thread, queue_context );
|
( *operations->enqueue )( queue, the_thread, queue_context );
|
||||||
|
|
||||||
_Thread_queue_Path_release_critical( queue_context );
|
_Thread_queue_Path_release( queue_context );
|
||||||
|
|
||||||
the_thread->Wait.return_code = STATUS_SUCCESSFUL;
|
the_thread->Wait.return_code = STATUS_SUCCESSFUL;
|
||||||
_Thread_Wait_flags_set( the_thread, THREAD_QUEUE_INTEND_TO_BLOCK );
|
_Thread_Wait_flags_set( the_thread, THREAD_QUEUE_INTEND_TO_BLOCK );
|
||||||
|
|||||||
@@ -1186,7 +1186,7 @@ static void _Thread_queue_Priority_inherit_extract(
|
|||||||
* resolves the deadlock. Thread T1 and T2 can the complete their
|
* resolves the deadlock. Thread T1 and T2 can the complete their
|
||||||
* operations.
|
* operations.
|
||||||
*/
|
*/
|
||||||
_Thread_queue_Path_acquire_critical( queue, the_thread, queue_context );
|
(void) _Thread_queue_Path_acquire( queue, the_thread, queue_context );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_Thread_queue_Queue_extract(
|
_Thread_queue_Queue_extract(
|
||||||
@@ -1199,7 +1199,7 @@ static void _Thread_queue_Priority_inherit_extract(
|
|||||||
);
|
);
|
||||||
|
|
||||||
#if defined(RTEMS_SMP)
|
#if defined(RTEMS_SMP)
|
||||||
_Thread_queue_Path_release_critical( queue_context );
|
_Thread_queue_Path_release( queue_context );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user