/** * @file * * @brief Inlined Routines Associated with the Manipulation of the Scheduler * * This inline file contains all of the inlined routines associated with * the manipulation of the scheduler. */ /* * Copyright (C) 2010 Gedare Bloom. * Copyright (C) 2011 On-Line Applications Research Corporation (OAR). * * 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_SCHEDULERIMPL_H #define _RTEMS_SCORE_SCHEDULERIMPL_H #include #include #include #ifdef __cplusplus extern "C" { #endif /** * @addtogroup ScoreScheduler */ /**@{**/ /** * @brief Initializes the scheduler to the policy chosen by the user. * * This routine initializes the scheduler to the policy chosen by the user * through confdefs, or to the priority scheduler with ready chains by * default. */ void _Scheduler_Handler_initialization( void ); /** * The preferred method to add a new scheduler is to define the jump table * entries and add a case to the _Scheduler_Initialize routine. * * Generic scheduling implementations that rely on the ready queue only can * be found in the _Scheduler_queue_XXX functions. */ /* * Passing the Scheduler_Control* to these functions allows for multiple * scheduler's to exist simultaneously, which could be useful on an SMP * system. Then remote Schedulers may be accessible. How to protect such * accesses remains an open problem. */ /** * @brief Scheduler schedule. * * This kernel routine implements the scheduling decision logic for * the scheduler. It does NOT dispatch. * * @param[in] the_thread The thread which state changed previously. */ RTEMS_INLINE_ROUTINE void _Scheduler_Schedule( const Scheduler_Control *scheduler, Thread_Control *the_thread ) { ( *scheduler->Operations.schedule )( scheduler, the_thread ); } /** * @brief Scheduler yield with a particular thread. * * This routine is invoked when a thread wishes to voluntarily transfer control * of the processor to another thread. * * @param[in] the_thread The yielding thread. */ RTEMS_INLINE_ROUTINE void _Scheduler_Yield( const Scheduler_Control *scheduler, Thread_Control *the_thread ) { ( *scheduler->Operations.yield )( scheduler, the_thread ); } /** * @brief Scheduler block. * * This routine removes @a the_thread from the scheduling decision for * the scheduler. The primary task is to remove the thread from the * ready queue. It performs any necessary schedulering operations * including the selection of a new heir thread. */ RTEMS_INLINE_ROUTINE void _Scheduler_Block( const Scheduler_Control *scheduler, Thread_Control *the_thread ) { ( *scheduler->Operations.block )( scheduler, the_thread ); } /** * @brief Scheduler unblock. * * This routine adds @a the_thread to the scheduling decision for * the scheduler. The primary task is to add the thread to the * ready queue per the schedulering policy and update any appropriate * scheduling variables, for example the heir thread. */ RTEMS_INLINE_ROUTINE void _Scheduler_Unblock( const Scheduler_Control *scheduler, Thread_Control *the_thread ) { ( *scheduler->Operations.unblock )( scheduler, the_thread ); } /** * @brief Scheduler allocate. * * This routine allocates @a the_thread->scheduler */ RTEMS_INLINE_ROUTINE bool _Scheduler_Allocate( const Scheduler_Control *scheduler, Thread_Control *the_thread ) { return ( *scheduler->Operations.allocate )( scheduler, the_thread ); } /** * @brief Scheduler free. * * This routine frees @a the_thread->scheduler */ RTEMS_INLINE_ROUTINE void _Scheduler_Free( const Scheduler_Control *scheduler, Thread_Control *the_thread ) { ( *scheduler->Operations.free )( scheduler, the_thread ); } /** * @brief Scheduler update. * * This routine updates @a the_thread->scheduler */ RTEMS_INLINE_ROUTINE void _Scheduler_Update( const Scheduler_Control *scheduler, Thread_Control *the_thread ) { ( *scheduler->Operations.update )( scheduler, the_thread ); } /** * @brief Scheduler enqueue. * * This routine enqueue @a the_thread->scheduler */ RTEMS_INLINE_ROUTINE void _Scheduler_Enqueue( const Scheduler_Control *scheduler, Thread_Control *the_thread ) { ( *scheduler->Operations.enqueue )( scheduler, the_thread ); } /** * @brief Scheduler enqueue first. * * This routine enqueue_first @a the_thread->scheduler */ RTEMS_INLINE_ROUTINE void _Scheduler_Enqueue_first( const Scheduler_Control *scheduler, Thread_Control *the_thread ) { ( *scheduler->Operations.enqueue_first )( scheduler, the_thread ); } /** * @brief Scheduler extract. * * This routine extract @a the_thread->scheduler */ RTEMS_INLINE_ROUTINE void _Scheduler_Extract( const Scheduler_Control *scheduler, Thread_Control *the_thread ) { ( *scheduler->Operations.extract )( scheduler, the_thread ); } /** * @brief Scheduler priority compare. * * This routine compares two priorities. */ RTEMS_INLINE_ROUTINE int _Scheduler_Priority_compare( const Scheduler_Control *scheduler, Priority_Control p1, Priority_Control p2 ) { return ( *scheduler->Operations.priority_compare )( p1, p2 ); } /** * @brief Scheduler release job. * * This routine is called when a new period of task is issued. */ RTEMS_INLINE_ROUTINE void _Scheduler_Release_job( const Scheduler_Control *scheduler, Thread_Control *the_thread, uint32_t length ) { ( *scheduler->Operations.release_job )( scheduler, the_thread, length ); } /** * @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. */ RTEMS_INLINE_ROUTINE void _Scheduler_Tick( const Scheduler_Control *scheduler ) { ( *scheduler->Operations.tick )( scheduler ); } /** * @brief Starts the idle thread for a particular processor. * * @param[in,out] the_thread The idle thread for the processor. * @parma[in,out] processor The processor for the idle thread. * * @see _Thread_Create_idle(). */ RTEMS_INLINE_ROUTINE void _Scheduler_Start_idle( const Scheduler_Control *scheduler, Thread_Control *the_thread, Per_CPU_Control *cpu ) { ( *scheduler->Operations.start_idle )( scheduler, the_thread, cpu ); } #if defined(__RTEMS_HAVE_SYS_CPUSET_H__) RTEMS_INLINE_ROUTINE void _Scheduler_Get_processor_set( const Scheduler_Control *scheduler, size_t cpusetsize, cpu_set_t *cpuset ) { uint32_t cpu_count = _SMP_Get_processor_count(); uint32_t cpu_index; (void) scheduler; CPU_ZERO_S( cpusetsize, cpuset ); for ( cpu_index = 0 ; cpu_index < cpu_count ; ++cpu_index ) { CPU_SET_S( (int) cpu_index, cpusetsize, cpuset ); } } RTEMS_INLINE_ROUTINE bool _Scheduler_default_Get_affinity_body( const Scheduler_Control *scheduler, Thread_Control *the_thread, size_t cpusetsize, cpu_set_t *cpuset ) { (void) the_thread; _Scheduler_Get_processor_set( scheduler, cpusetsize, cpuset ); return true; } bool _Scheduler_Get_affinity( const Scheduler_Control *scheduler, Thread_Control *the_thread, size_t cpusetsize, cpu_set_t *cpuset ); RTEMS_INLINE_ROUTINE bool _Scheduler_default_Set_affinity_body( const Scheduler_Control *scheduler, Thread_Control *the_thread, size_t cpusetsize, const cpu_set_t *cpuset ) { size_t cpu_max = _CPU_set_Maximum_CPU_count( cpusetsize ); uint32_t cpu_count = _SMP_Get_processor_count(); uint32_t cpu_index; bool ok = true; (void) scheduler; (void) the_thread; for ( cpu_index = 0 ; cpu_index < cpu_count ; ++cpu_index ) { ok = ok && CPU_ISSET_S( (int) cpu_index, cpusetsize, cpuset ); } for ( ; cpu_index < cpu_max ; ++cpu_index ) { ok = ok && !CPU_ISSET_S( (int) cpu_index, cpusetsize, cpuset ); } return ok; } bool _Scheduler_Set_affinity( const Scheduler_Control *scheduler, Thread_Control *the_thread, size_t cpusetsize, const cpu_set_t *cpuset ); #endif /* defined(__RTEMS_HAVE_SYS_CPUSET_H__) */ RTEMS_INLINE_ROUTINE void _Scheduler_Update_heir( Thread_Control *heir, bool force_dispatch ) { Thread_Control *executing = _Thread_Executing; _Thread_Heir = heir; if ( executing != heir && ( force_dispatch || executing->is_preemptible ) ) _Thread_Dispatch_necessary = true; } RTEMS_INLINE_ROUTINE void _Scheduler_Generic_block( const Scheduler_Control *scheduler, Thread_Control *the_thread, void ( *extract )( const Scheduler_Control *, Thread_Control * ), void ( *schedule )( const Scheduler_Control *, Thread_Control *, bool ) ) { ( *extract )( scheduler, the_thread ); /* TODO: flash critical section? */ if ( _Thread_Is_executing( the_thread ) || _Thread_Is_heir( the_thread ) ) { ( *schedule )( scheduler, the_thread, true ); } } /** * @brief Returns true if @p1 encodes a lower priority than @a p2 in the * intuitive sense of priority. */ RTEMS_INLINE_ROUTINE bool _Scheduler_Is_priority_lower_than( const Scheduler_Control *scheduler, Priority_Control p1, Priority_Control p2 ) { return _Scheduler_Priority_compare( scheduler, p1, p2 ) < 0; } /** * @brief Returns true if @p1 encodes a higher priority than @a p2 in the * intuitive sense of priority. */ RTEMS_INLINE_ROUTINE bool _Scheduler_Is_priority_higher_than( const Scheduler_Control *scheduler, Priority_Control p1, Priority_Control p2 ) { return _Scheduler_Priority_compare( scheduler, p1, p2 ) > 0; } /** * @brief Returns the priority encoding @a p1 or @a p2 with the higher priority * in the intuitive sense of priority. */ RTEMS_INLINE_ROUTINE Priority_Control _Scheduler_Highest_priority_of_two( const Scheduler_Control *scheduler, Priority_Control p1, Priority_Control p2 ) { return _Scheduler_Is_priority_higher_than( scheduler, p1, p2 ) ? p1 : p2; } /** * @brief Sets the thread priority to @a priority if it is higher than the * current priority of the thread in the intuitive sense of priority. */ RTEMS_INLINE_ROUTINE void _Scheduler_Set_priority_if_higher( const Scheduler_Control *scheduler, Thread_Control *the_thread, Priority_Control priority ) { Priority_Control current = the_thread->current_priority; if ( _Scheduler_Is_priority_higher_than( scheduler, priority, current ) ) { _Thread_Set_priority( the_thread, priority ); } } /** * @brief Changes the thread priority to @a priority if it is higher than the * current priority of the thread in the intuitive sense of priority. */ RTEMS_INLINE_ROUTINE void _Scheduler_Change_priority_if_higher( const Scheduler_Control *scheduler, Thread_Control *the_thread, Priority_Control priority, bool prepend_it ) { Priority_Control current = the_thread->current_priority; if ( _Scheduler_Is_priority_higher_than( scheduler, priority, current ) ) { _Thread_Change_priority( the_thread, priority, prepend_it ); } } RTEMS_INLINE_ROUTINE const Scheduler_Control *_Scheduler_Get( Thread_Control *the_thread ) { (void) the_thread; return &_Scheduler_Table[ 0 ]; } RTEMS_INLINE_ROUTINE bool _Scheduler_Set( const Scheduler_Control *scheduler, Thread_Control *the_thread ) { bool ok; (void) scheduler; if ( _States_Is_dormant( the_thread->current_state ) ) { ok = true; } else { ok = false; } return ok; } RTEMS_INLINE_ROUTINE Objects_Id _Scheduler_Build_id( uint32_t scheduler_index ) { return _Objects_Build_id( OBJECTS_FAKE_OBJECTS_API, OBJECTS_FAKE_OBJECTS_SCHEDULERS, _Objects_Local_node, scheduler_index + 1 ); } RTEMS_INLINE_ROUTINE bool _Scheduler_Get_by_id( Objects_Id id, const Scheduler_Control **scheduler ) { uint32_t minimum_id = _Scheduler_Build_id( 0 ); uint32_t index = id - minimum_id; *scheduler = &_Scheduler_Table[ index ]; return index < _Scheduler_Count; } RTEMS_INLINE_ROUTINE uint32_t _Scheduler_Get_index( const Scheduler_Control *scheduler ) { return (uint32_t) (scheduler - &_Scheduler_Table[ 0 ]); } /** @} */ #ifdef __cplusplus } #endif #endif /* end of include file */