Exemple #1
0
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
}
Exemple #2
0
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
}
Exemple #3
0
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;
}