Converts sys_halt_core() to use alarms
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 4 May 2011 22:50:57 +0000 (15:50 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:36:02 +0000 (17:36 -0700)
Not sure what we want to do long term for core halting.  This will keep
halting the core until the timer is up, servicing interrupts along the
way.  There are a lot of interrupts coming in to core 0 on hardware too.

Note if you want to kfunc sys_halt_core(), your arguments are in hex. =P

kern/src/alarm.c
kern/src/syscall.c
tests/idle.c

index 48e99d4..da03cc9 100644 (file)
@@ -77,10 +77,12 @@ static void reset_tchain_interrupt(struct timer_chain *tchain)
        assert(!irq_is_enabled());
        if (TAILQ_EMPTY(&tchain->waiters)) {
                /* Turn it off */
+               printd("Turning alarm off\n");
                tchain->set_interrupt(0, tchain);
        } else {
                /* Make sure it is on and set to the earliest time */
                /* TODO: check for times in the past or very close to now */
+               printd("Turning alarm on for %llu\n", tchain->earliest_time);
                tchain->set_interrupt(tchain->earliest_time, tchain);
        }
 }
@@ -110,7 +112,7 @@ void trigger_tchain(struct timer_chain *tchain)
        bool changed_list = FALSE;
        assert(!irq_is_enabled());
        TAILQ_FOREACH_SAFE(i, &tchain->waiters, next, temp) {
-               printd("Trying to wake up %08p who is due at %llu and it is now %llu\n",
+               printd("Trying to wake up %08p who is due at %llu and now is %llu\n",
                       i, i->wake_up_time, now);
                /* TODO: Could also do something in cases where we're close to now */
                if (i->wake_up_time <= now) {
@@ -174,7 +176,8 @@ void set_alarm(struct timer_chain *tchain, struct alarm_waiter *waiter)
        enable_irqsave(&irq_state);
 }
 
-/* Removes waiter from the tchain before it goes off.  */
+/* Removes waiter from the tchain before it goes off. 
+ * TODO: handle waiters that already went off. */
 void unset_alarm(struct timer_chain *tchain, struct alarm_waiter *waiter)
 {
        struct alarm_waiter *temp;
@@ -182,6 +185,7 @@ void unset_alarm(struct timer_chain *tchain, struct alarm_waiter *waiter)
        int8_t irq_state = 0;
 
        disable_irqsave(&irq_state);
+       warn("Code currently assumes the alarm waiter hasn't triggered yet!");
        /* Need to make sure earliest and latest are set, in case we're mucking with
         * the first and/or last element of the chain. */
        if (TAILQ_FIRST(&tchain->waiters) == waiter) {
index 07d5411..01360f6 100644 (file)
@@ -694,17 +694,31 @@ static int sys_self_notify(struct proc *p, uint32_t vcoreid,
        return 0;
 }
 
-/* This will set a local timer for usec, then shut down the core */
+/* This will set a local timer for usec, then shut down the core.  There's a
+ * slight race between spinner and halt.  For now, the core will wake up for
+ * other interrupts and service them, but will not process routine messages or
+ * do anything other than halt until the alarm goes off.  We could just unset
+ * the alarm and return early.  On hardware, there are a lot of interrupts that
+ * come in.  If we ever use this, we can take a closer look.  */
 static int sys_halt_core(struct proc *p, unsigned int usec)
 {
-       /* TODO: ought to check and see if a timer was already active, etc, esp so
-        * userspace can't turn off timers.  also note we will also call whatever
-        * timer_interrupt() will do, though all we care about is just
-        * self_ipi/interrupting. */
-       set_core_timer(usec);
-       cpu_halt();
-       set_core_timer(0);              /* Disable the timer (we don't have a 0-shot yet) */
-
+       struct timer_chain *tchain = &per_cpu_info[core_id()].tchain;
+       struct alarm_waiter a_waiter;
+       bool spinner = TRUE;
+       void unblock(struct alarm_waiter *waiter)
+       {
+               spinner = FALSE;
+       }
+       init_awaiter(&a_waiter, unblock);
+       set_awaiter_rel(&a_waiter, MAX(usec, 100));
+       set_alarm(tchain, &a_waiter);
+       enable_irq();
+       /* Could wake up due to another interrupt, but we want to sleep still. */
+       while (spinner) {
+               cpu_halt();     /* slight race between spinner and halt */
+               cpu_relax();
+       }
+       printd("Returning from halting\n");
        return 0;
 }
 
index a4bca82..7570069 100644 (file)
@@ -1,12 +1,22 @@
 #include <parlib.h>
 #include <stdio.h>
+#include <stdlib.h>
 
 /* This will keep a core from spinning forever, but will also allow it to still
- * schedule() and run _S processes. */
+ * schedule() and run _S processes.  arg1 is the number of loops (0 for
+ * forever), and arg2 is how many usec to wait per loop. */
 int main(int argc, char** argv)
 {
-       while (1) {
-               sys_halt_core(5000000); // 5 sec, adjust accordingly
+       unsigned long nr_loops = 1;                     /* default, 1 loop */
+       unsigned long timeout = 5000000;        /* default, 5 sec */
+       int i = 0;
+       if (argc > 1)
+               nr_loops = strtol(argv[1], 0, 10);
+       if (argc > 2)
+               timeout = strtol(argv[2], 0, 10);
+       printf("Idling for %d usec for %d loops\n", timeout, nr_loops);
+       while (!nr_loops || i++ < nr_loops) {
+               sys_halt_core(timeout);
                sys_yield(0);
        }
        return 0;