diff options
Diffstat (limited to 'cpukit/include/rtems/score/schedulerimpl.h')
-rw-r--r-- | cpukit/include/rtems/score/schedulerimpl.h | 629 |
1 files changed, 131 insertions, 498 deletions
diff --git a/cpukit/include/rtems/score/schedulerimpl.h b/cpukit/include/rtems/score/schedulerimpl.h index 98f8e337fd..2ca3e6e8b7 100644 --- a/cpukit/include/rtems/score/schedulerimpl.h +++ b/cpukit/include/rtems/score/schedulerimpl.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /** * @file * @@ -10,11 +12,28 @@ /* * Copyright (C) 2010 Gedare Bloom. * Copyright (C) 2011 On-Line Applications Research Corporation (OAR). - * Copyright (c) 2014, 2017 embedded brains GmbH - * - * 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. + * Copyright (C) 2014, 2017 embedded brains GmbH & Co. KG + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. */ #ifndef _RTEMS_SCORE_SCHEDULERIMPL_H @@ -82,7 +101,7 @@ void _Scheduler_Handler_initialization( void ); * * @return The context of @a scheduler. */ -RTEMS_INLINE_ROUTINE Scheduler_Context *_Scheduler_Get_context( +static inline Scheduler_Context *_Scheduler_Get_context( const Scheduler_Control *scheduler ) { @@ -96,7 +115,7 @@ RTEMS_INLINE_ROUTINE Scheduler_Context *_Scheduler_Get_context( * * @return The scheduler for the cpu. */ -RTEMS_INLINE_ROUTINE const Scheduler_Control *_Scheduler_Get_by_CPU( +static inline const Scheduler_Control *_Scheduler_Get_by_CPU( const Per_CPU_Control *cpu ) { @@ -116,7 +135,7 @@ RTEMS_INLINE_ROUTINE const Scheduler_Control *_Scheduler_Get_by_CPU( * @param lock_context The lock context to use for * _Scheduler_Release_critical(). */ -RTEMS_INLINE_ROUTINE void _Scheduler_Acquire_critical( +static inline void _Scheduler_Acquire_critical( const Scheduler_Control *scheduler, ISR_lock_Context *lock_context ) @@ -140,7 +159,7 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Acquire_critical( * @param lock_context The lock context used for * _Scheduler_Acquire_critical(). */ -RTEMS_INLINE_ROUTINE void _Scheduler_Release_critical( +static inline void _Scheduler_Release_critical( const Scheduler_Control *scheduler, ISR_lock_Context *lock_context ) @@ -166,7 +185,7 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Release_critical( * @return True if the non-preempt mode for threads is supported by the * scheduler, otherwise false. */ -RTEMS_INLINE_ROUTINE bool _Scheduler_Is_non_preempt_mode_supported( +static inline bool _Scheduler_Is_non_preempt_mode_supported( const Scheduler_Control *scheduler ) { @@ -174,30 +193,6 @@ RTEMS_INLINE_ROUTINE bool _Scheduler_Is_non_preempt_mode_supported( } #endif -#if defined(RTEMS_SMP) -void _Scheduler_Request_ask_for_help( Thread_Control *the_thread ); - -/** - * @brief Registers an ask for help request if necessary. - * - * The actual ask for help operation is carried out during - * _Thread_Do_dispatch() on a processor related to the thread. This yields a - * better separation of scheduler instances. A thread of one scheduler - * instance should not be forced to carry out too much work for threads on - * other scheduler instances. - * - * @param the_thread The thread in need for help. - */ -RTEMS_INLINE_ROUTINE void _Scheduler_Ask_for_help( Thread_Control *the_thread ) -{ - _Assert( _Thread_State_is_owner( the_thread ) ); - - if ( the_thread->Scheduler.helping_nodes > 0 ) { - _Scheduler_Request_ask_for_help( the_thread ); - } -} -#endif - /** * The preferred method to add a new scheduler is to define the jump table * entries and add a case to the _Scheduler_Initialize routine. @@ -221,7 +216,7 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Ask_for_help( Thread_Control *the_thread ) * * @param the_thread The thread which state changed previously. */ -RTEMS_INLINE_ROUTINE void _Scheduler_Schedule( Thread_Control *the_thread ) +static inline void _Scheduler_Schedule( Thread_Control *the_thread ) { const Scheduler_Control *scheduler; ISR_lock_Context lock_context; @@ -242,7 +237,7 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Schedule( Thread_Control *the_thread ) * * @param the_thread The yielding thread. */ -RTEMS_INLINE_ROUTINE void _Scheduler_Yield( Thread_Control *the_thread ) +static inline void _Scheduler_Yield( Thread_Control *the_thread ) { const Scheduler_Control *scheduler; ISR_lock_Context lock_context; @@ -267,7 +262,7 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Yield( Thread_Control *the_thread ) * * @param the_thread The thread. */ -RTEMS_INLINE_ROUTINE void _Scheduler_Block( Thread_Control *the_thread ) +static inline void _Scheduler_Block( Thread_Control *the_thread ) { #if defined(RTEMS_SMP) Chain_Node *node; @@ -329,7 +324,7 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Block( Thread_Control *the_thread ) * * @see _Scheduler_Node_get_priority(). */ -RTEMS_INLINE_ROUTINE void _Scheduler_Unblock( Thread_Control *the_thread ) +static inline void _Scheduler_Unblock( Thread_Control *the_thread ) { Scheduler_Node *scheduler_node; const Scheduler_Control *scheduler; @@ -364,7 +359,7 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Unblock( Thread_Control *the_thread ) * * @see _Scheduler_Node_get_priority(). */ -RTEMS_INLINE_ROUTINE void _Scheduler_Update_priority( Thread_Control *the_thread ) +static inline void _Scheduler_Update_priority( Thread_Control *the_thread ) { #if defined(RTEMS_SMP) Chain_Node *node; @@ -405,65 +400,6 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Update_priority( Thread_Control *the_thread #endif } -#if defined(RTEMS_SMP) -/** - * @brief Changes the sticky level of the home scheduler node and propagates a - * priority change of a thread to the scheduler. - * - * @param the_thread The thread changing its priority or sticky level. - * - * @see _Scheduler_Update_priority(). - */ -RTEMS_INLINE_ROUTINE void _Scheduler_Priority_and_sticky_update( - Thread_Control *the_thread, - int sticky_level_change -) -{ - Chain_Node *node; - const Chain_Node *tail; - Scheduler_Node *scheduler_node; - const Scheduler_Control *scheduler; - ISR_lock_Context lock_context; - - _Thread_Scheduler_process_requests( the_thread ); - - node = _Chain_First( &the_thread->Scheduler.Scheduler_nodes ); - scheduler_node = SCHEDULER_NODE_OF_THREAD_SCHEDULER_NODE( node ); - scheduler = _Scheduler_Node_get_scheduler( scheduler_node ); - - _Scheduler_Acquire_critical( scheduler, &lock_context ); - - scheduler_node->sticky_level += sticky_level_change; - _Assert( scheduler_node->sticky_level >= 0 ); - - ( *scheduler->Operations.update_priority )( - scheduler, - the_thread, - scheduler_node - ); - - _Scheduler_Release_critical( scheduler, &lock_context ); - - tail = _Chain_Immutable_tail( &the_thread->Scheduler.Scheduler_nodes ); - node = _Chain_Next( node ); - - while ( node != tail ) { - scheduler_node = SCHEDULER_NODE_OF_THREAD_SCHEDULER_NODE( node ); - scheduler = _Scheduler_Node_get_scheduler( scheduler_node ); - - _Scheduler_Acquire_critical( scheduler, &lock_context ); - ( *scheduler->Operations.update_priority )( - scheduler, - the_thread, - scheduler_node - ); - _Scheduler_Release_critical( scheduler, &lock_context ); - - node = _Chain_Next( node ); - } -} -#endif - /** * @brief Maps a thread priority from the user domain to the scheduler domain. * @@ -477,7 +413,7 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Priority_and_sticky_update( * * @return The corresponding thread priority of the scheduler domain is returned. */ -RTEMS_INLINE_ROUTINE Priority_Control _Scheduler_Map_priority( +static inline Priority_Control _Scheduler_Map_priority( const Scheduler_Control *scheduler, Priority_Control priority ) @@ -493,7 +429,7 @@ RTEMS_INLINE_ROUTINE Priority_Control _Scheduler_Map_priority( * * @return The corresponding thread priority of the user domain is returned. */ -RTEMS_INLINE_ROUTINE Priority_Control _Scheduler_Unmap_priority( +static inline Priority_Control _Scheduler_Unmap_priority( const Scheduler_Control *scheduler, Priority_Control priority ) @@ -514,7 +450,7 @@ RTEMS_INLINE_ROUTINE Priority_Control _Scheduler_Unmap_priority( * @param the_thread The thread of the scheduler node to initialize. * @param priority The thread priority. */ -RTEMS_INLINE_ROUTINE void _Scheduler_Node_initialize( +static inline void _Scheduler_Node_initialize( const Scheduler_Control *scheduler, Scheduler_Node *node, Thread_Control *the_thread, @@ -538,7 +474,7 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Node_initialize( * @param scheduler The scheduler instance. * @param[out] node The scheduler node to destroy. */ -RTEMS_INLINE_ROUTINE void _Scheduler_Node_destroy( +static inline void _Scheduler_Node_destroy( const Scheduler_Control *scheduler, Scheduler_Node *node ) @@ -555,7 +491,7 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Node_destroy( * @param queue_context The thread queue context to provide the set of * threads for _Thread_Priority_update(). */ -RTEMS_INLINE_ROUTINE void _Scheduler_Release_job( +static inline void _Scheduler_Release_job( Thread_Control *the_thread, Priority_Node *priority_node, uint64_t deadline, @@ -582,7 +518,7 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Release_job( * @param queue_context The thread queue context to provide the set of * threads for _Thread_Priority_update(). */ -RTEMS_INLINE_ROUTINE void _Scheduler_Cancel_job( +static inline void _Scheduler_Cancel_job( Thread_Control *the_thread, Priority_Node *priority_node, Thread_queue_Context *queue_context @@ -600,44 +536,6 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Cancel_job( } /** - * @brief Scheduler method invoked at each clock tick. - * - * This method is invoked at each clock tick to allow the scheduler - * implementation to perform any activities required. For the - * scheduler which support standard RTEMS features, this includes - * time-slicing management. - * - * @param cpu The cpu control for the operation. - */ -RTEMS_INLINE_ROUTINE void _Scheduler_Tick( const Per_CPU_Control *cpu ) -{ - const Scheduler_Control *scheduler; - Thread_Control *executing; - - scheduler = _Scheduler_Get_by_CPU( cpu ); - -#if defined(RTEMS_SMP) - if ( scheduler == NULL ) { - /* - * In SMP configurations, processors may be removed/added at runtime - * from/to a scheduler. There may be still clock interrupts on currently - * unassigned processors. - */ - return; - } -#endif - - /* - * Each online processor has at least an idle thread as the executing thread - * even in case it has currently no scheduler assigned. Clock interrupts on - * processors which are not online would be a severe bug of the Clock Driver. - */ - executing = _Per_CPU_Get_executing( cpu ); - _Assert( executing != NULL ); - ( *scheduler->Operations.tick )( scheduler, executing ); -} - -/** * @brief Starts the idle thread for a particular processor. * * @param scheduler The scheduler instance. @@ -646,7 +544,7 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Tick( const Per_CPU_Control *cpu ) * * @see _Thread_Create_idle(). */ -RTEMS_INLINE_ROUTINE void _Scheduler_Start_idle( +static inline void _Scheduler_Start_idle( const Scheduler_Control *scheduler, Thread_Control *the_thread, Per_CPU_Control *cpu @@ -665,7 +563,7 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Start_idle( * @retval true The scheduler of the cpu is the given @a scheduler. * @retval false The scheduler of the cpu is not the given @a scheduler. */ -RTEMS_INLINE_ROUTINE bool _Scheduler_Has_processor_ownership( +static inline bool _Scheduler_Has_processor_ownership( const Scheduler_Control *scheduler, uint32_t cpu_index ) @@ -693,7 +591,7 @@ RTEMS_INLINE_ROUTINE bool _Scheduler_Has_processor_ownership( * * @return The processors of the context of the given scheduler. */ -RTEMS_INLINE_ROUTINE const Processor_mask *_Scheduler_Get_processors( +static inline const Processor_mask *_Scheduler_Get_processors( const Scheduler_Control *scheduler ) { @@ -734,7 +632,7 @@ Status_Control _Scheduler_Get_affinity( * @retval STATUS_INVALID_NUMBER The affinity is not a subset of the online * processors. */ -RTEMS_INLINE_ROUTINE Status_Control _Scheduler_default_Set_affinity_body( +static inline Status_Control _Scheduler_default_Set_affinity_body( const Scheduler_Control *scheduler, Thread_Control *the_thread, Scheduler_Node *node, @@ -771,47 +669,13 @@ Status_Control _Scheduler_Set_affinity( ); /** - * @brief Blocks the thread. - * - * @param scheduler The scheduler instance. - * @param the_thread The thread to block. - * @param node The corresponding scheduler node. - * @param extract Method to extract the thread. - * @param schedule Method for scheduling threads. - */ -RTEMS_INLINE_ROUTINE void _Scheduler_Generic_block( - const Scheduler_Control *scheduler, - Thread_Control *the_thread, - Scheduler_Node *node, - void ( *extract )( - const Scheduler_Control *, - Thread_Control *, - Scheduler_Node * - ), - void ( *schedule )( - const Scheduler_Control *, - Thread_Control *, - bool - ) -) -{ - ( *extract )( scheduler, the_thread, node ); - - /* TODO: flash critical section? */ - - if ( _Thread_Is_executing( the_thread ) || _Thread_Is_heir( the_thread ) ) { - ( *schedule )( scheduler, the_thread, true ); - } -} - -/** * @brief Gets the number of processors of the scheduler. * * @param scheduler The scheduler instance to get the number of processors of. * * @return The number of processors. */ -RTEMS_INLINE_ROUTINE uint32_t _Scheduler_Get_processor_count( +static inline uint32_t _Scheduler_Get_processor_count( const Scheduler_Control *scheduler ) { @@ -833,7 +697,7 @@ RTEMS_INLINE_ROUTINE uint32_t _Scheduler_Get_processor_count( * * @return The build id. */ -RTEMS_INLINE_ROUTINE Objects_Id _Scheduler_Build_id( uint32_t scheduler_index ) +static inline Objects_Id _Scheduler_Build_id( uint32_t scheduler_index ) { return _Objects_Build_id( OBJECTS_FAKE_OBJECTS_API, @@ -850,7 +714,7 @@ RTEMS_INLINE_ROUTINE Objects_Id _Scheduler_Build_id( uint32_t scheduler_index ) * * @return The scheduler index. */ -RTEMS_INLINE_ROUTINE uint32_t _Scheduler_Get_index_by_id( Objects_Id id ) +static inline uint32_t _Scheduler_Get_index_by_id( Objects_Id id ) { uint32_t minimum_id = _Scheduler_Build_id( 0 ); @@ -864,7 +728,7 @@ RTEMS_INLINE_ROUTINE uint32_t _Scheduler_Get_index_by_id( Objects_Id id ) * * @return The scheduler to the object id. */ -RTEMS_INLINE_ROUTINE const Scheduler_Control *_Scheduler_Get_by_id( +static inline const Scheduler_Control *_Scheduler_Get_by_id( Objects_Id id ) { @@ -886,7 +750,7 @@ RTEMS_INLINE_ROUTINE const Scheduler_Control *_Scheduler_Get_by_id( * * @return The index of the given scheduler. */ -RTEMS_INLINE_ROUTINE uint32_t _Scheduler_Get_index( +static inline uint32_t _Scheduler_Get_index( const Scheduler_Control *scheduler ) { @@ -895,26 +759,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 node is the node to release. * - * @param context The scheduler instance context. - * @param idle The idle thread 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 ); /** @@ -923,7 +787,7 @@ typedef void ( *Scheduler_Release_idle_thread )( * @param[out] the_thread The thread to change the state of. * @param new_state The new state for @a the_thread. */ -RTEMS_INLINE_ROUTINE void _Scheduler_Thread_change_state( +static inline void _Scheduler_Thread_change_state( Thread_Control *the_thread, Thread_Scheduler_state new_state ) @@ -938,353 +802,122 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Thread_change_state( } /** - * @brief Sets the scheduler node's idle thread. + * @brief Uses an idle thread for the scheduler node. * - * @param[in, out] node The node to receive an idle thread. - * @param idle The idle thread control for the operation. - */ -RTEMS_INLINE_ROUTINE void _Scheduler_Set_idle_thread( - Scheduler_Node *node, - Thread_Control *idle -) -{ - _Assert( _Scheduler_Node_get_idle( node ) == NULL ); - _Assert( - _Scheduler_Node_get_owner( node ) == _Scheduler_Node_get_user( node ) - ); - - _Scheduler_Node_set_user( node, idle ); - node->idle = idle; -} - -/** - * @brief Uses an idle thread for this scheduler node. + * @param[in, out] node is the node which wants to use an idle thread. * - * 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 get_idle_node is the get idle node handler. * - * @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 arg is the handler argument. */ -RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_Use_idle_thread( - Scheduler_Context *context, - Scheduler_Node *node, - Per_CPU_Control *cpu, - Scheduler_Get_idle_thread get_idle_thread +static inline Thread_Control *_Scheduler_Use_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 ); - _Scheduler_Set_idle_thread( node, idle ); - _Thread_Set_CPU( idle, cpu ); 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, - const Thread_Control *idle, - Scheduler_Get_idle_thread get_idle_thread +static inline 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 ( idle != NULL ) { - action = SCHEDULER_TRY_TO_SCHEDULE_DO_IDLE_EXCHANGE; - } else { - _Scheduler_Use_idle_thread( - context, - node, - _Thread_Get_CPU( owner ), - get_idle_thread - ); - } - - _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. * - * @retval idle The idle thread which used this node. - * @retval NULL This node had no idle thread as an user. + * @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. + * + * @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 +static inline 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. + * @brief Discards the idle thread used by the scheduler node. * - * @param needs_idle The scheduler node that needs an idle thread. - * @param uses_idle The scheduler node that used the idle thread. - * @param idle The idle thread that is exchanged. - */ -RTEMS_INLINE_ROUTINE void _Scheduler_Exchange_idle_thread( - Scheduler_Node *needs_idle, - Scheduler_Node *uses_idle, - Thread_Control *idle -) -{ - uses_idle->idle = NULL; - _Scheduler_Node_set_user( - uses_idle, - _Scheduler_Node_get_owner( uses_idle ) - ); - _Scheduler_Set_idle_thread( needs_idle, idle ); -} - -/** - * @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. - * - * @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 -) -{ - int sticky_level; - ISR_lock_Context lock_context; - Per_CPU_Control *thread_cpu; - - sticky_level = node->sticky_level; - --sticky_level; - node->sticky_level = sticky_level; - _Assert( sticky_level >= 0 ); - - _Thread_Scheduler_acquire_critical( thread, &lock_context ); - thread_cpu = _Thread_Get_CPU( thread ); - _Thread_Scheduler_cancel_need_for_help( thread, thread_cpu ); - _Scheduler_Thread_change_state( thread, THREAD_SCHEDULER_BLOCKED ); - _Thread_Scheduler_release_critical( thread, &lock_context ); - - if ( sticky_level > 0 ) { - if ( is_scheduled && _Scheduler_Node_get_idle( node ) == NULL ) { - Thread_Control *idle; - - idle = _Scheduler_Use_idle_thread( - context, - node, - thread_cpu, - get_idle_thread - ); - _Thread_Dispatch_update_heir( _Per_CPU_Get(), thread_cpu, idle ); - } - - return NULL; - } - - _Assert( thread == _Scheduler_Node_get_user( node ) ); - return thread_cpu; -} - -/** - * @brief Discard the idle thread from 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 +static inline void _Scheduler_Discard_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 ); _Thread_Dispatch_update_heir( _Per_CPU_Get(), cpu, the_thread ); } - -/** - * @brief Unblocks this scheduler node. - * - * @param context The scheduler instance context. - * @param[in, out] the_thread The thread which wants to get unblocked. - * @param[in, out] node The node which wants to get unblocked. - * @param is_scheduled This node is scheduled. - * @param release_idle_thread Function to release an idle thread. - * - * @retval true Continue with the unblocking operation. - * @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 -) -{ - bool unblock; - - ++node->sticky_level; - _Assert( node->sticky_level > 0 ); - - if ( is_scheduled ) { - _Scheduler_Discard_idle_thread( - context, - the_thread, - node, - release_idle_thread - ); - _Scheduler_Thread_change_state( the_thread, THREAD_SCHEDULER_SCHEDULED ); - unblock = false; - } else { - _Scheduler_Thread_change_state( the_thread, THREAD_SCHEDULER_READY ); - unblock = true; - } - - return unblock; -} #endif /** - * @brief Updates the heir. - * - * @param[in, out] new_heir The new heir. - * @param force_dispatch Indicates whether the dispatch happens also if the - * currently running thread is set as not preemptible. - */ -RTEMS_INLINE_ROUTINE void _Scheduler_Update_heir( - Thread_Control *new_heir, - bool force_dispatch -) -{ - Thread_Control *heir = _Thread_Heir; - - if ( heir != new_heir && ( heir->is_preemptible || force_dispatch ) ) { -#if defined(RTEMS_SMP) - /* - * We need this state only for _Thread_Get_CPU_time_used(). Cannot use - * _Scheduler_Thread_change_state() since THREAD_SCHEDULER_BLOCKED to - * THREAD_SCHEDULER_BLOCKED state changes are illegal for the real SMP - * schedulers. - */ - heir->Scheduler.state = THREAD_SCHEDULER_BLOCKED; - new_heir->Scheduler.state = THREAD_SCHEDULER_SCHEDULED; -#endif - _Thread_Update_CPU_time_used( heir, _Thread_Get_CPU( heir ) ); - _Thread_Heir = new_heir; - _Thread_Dispatch_necessary = true; - } -} - -/** * @brief Sets a new scheduler. * * @param new_scheduler The new scheduler to set. @@ -1295,7 +928,7 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Update_heir( * @retval STATUS_RESOURCE_IN_USE The thread's wait queue is not empty. * @retval STATUS_UNSATISFIED The new scheduler has no processors. */ -RTEMS_INLINE_ROUTINE Status_Control _Scheduler_Set( +static inline Status_Control _Scheduler_Set( const Scheduler_Control *new_scheduler, Thread_Control *the_thread, Priority_Control priority |