diff options
Diffstat (limited to 'cpukit/include/rtems/score/schedulerimpl.h')
-rw-r--r-- | cpukit/include/rtems/score/schedulerimpl.h | 276 |
1 files changed, 99 insertions, 177 deletions
diff --git a/cpukit/include/rtems/score/schedulerimpl.h b/cpukit/include/rtems/score/schedulerimpl.h index eb279876c7..12b6806402 100644 --- a/cpukit/include/rtems/score/schedulerimpl.h +++ b/cpukit/include/rtems/score/schedulerimpl.h @@ -798,26 +798,26 @@ RTEMS_INLINE_ROUTINE uint32_t _Scheduler_Get_index( #if defined(RTEMS_SMP) /** - * @brief Gets an idle thread from the scheduler instance. + * @brief Gets a scheduler node which is owned by an unused idle thread. * - * @param context The scheduler instance context. + * @param arg is the handler argument. * - * @return idle An idle thread for use. This function must always return an - * idle thread. If none is available, then this is a fatal error. + * @return Returns a scheduler node owned by an idle thread for use. This + * handler must always return a node. If none is available, then this is a + * fatal error. */ -typedef Thread_Control *( *Scheduler_Get_idle_thread )( - Scheduler_Context *context -); +typedef Scheduler_Node *( *Scheduler_Get_idle_node )( void *arg ); /** - * @brief Releases an idle thread to the scheduler instance for reuse. + * @brief Releases the scheduler node which is owned by an idle thread. * - * @param context The scheduler instance context. - * @param idle The idle thread to release. + * @param node is the node to release. + * + * @param arg is the handler argument. */ -typedef void ( *Scheduler_Release_idle_thread )( - Scheduler_Context *context, - Thread_Control *idle +typedef void ( *Scheduler_Release_idle_node )( + Scheduler_Node *node, + void *arg ); /** @@ -841,189 +841,114 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Thread_change_state( } /** - * @brief Uses an idle thread for this scheduler node. + * @brief Uses an idle thread for the scheduler node. * - * A thread whose home scheduler node has a sticky level greater than zero may - * use an idle thread in the home scheduler instance in the case it executes - * currently in another scheduler instance or in the case it is in a blocking - * state. + * @param[in, out] node is the node which wants to use an idle thread. * - * @param context The scheduler instance context. - * @param[in, out] node The node which wants to use the idle thread. - * @param cpu The processor for the idle thread. - * @param get_idle_thread Function to get an idle thread. + * @param get_idle_node is the get idle node handler. + * + * @param arg is the handler argument. */ RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_Use_idle_thread( - Scheduler_Context *context, - Scheduler_Node *node, - Scheduler_Get_idle_thread get_idle_thread + Scheduler_Node *node, + Scheduler_Get_idle_node get_idle_node, + void *arg ) { - Thread_Control *idle = ( *get_idle_thread )( context ); + Scheduler_Node *idle_node; + Thread_Control *idle; + idle_node = ( *get_idle_node )( arg ); + idle = _Scheduler_Node_get_owner( idle_node ); + _Assert( idle->is_idle ); _Scheduler_Node_set_idle_user( node, idle ); + return idle; } /** - * @brief This enumeration defines what a scheduler should do with a node which - * could be scheduled. - */ -typedef enum { - SCHEDULER_TRY_TO_SCHEDULE_DO_SCHEDULE, - SCHEDULER_TRY_TO_SCHEDULE_DO_IDLE_EXCHANGE, - SCHEDULER_TRY_TO_SCHEDULE_DO_BLOCK -} Scheduler_Try_to_schedule_action; - -/** - * @brief Tries to schedule the scheduler node. - * - * When a scheduler needs to schedule a node, it shall use this function to - * determine what it shall do with the node. The node replaces a victim node if - * it can be scheduled. - * - * This function uses the state of the node and the scheduler state of the owner - * thread to determine what shall be done. Each scheduler maintains its nodes - * independent of other schedulers. This function ensures that a thread is - * scheduled by at most one scheduler. If a node requires an executing thread - * due to some locking protocol and the owner thread is already scheduled by - * another scheduler, then an idle thread shall be attached to the node. - * - * @param[in, out] context is the scheduler context. - * @param[in, out] node is the node which could be scheduled. - * @param idle is an idle thread used by the victim node or NULL. - * @param get_idle_thread points to a function to get an idle thread. - * - * @retval SCHEDULER_TRY_TO_SCHEDULE_DO_SCHEDULE The node shall be scheduled. - * - * @retval SCHEDULER_TRY_TO_SCHEDULE_DO_IDLE_EXCHANGE The node shall be - * scheduled and the provided idle thread shall be attached to the node. This - * action is returned, if the node cannot use the owner thread and shall use - * an idle thread instead. In this case, the idle thread is provided by the - * victim node. - * - * @retval SCHEDULER_TRY_TO_SCHEDULE_DO_BLOCK The node shall be blocked. This - * action is returned, if the owner thread is already scheduled by another - * scheduler. + * @brief Releases the idle thread used by the scheduler node. + * + * @param[in, out] node is the node which wants to release the idle thread. + * + * @param idle is the idle thread to release. + * + * @param release_idle_node is the release idle node handler. + * + * @param arg is the handler argument. */ -RTEMS_INLINE_ROUTINE Scheduler_Try_to_schedule_action -_Scheduler_Try_to_schedule_node( - Scheduler_Context *context, - Scheduler_Node *node, - Scheduler_Node *victim, - Scheduler_Get_idle_thread get_idle_thread +RTEMS_INLINE_ROUTINE void _Scheduler_Release_idle_thread( + Scheduler_Node *node, + const Thread_Control *idle, + Scheduler_Release_idle_node release_idle_node, + void *arg ) { - ISR_lock_Context lock_context; - Scheduler_Try_to_schedule_action action; - Thread_Control *owner; + Thread_Control *owner; + Scheduler_Node *idle_node; - action = SCHEDULER_TRY_TO_SCHEDULE_DO_SCHEDULE; owner = _Scheduler_Node_get_owner( node ); - _Assert( _Scheduler_Node_get_user( node ) == owner ); - _Assert( _Scheduler_Node_get_idle( node ) == NULL ); - - _Thread_Scheduler_acquire_critical( owner, &lock_context ); - - if ( owner->Scheduler.state == THREAD_SCHEDULER_READY ) { - _Thread_Scheduler_cancel_need_for_help( owner, _Thread_Get_CPU( owner ) ); - _Scheduler_Thread_change_state( owner, THREAD_SCHEDULER_SCHEDULED ); - } else if ( - owner->Scheduler.state == THREAD_SCHEDULER_SCHEDULED - && node->sticky_level <= 1 - ) { - action = SCHEDULER_TRY_TO_SCHEDULE_DO_BLOCK; - } else if ( node->sticky_level == 0 ) { - action = SCHEDULER_TRY_TO_SCHEDULE_DO_BLOCK; - } else if ( _Scheduler_Node_get_idle( victim ) != NULL ) { - action = SCHEDULER_TRY_TO_SCHEDULE_DO_IDLE_EXCHANGE; - } else { - Thread_Control *idle; - Thread_Control *user; - - idle = _Scheduler_Use_idle_thread( context, node, get_idle_thread ); - user = _Scheduler_Node_get_user( node ); - _Thread_Set_CPU( idle, _Thread_Get_CPU( user ) ); - } - - _Thread_Scheduler_release_critical( owner, &lock_context ); - return action; + _Assert( _Scheduler_Node_get_user( node ) == idle ); + _Scheduler_Node_set_user( node, owner ); + node->idle = NULL; + idle_node = _Thread_Scheduler_get_home_node( idle ); + ( *release_idle_node )( idle_node, arg ); } /** - * @brief Releases an idle thread using this scheduler node. + * @brief Releases the idle thread used by the scheduler node if the node uses + * an idle thread. * - * @param context The scheduler instance context. - * @param[in, out] node The node which may have an idle thread as user. - * @param release_idle_thread Function to release an idle thread. + * @param[in, out] node is the node which wants to release the idle thread. + * + * @param release_idle_node is the release idle node handler. + * + * @param arg is the handler argument. + * + * @retval NULL The scheduler node did not use an idle thread. * - * @retval idle The idle thread which used this node. - * @retval NULL This node had no idle thread as an user. + * @return Returns the idle thread used by the scheduler node. */ -RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_Release_idle_thread( - Scheduler_Context *context, - Scheduler_Node *node, - Scheduler_Release_idle_thread release_idle_thread +RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_Release_idle_thread_if_necessary( + Scheduler_Node *node, + Scheduler_Release_idle_node release_idle_node, + void *arg ) { - Thread_Control *idle = _Scheduler_Node_get_idle( node ); + Thread_Control *idle; - if ( idle != NULL ) { - Thread_Control *owner = _Scheduler_Node_get_owner( node ); + idle = _Scheduler_Node_get_idle( node ); - node->idle = NULL; - _Scheduler_Node_set_user( node, owner ); - ( *release_idle_thread )( context, idle ); + if ( idle != NULL ) { + _Scheduler_Release_idle_thread( node, idle, release_idle_node, arg ); } return idle; } /** - * @brief Exchanges an idle thread from the scheduler node that uses it - * right now to another scheduler node. - * - * @param needs_idle is the scheduler node that needs an idle thread. - * - * @param uses_idle is the scheduler node that used the idle thread. - */ -RTEMS_INLINE_ROUTINE void _Scheduler_Exchange_idle_thread( - Scheduler_Node *needs_idle, - Scheduler_Node *uses_idle -) -{ - _Scheduler_Node_set_idle_user( - needs_idle, - _Scheduler_Node_get_idle( uses_idle ) - ); - _Scheduler_Node_set_user( - uses_idle, - _Scheduler_Node_get_owner( uses_idle ) - ); - uses_idle->idle = NULL; -} - -/** * @brief Blocks this scheduler node. * - * @param context The scheduler instance context. * @param[in, out] thread The thread which wants to get blocked referencing this * node. This is not necessarily the user of this node in case the node * participates in the scheduler helping protocol. - * @param[in, out] node The node which wants to get blocked. - * @param is_scheduled This node is scheduled. - * @param get_idle_thread Function to get an idle thread. + * + * @param[in, out] node is the node which wants to get blocked. + * + * @param get_idle_node is the get idle node handler. + * + * @param arg is the get idle node handler argument. * * @retval thread_cpu The processor of the thread. Indicates to continue with * the blocking operation. * @retval NULL Otherwise. */ RTEMS_INLINE_ROUTINE Per_CPU_Control *_Scheduler_Block_node( - Scheduler_Context *context, - Thread_Control *thread, - Scheduler_Node *node, - bool is_scheduled, - Scheduler_Get_idle_thread get_idle_thread + Thread_Control *thread, + Scheduler_Node *node, + bool is_scheduled, + Scheduler_Get_idle_node get_idle_node, + void *arg ) { int sticky_level; @@ -1045,7 +970,7 @@ RTEMS_INLINE_ROUTINE Per_CPU_Control *_Scheduler_Block_node( if ( is_scheduled && _Scheduler_Node_get_idle( node ) == NULL ) { Thread_Control *idle; - idle = _Scheduler_Use_idle_thread( context, node, get_idle_thread ); + idle = _Scheduler_Use_idle_thread( node, get_idle_node, arg ); _Thread_Set_CPU( idle, thread_cpu ); _Thread_Dispatch_update_heir( _Per_CPU_Get(), thread_cpu, idle ); } @@ -1058,31 +983,28 @@ RTEMS_INLINE_ROUTINE Per_CPU_Control *_Scheduler_Block_node( } /** - * @brief Discard the idle thread from the scheduler node. + * @brief Discards the idle thread used by the scheduler node. + * + * @param[in, out] the_thread is the thread owning the node. + * + * @param[in, out] node is the node which wants to release the idle thread. + * + * @param release_idle_node is the release idle node handler. * - * @param context The scheduler context. - * @param[in, out] the_thread The thread for the operation. - * @param[in, out] node The scheduler node to discard the idle thread from. - * @param release_idle_thread Method to release the idle thread from the context. + * @param arg is the handler argument. */ RTEMS_INLINE_ROUTINE void _Scheduler_Discard_idle_thread( - Scheduler_Context *context, - Thread_Control *the_thread, - Scheduler_Node *node, - Scheduler_Release_idle_thread release_idle_thread + Thread_Control *the_thread, + Scheduler_Node *node, + Scheduler_Release_idle_node release_idle_node, + void *arg ) { Thread_Control *idle; - Thread_Control *owner; Per_CPU_Control *cpu; idle = _Scheduler_Node_get_idle( node ); - owner = _Scheduler_Node_get_owner( node ); - - node->idle = NULL; - _Assert( _Scheduler_Node_get_user( node ) == idle ); - _Scheduler_Node_set_user( node, owner ); - ( *release_idle_thread )( context, idle ); + _Scheduler_Release_idle_thread( node, idle, release_idle_node, arg ); cpu = _Thread_Get_CPU( idle ); _Thread_Set_CPU( the_thread, cpu ); @@ -1102,11 +1024,11 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Discard_idle_thread( * @retval false Do not continue with the unblocking operation. */ RTEMS_INLINE_ROUTINE bool _Scheduler_Unblock_node( - Scheduler_Context *context, - Thread_Control *the_thread, - Scheduler_Node *node, - bool is_scheduled, - Scheduler_Release_idle_thread release_idle_thread + Thread_Control *the_thread, + Scheduler_Node *node, + bool is_scheduled, + Scheduler_Release_idle_node release_idle_node, + void *arg ) { bool unblock; @@ -1115,13 +1037,13 @@ RTEMS_INLINE_ROUTINE bool _Scheduler_Unblock_node( _Assert( node->sticky_level > 0 ); if ( is_scheduled ) { + _Scheduler_Thread_change_state( the_thread, THREAD_SCHEDULER_SCHEDULED ); _Scheduler_Discard_idle_thread( - context, the_thread, node, - release_idle_thread + release_idle_node, + arg ); - _Scheduler_Thread_change_state( the_thread, THREAD_SCHEDULER_SCHEDULED ); unblock = false; } else { _Scheduler_Thread_change_state( the_thread, THREAD_SCHEDULER_READY ); |