alarm: Do not hold the tchain lock during handlers
[akaros.git] / kern / src / schedule.c
index aeceb1b..4804885 100644 (file)
@@ -16,6 +16,7 @@
 #include <alarm.h>
 #include <sys/queue.h>
 #include <arsc_server.h>
+#include <hashtable.h>
 
 /* Process Lists.  'unrunnable' is a holding list for SCPs that are running or
  * waiting or otherwise not considered for sched decisions. */
@@ -78,12 +79,6 @@ static void set_ksched_alarm(void)
        set_alarm(&per_cpu_info[core_id()].tchain, &ksched_waiter);
 }
 
-/* Need a kmsg to just run the sched, but not to rearm */
-static void __just_sched(uint32_t srcid, long a0, long a1, long a2)
-{
-       run_scheduler();
-}
-
 /* RKM alarm, to run the scheduler tick (not in interrupt context) and reset the
  * alarm.  Note that interrupts will be disabled, but this is not the same as
  * interrupt context.  We're a routine kmsg, which means the core is in a
@@ -92,10 +87,12 @@ static void __ksched_tick(struct alarm_waiter *waiter)
 {
        /* TODO: imagine doing some accounting here */
        run_scheduler();
-       /* Set our alarm to go off, incrementing from our last tick (instead of
-        * setting it relative to now, since some time has passed since the alarm
-        * first went off.  Note, this may be now or in the past! */
-       set_awaiter_inc(&ksched_waiter, TIMER_TICK_USEC);
+       /* Set our alarm to go off, relative to now.  This means we might lag a bit,
+        * and our ticks won't match wall clock time.  But if we do incremental,
+        * we'll actually punish the next process because the kernel took too long
+        * for the previous process.  Ultimately, if we really care, we should
+        * account for the actual time used. */
+       set_awaiter_rel(&ksched_waiter, TIMER_TICK_USEC);
        set_alarm(&per_cpu_info[core_id()].tchain, &ksched_waiter);
 }
 
@@ -109,6 +106,9 @@ void schedule_init(void)
        spin_unlock(&sched_lock);
 
 #ifdef CONFIG_ARSC_SERVER
+       /* Most likely we'll have a syscall and a process that dedicates itself to
+        * running this.  Or if it's a kthread, we don't need a core. */
+       #error "Find a way to get a core.  Probably a syscall to run a server."
        int arsc_coreid = get_any_idle_core();
        assert(arsc_coreid >= 0);
        send_kernel_message(arsc_coreid, arsc_server, 0, 0, 0, KMSG_ROUTINE);
@@ -159,7 +159,7 @@ static void remove_from_any_list(struct proc *p)
  *   DYING */
 void __sched_proc_register(struct proc *p)
 {
-       assert(p->state != PROC_DYING); /* shouldn't be abel to happen yet */
+       assert(!proc_is_dying(p));              /* shouldn't be able to happen yet */
        /* one ref for the proc's existence, cradle-to-grave */
        proc_incref(p, 1);      /* need at least this OR the 'one for existing' */
        spin_lock(&sched_lock);
@@ -175,7 +175,7 @@ void __sched_proc_change_to_m(struct proc *p)
        /* Need to make sure they aren't dying.  if so, we already dealt with their
         * list membership, etc (or soon will).  taking advantage of the 'immutable
         * state' of dying (so long as refs are held). */
-       if (p->state == PROC_DYING) {
+       if (proc_is_dying(p)) {
                spin_unlock(&sched_lock);
                return;
        }
@@ -219,7 +219,7 @@ void __sched_proc_destroy(struct proc *p, uint32_t *pc_arr, uint32_t nr_cores)
 void __sched_mcp_wakeup(struct proc *p)
 {
        spin_lock(&sched_lock);
-       if (p->state == PROC_DYING) {
+       if (proc_is_dying(p)) {
                spin_unlock(&sched_lock);
                return;
        }
@@ -233,7 +233,7 @@ void __sched_mcp_wakeup(struct proc *p)
 void __sched_scp_wakeup(struct proc *p)
 {
        spin_lock(&sched_lock);
-       if (p->state == PROC_DYING) {
+       if (proc_is_dying(p)) {
                spin_unlock(&sched_lock);
                return;
        }
@@ -247,10 +247,6 @@ void __sched_scp_wakeup(struct proc *p)
        if (!management_core()) {
                /* TODO: pick a better core and only send if halted.
                 *
-                * FYI, a POKE on x86 might lose a rare race with halt code, since the
-                * poke handler does not abort halts.  if this happens, the next timer
-                * IRQ would wake up the core.
-                *
                 * ideally, we'd know if a specific mgmt core is sleeping and wake it
                 * up.  o/w, we could interrupt an already-running mgmt core that won't
                 * get to our new proc anytime soon.  also, by poking core 0, a
@@ -298,9 +294,8 @@ static bool __schedule_scp(void)
                        spin_lock(&pcpui->owning_proc->proc_lock);
                        /* process might be dying, with a KMSG to clean it up waiting on
                         * this core.  can't do much, so we'll attempt to restart */
-                       if (pcpui->owning_proc->state == PROC_DYING) {
-                               send_kernel_message(core_id(), __just_sched, 0, 0, 0,
-                                                   KMSG_ROUTINE);
+                       if (proc_is_dying(pcpui->owning_proc)) {
+                               run_as_rkm(run_scheduler);
                                spin_unlock(&pcpui->owning_proc->proc_lock);
                                return FALSE;
                        }
@@ -418,7 +413,7 @@ static void __run_mcp_ksched(void *arg)
                         * DYING, it'll remain DYING until we decref.  And if there is a
                         * concurrent death, that will spin on the ksched lock (which we
                         * hold, and which protects the proc lists). */
-                       if (p->state != PROC_DYING)
+                       if (!proc_is_dying(p))
                                add_to_list(p, secondary_mcps);
                        proc_decref(p);                 /* fyi, this may trigger __proc_free */
                        /* need to break: the proc lists may have changed when we unlocked
@@ -497,30 +492,6 @@ void avail_res_changed(int res_type, long change)
        printk("[kernel] ksched doesn't track any resources yet!\n");
 }
 
-int get_any_idle_core(void)
-{
-       spin_lock(&sched_lock);
-       int ret = __get_any_idle_core();
-       spin_unlock(&sched_lock);
-       return ret;
-}
-
-int get_specific_idle_core(int coreid)
-{
-       spin_lock(&sched_lock);
-       int ret = __get_specific_idle_core(coreid);
-       spin_unlock(&sched_lock);
-       return ret;
-}
-
-/* similar to __sched_put_idle_core, but without the prov tracking */
-void put_idle_core(int coreid)
-{
-       spin_lock(&sched_lock);
-       __put_idle_core(coreid);
-       spin_unlock(&sched_lock);
-}
-
 /* This deals with a request for more cores.  The amt of new cores needed is
  * passed in.  The ksched lock is held, but we are free to unlock if we want
  * (and we must, if calling out of the ksched to anything high-level).