From e6498659f32a8f17cb66d2aa3cb068d790c6adbc Mon Sep 17 00:00:00 2001 From: Petr Benes Date: Sun, 17 Apr 2011 15:20:02 +0200 Subject: [PATCH] Scheduler modified in order to have an extention of CBS. The CBS does not work yet. --- src/edf/rbtree.h | 4 +++ src/edf/scheduler_edf.c | 68 +++++++++++++++++++++++++++++++++++------ src/edf/scheduler_edf.h | 4 ++- 3 files changed, 66 insertions(+), 10 deletions(-) diff --git a/src/edf/rbtree.h b/src/edf/rbtree.h index b9c461f..9ac043b 100644 --- a/src/edf/rbtree.h +++ b/src/edf/rbtree.h @@ -7,6 +7,8 @@ extern "C" { #include "edf_types.h" #include + +#include // This struct will be embedded into the Thread_Control control // as scheduler_info @@ -19,6 +21,8 @@ typedef struct RBT_node_struct { Node_Color color; EDF_Chain_Control *ready_chain; uint8_t is_enqueued; + uint32_t cmp_time; + rtems_id timer_id; } RBT_Node; void _RBT_Insert(EDF_Chain_Control *chain,EDF_Node *node); diff --git a/src/edf/scheduler_edf.c b/src/edf/scheduler_edf.c index 51f7652..536fa2a 100644 --- a/src/edf/scheduler_edf.c +++ b/src/edf/scheduler_edf.c @@ -13,25 +13,67 @@ void edf_next_period(void) { Thread_Control *the_thread = _Per_CPU_Information.executing; RBT_Node *node = (RBT_Node*)the_thread->scheduler_info; - the_thread->real_priority = the_thread->current_priority = (_Watchdog_Ticks_since_boot + node->rel_deadline) % EDF_HYBRID_MASK; - _Scheduler_edf_Update(the_thread); + //FIXME: Think about this a bit more, what the order should be (making use of ratemonotonic) + if (node->abs_deadline == 0) { // for the first time + the_thread->real_priority = (_Watchdog_Ticks_since_boot + node->rel_deadline) % EDF_HYBRID_MASK; + } else { // any other time + the_thread->real_priority = (node->abs_deadline + node->rel_deadline) % EDF_HYBRID_MASK; + } + node->abs_deadline = the_thread->current_priority = the_thread->real_priority; + if (node->cmp_time) + the_thread->cpu_time_budget = node->cmp_time; //FIXME: what units? + //_Scheduler_edf_Update(the_thread); + } -void edf_deadline_init(uint32_t __rel_deadline__) { +// if cmp_time is 0, no CBS is used, only pure EDF +void edf_deadline_init(uint32_t __rel_deadline__, uint32_t __cmp_time__, rtems_asr_entry *budget_overrun_handler) { Thread_Control *the_thread = _Per_CPU_Information.executing; RBT_Node *node = (RBT_Node*)the_thread->scheduler_info; node->rel_deadline = __rel_deadline__; + if (__cmp_time__) { + rtems_signal_catch(*budget_overrun_handler, RTEMS_DEFAULT_MODES); + node->cmp_time = __cmp_time__; + the_thread->is_preemptible = true; + the_thread->budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_CALLOUT; + the_thread->budget_callout = (void *) edf_budget_overrun_callout; + rtems_timer_create(rtems_build_name( 'C', 'B', 'S', 'T' ), &node->timer_id); + } } +// return to start params void edf_deadline_cancel(void) { Thread_Control *the_thread = _Per_CPU_Information.executing; + RBT_Node *node = (RBT_Node*)the_thread->scheduler_info; the_thread->real_priority = the_thread->Start.initial_priority + EDF_HYBRID_MASK; the_thread->current_priority = the_thread->real_priority; + if(node->cmp_time) + rtems_timer_delete(node->timer_id); + the_thread->budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_NONE; + the_thread->budget_callout = NULL; _Scheduler_edf_Update(the_thread); } +// invoked when a limited time quantum (cmp_time) is exceeded +Thread_CPU_budget_algorithm_callout edf_budget_overrun_callout() { + Thread_Control *the_thread = _Per_CPU_Information.executing; + RBT_Node *node = (RBT_Node*)the_thread->scheduler_info; + rtems_signal_send(the_thread->Object.id, RTEMS_SIGNAL_18); + _Thread_Suspend (the_thread); + //wait until next period to enable the task again + uint32_t ticks = node->abs_deadline - _Watchdog_Ticks_since_boot; + rtems_timer_fire_after(node->timer_id, ticks, (void *) edf_budget_overrun_reenable, the_thread); + return 0; +} + +rtems_timer_service_routine_entry edf_budget_overrun_reenable(Thread_Control *the_thread) { + _Thread_Resume(the_thread, false); + return 0; +} + //======================================================================================= + int _Scheduler_edf_Priority_compare (Priority_Control p1, Priority_Control p2) { uint32_t time = _Watchdog_Ticks_since_boot; //correct priorities @@ -77,16 +119,16 @@ void * _Scheduler_edf_Allocate( Thread_Control *the_thread) { the_thread->scheduler_info = (RBT_Node *) sched; //edf_initial_priority_shift(&(the_thread->real_priority)); - the_thread->real_priority += (EDF_HYBRID_MASK); - the_thread->current_priority = the_thread->real_priority; + the_thread->Start.initial_priority += (EDF_HYBRID_MASK); schinfo = (RBT_Node *)(the_thread->scheduler_info); schinfo->rel_deadline = 0; // This has to be negotiated afterwards schinfo->abs_deadline = 0; - schinfo->is_enqueued = 0; + schinfo->is_enqueued = 2; schinfo->left = NULL; schinfo->right = NULL; schinfo->parent = NULL; + schinfo->cmp_time = 0; schinfo->ready_chain = &_Thread_Ready_EDF_chain; return sched; @@ -98,15 +140,22 @@ void _Scheduler_edf_Free( Thread_Control *the_thread) { void _Scheduler_edf_Update( Thread_Control *the_thread) { RBT_Node *node = (RBT_Node*)the_thread->scheduler_info; + // Make sure the previous priority meaning does not show up + // if the task was just initialized + if (node->is_enqueued == 2) { + the_thread->real_priority = the_thread->Start.initial_priority; + the_thread->current_priority = the_thread->real_priority; + node->is_enqueued = 0; + } // Update deadlines for deadline driven tasks - if (!(the_thread->current_priority && EDF_HYBRID_MASK)) + if (!(the_thread->current_priority & EDF_HYBRID_MASK)) ((RBT_Node*)the_thread->scheduler_info)->abs_deadline = the_thread->current_priority; else ((RBT_Node*)the_thread->scheduler_info)->abs_deadline = 0; - if(node->is_enqueued) { + if(node->is_enqueued == 1) { _Scheduler_edf_Extract(the_thread); _Scheduler_edf_Enqueue(the_thread); - if ( the_thread->current_priority < _Thread_Heir->current_priority ) { + if ( the_thread->current_priority < _Thread_Heir->current_priority ) { //TODO: compare priorities _Thread_Heir = the_thread; if ( _Thread_Executing->is_preemptible || the_thread->current_priority == 0 ) _Thread_Dispatch_necessary = true; @@ -135,6 +184,7 @@ void _Scheduler_edf_Unblock( Thread_Control *the_thread ) { if ( _Thread_Executing->is_preemptible || the_thread->current_priority == 0 ) _Thread_Dispatch_necessary = true; } + } void _Scheduler_edf_Yield( void ) { diff --git a/src/edf/scheduler_edf.h b/src/edf/scheduler_edf.h index a53cc34..ed4ba35 100644 --- a/src/edf/scheduler_edf.h +++ b/src/edf/scheduler_edf.h @@ -16,12 +16,14 @@ void edf_next_period(void); /// Changes scheduling policy from priorities to deadlines /// @param __rel_deadline__ in ticks required -void edf_deadline_init(uint32_t __rel_deadline__); +void edf_deadline_init(uint32_t __rel_deadline__, uint32_t __cmp_time__, rtems_asr_entry *budget_overrun_handler); /// Changes scheduling policy from deadlines to priorities void edf_deadline_cancel(void); +Thread_CPU_budget_algorithm_callout edf_budget_overrun_callout(); +rtems_timer_service_routine_entry edf_budget_overrun_reenable(Thread_Control *the_thread); /// Pluggable scheduler callback functions -- 2.39.2