Multicore Real-Time Operating System RTEMS (2) – Types of Schedulers

Technical experience sharing, welcome to follow and provide guidance

RTEMS supports various scheduling algorithms, with the default being a priority-based scheduler. To understand these scheduler algorithms, this article lists the types of schedulers supported by RTEMS for subsequent testing and research.

1. Simple Priority Scheduling

The Simple Priority Scheduler is a simplified algorithm based on priority scheduling, initialized as follows:

    #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 \
  }

2. Priority Scheduling

The Priority Scheduler is the default priority-based scheduler, initialized as follows:

#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 \
  }

3. Earliest Deadline First Scheduling

The Earliest Deadline First scheduling determines task priority based on the task’s deadline, initialized as follows:

#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 \
  }

4. Constant Bandwidth Scheduling

The Constant Bandwidth Server scheduling is an extension based on EDF, where tasks are allocated a fixed bandwidth (budget) by default, and then scheduled based on deadlines.

#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 \
  }

5. SMP Scheduler Extensions

To support SMP, the Simple Priority, Priority, and EDF schedulers have been extended for SMP support, as follows:

#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 ) \
  }

6. Other Schedulers

In addition to the above schedulers, there are SMP schedulers based on CPU affinity priority, such as RTEMS_SCHEDULER_TABLE_PRIORITY_AFFINITY_SMP, which adjusts the priority-based scheduler according to CPU affinity, ensuring that a task is allowed to run only on a specific CPU.

There are also preemptive SMP schedulers that support CPU affinity settings.

7. Default System Scheduler

The default system scheduler is the priority scheduler, defined as follows:

#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

The configuration effect is as follows:

#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
};

Then we expand the macro definitions as follows:

  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,

We can see that the default scheduler we configured is indeed the priority scheduler, and there is only one. Remember when we looked at the initialization code earlier, in the rtems_initialize_data_structures function, it calls _Scheduler_Handler_initialization, which is implemented as follows:

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 );
  }
}

This directly calls the initialize function of the scheduler. Thus, the initialization of the scheduler begins.

Leave a Comment