static void _Thread_queue_Path_release( Thread_queue_Path *path ) { #if defined(RTEMS_SMP) Chain_Node *head; Chain_Node *node; head = _Chain_Head( &path->Links ); node = _Chain_Last( &path->Links ); if ( head != node ) { Thread_queue_Link *link; /* * The terminal link may have an owner which does not wait on a thread * queue. */ link = THREAD_QUEUE_LINK_OF_PATH_NODE( node ); if ( link->Queue_context.Wait.queue == NULL ) { _Thread_Wait_release_default_critical( link->owner, &link->Queue_context.Lock_context ); node = _Chain_Previous( node ); #if defined(RTEMS_DEBUG) _Chain_Set_off_chain( &link->Path_node ); #endif } while ( head != node ) { /* The other links have an owner which waits on a thread queue */ link = THREAD_QUEUE_LINK_OF_PATH_NODE( node ); _Assert( link->Queue_context.Wait.queue != NULL ); _Thread_queue_Link_remove( link ); _Thread_Wait_release_queue_critical( link->Queue_context.Wait.queue, &link->Queue_context ); _Thread_Wait_remove_request( link->owner, &link->Queue_context ); node = _Chain_Previous( node ); #if defined(RTEMS_DEBUG) _Chain_Set_off_chain( &link->Path_node ); #endif } } #else (void) path; #endif }
static #endif void _Thread_queue_Path_release_critical( Thread_queue_Context *queue_context ) { #if defined(RTEMS_SMP) Chain_Node *head; Chain_Node *node; head = _Chain_Head( &queue_context->Path.Links ); node = _Chain_Last( &queue_context->Path.Links ); while ( head != node ) { Thread_queue_Link *link; link = THREAD_QUEUE_LINK_OF_PATH_NODE( node ); if ( link->Lock_context.Wait.queue != NULL ) { _Thread_queue_Link_remove( link ); _Thread_Wait_release_queue_critical( link->Lock_context.Wait.queue, &link->Lock_context ); _Thread_Wait_remove_request( link->owner, &link->Lock_context ); } else { _Thread_Wait_release_default_critical( link->owner, &link->Lock_context.Lock_context ); } node = _Chain_Previous( node ); #if defined(RTEMS_DEBUG) _Chain_Set_off_chain( &link->Path_node ); #endif } #else (void) queue_context; #endif }
static #endif bool _Thread_queue_Path_acquire_critical( Thread_queue_Queue *queue, Thread_Control *the_thread, Thread_queue_Context *queue_context ) { Thread_Control *owner; #if defined(RTEMS_SMP) Thread_queue_Link *link; Thread_queue_Queue *target; /* * For an overview please look at the non-SMP part below. We basically do * the same on SMP configurations. The fact that we may have more than one * executing thread and each thread queue has its own SMP lock makes the task * a bit more difficult. We have to avoid deadlocks at SMP lock level, since * this would result in an unrecoverable deadlock of the overall system. */ _Chain_Initialize_empty( &queue_context->Path.Links ); owner = queue->owner; if ( owner == NULL ) { return true; } if ( owner == the_thread ) { return false; } _Chain_Initialize_node( &queue_context->Path.Start.Lock_context.Wait.Gate.Node ); link = &queue_context->Path.Start; _RBTree_Initialize_node( &link->Registry_node ); _Chain_Initialize_node( &link->Path_node ); do { _Chain_Append_unprotected( &queue_context->Path.Links, &link->Path_node ); link->owner = owner; _Thread_Wait_acquire_default_critical( owner, &link->Lock_context.Lock_context ); target = owner->Wait.queue; link->Lock_context.Wait.queue = target; if ( target != NULL ) { if ( _Thread_queue_Link_add( link, queue, target ) ) { _Thread_queue_Gate_add( &owner->Wait.Lock.Pending_requests, &link->Lock_context.Wait.Gate ); _Thread_Wait_release_default_critical( owner, &link->Lock_context.Lock_context ); _Thread_Wait_acquire_queue_critical( target, &link->Lock_context ); if ( link->Lock_context.Wait.queue == NULL ) { _Thread_queue_Link_remove( link ); _Thread_Wait_release_queue_critical( target, &link->Lock_context ); _Thread_Wait_acquire_default_critical( owner, &link->Lock_context.Lock_context ); _Thread_Wait_remove_request_locked( owner, &link->Lock_context ); _Assert( owner->Wait.queue == NULL ); return true; } } else { link->Lock_context.Wait.queue = NULL; _Thread_queue_Path_append_deadlock_thread( owner, queue_context ); return false; } } else { return true; } link = &owner->Wait.Link; queue = target; owner = queue->owner; } while ( owner != NULL ); #else do { owner = queue->owner; if ( owner == NULL ) { return true; } if ( owner == the_thread ) { return false; } queue = owner->Wait.queue; } while ( queue != NULL ); #endif return true; }