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