Example #1
0
void _Thread_queue_Enqueue_with_handler(
  Thread_queue_Control         *the_thread_queue,
  Watchdog_Interval             timeout,
  Thread_queue_Timeout_callout  handler
)
{
  Thread_Control                   *the_thread;
  ISR_Level                         level;
  Thread_blocking_operation_States  sync_state;
  Thread_blocking_operation_States (*enqueue_p)(
    Thread_queue_Control *,
    Thread_Control *,
    ISR_Level *
  );

  the_thread = _Thread_Executing;

#if defined(RTEMS_MULTIPROCESSING)
  if ( _Thread_MP_Is_receive( the_thread ) && the_thread->receive_packet )
    the_thread = _Thread_MP_Allocate_proxy( the_thread_queue->state );
  else
#endif
  /*
   *  Set the blocking state for this thread queue in the thread.
   */
  _Thread_Set_state( the_thread, the_thread_queue->state );

  /*
   *  If the thread wants to timeout, then schedule its timer.
   */
  if ( timeout ) {
    _Watchdog_Initialize(
       &the_thread->Timer,
       handler,
       the_thread->Object.id,
       NULL
    );

    _Watchdog_Insert_ticks( &the_thread->Timer, timeout );
  }

  /*
   *  Now enqueue the thread per the discipline for this thread queue.
   */
  if ( the_thread_queue->discipline == THREAD_QUEUE_DISCIPLINE_PRIORITY )
    enqueue_p = _Thread_queue_Enqueue_priority;
  else /* must be THREAD_QUEUE_DISCIPLINE_FIFO */
    enqueue_p = _Thread_queue_Enqueue_fifo;

  sync_state = (*enqueue_p)( the_thread_queue, the_thread, &level );
  if ( sync_state != THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED )
    _Thread_blocking_operation_Cancel( sync_state, the_thread, level );
}
Example #2
0
void _Thread_queue_Enqueue(
  Thread_queue_Control *the_thread_queue,
  Thread_Control       *the_thread,
  States_Control        state,
  Watchdog_Interval     timeout
)
{
  ISR_lock_Context                 lock_context;
  Thread_blocking_operation_States sync_state;

#if defined(RTEMS_MULTIPROCESSING)
  if ( _Thread_MP_Is_receive( the_thread ) && the_thread->receive_packet )
    the_thread = _Thread_MP_Allocate_proxy( state );
  else
#endif
  /*
   *  Set the blocking state for this thread queue in the thread.
   */
  _Thread_Set_state( the_thread, state );

  /*
   *  If the thread wants to timeout, then schedule its timer.
   */
  if ( timeout ) {
    _Watchdog_Initialize(
       &the_thread->Timer,
       _Thread_queue_Timeout,
       the_thread->Object.id,
       NULL
    );

    _Watchdog_Insert_ticks( &the_thread->Timer, timeout );
  }

  /*
   * Now initiate the enqueuing and checking if the blocking operation
   * should be completed or the thread has had its blocking condition
   * satisfied before we got here.
   */
  _Thread_queue_Acquire( &lock_context );

  sync_state = the_thread_queue->sync_state;
  the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_SYNCHRONIZED;

  if ( sync_state == THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED ) {
    /*
     * Invoke the discipline specific enqueue method.
     */
    if ( the_thread_queue->discipline == THREAD_QUEUE_DISCIPLINE_FIFO ) {
      _Chain_Append_unprotected(
        &the_thread_queue->Queues.Fifo,
        &the_thread->Object.Node
      );
    } else { /* must be THREAD_QUEUE_DISCIPLINE_PRIORITY */
      _Thread_Lock_set( the_thread, &_Thread_queue_Lock );
      _Thread_Priority_set_change_handler(
        the_thread,
        _Thread_queue_Requeue_priority,
        the_thread_queue
      );
      _RBTree_Insert(
        &the_thread_queue->Queues.Priority,
        &the_thread->RBNode,
        _Thread_queue_Compare_priority,
        false
      );
    }

    the_thread->Wait.queue = the_thread_queue;
    the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_SYNCHRONIZED;
    _Thread_queue_Release( &lock_context );
  } else {
    /* Cancel a blocking operation due to ISR */

    _Assert(
      sync_state == THREAD_BLOCKING_OPERATION_TIMEOUT ||
        sync_state == THREAD_BLOCKING_OPERATION_SATISFIED
    );

    _Thread_blocking_operation_Finalize( the_thread, &lock_context );
  }
}
Example #3
0
void _Thread_queue_Enqueue(
    Thread_queue_Queue            *queue,
    const Thread_queue_Operations *operations,
    Thread_Control                *the_thread,
    Thread_queue_Context          *queue_context
)
{
    Per_CPU_Control *cpu_self;
    bool             success;

    _Assert( queue_context->enqueue_callout != NULL );
    _Assert( (uint8_t) queue_context->timeout_discipline != 0x7f );

#if defined(RTEMS_MULTIPROCESSING)
    if ( _Thread_MP_Is_receive( the_thread ) && the_thread->receive_packet ) {
        the_thread = _Thread_MP_Allocate_proxy( queue_context->thread_state );
    }
#endif

    _Thread_Wait_claim( the_thread, queue );

    if ( !_Thread_queue_Path_acquire_critical( queue, the_thread, queue_context ) ) {
        _Thread_queue_Path_release_critical( queue_context );
        _Thread_Wait_restore_default( the_thread );
        _Thread_queue_Queue_release( queue, &queue_context->Lock_context.Lock_context );
        _Thread_Wait_tranquilize( the_thread );
        _Assert( queue_context->deadlock_callout != NULL );
        ( *queue_context->deadlock_callout )( the_thread );
        return;
    }

    _Thread_queue_Context_clear_priority_updates( queue_context );
    _Thread_Wait_claim_finalize( the_thread, operations );
    ( *operations->enqueue )( queue, the_thread, queue_context );

    _Thread_queue_Path_release_critical( queue_context );

    the_thread->Wait.return_code = STATUS_SUCCESSFUL;
    _Thread_Wait_flags_set( the_thread, THREAD_QUEUE_INTEND_TO_BLOCK );
    cpu_self = _Thread_Dispatch_disable_critical(
                   &queue_context->Lock_context.Lock_context
               );
    _Thread_queue_Queue_release( queue, &queue_context->Lock_context.Lock_context );

    ( *queue_context->enqueue_callout )( queue, the_thread, queue_context );

    /*
     *  Set the blocking state for this thread queue in the thread.
     */
    _Thread_Set_state( the_thread, queue_context->thread_state );

    /*
     *  If the thread wants to timeout, then schedule its timer.
     */
    _Thread_queue_Timeout( the_thread, cpu_self, queue_context );

    /*
     * At this point thread dispatching is disabled, however, we already released
     * the thread queue lock.  Thus, interrupts or threads on other processors
     * may already changed our state with respect to the thread queue object.
     * The request could be satisfied or timed out.  This situation is indicated
     * by the thread wait flags.  Other parties must not modify our thread state
     * as long as we are in the THREAD_QUEUE_INTEND_TO_BLOCK thread wait state,
     * thus we have to cancel the blocking operation ourself if necessary.
     */
    success = _Thread_Wait_flags_try_change_acquire(
                  the_thread,
                  THREAD_QUEUE_INTEND_TO_BLOCK,
                  THREAD_QUEUE_BLOCKED
              );
    if ( !success ) {
        _Thread_Remove_timer_and_unblock( the_thread, queue );
    }

    _Thread_Priority_update( queue_context );
    _Thread_Dispatch_direct( cpu_self );
}
Example #4
0
void _Thread_queue_Enqueue_critical(
  Thread_queue_Queue            *queue,
  const Thread_queue_Operations *operations,
  Thread_Control                *the_thread,
  States_Control                 state,
  Thread_queue_Context          *queue_context
)
{
  Thread_queue_Path  path;
  Per_CPU_Control   *cpu_self;
  bool               success;

#if defined(RTEMS_MULTIPROCESSING)
  if ( _Thread_MP_Is_receive( the_thread ) && the_thread->receive_packet ) {
    the_thread = _Thread_MP_Allocate_proxy( state );
  }
#endif

  _Thread_Wait_claim( the_thread, queue, operations );

  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;
  }

  ( *operations->enqueue )( queue, the_thread, &path );

  _Thread_queue_Path_release( &path );

  the_thread->Wait.return_code = STATUS_SUCCESSFUL;
  _Thread_Wait_flags_set( the_thread, THREAD_QUEUE_INTEND_TO_BLOCK );
  cpu_self = _Thread_Dispatch_disable_critical( &queue_context->Lock_context );
  _Thread_queue_Queue_release( queue, &queue_context->Lock_context );

  if (
    cpu_self->thread_dispatch_disable_level
      != queue_context->expected_thread_dispatch_disable_level
  ) {
    _Terminate(
      INTERNAL_ERROR_CORE,
      false,
      INTERNAL_ERROR_THREAD_QUEUE_ENQUEUE_FROM_BAD_STATE
    );
  }

  /*
   *  Set the blocking state for this thread queue in the thread.
   */
  _Thread_Set_state( the_thread, state );

  /*
   *  If the thread wants to timeout, then schedule its timer.
   */
  switch ( queue_context->timeout_discipline ) {
    case WATCHDOG_RELATIVE:
      /* A relative timeout of 0 is a special case indefinite (no) timeout */
      if ( queue_context->timeout != 0 ) {
        _Thread_Timer_insert_relative(
          the_thread,
          cpu_self,
          _Thread_Timeout,
          (Watchdog_Interval) queue_context->timeout
        );
      }
      break;
    case WATCHDOG_ABSOLUTE:
      _Thread_Timer_insert_absolute(
        the_thread,
        cpu_self,
        _Thread_Timeout,
        queue_context->timeout
      );
      break;
    default:
      break;
  }

  /*
   * At this point thread dispatching is disabled, however, we already released
   * the thread queue lock.  Thus, interrupts or threads on other processors
   * may already changed our state with respect to the thread queue object.
   * The request could be satisfied or timed out.  This situation is indicated
   * by the thread wait flags.  Other parties must not modify our thread state
   * as long as we are in the THREAD_QUEUE_INTEND_TO_BLOCK thread wait state,
   * thus we have to cancel the blocking operation ourself if necessary.
   */
  success = _Thread_Wait_flags_try_change_acquire(
    the_thread,
    THREAD_QUEUE_INTEND_TO_BLOCK,
    THREAD_QUEUE_BLOCKED
  );
  if ( !success ) {
    _Thread_Remove_timer_and_unblock( the_thread, queue );
  }

  _Thread_Update_priority( path.update_priority );
  _Thread_Dispatch_enable( cpu_self );
}