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
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;
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;
if ( _Thread_Executing->is_preemptible || the_thread->current_priority == 0 )
_Thread_Dispatch_necessary = true;
}
+
}
void _Scheduler_edf_Yield( void ) {