diff --git a/cpukit/include/rtems/scheduler.h b/cpukit/include/rtems/scheduler.h index 955a83cfb48..3ec9b3aeabb 100644 --- a/cpukit/include/rtems/scheduler.h +++ b/cpukit/include/rtems/scheduler.h @@ -257,7 +257,9 @@ #define RTEMS_SCHEDULER_STRONG_APA( name, prio_count ) \ static struct { \ Scheduler_strong_APA_Context Base; \ - Chain_Control Ready[ ( prio_count ) ]; \ + Scheduler_strong_APA_Queue Cpu[ CONFIGURE_MAXIMUM_PROCESSORS ]; \ + Scheduler_strong_APA_Caller caller[ CONFIGURE_MAXIMUM_PROCESSORS ]; \ + Scheduler_strong_APA_Visited visited[ CONFIGURE_MAXIMUM_PROCESSORS ]; } SCHEDULER_STRONG_APA_CONTEXT_NAME( name ) #define RTEMS_SCHEDULER_TABLE_STRONG_APA( name, obj_name ) \ diff --git a/cpukit/include/rtems/score/schedulerstrongapa.h b/cpukit/include/rtems/score/schedulerstrongapa.h index 0ac28cb4393..1947585a19f 100644 --- a/cpukit/include/rtems/score/schedulerstrongapa.h +++ b/cpukit/include/rtems/score/schedulerstrongapa.h @@ -6,26 +6,29 @@ * @brief Strong APA Scheduler API */ -/* - * Copyright (c) 2013, 2018 embedded brains GmbH. All rights reserved. +/* + * Copyright (c) 2013, 2018 embedded brains GmbH, 2020 Richi Dubey. + * All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * * - * embedded brains GmbH - * Dornierstr. 4 - * 82178 Puchheim - * Germany - * - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at + * Richi Dubey: richidubey@gmail.com + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at * http://www.rtems.org/license/LICENSE. */ - + #ifndef _RTEMS_SCORE_SCHEDULERSTRONGAPA_H #define _RTEMS_SCORE_SCHEDULERSTRONGAPA_H #include -#include #include +#include #ifdef __cplusplus extern "C" { @@ -38,43 +41,105 @@ extern "C" { * * @brief Strong APA Scheduler * - * This is an implementation of the global fixed priority scheduler (G-FP). It - * uses one ready chain per priority to ensure constant time insert operations. - * The scheduled chain uses linear insert operations and has at most processor - * count entries. Since the processor and priority count are constants all - * scheduler operations complete in a bounded execution time. - * - * The the_thread preempt mode will be ignored. + * This is an implementation of the Strong APA scheduler defined by + * Cerqueira et al. in Linux's Processor Affinity API, Refined: + * Shifting Real-Time Tasks Towards Higher Schedulability. * * @{ */ -/** - * @brief Scheduler context specialization for Strong APA - * schedulers. + /** + * @brief Scheduler context for Strong APA scheduler. + * + * Has the structure for scheduler context + * and Node defintion for Strong APA scheduler */ typedef struct { - Scheduler_SMP_Context Base; - Priority_bit_map_Control Bit_map; - Chain_Control Ready[ RTEMS_ZERO_LENGTH_ARRAY ]; + /** + * @brief SMP Context to refer to SMP implementation + * code. + */ + Scheduler_SMP_Context Base; + + /** + * @brief Chain of all the nodes present in + * the system. Accounts for ready and scheduled nodes. + */ + Chain_Control All_nodes; + + /** + * @brief Queue for this context + */ + Scheduler_strong_APA_Queue *queue; + + /** + * @brief Pointer to structure with array of + * boolean visited values + */ + Scheduler_strong_APA_Visited *visited; + + /** + * @brief Pointer to structure with array of + * caller corresponding to a CPU + */ + Scheduler_strong_APA_Caller *caller; } Scheduler_strong_APA_Context; /** - * @brief Scheduler node specialization for Strong APA - * schedulers. + * @brief Scheduler node specialization for Strong APA schedulers. */ typedef struct { + /** + * @brief Chain node for Scheduler_strong_APA_Context::allNodes + */ + Chain_Node Node; + /** * @brief SMP scheduler node. */ Scheduler_SMP_Node Base; /** - * @brief The associated ready queue of this node. + * @brief The associated affinity set of this node. */ - Scheduler_priority_Ready_queue Ready_queue; + Processor_mask Affinity; } Scheduler_strong_APA_Node; +/** + * @brief CPU structure to be used while traversing in the FIFO Queue + */ +typedef struct +{ + /** + * @brief Array of Cpu to be used for the queue operations + */ + Per_CPU_Control Cpu[ RTEMS_ZERO_LENGTH_ARRAY ]; +} Scheduler_strong_APA_Queue; + +/** + * @brief Caller corresponding to a Cpu in Scheduler_strong_APA_Queue + */ +typedef struct +{ + /** + * @brief Array of caller each corresponding to the + * Scheduler_strong_APA_Queue::Cpu at the same index + */ + Scheduler_strong_APA_Node *caller[ RTEMS_ZERO_LENGTH_ARRAY ]; +} Scheduler_strong_APA_Caller; + +/** + * @brief to a Cpu in Scheduler_strong_APA_Queue + */ +typedef struct +{ + /** + * @brief Array of boolean each corresponding to the visited status of + * Scheduler_strong_APA_Queue::Cpu at the same index + */ + bool *visited[ RTEMS_ZERO_LENGTH_ARRAY ]; +} Scheduler_strong_APA_Visited; + /** * @brief Entry points for the Strong APA Scheduler. */ @@ -100,81 +165,90 @@ typedef struct { _Scheduler_default_Release_job, \ _Scheduler_default_Cancel_job, \ _Scheduler_default_Tick, \ - _Scheduler_SMP_Start_idle \ - SCHEDULER_OPERATION_DEFAULT_GET_SET_AFFINITY \ + _Scheduler_strong_APA_Start_idle, \ + _Scheduler_strong_APA_Set_affinity \ } /** - * @brief Initializes the scheduler. + * @brief Initializes the Strong_APA scheduler. * - * @param scheduler The scheduler to initialize. - */ -void _Scheduler_strong_APA_Initialize( const Scheduler_Control *scheduler ); - + * Sets the chain containing all the nodes to empty + * and initializes the SMP scheduler. + * + * @param scheduler used to get reference to Strong APA scheduler context + * @retval void + * @see _Scheduler_strong_APA_Node_initialize() + */ +void _Scheduler_strong_APA_Initialize( + const Scheduler_Control *scheduler +); + /** - * @brief Initializes the node with the given priority. + * @brief Called when a node yields the processor * * @param scheduler The scheduler control instance. - * @param[out] node The node to initialize. - * @param the_thread The thread of the node to initialize. - * @param priority The priority for @a node. + * @param thread Thread corresponding to @node + * @param node Node that yield the processor */ -void _Scheduler_strong_APA_Node_initialize( +void _Scheduler_strong_APA_Yield( const Scheduler_Control *scheduler, - Scheduler_Node *node, - Thread_Control *the_thread, - Priority_Control priority + Thread_Control *thread, + Scheduler_Node *node ); /** - * @brief Blocks the thread. + * @brief Blocks a node * - * @param scheduler The scheduler control instance. - * @param[in, out] the_thread The thread to block. - * @param[in, out] node The node of the thread to block. - */ + * Changes the state of the node and extracts it from the queue + * calls _Scheduler_SMP_Block(). + * + * @param context The scheduler control instance. + * @param thread Thread correspoding to the @node. + * @param node node which is to be blocked + */ void _Scheduler_strong_APA_Block( const Scheduler_Control *scheduler, - Thread_Control *the_thread, + Thread_Control *thread, Scheduler_Node *node ); /** - * @brief Unblocks the thread. + * @brief Unblocks a node + * + * Changes the state of the node and calls _Scheduler_SMP_Unblock(). * * @param scheduler The scheduler control instance. - * @param[in, out] the_thread The thread to unblock. - * @param[in, out] node The node of the thread to unblock. - */ + * @param thread Thread correspoding to the @node. + * @param node node which is to be unblocked + * @see _Scheduler_strong_APA_Enqueue() + * @see _Scheduler_strong_APA_Do_update() + */ void _Scheduler_strong_APA_Unblock( const Scheduler_Control *scheduler, - Thread_Control *the_thread, + Thread_Control *thread, Scheduler_Node *node ); /** - * @brief Updates the priority of the node. + * @brief Updates the priority of the node * * @param scheduler The scheduler control instance. - * @param the_thread The thread for the operation. - * @param[in, out] node The node to update the priority of. - */ + * @param thread Thread correspoding to the @node. + * @param node Node whose priority has to be updated + */ void _Scheduler_strong_APA_Update_priority( const Scheduler_Control *scheduler, - Thread_Control *the_thread, + Thread_Control *thread, Scheduler_Node *node ); /** - * @brief Asks for help. - * - * @param scheduler The scheduler control instance. - * @param the_thread The thread that asks for help. - * @param node The node of @a the_thread. + * @brief Calls the SMP Ask_for_help * - * @retval true The request for help was successful. - * @retval false The request for help was not successful. - */ + * @param scheduler The scheduler control instance. + * @param thread Thread correspoding to the @node that asks for help. + * @param node node associated with @thread + */ bool _Scheduler_strong_APA_Ask_for_help( const Scheduler_Control *scheduler, Thread_Control *the_thread, @@ -182,12 +256,13 @@ bool _Scheduler_strong_APA_Ask_for_help( ); /** - * @brief Reconsiders help request. + * @brief To Reconsider the help request * * @param scheduler The scheduler control instance. - * @param the_thread The thread to reconsider the help request of. - * @param[in, out] node The node of @a the_thread - */ + * @param thread Thread correspoding to the @node. + * @param node Node corresponding to @thread which asks for + * reconsideration + */ void _Scheduler_strong_APA_Reconsider_help_request( const Scheduler_Control *scheduler, Thread_Control *the_thread, @@ -195,13 +270,13 @@ void _Scheduler_strong_APA_Reconsider_help_request( ); /** - * @brief Withdraws the node. + * @brief Withdraws a node * * @param scheduler The scheduler control instance. - * @param[in, out] the_thread The thread to change the state to @a next_state. - * @param[in, out] node The node to withdraw. - * @param next_state The next state for @a the_thread. - */ + * @param thread Thread correspoding to the @node. + * @param node Node that has to be withdrawn + * @param next_state the state that the node goes to + */ void _Scheduler_strong_APA_Withdraw_node( const Scheduler_Control *scheduler, Thread_Control *the_thread, @@ -210,42 +285,66 @@ void _Scheduler_strong_APA_Withdraw_node( ); /** - * @brief Adds the idle thread to a processor. + * @brief Adds a processor to the scheduler instance + * + * and allocates an idle thread to the processor. * * @param scheduler The scheduler control instance. - * @param[in, out] The idle thread to add to the processor. - */ + * @param idle Idle thread to be allocated to the processor + */ void _Scheduler_strong_APA_Add_processor( const Scheduler_Control *scheduler, Thread_Control *idle ); /** - * @brief Removes an idle thread from the given cpu. - * - * @param scheduler The scheduler instance. - * @param cpu The cpu control to remove from @a scheduler. + * @brief Removes a processor from the scheduler instance * - * @return The idle thread of the processor. - */ + * @param scheduler The scheduler control instance. + * @param cpu processor that is removed + */ Thread_Control *_Scheduler_strong_APA_Remove_processor( const Scheduler_Control *scheduler, - struct Per_CPU_Control *cpu + Per_CPU_Control *cpu ); /** - * @brief Performs a yield operation. + * @brief Initializes the node with the given priority. * * @param scheduler The scheduler control instance. - * @param the_thread The thread to yield. - * @param[in, out] node The node of @a the_thread. + * @param[out] node The node to initialize. + * @param the_thread The thread of the node to initialize. + * @param priority The priority for @a node. */ -void _Scheduler_strong_APA_Yield( +void _Scheduler_strong_APA_Node_initialize( const Scheduler_Control *scheduler, + Scheduler_Node *node, Thread_Control *the_thread, - Scheduler_Node *node + Priority_Control priority ); +/** + * @brief Starts an idle thread on a CPU + * + * @param scheduler The scheduler control instance. + * @param idle Idle Thread + * @param cpu processor that gets the idle thread + */ +void _Scheduler_strong_APA_Start_idle( + const Scheduler_Control *scheduler, + Thread_Control *idle, + Per_CPU_Control *cpu +); + +/** + * @brief Sets the affinity of the @node_base to @affinity + */ +bool _Scheduler_strong_APA_Set_affinity( + const Scheduler_Control *scheduler, + Thread_Control *thread, + Scheduler_Node *node_base, + const Processor_mask *affinity +); /** @} */ #ifdef __cplusplus diff --git a/cpukit/score/src/schedulerstrongapa.c b/cpukit/score/src/schedulerstrongapa.c index 924cd86412c..9dd0ea610a7 100644 --- a/cpukit/score/src/schedulerstrongapa.c +++ b/cpukit/score/src/schedulerstrongapa.c @@ -6,248 +6,476 @@ * @brief Strong APA Scheduler Implementation */ -/* - * Copyright (c) 2013, 2016 embedded brains GmbH. All rights reserved. +/* + * Copyright (c) 2013, 2018 embedded brains GmbH, 2020 Richi Dubey. + * All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * * - * embedded brains GmbH - * Dornierstr. 4 - * 82178 Puchheim - * Germany - * - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at + * Richi Dubey + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at * http://www.rtems.org/license/LICENSE. */ - + #ifdef HAVE_CONFIG_H #include "config.h" #endif #include -#include #include +#include +#include -static Scheduler_strong_APA_Context *_Scheduler_strong_APA_Get_self( - Scheduler_Context *context -) +static inline Scheduler_strong_APA_Context * +_Scheduler_strong_APA_Get_context( const Scheduler_Control *scheduler ) +{ + return (Scheduler_strong_APA_Context *) _Scheduler_Get_context( scheduler ); +} + +static inline Scheduler_strong_APA_Context * +_Scheduler_strong_APA_Get_self( Scheduler_Context *context ) { return (Scheduler_strong_APA_Context *) context; } -static Scheduler_strong_APA_Node * +static inline Scheduler_strong_APA_Node * _Scheduler_strong_APA_Node_downcast( Scheduler_Node *node ) { return (Scheduler_strong_APA_Node *) node; } -static void _Scheduler_strong_APA_Move_from_scheduled_to_ready( +static inline void _Scheduler_strong_APA_Do_update( Scheduler_Context *context, - Scheduler_Node *scheduled_to_ready + Scheduler_Node *node, + Priority_Control new_priority ) { - Scheduler_strong_APA_Context *self = - _Scheduler_strong_APA_Get_self( context ); - Scheduler_strong_APA_Node *node = - _Scheduler_strong_APA_Node_downcast( scheduled_to_ready ); - - _Chain_Extract_unprotected( &node->Base.Base.Node.Chain ); - _Scheduler_priority_Ready_queue_enqueue_first( - &node->Base.Base.Node.Chain, - &node->Ready_queue, - &self->Bit_map - ); + Scheduler_SMP_Node *smp_node; + (void) context; + + smp_node = _Scheduler_SMP_Node_downcast( node ); + _Scheduler_SMP_Node_update_priority( smp_node, new_priority ); } -static void _Scheduler_strong_APA_Move_from_ready_to_scheduled( +static inline bool _Scheduler_strong_APA_Has_ready( Scheduler_Context *context ) +{ + Scheduler_strong_APA_Context *self = _Scheduler_strong_APA_Get_self( context ); + + bool ret; + const Chain_Node *tail; + Chain_Node *next; + Scheduler_strong_APA_Node *node; + + tail = _Chain_Immutable_tail( &self->allNodes ); + next = _Chain_First( &self->allNodes ); + + ret = false; + + while ( next != tail ) { + node = (Scheduler_strong_APA_Node *) next; + + if ( + _Scheduler_SMP_Node_state( &node->Base.Base ) == SCHEDULER_SMP_NODE_READY + ) { + ret = true; + break; + } + + next = _Chain_Next( next ); + } + + return ret; +} + +static inline Scheduler_Node *_Scheduler_strong_APA_Get_highest_ready( Scheduler_Context *context, - Scheduler_Node *ready_to_scheduled -) + Scheduler_Node *filter +) //TODO { - Scheduler_strong_APA_Context *self; - Scheduler_strong_APA_Node *node; - Priority_Control insert_priority; + //Plan for this function: (Pseudo Code): + Scheduler_strong_APA_Context *self=_Scheduler_strong_APA_Get_self( context ); + + CPU *Qcpu; + Thread_Control *thread; + Per_CPU_Control *thread_cpu; + Per_CPU_Control *curr_CPU; + Per_CPU_Control *assigned_cpu; + Scheduler_Node *ret; + Priority_Control max_priority; + Priority_Control curr_priority; + Scheduler_SMP_Node_state curr_state; + const Chain_Node *tail; + Chain_Node *next; + Per_CPU_Control *queue; //Array of Cpu that serves as a queue + bool *visited; //Array of bool values each corresponding to a cpu + + //Denotes front and rear of the queue + uint32_t front; + uint32_t rear; + + front = 0; + rear = -1; + + visited = self->visited->visited; + queue = self->queue->Cpu; + + thread = filter->user; + thread_cpu = _Thread_Get_CPU( thread ); + + //Implement the BFS Algorithm for task departure + //to get the highest ready task for a particular CPU + + max_priority = _Scheduler_Node_get_priority( filter ); + max_priority = SCHEDULER_PRIORITY_PURIFY( max_priority ); + + ret = filter; + + rear = rear + 1; + queue[ rear ] = thread_cpu; + visited[ _Per_CPU_Get_index( thread_cpu ) ]=true; + + while( front <= rear ) { + curr_CPU = queue[ front ]; + front = front + 1; + + tail = _Chain_Immutable_tail( &self->allNodes ); + next = _Chain_First( &self->allNodes ); + + while ( next != tail ) { + Scheduler_strong_APA_Node *node; + node = (Scheduler_strong_APA_Node *) next; + curr_state = _Scheduler_SMP_Node_state( &node->Base.Base ); + + if ( + _Processor_mask_Is_set(&node->affinity, _Per_CPU_Get_index( curr_CPU)) + ) { + //Checks if the thread_CPU is in the affinity set of the node + + if ( curr_state == SCHEDULER_SMP_NODE_SCHEDULED) { + assigned_cpu = _Thread_Get_CPU( node->Base.Base.user ); + + if ( visited[ _Per_CPU_Get_index( assigned_cpu ) ] == false) { + Qcpu = rtems_malloc( sizeof(CPU) ); + //rtems_malloc does not return a errnum in case of failure + Qcpu->cpu=*assigned_cpu; + + _Chain_Initialize_node( &Qcpu->node ); + _Chain_Append_unprotected( &Queue, &Qcpu->node ); + //Insert thread_CPU in the Queue + visited[ _Per_CPU_Get_index (assigned_cpu) ]=true; + } + } + else if ( curr_state == SCHEDULER_SMP_NODE_READY) { + curr_priority = _Scheduler_Node_get_priority( (Scheduler_Node *) next ); + curr_priority = SCHEDULER_PRIORITY_PURIFY( curr_priority ); + + if ( curr_priorityBase.Base; + } + } + } + next = _Chain_Next( next ); + } + } + + if ( ret != filter) + { + //Backtrack on the path from + //thread_cpu to ret, shifting along every task. + + //After this, thread_cpu receives the ret task + // So the ready task ret gets scheduled as well. + } + + return ret; +} +static inline Scheduler_Node *_Scheduler_strong_APA_Get_lowest_scheduled( + Scheduler_Context *context, + Scheduler_Node *filter_base +) +{ + //Idea: BFS Algorithm for task arrival + + uint32_t cpu_max; + uint32_t cpu_index; + Priority_Control filter_priority; + + Per_CPU_Control *curr_CPU; + Per_CPU_Control *next_cpu; + Per_CPU_Control *cpu_to_preempt; + Thread_Control *curr_thread; + Scheduler_Node *curr_node; + Scheduler_Node *ret; + Priority_Control max_priority; + Priority_Control curr_priority; + + Scheduler_strong_APA_Node *curr_strong_node; //Current Strong_APA_Node + Scheduler_strong_APA_Node *filter_node; + Scheduler_strong_APA_Context *self; + Per_CPU_Control *queue; //Array of Cpu that serves as a queue + bool *visited; //Array of bool values each corresponding to a cpu. + + //Node that has a CPU in its affinity set which gets used for backtracking. + Scheduler_strong_APA_Node *caller; //Caller node for a CPU. + + //Denotes front and rear of the queue + uint32_t front; + uint32_t rear; + + front = 0; + rear = -1; + + visited = self->visited->visited; + queue = self->queue->Cpu; + caller = Caller->caller; + + filter_priority = _Scheduler_Node_get_priority( filter_base ); + filter_priority = SCHEDULER_PRIORITY_PURIFY( filter_priority ); + self = _Scheduler_strong_APA_Get_self( context ); - node = _Scheduler_strong_APA_Node_downcast( ready_to_scheduled ); - - _Scheduler_priority_Ready_queue_extract( - &node->Base.Base.Node.Chain, - &node->Ready_queue, - &self->Bit_map - ); - insert_priority = _Scheduler_SMP_Node_priority( &node->Base.Base ); - insert_priority = SCHEDULER_PRIORITY_APPEND( insert_priority ); - _Chain_Insert_ordered_unprotected( - &self->Base.Scheduled, - &node->Base.Base.Node.Chain, - &insert_priority, - _Scheduler_SMP_Priority_less_equal - ); + + ret = NULL; //To remove compiler warning. + //ret would always point to the node with the lowest priority + //node unless the affinity of filter_base is NULL. + + filter_node = _Scheduler_strong_APA_Node_downcast( filter_base ); + + max_priority_num = 0;//Max (Lowest) priority encountered so far. + + //This assert makes sure that there always exist an element in the + // Queue when we start the queue traversal. + _Assert( !_Processor_mask_Zero( &filter_node->affinity ) ); + + cpu_max = _SMP_Get_processor_maximum(); + + for ( cpu_index = 0 ; cpu_index < cpu_max ; ++cpu_index ) { + visited[ cpu_index ] = false; + + //Checks if the thread_CPU is in the affinity set of the node + if ( _Processor_mask_Is_set( &filter_node->affinity, cpu_index)) { + Per_CPU_Control *cpu = _Per_CPU_Get_by_index( cpu_index ); + + if ( _Per_CPU_Is_processor_online( cpu ) ) { + rear = rear + 1; + queue[ rear ] = cpu; + visited[ cpu_index ] = true; + caller[ cpu_index ] = filter_base; + } + } + } + + while( front <= rear ) { + curr_CPU = queue[ front ]; + front = front + 1; + + curr_thread = curr_CPU->executing; + curr_node = _Thread_Scheduler_get_home_node( curr_thread ); + + curr_priority = _Scheduler_Node_get_priority( curr_node ); + curr_priority = SCHEDULER_PRIORITY_PURIFY( curr_priority ); + + curr_strong_node = _Scheduler_strong_APA_Node_downcast( curr_node ); + + if ( curr_priority > max_priority_num) { + ret = curr_node; + max_priority_num = curr_priority; + + if( curr_priority > filter_priority) + { + cpu_to_preempt = curr_CPU; + } + } + + if ( !curr_thread->is_idle ) { + for ( cpu_index = 0 ; cpu_index < cpu_max ; ++cpu_index ) { + if ( _Processor_mask_Is_set( &Scurr_node->affinity, cpu_index ) ) { + //Checks if the thread_CPU is in the affinity set of the node + Per_CPU_Control *cpu = _Per_CPU_Get_by_index( cpu_index ); + if ( _Per_CPU_Is_processor_online( cpu ) && visited[ cpu_index ] == false ) { + rear = rear + 1; + queue[ rear ] = cpu; + visited[ cpu_index ] = true; + caller[ cpu_index ] = curr_node; + } + } + } + } + } + + if( ret->Priority.value > filter_priority ) { + //Backtrack on the path from + //_Thread_Get_CPU(ret->user) to ret, shifting along every task + + curr_node = caller[ _Per_CPU_Get_index(cpu_to_preempt) ]; + curr_cpu = _Thread_Get_CPU( curr_node->user ); + + curr_node = caller [ _Per_CPU_Get_index( curr_cpu ) ]; + curr_cpu = _Thread_Get_CPU( curr_node->user ); + + do{ + next_cpu = _Thread_Get_CPU( curr_node->user ); + + _Scheduler_SMP_Preempt( + context, + curr_node, + _Thread_Scheduler_get_home_node( curr_cpu->executing ), + _Scheduler_strong_APA_Allocate_processor + ); + + curr_cpu = _Per_CPU_Get_index( next_cpu ); + curr_node = caller[ curr_cpu ]; + + }while( curr_node != filter_base ); + + _Scheduler_SMP_Preempt( + context, + curr_node, + _Thread_Scheduler_get_home_node( curr_cpu->executing ), + _Scheduler_strong_APA_Allocate_processor + ); + + filter_base = caller[ _Per_CPU_Get_index(cpu_to_preempt) ]; + } + return ret; } -static void _Scheduler_strong_APA_Insert_ready( +static inline void _Scheduler_strong_APA_Extract_from_scheduled( Scheduler_Context *context, - Scheduler_Node *node_base, - Priority_Control insert_priority + Scheduler_Node *node_to_extract ) { Scheduler_strong_APA_Context *self; Scheduler_strong_APA_Node *node; self = _Scheduler_strong_APA_Get_self( context ); - node = _Scheduler_strong_APA_Node_downcast( node_base ); + node = _Scheduler_strong_APA_Node_downcast( node_to_extract ); - if ( SCHEDULER_PRIORITY_IS_APPEND( insert_priority ) ) { - _Scheduler_priority_Ready_queue_enqueue( - &node->Base.Base.Node.Chain, - &node->Ready_queue, - &self->Bit_map - ); - } else { - _Scheduler_priority_Ready_queue_enqueue_first( - &node->Base.Base.Node.Chain, - &node->Ready_queue, - &self->Bit_map - ); - } + _Scheduler_SMP_Extract_from_scheduled( &self->Base.Base, &node->Base.Base ); + //Not removing it from allNodes since the node could go in the ready state. } -static void _Scheduler_strong_APA_Extract_from_ready( +static inline void _Scheduler_strong_APA_Extract_from_ready( Scheduler_Context *context, - Scheduler_Node *the_thread + Scheduler_Node *node_to_extract ) { - Scheduler_strong_APA_Context *self = - _Scheduler_strong_APA_Get_self( context ); - Scheduler_strong_APA_Node *node = - _Scheduler_strong_APA_Node_downcast( the_thread ); - - _Scheduler_priority_Ready_queue_extract( - &node->Base.Base.Node.Chain, - &node->Ready_queue, - &self->Bit_map - ); + Scheduler_strong_APA_Context *self; + Scheduler_strong_APA_Node *node; + + self = _Scheduler_strong_APA_Get_self( context ); + node = _Scheduler_strong_APA_Node_downcast( node_to_extract ); + + _Assert( !_Chain_Is_empty(self->allNodes) ); + _Assert( !_Chain_Is_node_off_chain( &node->Node ) ); + + _Chain_Extract_unprotected( &node->Node ); //Removed from allNodes + _Chain_Set_off_chain( &node->Node ); } -static void _Scheduler_strong_APA_Do_update( +static inline void _Scheduler_strong_APA_Move_from_scheduled_to_ready( Scheduler_Context *context, - Scheduler_Node *node_to_update, - Priority_Control new_priority + Scheduler_Node *scheduled_to_ready ) { - Scheduler_strong_APA_Context *self = - _Scheduler_strong_APA_Get_self( context ); - Scheduler_strong_APA_Node *node = - _Scheduler_strong_APA_Node_downcast( node_to_update ); - - _Scheduler_SMP_Node_update_priority( &node->Base, new_priority ); - _Scheduler_priority_Ready_queue_update( - &node->Ready_queue, - SCHEDULER_PRIORITY_UNMAP( new_priority ), - &self->Bit_map, - &self->Ready[ 0 ] - ); -} + Priority_Control insert_priority; -static Scheduler_strong_APA_Context * -_Scheduler_strong_APA_Get_context( const Scheduler_Control *scheduler ) -{ - return (Scheduler_strong_APA_Context *) _Scheduler_Get_context( scheduler ); + _Scheduler_SMP_Extract_from_scheduled( context, scheduled_to_ready ); + insert_priority = _Scheduler_SMP_Node_priority( scheduled_to_ready ); + + _Scheduler_strong_APA_Insert_ready( + context, + scheduled_to_ready, + insert_priority + ); } -void _Scheduler_strong_APA_Initialize( const Scheduler_Control *scheduler ) +static inline void _Scheduler_strong_APA_Move_from_ready_to_scheduled( + Scheduler_Context *context, + Scheduler_Node *ready_to_scheduled +) { - Scheduler_strong_APA_Context *self = - _Scheduler_strong_APA_Get_context( scheduler ); + Priority_Control insert_priority; - _Scheduler_SMP_Initialize( &self->Base ); - _Priority_bit_map_Initialize( &self->Bit_map ); - _Scheduler_priority_Ready_queue_initialize( - &self->Ready[ 0 ], - scheduler->maximum_priority + _Scheduler_strong_APA_Extract_from_ready( context, ready_to_scheduled ); + insert_priority = _Scheduler_SMP_Node_priority( ready_to_scheduled ); + insert_priority = SCHEDULER_PRIORITY_APPEND( insert_priority ); + _Scheduler_SMP_Insert_scheduled( + context, + ready_to_scheduled, + insert_priority ); + //Note: The node still stays in the allNodes chain } -void _Scheduler_strong_APA_Node_initialize( - const Scheduler_Control *scheduler, - Scheduler_Node *node, - Thread_Control *the_thread, - Priority_Control priority +static inline void _Scheduler_strong_APA_Set_scheduled( + _Scheduler_strong_APA_Context *self, + _Scheduler_strong_APA_Node *scheduled, + const Per_CPU_Control *cpu ) { - Scheduler_Context *context; - Scheduler_strong_APA_Context *self; - Scheduler_strong_APA_Node *the_node; - - the_node = _Scheduler_strong_APA_Node_downcast( node ); - _Scheduler_SMP_Node_initialize( - scheduler, - &the_node->Base, - the_thread, - priority - ); - - context = _Scheduler_Get_context( scheduler ); - self = _Scheduler_strong_APA_Get_self( context ); - _Scheduler_priority_Ready_queue_update( - &the_node->Ready_queue, - SCHEDULER_PRIORITY_UNMAP( priority ), - &self->Bit_map, - &self->Ready[ 0 ] - ); + self->CPU[ _Per_CPU_Get_index( cpu ) ].scheduled = scheduled; } -static bool _Scheduler_strong_APA_Has_ready( Scheduler_Context *context ) +static inline Scheduler_EDF_SMP_Node *_Scheduler_strong_APA_Get_scheduled( + const _Scheduler_strong_APA_Context *self, + uint8_t cpu +) { - Scheduler_strong_APA_Context *self = - _Scheduler_strong_APA_Get_self( context ); - - return !_Priority_bit_map_Is_empty( &self->Bit_map ); + return self->CPU[ cpu ].scheduled; } -static Scheduler_Node *_Scheduler_strong_APA_Get_highest_ready( +static inline void _Scheduler_strong_APA_Insert_ready( Scheduler_Context *context, - Scheduler_Node *node + Scheduler_Node *node_base, + Priority_Control insert_priority ) { - Scheduler_strong_APA_Context *self = - _Scheduler_strong_APA_Get_self( context ); - - (void) node; + Scheduler_strong_APA_Context *self; + Scheduler_strong_APA_Node *node; - return (Scheduler_Node *) _Scheduler_priority_Ready_queue_first( - &self->Bit_map, - &self->Ready[ 0 ] - ); + self = _Scheduler_strong_APA_Get_self( context ); + node = _Scheduler_strong_APA_Node_downcast( node_base ); + + _Assert( !_Chain_Is_node_off_chain( &node->Node ) ); + + _Chain_Append_unprotected( &self->allNodes, &node->Node ); } -void _Scheduler_strong_APA_Block( - const Scheduler_Control *scheduler, - Thread_Control *the_thread, - Scheduler_Node *node +static inline void _Scheduler_strong_APA_Allocate_processor( + Scheduler_Context *context, + Scheduler_Node *scheduled_base, + Scheduler_Node *victim_base, + Per_CPU_Control *victim_cpu ) { - Scheduler_Context *context = _Scheduler_Get_context( scheduler ); + Scheduler_strong_APA_Node *scheduled; + + (void) victim_base; + scheduled = _Scheduler_strong_APA_Node_downcast( scheduled_base ); - _Scheduler_SMP_Block( + _Scheduler_SMP_Allocate_processor_exact( context, - the_thread, - node, - _Scheduler_SMP_Extract_from_scheduled, - _Scheduler_strong_APA_Extract_from_ready, - _Scheduler_strong_APA_Get_highest_ready, - _Scheduler_strong_APA_Move_from_ready_to_scheduled, - _Scheduler_SMP_Allocate_processor_exact + &(scheduled->Base.Base), + NULL, + victim_cpu ); } -static bool _Scheduler_strong_APA_Enqueue( +static inline bool _Scheduler_strong_APA_Enqueue( Scheduler_Context *context, Scheduler_Node *node, Priority_Control insert_priority ) -{ +{//I'm hoping all this works on its own. return _Scheduler_SMP_Enqueue( context, node, @@ -256,17 +484,17 @@ static bool _Scheduler_strong_APA_Enqueue( _Scheduler_strong_APA_Insert_ready, _Scheduler_SMP_Insert_scheduled, _Scheduler_strong_APA_Move_from_scheduled_to_ready, - _Scheduler_SMP_Get_lowest_scheduled, - _Scheduler_SMP_Allocate_processor_exact + _Scheduler_strong_APA_Get_lowest_scheduled, + _Scheduler_strong_APA_Allocate_processor ); } -static bool _Scheduler_strong_APA_Enqueue_scheduled( +static inline bool _Scheduler_strong_APA_Enqueue_scheduled( Scheduler_Context *context, Scheduler_Node *node, - Priority_Control insert_priority + Priority_Control insert_priority ) -{ +{ return _Scheduler_SMP_Enqueue_scheduled( context, node, @@ -277,49 +505,123 @@ static bool _Scheduler_strong_APA_Enqueue_scheduled( _Scheduler_strong_APA_Insert_ready, _Scheduler_SMP_Insert_scheduled, _Scheduler_strong_APA_Move_from_ready_to_scheduled, - _Scheduler_SMP_Allocate_processor_exact + _Scheduler_strong_APA_Allocate_processor ); } -void _Scheduler_strong_APA_Unblock( +static inline bool _Scheduler_strong_APA_Do_ask_for_help( + Scheduler_Context *context, + Thread_Control *the_thread, + Scheduler_Node *node +) +{ + return _Scheduler_SMP_Ask_for_help( + context, + the_thread, + node, + _Scheduler_SMP_Priority_less_equal, + _Scheduler_strong_APA_Insert_ready, + _Scheduler_SMP_Insert_scheduled, + _Scheduler_strong_APA_Move_from_scheduled_to_ready, + _Scheduler_strong_APA_Get_lowest_scheduled, + _Scheduler_strong_APA_Allocate_processor + ); +} + +static inline void _Scheduler_strong_APA_Register_idle( + Scheduler_Context *context, + Scheduler_Node *idle_base, + Per_CPU_Control *cpu +) +{ + (void) context; + (void) idle_base; + (void) cpu; + //We do not maintain a variable to access the scheduled + //node for a CPU. So this function does nothing. +} + +static inline void _Scheduler_strong_APA_Do_set_affinity( + Scheduler_Context *context, + Scheduler_Node *node_base, + void *arg +) +{ + Scheduler_strong_APA_Node *node; + const Processor_mask *affinity; + + node = _Scheduler_strong_APA_Node_downcast( node_base ); + affinity = arg; + node->affinity = *affinity; +} + +void _Scheduler_strong_APA_Initialize( const Scheduler_Control *scheduler ) +{ + Scheduler_strong_APA_Context *self = + _Scheduler_strong_APA_Get_context( scheduler ); + + _Scheduler_SMP_Initialize( &self->Base ); + _Chain_Initialize_empty( &self->allNodes ); +} + +void _Scheduler_strong_APA_Yield( const Scheduler_Control *scheduler, - Thread_Control *the_thread, + Thread_Control *thread, Scheduler_Node *node ) { Scheduler_Context *context = _Scheduler_Get_context( scheduler ); - _Scheduler_SMP_Unblock( + _Scheduler_SMP_Yield( context, - the_thread, + thread, node, - _Scheduler_strong_APA_Do_update, - _Scheduler_strong_APA_Enqueue + _Scheduler_strong_APA_Extract_from_ready, + _Scheduler_strong_APA_Enqueue, + _Scheduler_strong_APA_Enqueue_scheduled ); } -static bool _Scheduler_strong_APA_Do_ask_for_help( - Scheduler_Context *context, - Thread_Control *the_thread, - Scheduler_Node *node +void _Scheduler_strong_APA_Block( + const Scheduler_Control *scheduler, + Thread_Control *thread, + Scheduler_Node *node ) { - return _Scheduler_SMP_Ask_for_help( + Scheduler_Context *context = _Scheduler_Get_context( scheduler ); +//The extract from ready automatically removes the node from allNodes chain. + _Scheduler_SMP_Block( context, - the_thread, + thread, node, - _Scheduler_SMP_Priority_less_equal, - _Scheduler_strong_APA_Insert_ready, - _Scheduler_SMP_Insert_scheduled, - _Scheduler_strong_APA_Move_from_scheduled_to_ready, - _Scheduler_SMP_Get_lowest_scheduled, - _Scheduler_SMP_Allocate_processor_lazy + _Scheduler_strong_APA_Extract_from_scheduled, + _Scheduler_strong_APA_Extract_from_ready, + _Scheduler_strong_APA_Get_highest_ready, + _Scheduler_strong_APA_Move_from_ready_to_scheduled, + _Scheduler_strong_APA_Allocate_processor + ); +} + +void _Scheduler_strong_APA_Unblock( + const Scheduler_Control *scheduler, + Thread_Control *thread, + Scheduler_Node *node +) +{ + Scheduler_Context *context = _Scheduler_Get_context( scheduler ); + + _Scheduler_SMP_Unblock( + context, + thread, + node, + _Scheduler_strong_APA_Do_update, + _Scheduler_strong_APA_Enqueue ); } void _Scheduler_strong_APA_Update_priority( const Scheduler_Control *scheduler, - Thread_Control *the_thread, + Thread_Control *thread, Scheduler_Node *node ) { @@ -327,7 +629,7 @@ void _Scheduler_strong_APA_Update_priority( _Scheduler_SMP_Update_priority( context, - the_thread, + thread, node, _Scheduler_strong_APA_Extract_from_ready, _Scheduler_strong_APA_Do_update, @@ -345,7 +647,11 @@ bool _Scheduler_strong_APA_Ask_for_help( { Scheduler_Context *context = _Scheduler_Get_context( scheduler ); - return _Scheduler_strong_APA_Do_ask_for_help( context, the_thread, node ); + return _Scheduler_strong_APA_Do_ask_for_help( + context, + the_thread, + node + ); } void _Scheduler_strong_APA_Reconsider_help_request( @@ -381,10 +687,55 @@ void _Scheduler_strong_APA_Withdraw_node( _Scheduler_strong_APA_Extract_from_ready, _Scheduler_strong_APA_Get_highest_ready, _Scheduler_strong_APA_Move_from_ready_to_scheduled, - _Scheduler_SMP_Allocate_processor_lazy + _Scheduler_strong_APA_Allocate_processor ); } +void _Scheduler_strong_APA_Pin( + const Scheduler_Control *scheduler, + Thread_Control *thread, + Scheduler_Node *node_base, + struct Per_CPU_Control *cpu +) +{ + Scheduler_strong_APA_Node *node; + uint32_t pin_cpu; + + (void) scheduler; + node = _Scheduler_strong_APA_Node_downcast( node_base ); + pin_cpu = (uint32_t) _Per_CPU_Get_index( cpu ); + + _Assert( + _Scheduler_SMP_Node_state( &node->Base.Base ) == SCHEDULER_SMP_NODE_BLOCKED + ); + + node = _Scheduler_strong_APA_Node_downcast( node_base ); + + _Processor_mask_Zero( &node->affinity ); + _Processor_mask_Set( &node->affinity, pin_cpu ); +} + +void _Scheduler_strong_APA_Unpin( + const Scheduler_Control *scheduler, + Thread_Control *thread, + Scheduler_Node *node_base, + struct Per_CPU_Control *cpu +) +{ + Scheduler_strong_APA_Node *node; + + (void) scheduler; + (void) cpu; + node = _Scheduler_strong_APA_Node_downcast( node_base ); + + _Assert( + _Scheduler_SMP_Node_state( &node->Base.Base ) == SCHEDULER_SMP_NODE_BLOCKED + ); + + _Processor_mask_Zero( &node->affinity ); + _Processor_mask_Assign( &node->affinity, &node->unpin_affinity ); +} + void _Scheduler_strong_APA_Add_processor( const Scheduler_Control *scheduler, Thread_Control *idle @@ -397,7 +748,7 @@ void _Scheduler_strong_APA_Add_processor( idle, _Scheduler_strong_APA_Has_ready, _Scheduler_strong_APA_Enqueue_scheduled, - _Scheduler_SMP_Do_nothing_register_idle + _Scheduler_strong_APA_Register_idle ); } @@ -416,20 +767,76 @@ Thread_Control *_Scheduler_strong_APA_Remove_processor( ); } -void _Scheduler_strong_APA_Yield( +void _Scheduler_strong_APA_Node_initialize( const Scheduler_Control *scheduler, + Scheduler_Node *node, Thread_Control *the_thread, - Scheduler_Node *node + Priority_Control priority ) { - Scheduler_Context *context = _Scheduler_Get_context( scheduler ); + Scheduler_SMP_Node *smp_node; + + smp_node = _Scheduler_SMP_Node_downcast( node ); + _Scheduler_SMP_Node_initialize( scheduler, smp_node, the_thread, priority ); +} - _Scheduler_SMP_Yield( +void _Scheduler_strong_APA_Start_idle( + const Scheduler_Control *scheduler, + Thread_Control *idle, + Per_CPU_Control *cpu +) +{ + Scheduler_Context *context; + + context = _Scheduler_Get_context( scheduler ); + + _Scheduler_SMP_Do_start_idle( context, - the_thread, - node, - _Scheduler_strong_APA_Extract_from_ready, - _Scheduler_strong_APA_Enqueue, - _Scheduler_strong_APA_Enqueue_scheduled + idle, + cpu, + _Scheduler_strong_APA_Register_idle ); } + +bool _Scheduler_strong_APA_Set_affinity( + const Scheduler_Control *scheduler, + Thread_Control *thread, + Scheduler_Node *node_base, + const Processor_mask *affinity +) +{ + Scheduler_Context *context; + Scheduler_strong_APA_Node *node; + Processor_mask local_affinity; + + context = _Scheduler_Get_context( scheduler ); + _Processor_mask_And( &local_affinity, &context->Processors, affinity ); + + if ( _Processor_mask_Is_zero( &local_affinity ) ) { + return false; + } + + node = _Scheduler_strong_APA_Node_downcast( node_base ); + + if ( _Processor_mask_Is_equal( &node->affinity, affinity ) ) + return true; //Nothing to do. Return true. + + _Processor_mask_Assign( &node->affinity, &local_affinity ); + _Processor_mask_Assign( &node->unpin_affinity, &local_affinity ); + + _Scheduler_SMP_Set_affinity( + context, + thread, + node_base, + &local_affinity, + _Scheduler_strong_APA_Do_set_affinity, + _Scheduler_strong_APA_Extract_from_ready, + _Scheduler_strong_APA_Get_highest_ready, + _Scheduler_strong_APA_Move_from_ready_to_scheduled, + _Scheduler_strong_APA_Enqueue, + _Scheduler_strong_APA_Allocate_processor + ); + + return true; +} +