alarm: Do not hold the tchain lock during handlers
[akaros.git] / kern / src / schedule.c
index 83fc2bc..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. */
@@ -42,7 +43,7 @@ static uint32_t get_cores_needed(struct proc *p);
 /* poke-style ksched - ensures the MCP ksched only runs once at a time.  since
  * only one mcp ksched runs at a time, while this is set, the ksched knows no
  * cores are being allocated by other code (though they could be dealloc, due to
- * yield). 
+ * yield).
  *
  * The main value to this sync method is to make the 'make sure the ksched runs
  * only once at a time and that it actually runs' invariant/desire wait-free, so
@@ -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
@@ -290,23 +286,17 @@ static bool __schedule_scp(void)
        struct proc *p;
        uint32_t pcoreid = core_id();
        struct per_cpu_info *pcpui = &per_cpu_info[pcoreid];
-       int8_t state = 0;
        /* if there are any runnables, run them here and put any currently running
         * SCP on the tail of the runnable queue. */
        if ((p = TAILQ_FIRST(&runnable_scps))) {
-               /* protect owning proc, cur_ctx, etc.  note this nests with the
-                * calls in proc_yield_s */
-               disable_irqsave(&state);
                /* someone is currently running, dequeue them */
                if (pcpui->owning_proc) {
                        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);
-                               enable_irqsave(&state);
                                return FALSE;
                        }
                        printd("Descheduled %d in favor of %d\n", pcpui->owning_proc->pid,
@@ -330,12 +320,11 @@ static bool __schedule_scp(void)
                         * proc_run_s would pick it up.  This way is a bit safer for
                         * future changes, but has an extra (empty) TLB flush.  */
                        abandon_core();
-               } 
+               }
                /* Run the new proc */
                switch_lists(p, &runnable_scps, &unrunnable_scps);
                printd("PID of the SCP i'm running: %d\n", p->pid);
                proc_run_s(p);  /* gives it core we're running on */
-               enable_irqsave(&state);
                return TRUE;
        }
        return FALSE;
@@ -424,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
@@ -442,7 +431,7 @@ static void __run_mcp_ksched(void *arg)
 }
 
 /* Something has changed, and for whatever reason the scheduler should
- * reevaluate things. 
+ * reevaluate things.
  *
  * Don't call this if you are processing a syscall or otherwise care about your
  * kthread variables, cur_proc/owning_proc, etc.
@@ -503,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).