/*! * Deactivate thread because: * 1. higher priority thread becomes active * 2. this thread time slice is expired * 3. this thread blocks on some queue */ static int rr_thread_deactivate ( kthread_t *kthread ) { /* Get current time and recalculate remainder */ time_t t; kthread_sched_data_t *tsched = kthread_get_sched_param ( kthread ); ksched_t *gsched = ksched_get ( tsched->sched_policy ); if (tsched->params.rr.remainder.sec + tsched->params.rr.remainder.nsec) { /* * "slice interrupted" * recalculate remainder */ k_get_time ( &t ); time_sub ( &tsched->params.rr.slice_end, &t ); tsched->params.rr.remainder = tsched->params.rr.slice_end; if ( kthread_is_ready ( kthread ) ) { /* is remainder too small or not? */ if ( time_cmp ( &tsched->params.rr.remainder, &gsched->params.rr.threshold ) <= 0 ) { kthread_move_to_ready ( kthread, LAST ); } else { kthread_move_to_ready ( kthread, FIRST ); } } } /* else = remainder is zero, thread is already enqueued in ready queue*/ return 0; }
/*! Start time slice for thread (or countinue interrupted) */ static int rr_thread_activate ( kthread_t *kthread ) { kthread_sched_data_t *tsched = kthread_get_sched_param ( kthread ); ksched_t *gsched = ksched_get ( tsched->sched_policy ); /* check remainder if needs to be replenished */ if ( time_cmp ( &tsched->params.rr.remainder, &gsched->params.rr.threshold ) <= 0 ) { time_add ( &tsched->params.rr.remainder, &gsched->params.rr.time_slice ); } /* Get current time and store it */ k_get_time ( &tsched->params.rr.slice_start ); /* When to wake up? */ tsched->params.rr.slice_end = tsched->params.rr.slice_start; time_add ( &tsched->params.rr.slice_end, &tsched->params.rr.remainder ); /* Set alarm for remainder time */ gsched->params.rr.alarm.exp_time = tsched->params.rr.slice_end; gsched->params.rr.alarm.param = kthread; k_alarm_set ( gsched->params.rr.rr_alarm, &gsched->params.rr.alarm ); return 0; }
static int edf_thread_add ( kthread_t *kthread ) { kthread_sched_data_t *tsched = kthread_get_sched_param ( kthread ); tsched->params.edf.edf_period_alarm = NULL; return 0; }
/*! Add thread to RR scheduler (give him initial time slice) */ static int rr_thread_add ( kthread_t *kthread ) { kthread_sched_data_t *tsched = kthread_get_sched_param ( kthread ); ksched_t *gsched = ksched_get ( tsched->sched_policy ); tsched->params.rr.remainder = gsched->params.rr.time_slice; return 0; }
static int edf_arm_deadline ( kthread_t *kthread ) { kthread_sched_data_t *tsched = kthread_get_sched_param ( kthread ); alarm_t alarm; alarm.action = edf_deadline_timer; alarm.param = kthread; alarm.flags = 0; alarm.period.sec = alarm.period.nsec = 0; alarm.exp_time.sec = alarm.exp_time.nsec = 0; return k_alarm_new ( &tsched->params.edf.edf_deadline_alarm, &alarm, KERNELCALL ); }
static int edf_arm_period ( kthread_t *kthread ) { kthread_sched_data_t *tsched = kthread_get_sched_param ( kthread ); alarm_t alarm; alarm.action = edf_period_timer; alarm.param = kthread; alarm.flags = ALARM_PERIODIC; alarm.period = tsched->params.edf.period; alarm.exp_time = tsched->params.edf.next_run; return k_alarm_new ( &tsched->params.edf.edf_period_alarm, &alarm, KERNELCALL ); }
/*! * Check if task hasn't overrun its deadline at its start * Handle deadline overrun, based on flags */ static int edf_check_deadline ( kthread_t *kthread ) { /* * Check if "now" is greater than "active_deadline" */ time_t now; kthread_sched_data_t *tsched = kthread_get_sched_param ( kthread ); k_get_time ( &now ); if ( time_cmp ( &now, &tsched->params.edf.active_deadline ) > 0 ) { LOG( DEBUG, "%x [DEADLINE OVERRUN]", kthread ); return -1; } return 0; }
static int edf_thread_remove ( kthread_t *kthread ) { kthread_sched_data_t *tsched = kthread_get_sched_param ( kthread ); ksched_t *gsched = ksched_get ( tsched->sched_policy ); if ( gsched->params.edf.active == kthread ) gsched->params.edf.active = NULL; if ( tsched->params.edf.edf_period_alarm ) { k_alarm_remove ( tsched->params.edf.edf_period_alarm ); tsched->params.edf.edf_period_alarm = NULL; } tsched->sched_policy = SCHED_FIFO; k_edf_schedule (); return 0; }
/*! Timer interrupt for Round Robin */ static void rr_timer ( void *p ) { kthread_t *kthread = p; kthread_sched_data_t *tsched; if ( kthread_get_active () != kthread ) { /* bug or rr thread got canceled! Let asume second :) */ return; } tsched = kthread_get_sched_param ( kthread ); /* given time is elapsed, set remainder to zero */ tsched->params.rr.remainder.sec = tsched->params.rr.remainder.nsec = 0; /* move thread to ready queue - as last in coresponding queue */ kthread_move_to_ready ( kthread, LAST ); kthreads_schedule (); }
static void edf_deadline_timer ( void *p ) { alarm_t alarm; kthread_t *kthread = p, *test; kthread_sched_data_t *tsched = kthread_get_sched_param ( kthread ); ASSERT ( kthread ); test = kthreadq_remove ( &ksched_edf.params.edf.wait, kthread ); LOG( DEBUG, "%x %x [Deadline alarm]", kthread, test ); if( test == kthread ) { if ( edf_check_deadline ( kthread ) ) { LOG( DEBUG, "%x [Waked, but too late]", kthread ); kthread_set_syscall_retval ( kthread, -1 ); kthread_move_to_ready ( kthread, LAST ); if ( tsched->params.edf.flags & EDF_TERMINATE ) { LOG( DEBUG, "%x [EDF_TERMINATE]", kthread ); tsched = kthread_get_sched_param ( kthread ); k_alarm_remove ( tsched->params.edf.edf_period_alarm ); k_alarm_remove ( tsched->params.edf.edf_deadline_alarm ); tsched->params.edf.edf_period_alarm = NULL; kthread_cancel ( kthread, -E_DEADLINE ); } kthreads_schedule (); } } else { /* * thread is not in edf.wait queue, but might be running or its * blocked - it is probable (sure?) it missed deadline */ LOG( DEBUG, "%x [Not in edf.wait. Missed deadline?]", kthread ); if ( edf_check_deadline ( kthread ) ) { /* what to do if its missed? kill thread? */ tsched = kthread_get_sched_param ( kthread ); if ( tsched->params.edf.flags & EDF_TERMINATE ) { LOG( DEBUG, "%x [EDF_TERMINATE]", kthread ); k_alarm_remove ( tsched->params.edf.edf_period_alarm ); k_alarm_remove ( tsched->params.edf.edf_deadline_alarm ); tsched->params.edf.edf_period_alarm = NULL; kthread_cancel ( kthread, -E_DEADLINE ); } else if ( tsched->params.edf.flags & EDF_CONTINUE ) { /* continue as deadline is not missed */ LOG( DEBUG, "%x [EDF_CONTINUE]", kthread ); } else if ( tsched->params.edf.flags & EDF_SKIP ) { /* skip deadline */ /* set times for next period */ LOG( DEBUG, "%x [EDF_SKIP]", kthread ); time_add ( &tsched->params.edf.next_run, &tsched->params.edf.period ); tsched->params.edf.active_deadline = tsched->params.edf.next_run; time_add ( &tsched->params.edf.active_deadline, &tsched->params.edf.relative_deadline ); if ( kthread == ksched_edf.params.edf.active ) ksched_edf.params.edf.active = NULL; alarm.action = edf_deadline_timer; alarm.param = kthread; alarm.flags = 0; alarm.period.sec = alarm.period.nsec = 0; alarm.exp_time = tsched->params.edf.active_deadline; k_alarm_set ( tsched->params.edf.edf_deadline_alarm, &alarm ); alarm.action = edf_period_timer; alarm.param = kthread; alarm.flags = ALARM_PERIODIC; alarm.period = tsched->params.edf.period; alarm.exp_time = tsched->params.edf.next_run; k_alarm_set ( tsched->params.edf.edf_period_alarm, &alarm ); kthread_enqueue ( kthread, &ksched_edf.params.edf.ready ); kthreads_schedule (); /* will call edf_schedule() */ } } } }
static int k_edf_schedule () { kthread_t *first, *next, *edf_active; kthread_sched_data_t *sch_first, *sch_next; ksched_t *gsched = ksched_get ( SCHED_EDF ); int retval = 0; edf_active = gsched->params.edf.active; first = kthreadq_get ( &gsched->params.edf.ready ); LOG( DEBUG, "%x [active]", edf_active ); LOG( DEBUG, "%x [first]", first ); //LOG( DEBUG, "%x [next]", next ); if ( !first ) return 0; /* no threads in edf.ready queue, edf.active unch. */ if ( edf_active ) { next = first; first = edf_active; LOG( DEBUG, "%x [next]", kthreadq_get_next ( next ) ); } else { next = kthreadq_get_next ( first ); LOG( DEBUG, "%x [next]", next ); } while ( first && next ) { sch_first = kthread_get_sched_param ( first ); sch_next = kthread_get_sched_param ( next ); if ( time_cmp ( &sch_first->params.edf.active_deadline, &sch_next->params.edf.active_deadline ) > 0 ) { first = next; } next = kthreadq_get_next ( next ); } if ( first && first != edf_active ) { next = kthreadq_remove ( &gsched->params.edf.ready, first ); LOG ( DEBUG, "%x removed, %x is now first", next, kthreadq_get ( &gsched->params.edf.ready ) ); if ( edf_active ) { LOG( DEBUG, "%x=>%x [EDF_SCHED_PREEMPT]", edf_active, first ); /* * change active EDF thread: * -remove it from active/ready list * -put it into edf.ready list */ if ( kthread_is_ready (edf_active) ) { if ( !kthread_is_active (edf_active) ) { kthread_remove_from_ready (edf_active); /* * set "deactivated" flag, don't need * another call to "edf_schedule" */ } else { kthread_get_sched_param (edf_active) ->activated = 0; } kthread_enqueue ( edf_active, &gsched->params.edf.ready ); } /* else = thread is blocked - leave it there */ } gsched->params.edf.active = first; LOG( DEBUG, "%x [new active]", first ); kthread_move_to_ready ( first, LAST ); retval = 1; } return retval; }
static int edf_set_thread_sched_parameters (kthread_t *kthread, sched_t *params) { time_t now; alarm_t alarm; kthread_sched_data_t *tsched = kthread_get_sched_param ( kthread ); ksched_t *gsched = ksched_get ( SCHED_EDF ); if ( gsched->params.edf.active == kthread ) gsched->params.edf.active = NULL; k_get_time ( &now ); if ( params->edf.flags & EDF_SET ) { /*LOG( DEBUG, "%x [SET]", kthread ); */ tsched->params.edf.period = params->edf.period; tsched->params.edf.relative_deadline = params->edf.deadline; tsched->params.edf.flags = params->edf.flags; /* set periodic alarm */ tsched->params.edf.next_run = now; time_add ( &tsched->params.edf.next_run, ¶ms->edf.period ); edf_arm_deadline ( kthread ); edf_arm_period ( kthread ); /* * adjust "next_run" and "deadline" for "0" period * - first "edf_wait" will set correct values for first period */ tsched->params.edf.next_run = now; time_sub ( &tsched->params.edf.next_run, ¶ms->edf.period ); tsched->params.edf.active_deadline = now; time_add ( &tsched->params.edf.active_deadline, ¶ms->edf.deadline ); } else if ( params->edf.flags & EDF_WAIT ) { if ( edf_check_deadline ( kthread ) ) return -1; /* set times for next period */ if ( time_cmp ( &now, &tsched->params.edf.next_run ) > 0 ) { time_add ( &tsched->params.edf.next_run, &tsched->params.edf.period ); tsched->params.edf.active_deadline = tsched->params.edf.next_run; time_add ( &tsched->params.edf.active_deadline, &tsched->params.edf.relative_deadline ); if ( kthread == gsched->params.edf.active ) gsched->params.edf.active = NULL; /* set (separate) alarm for deadline */ alarm.action = edf_deadline_timer; alarm.param = kthread; alarm.flags = 0; alarm.period.sec = alarm.period.nsec = 0; alarm.exp_time = tsched->params.edf.active_deadline; k_alarm_set ( tsched->params.edf.edf_deadline_alarm, &alarm ); } /* is task ready for execution, or must wait until next period */ if ( time_cmp ( &tsched->params.edf.next_run, &now ) > 0 ) { /* wait till "next_run" */ LOG( DEBUG, "%x [EDF WAIT]", kthread ); kthread_enqueue ( kthread, &gsched->params.edf.wait ); kthreads_schedule (); /* will call edf_schedule() */ } else { /* "next_run" has already come, * activate task => move it to "EDF ready tasks" */ LOG( DEBUG, "%x [EDF READY]", kthread ); LOG( DEBUG, "%x [1st READY]", kthreadq_get ( &gsched->params.edf.ready ) ); kthread_enqueue ( kthread, &gsched->params.edf.ready ); kthreads_schedule (); /* will call edf_schedule() */ } } else if ( params->edf.flags & EDF_EXIT ) { if ( kthread == gsched->params.edf.active ) gsched->params.edf.active = NULL; //LOG( DEBUG, "%x [EXIT]", kthread ); if ( edf_check_deadline ( kthread ) ) { LOG( DEBUG, "%x [EXIT-error]", kthread ); return -1; } LOG( DEBUG, "%x [EXIT-normal]", kthread ); if ( tsched->params.edf.edf_period_alarm ) k_alarm_remove ( tsched->params.edf.edf_period_alarm ); if ( tsched->params.edf.edf_deadline_alarm ) k_alarm_remove ( tsched->params.edf.edf_deadline_alarm ); tsched->sched_policy = SCHED_FIFO; LOG( DEBUG, "%x [EXIT]", kthread ); if ( k_edf_schedule () ) { LOG( DEBUG, "%x [EXIT]", kthread ); kthreads_schedule (); /* will NOT call edf_schedule() */ } LOG( DEBUG, "%x [EXIT]", kthread ); } return 0; }