aboutsummaryrefslogtreecommitdiff
path: root/src/timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/timer.c')
-rw-r--r--src/timer.c31
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();
}