#include <list.h>
|
|
#include <sync.h>
|
|
#include <proc.h>
|
|
#include <sched.h>
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
#include <default_sched.h>
|
|
|
|
// the list of timer
|
|
static list_entry_t timer_list;
|
|
|
|
static struct sched_class *sched_class;
|
|
|
|
static struct run_queue *rq;
|
|
|
|
static inline void
|
|
sched_class_enqueue(struct proc_struct *proc) {
|
|
if (proc != idleproc) {
|
|
sched_class->enqueue(rq, proc);
|
|
}
|
|
}
|
|
|
|
static inline void
|
|
sched_class_dequeue(struct proc_struct *proc) {
|
|
sched_class->dequeue(rq, proc);
|
|
}
|
|
|
|
static inline struct proc_struct *
|
|
sched_class_pick_next(void) {
|
|
return sched_class->pick_next(rq);
|
|
}
|
|
|
|
static void
|
|
sched_class_proc_tick(struct proc_struct *proc) {
|
|
if (proc != idleproc) {
|
|
sched_class->proc_tick(rq, proc);
|
|
}
|
|
else {
|
|
proc->need_resched = 1;
|
|
}
|
|
}
|
|
|
|
static struct run_queue __rq;
|
|
|
|
void
|
|
sched_init(void) {
|
|
list_init(&timer_list);
|
|
|
|
sched_class = &default_sched_class;
|
|
|
|
rq = &__rq;
|
|
rq->max_time_slice = MAX_TIME_SLICE;
|
|
sched_class->init(rq);
|
|
|
|
cprintf("sched class: %s\n", sched_class->name);
|
|
}
|
|
|
|
void
|
|
wakeup_proc(struct proc_struct *proc) {
|
|
assert(proc->state != PROC_ZOMBIE);
|
|
bool intr_flag;
|
|
local_intr_save(intr_flag);
|
|
{
|
|
if (proc->state != PROC_RUNNABLE) {
|
|
proc->state = PROC_RUNNABLE;
|
|
proc->wait_state = 0;
|
|
if (proc != current) {
|
|
sched_class_enqueue(proc);
|
|
}
|
|
}
|
|
else {
|
|
warn("wakeup runnable process.\n");
|
|
}
|
|
}
|
|
local_intr_restore(intr_flag);
|
|
}
|
|
|
|
void
|
|
schedule(void) {
|
|
bool intr_flag;
|
|
struct proc_struct *next;
|
|
local_intr_save(intr_flag);
|
|
{
|
|
current->need_resched = 0;
|
|
if (current->state == PROC_RUNNABLE) {
|
|
sched_class_enqueue(current);
|
|
}
|
|
if ((next = sched_class_pick_next()) != NULL) {
|
|
sched_class_dequeue(next);
|
|
}
|
|
if (next == NULL) {
|
|
next = idleproc;
|
|
}
|
|
next->runs ++;
|
|
if (next != current) {
|
|
proc_run(next);
|
|
}
|
|
}
|
|
local_intr_restore(intr_flag);
|
|
}
|
|
|
|
void
|
|
add_timer(timer_t *timer) {
|
|
bool intr_flag;
|
|
local_intr_save(intr_flag);
|
|
{
|
|
assert(timer->expires > 0 && timer->proc != NULL);
|
|
assert(list_empty(&(timer->timer_link)));
|
|
list_entry_t *le = list_next(&timer_list);
|
|
while (le != &timer_list) {
|
|
timer_t *next = le2timer(le, timer_link);
|
|
if (timer->expires < next->expires) {
|
|
next->expires -= timer->expires;
|
|
break;
|
|
}
|
|
timer->expires -= next->expires;
|
|
le = list_next(le);
|
|
}
|
|
list_add_before(le, &(timer->timer_link));
|
|
}
|
|
local_intr_restore(intr_flag);
|
|
}
|
|
|
|
// del timer from timer_list
|
|
void
|
|
del_timer(timer_t *timer) {
|
|
bool intr_flag;
|
|
local_intr_save(intr_flag);
|
|
{
|
|
if (!list_empty(&(timer->timer_link))) {
|
|
if (timer->expires != 0) {
|
|
list_entry_t *le = list_next(&(timer->timer_link));
|
|
if (le != &timer_list) {
|
|
timer_t *next = le2timer(le, timer_link);
|
|
next->expires += timer->expires;
|
|
}
|
|
}
|
|
list_del_init(&(timer->timer_link));
|
|
}
|
|
}
|
|
local_intr_restore(intr_flag);
|
|
}
|
|
|
|
// call scheduler to update tick related info, and check the timer is expired? If expired, then wakup proc
|
|
void
|
|
run_timer_list(void) {
|
|
bool intr_flag;
|
|
local_intr_save(intr_flag);
|
|
{
|
|
list_entry_t *le = list_next(&timer_list);
|
|
if (le != &timer_list) {
|
|
timer_t *timer = le2timer(le, timer_link);
|
|
assert(timer->expires != 0);
|
|
timer->expires --;
|
|
while (timer->expires == 0) {
|
|
le = list_next(le);
|
|
struct proc_struct *proc = timer->proc;
|
|
if (proc->wait_state != 0) {
|
|
assert(proc->wait_state & WT_INTERRUPTED);
|
|
}
|
|
else {
|
|
warn("process %d's wait_state == 0.\n", proc->pid);
|
|
}
|
|
wakeup_proc(proc);
|
|
del_timer(timer);
|
|
if (le == &timer_list) {
|
|
break;
|
|
}
|
|
timer = le2timer(le, timer_link);
|
|
}
|
|
}
|
|
sched_class_proc_tick(current);
|
|
}
|
|
local_intr_restore(intr_flag);
|
|
}
|