示例#1
0
static Scheduler_Node *_Scheduler_priority_SMP_Get_highest_ready(
  Scheduler_Context *context,
  Scheduler_Node    *node
)
{
  Scheduler_priority_SMP_Context *self =
    _Scheduler_priority_SMP_Get_self( context );

  (void) node;

  return (Scheduler_Node *) _Scheduler_priority_Ready_queue_first(
    &self->Bit_map,
    &self->Ready[ 0 ]
  );
}
/*
 * This method is invoked at the end of certain scheduling operations
 * to ensure that the highest priority ready thread cannot be scheduled
 * to execute. When we schedule with affinity, there is the possibility
 * that we need to migrate a thread to another core to ensure that the
 * highest priority ready threads are in fact scheduled.
 */
static void _Scheduler_priority_affinity_SMP_Check_for_migrations(
  Scheduler_Context *context
)
{
  Scheduler_priority_SMP_Context *self;
  Scheduler_Node                 *lowest_scheduled;
  Scheduler_Node                 *highest_ready;

  self = _Scheduler_priority_SMP_Get_self( context );

  while (1) {
    if ( _Priority_bit_map_Is_empty( &self->Bit_map ) ) {
      /* Nothing to do */
      break;
    }

    highest_ready =
      _Scheduler_priority_affinity_SMP_Get_highest_ready( context, NULL );

    lowest_scheduled =
      _Scheduler_priority_affinity_SMP_Get_lowest_scheduled(
        context,
        highest_ready,
        _Scheduler_SMP_Insert_priority_lifo_order
      );

    /*
     * If we can't find a thread to displace from the scheduled set,
     * then we have placed all the highest priority threads possible
     * in the scheduled set.
     *
     * We found the absolute highest priority thread without
     * considering affinity. But now we have to consider that thread's
     * affinity as we look to place it.
     */
    if ( lowest_scheduled == NULL )
      break;

    /*
     * FIXME: Do not consider threads using the scheduler helping protocol
     * since this could produce more than one thread in need for help in one
     * operation which is currently not possible.
     */
    if ( lowest_scheduled->help_state != SCHEDULER_HELP_YOURSELF )
      break;

    /*
     * But if we found a thread which is lower priority than one
     * in the ready set, then we need to swap them out.
     */

    _Scheduler_SMP_Node_change_state(
      _Scheduler_SMP_Node_downcast( lowest_scheduled ),
      SCHEDULER_SMP_NODE_READY
    );
    _Scheduler_Thread_change_state(
      _Scheduler_Node_get_user( lowest_scheduled ),
      THREAD_SCHEDULER_READY
    );

    _Scheduler_SMP_Allocate_processor(
      context,
      highest_ready,
      lowest_scheduled,
      _Scheduler_SMP_Allocate_processor_exact
    );

    _Scheduler_priority_SMP_Move_from_ready_to_scheduled(
      context,
      highest_ready
    );

    _Scheduler_priority_SMP_Move_from_scheduled_to_ready(
      context,
      lowest_scheduled
    );
  }
}
/*
 * This method is unique to this scheduler because it takes into
 * account affinity as it determines the highest ready thread.
 * Since this is used to pick a new thread to replace the victim,
 * the highest ready thread must have affinity such that it can
 * be executed on the victim's processor.
 */
static Scheduler_Node *_Scheduler_priority_affinity_SMP_Get_highest_ready(
  Scheduler_Context *context,
  Scheduler_Node    *victim
)
{
  Scheduler_priority_SMP_Context       *self =
    _Scheduler_priority_SMP_Get_self( context );
  Priority_Control                      index;
  Scheduler_Node                       *highest = NULL;
  Thread_Control                       *victim_thread;
  uint32_t                              victim_cpu_index;
  Scheduler_priority_affinity_SMP_Node *node;

  /*
   * This is done when we need to check if reevaluations are needed.
   */
  if ( victim == NULL ) {
    node = (Scheduler_priority_affinity_SMP_Node *)
      _Scheduler_priority_Ready_queue_first(
        &self->Bit_map,
        &self->Ready[ 0 ]
      );

    return &node->Base.Base.Base;
  }

  victim_thread = _Scheduler_Node_get_owner( victim );
  victim_cpu_index = _Per_CPU_Get_index( _Thread_Get_CPU( victim_thread ) );

  /**
   * @todo The deterministic priority scheduler structure is optimized
   * for insertion, extraction, and finding the highest priority
   * thread. Scanning the list of ready threads is not a purpose
   * for which it was optimized. There are optimizations to be
   * made in this loop.
   *
   * + by checking the major bit, we could potentially skip entire
   *   groups of 16.
   *
   * When using this scheduler as implemented, the application's
   * choice of numeric priorities and their distribution can have
   * an impact on performance.
   */
  for ( index = _Priority_bit_map_Get_highest( &self->Bit_map ) ;
        index <= PRIORITY_MAXIMUM;
        index++ )
  {
    Chain_Control   *chain =  &self->Ready[index];
    Chain_Node      *chain_node;
    for ( chain_node = _Chain_First( chain );
          chain_node != _Chain_Immutable_tail( chain ) ;
          chain_node = _Chain_Next( chain_node ) )
    {
      node = (Scheduler_priority_affinity_SMP_Node *) chain_node;

      /*
       * Can this thread run on this CPU?
       */
      if ( CPU_ISSET( (int) victim_cpu_index, node->Affinity.set ) ) {
        highest = &node->Base.Base.Base;
        break;
      }
    }
    if ( highest )
      break;
  }

  _Assert( highest != NULL );

  return highest;
}