diff options
Diffstat (limited to 'src/timer.c')
| -rw-r--r-- | src/timer.c | 31 |
1 files changed, 29 insertions, 2 deletions
diff --git a/src/timer.c b/src/timer.c index 5583cd3..5b3ac86 100644 --- a/src/timer.c +++ b/src/timer.c @@ -73,6 +73,7 @@ static struct sp_root *__cpu_timers() void init_timer(const void *fdt) { + clear_timer(); ticks_per_sec = stat_timer(fdt); info("ticks_per_sec: %" PRIu64 "\n", ticks_per_sec); info("current ticks: %" PRIu64 "\n", current_ticks()); @@ -151,14 +152,23 @@ id_t new_rel_timer(id_t tid, ticks_t ticks) id_t new_abs_timer(id_t tid, ticks_t ticks) { + /* if there are no active timers or this timer is before the next active + * timer, start the hardware timer */ + struct timer *t = newest_timer(); + if (!t || ticks < t->ticks) + set_timer(ticks); + id_t id = __new_timer(tid, ticks); - set_timer(ticks); return id; } struct timer *newest_timer() { - struct sp_node *t = sp_first(sp_root(__cpu_timers())); + struct sp_node *r = sp_root(__cpu_timers()); + if (!r) + return NULL; + + struct sp_node *t = sp_first(r); return &timer_container(t)->timer; } @@ -202,9 +212,25 @@ void handle_timer() /** @todo should this also disable irqs? */ bkl_lock(); struct timer *t = newest_timer(); + if (!t) { + info("spurious timer\n"); + clear_timer(); + bkl_unlock(); + return; + } + id_t tid = t->tid; remove_timer(t); + + /* maybe schedule next timer event, maybe disable timer so we don't + * start infinitely retrigger the timer interrupt */ + t = newest_timer(); + if (t) + set_timer(t->ticks); + else + clear_timer(); + struct tcb *r = get_tcb(tid); if (!r || orphan(r)) { info("tcb %llu dead at timer\n", @@ -213,6 +239,7 @@ void handle_timer() return; } + /** @todo check that timer didn't trigger before scheduled time? */ notify(r, NOTIFY_TIMER); bkl_unlock(); } |
