RTEMS支持多种调度算法,默认情况下是基于优先级的调度器,为了了解这些调度器算法,本文列出RTEMS支持的调度器种类,方便后续逐一进行调度器的测试研究
Simple Priority Scheduler是基于优先级调度的一种简化算法,其初始化如下:
#define CONFIGURE_SCHEDULER_TABLE_ENTRIES \ RTEMS_SCHEDULER_TABLE_SIMPLE( dflt, CONFIGURE_SCHEDULER_NAME ) #define SCHEDULER_SIMPLE_ENTRY_POINTS \ { \ _Scheduler_simple_Initialize, /* initialize entry point */ \ _Scheduler_simple_Schedule, /* schedule entry point */ \ _Scheduler_simple_Yield, /* yield entry point */ \ _Scheduler_simple_Block, /* block entry point */ \ _Scheduler_simple_Unblock, /* unblock entry point */ \ _Scheduler_simple_Update_priority, /* update priority entry point */ \ _Scheduler_default_Map_priority, /* map priority entry point */ \ _Scheduler_default_Unmap_priority, /* unmap priority entry point */ \ SCHEDULER_DEFAULT_SMP_OPERATIONS \ _Scheduler_default_Node_initialize, /* node initialize entry point */ \ _Scheduler_default_Node_destroy, /* node destroy entry point */ \ _Scheduler_default_Release_job, /* new period of task */ \ _Scheduler_default_Cancel_job, /* cancel period of task */ \ _Scheduler_default_Start_idle /* start idle entry point */ \ SCHEDULER_DEFAULT_SET_AFFINITY_OPERATION \ }
Priority Scheduler是默认的基于优先级的调度器,其初始化如下
#define RTEMS_SCHEDULER_TABLE_PRIORITY( name, obj_name ) \ { \ &SCHEDULER_PRIORITY_CONTEXT_NAME( name ).Base.Base, \ SCHEDULER_PRIORITY_ENTRY_POINTS, \ RTEMS_ARRAY_SIZE( \ SCHEDULER_PRIORITY_CONTEXT_NAME( name ).Ready \ ) - 1, \ ( obj_name ) \ SCHEDULER_CONTROL_IS_NON_PREEMPT_MODE_SUPPORTED( true ) \ } #define SCHEDULER_PRIORITY_ENTRY_POINTS \ { \ _Scheduler_priority_Initialize, /* initialize entry point */ \ _Scheduler_priority_Schedule, /* schedule entry point */ \ _Scheduler_priority_Yield, /* yield entry point */ \ _Scheduler_priority_Block, /* block entry point */ \ _Scheduler_priority_Unblock, /* unblock entry point */ \ _Scheduler_priority_Update_priority, /* update priority entry point */ \ _Scheduler_default_Map_priority, /* map priority entry point */ \ _Scheduler_default_Unmap_priority, /* unmap priority entry point */ \ SCHEDULER_DEFAULT_SMP_OPERATIONS \ _Scheduler_priority_Node_initialize, /* node initialize entry point */ \ _Scheduler_default_Node_destroy, /* node destroy entry point */ \ _Scheduler_default_Release_job, /* new period of task */ \ _Scheduler_default_Cancel_job, /* cancel period of task */ \ _Scheduler_default_Start_idle /* start idle entry point */ \ SCHEDULER_DEFAULT_SET_AFFINITY_OPERATION \ }
Earliest Deadline First调度按照任务的截止时间来确定任务优先级,其初始化如下
#define RTEMS_SCHEDULER_TABLE_EDF( name, obj_name ) \ { \ &SCHEDULER_EDF_CONTEXT_NAME( name ).Base, \ SCHEDULER_EDF_ENTRY_POINTS, \ SCHEDULER_EDF_MAXIMUM_PRIORITY, \ ( obj_name ) \ SCHEDULER_CONTROL_IS_NON_PREEMPT_MODE_SUPPORTED( true ) \ } #define SCHEDULER_EDF_ENTRY_POINTS \ { \ _Scheduler_EDF_Initialize, /* initialize entry point */ \ _Scheduler_EDF_Schedule, /* schedule entry point */ \ _Scheduler_EDF_Yield, /* yield entry point */ \ _Scheduler_EDF_Block, /* block entry point */ \ _Scheduler_EDF_Unblock, /* unblock entry point */ \ _Scheduler_EDF_Update_priority, /* update priority entry point */ \ _Scheduler_EDF_Map_priority, /* map priority entry point */ \ _Scheduler_EDF_Unmap_priority, /* unmap priority entry point */ \ SCHEDULER_DEFAULT_SMP_OPERATIONS \ _Scheduler_EDF_Node_initialize, /* node initialize entry point */ \ _Scheduler_default_Node_destroy, /* node destroy entry point */ \ _Scheduler_EDF_Release_job, /* new period of task */ \ _Scheduler_EDF_Cancel_job, /* cancel period of task */ \ _Scheduler_default_Start_idle /* start idle entry point */ \ SCHEDULER_DEFAULT_SET_AFFINITY_OPERATION \ }
Constant Bandwidth Server调度是基于EDF的扩展,默认情况下,给任务分配固定的带宽(预算),然后再通过截止时间进行调度
#define RTEMS_SCHEDULER_TABLE_CBS( name, obj_name ) \ { \ &SCHEDULER_CBS_CONTEXT_NAME( name ).Base, \ SCHEDULER_CBS_ENTRY_POINTS, \ SCHEDULER_CBS_MAXIMUM_PRIORITY, \ ( obj_name ) \ SCHEDULER_CONTROL_IS_NON_PREEMPT_MODE_SUPPORTED( true ) \ } #define SCHEDULER_CBS_ENTRY_POINTS \ { \ _Scheduler_EDF_Initialize, /* initialize entry point */ \ _Scheduler_EDF_Schedule, /* schedule entry point */ \ _Scheduler_EDF_Yield, /* yield entry point */ \ _Scheduler_EDF_Block, /* block entry point */ \ _Scheduler_CBS_Unblock, /* unblock entry point */ \ _Scheduler_EDF_Update_priority, /* update priority entry point */ \ _Scheduler_EDF_Map_priority, /* map priority entry point */ \ _Scheduler_EDF_Unmap_priority, /* unmap priority entry point */ \ SCHEDULER_DEFAULT_SMP_OPERATIONS \ _Scheduler_CBS_Node_initialize, /* node initialize entry point */ \ _Scheduler_default_Node_destroy, /* node destroy entry point */ \ _Scheduler_CBS_Release_job, /* new period of task */ \ _Scheduler_CBS_Cancel_job, /* cancel period of task */ \ _Scheduler_default_Start_idle /* start idle entry point */ \ SCHEDULER_DEFAULT_SET_AFFINITY_OPERATION \ }
为了支持SMP,简单优先级,优先级,EDF都做了SMP的扩展支持,如下
#define RTEMS_SCHEDULER_TABLE_SIMPLE_SMP( name, obj_name ) \ { \ &SCHEDULER_SIMPLE_SMP_CONTEXT_NAME( name ).Base.Base, \ SCHEDULER_SIMPLE_SMP_ENTRY_POINTS, \ SCHEDULER_SIMPLE_SMP_MAXIMUM_PRIORITY, \ ( obj_name ) \ SCHEDULER_CONTROL_IS_NON_PREEMPT_MODE_SUPPORTED( false ) \ } #define RTEMS_SCHEDULER_TABLE_PRIORITY_SMP( name, obj_name ) \ { \ &SCHEDULER_PRIORITY_SMP_CONTEXT_NAME( name ).Base.Base.Base, \ SCHEDULER_PRIORITY_SMP_ENTRY_POINTS, \ RTEMS_ARRAY_SIZE( \ SCHEDULER_PRIORITY_SMP_CONTEXT_NAME( name ).Ready \ ) - 1, \ ( obj_name ) \ SCHEDULER_CONTROL_IS_NON_PREEMPT_MODE_SUPPORTED( false ) \ } #define RTEMS_SCHEDULER_TABLE_EDF_SMP( name, obj_name ) \ { \ &SCHEDULER_EDF_SMP_CONTEXT_NAME( name ).Base.Base.Base, \ SCHEDULER_EDF_SMP_ENTRY_POINTS, \ SCHEDULER_EDF_MAXIMUM_PRIORITY, \ ( obj_name ) \ SCHEDULER_CONTROL_IS_NON_PREEMPT_MODE_SUPPORTED( false ) \ }
除了上述调度器,还有基于CPU亲和性优先级的SMP调度器,如RTEMS_SCHEDULER_TABLE_PRIORITY_AFFINITY_SMP,他会根据CPU的亲和性来调整基于优先级的调度器,可以确保某个任务只允许运行在某个CPU上
还有基于抢占式的SMP调度器,并支持CPU的亲和性设置
系统默认调度器是优先级调度,其定义如下:
#if !defined(CONFIGURE_SCHEDULER_CBS) \ && !defined(CONFIGURE_SCHEDULER_EDF) \ && !defined(CONFIGURE_SCHEDULER_EDF_SMP) \ && !defined(CONFIGURE_SCHEDULER_PRIORITY) \ && !defined(CONFIGURE_SCHEDULER_PRIORITY_AFFINITY_SMP) \ && !defined(CONFIGURE_SCHEDULER_PRIORITY_SMP) \ && !defined(CONFIGURE_SCHEDULER_SIMPLE) \ && !defined(CONFIGURE_SCHEDULER_SIMPLE_SMP) \ && !defined(CONFIGURE_SCHEDULER_STRONG_APA) \ && !defined(CONFIGURE_SCHEDULER_USER) #if defined(RTEMS_SMP) && _CONFIGURE_MAXIMUM_PROCESSORS > 1 #define CONFIGURE_SCHEDULER_EDF_SMP #else #define CONFIGURE_SCHEDULER_PRIORITY #endif #endif
其配置作用如下:
#ifdef CONFIGURE_SCHEDULER /* * Ignore these warnings: * * - invalid use of structure with flexible array member * * - struct has no members */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" CONFIGURE_SCHEDULER; #pragma GCC diagnostic pop #endif const Scheduler_Control _Scheduler_Table[] = { CONFIGURE_SCHEDULER_TABLE_ENTRIES };
然后我们将宏定义展开,如下:
static struct { Scheduler_priority_Context Base; Chain_Control Ready[ ( 255 + 1 ) ]; } _Configuration_Scheduler_priority_dflt; const Scheduler_Control _Scheduler_Table[] = { { &_Configuration_Scheduler_priority_dflt.Base.Base, { _Scheduler_priority_Initialize, _Scheduler_priority_Schedule, _Scheduler_priority_Yield, _Scheduler_priority_Block, _Scheduler _priority_Unblock, _Scheduler_priority_Update_priority, _Scheduler_default_Map_priority, _Scheduler_default_Unmap_priority,
可以看到我们配置的默认调度器就是优先级调度,且有且就1个。还记得之前查看初始化代码的时候,我们在rtems_initialize_data_structures函数,会调用_Scheduler_Handler_initialization,其实现如下
void _Scheduler_Handler_initialization(void) { size_t n; size_t i; n = _Scheduler_Count; for ( i = 0 ; i < n ; ++i ) { const Scheduler_Control *scheduler; #if defined(RTEMS_SMP) Scheduler_Context *context; #endif scheduler = &_Scheduler_Table[ i ]; #if defined(RTEMS_SMP) context = _Scheduler_Get_context( scheduler ); #endif _ISR_lock_Initialize( &context->Lock, "Scheduler" ); ( *scheduler->Operations.initialize )( scheduler ); } }
这里会直接调用调度器的initialize函数。至此就开展调度器的初始化了