prof: samples userspace PCs
[akaros.git] / kern / src / schedule.c
index 3aa3218..ad7ab6c 100644 (file)
@@ -97,6 +97,12 @@ 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();
+}
+
 /* Kmsg, 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
@@ -104,7 +110,7 @@ static void set_ksched_alarm(void)
 static void __ksched_tick(uint32_t srcid, long a0, long a1, long a2)
 {
        /* TODO: imagine doing some accounting here */
-       schedule();
+       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! */
@@ -116,6 +122,8 @@ static void __ksched_tick(uint32_t srcid, long a0, long a1, long a2)
  * interrupt context). */
 static void __kalarm(struct alarm_waiter *waiter)
 {
+       /* Not necessary when alarms are running in RKM context (check
+        * timer_interrupt()) */
        send_kernel_message(core_id(), __ksched_tick, 0, 0, 0, KMSG_ROUTINE);
 }
 
@@ -131,15 +139,15 @@ void schedule_init(void)
        /* init the idlecore list.  if they turned off hyperthreading, give them the
         * odds from 1..max-1.  otherwise, give them everything by 0 (default mgmt
         * core).  TODO: (CG/LL) better LL/CG mgmt */
-#ifndef __CONFIG_DISABLE_SMT__
+#ifndef CONFIG_DISABLE_SMT
        for (int i = 1; i < num_cpus; i++)
                TAILQ_INSERT_TAIL(&idlecores, pcoreid2spc(i), alloc_next);
 #else
        assert(!(num_cpus % 2));
        for (int i = 1; i < num_cpus; i += 2)
                TAILQ_INSERT_TAIL(&idlecores, pcoreid2spc(i), alloc_next);
-#endif /* __CONFIG_DISABLE_SMT__ */
-#ifdef __CONFIG_ARSC_SERVER__
+#endif /* CONFIG_DISABLE_SMT */
+#ifdef CONFIG_ARSC_SERVER
        struct sched_pcore *a_core = TAILQ_FIRST(&idlecores);
        assert(a_core);
        TAILQ_REMOVE(&idlecores, a_core, alloc_next);
@@ -147,7 +155,7 @@ void schedule_init(void)
                            KMSG_ROUTINE);
        warn("Using core %d for the ARSCs - there are probably issues with this.",
             spc2pcoreid(a_core));
-#endif /* __CONFIG_ARSC_SERVER__ */
+#endif /* CONFIG_ARSC_SERVER */
        spin_unlock(&sched_lock);
        return;
 }
@@ -287,10 +295,7 @@ void __sched_mcp_wakeup(struct proc *p)
                spin_unlock(&sched_lock);
                return;
        }
-       /* could try and prioritize p somehow (move it to the front of the list).
-        * for now, just help them out a bit (mild help here, can remove this) */
-       if (!p->procdata->res_req[RES_CORES].amt_wanted)
-               p->procdata->res_req[RES_CORES].amt_wanted = 1;
+       /* could try and prioritize p somehow (move it to the front of the list). */
        spin_unlock(&sched_lock);
        /* note they could be dying at this point too. */
        poke(&ksched_poker, p);
@@ -366,13 +371,25 @@ static bool __schedule_scp(void)
                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);
+                               spin_unlock(&pcpui->owning_proc->proc_lock);
+                               enable_irqsave(&state);
+                               return FALSE;
+                       }
                        printd("Descheduled %d in favor of %d\n", pcpui->owning_proc->pid,
                               p->pid);
-                       /* locking just to be safe */
-                       spin_lock(&p->proc_lock);
                        __proc_set_state(pcpui->owning_proc, PROC_RUNNABLE_S);
+                       /* Saving FP state aggressively.  Odds are, the SCP was hit by an
+                        * IRQ and has a HW ctx, in which case we must save. */
+                       __proc_save_fpu_s(pcpui->owning_proc);
                        __proc_save_context_s(pcpui->owning_proc, pcpui->cur_ctx);
-                       spin_unlock(&p->proc_lock);
+                       vcore_account_offline(pcpui->owning_proc, 0); /* VC# */
+                       spin_unlock(&pcpui->owning_proc->proc_lock);
                        /* round-robin the SCPs (inserts at the end of the queue) */
                        switch_lists(pcpui->owning_proc, &unrunnable_scps, &runnable_scps);
                        clear_owning_proc(pcoreid);
@@ -402,6 +419,18 @@ static uint32_t get_cores_needed(struct proc *p)
        /* Help them out - if they ask for something impossible, give them 1 so they
         * can make some progress. (this is racy, and unnecessary). */
        if (amt_wanted > p->procinfo->max_vcores) {
+               printk("[kernel] proc %d wanted more than max, wanted %d\n", p->pid,
+                      amt_wanted);
+               p->procdata->res_req[RES_CORES].amt_wanted = 1;
+               amt_wanted = 1;
+       }
+       /* There are a few cases where amt_wanted is 0, but they are still RUNNABLE
+        * (involving yields, events, and preemptions).  In these cases, give them
+        * at least 1, so they can make progress and yield properly.  If they are
+        * not WAITING, they did not yield and may have missed a message. */
+       if (!amt_wanted) {
+               /* could ++, but there could be a race and we don't want to give them
+                * more than they ever asked for (in case they haven't prepped) */
                p->procdata->res_req[RES_CORES].amt_wanted = 1;
                amt_wanted = 1;
        }
@@ -484,8 +513,11 @@ static void __run_mcp_ksched(void *arg)
 /* Something has changed, and for whatever reason the scheduler should
  * reevaluate things. 
  *
+ * Don't call this if you are processing a syscall or otherwise care about your
+ * kthread variables, cur_proc/owning_proc, etc.
+ *
  * Don't call this from interrupt context (grabs proclocks). */
-void schedule(void)
+void run_scheduler(void)
 {
        /* MCP scheduling: post work, then poke.  for now, i just want the func to
         * run again, so merely a poke is sufficient. */
@@ -500,7 +532,7 @@ void schedule(void)
 /* A process is asking the ksched to look at its resource desires.  The
  * scheduler is free to ignore this, for its own reasons, so long as it
  * eventually gets around to looking at resource desires. */
-void poke_ksched(struct proc *p, int res_type)
+void poke_ksched(struct proc *p, unsigned int res_type)
 {
        /* ignoring res_type for now.  could post that if we wanted (would need some
         * other structs/flags) */
@@ -544,11 +576,11 @@ void avail_res_changed(int res_type, long change)
 uint32_t max_vcores(struct proc *p)
 {
 /* TODO: (CG/LL) */
-#ifdef __CONFIG_DISABLE_SMT__
+#ifdef CONFIG_DISABLE_SMT
        return num_cpus >> 1;
 #else
        return num_cpus - 1;    /* reserving core 0 */
-#endif /* __CONFIG_DISABLE_SMT__ */
+#endif /* CONFIG_DISABLE_SMT */
 }
 
 /* This deals with a request for more cores.  The amt of new cores needed is
@@ -822,7 +854,7 @@ void print_idlecoremap(void)
        /* not locking, so we can look at this without deadlocking. */
        printk("Idle cores (unlocked!):\n");
        TAILQ_FOREACH(spc_i, &idlecores, alloc_next)
-               printk("Core %d, prov to %d (%08p)\n", spc2pcoreid(spc_i),
+               printk("Core %d, prov to %d (%p)\n", spc2pcoreid(spc_i),
                       spc_i->prov_proc ? spc_i->prov_proc->pid : 0, spc_i->prov_proc);
 }
 
@@ -855,7 +887,7 @@ void print_prov_map(void)
        printk("Which cores are provisioned to which procs:\n------------------\n");
        for (int i = 0; i < num_cpus; i++) {
                spc_i = pcoreid2spc(i);
-               printk("Core %02d, prov: %d(%08p) alloc: %d(%08p)\n", i,
+               printk("Core %02d, prov: %d(%p) alloc: %d(%p)\n", i,
                       spc_i->prov_proc ? spc_i->prov_proc->pid : 0, spc_i->prov_proc,
                       spc_i->alloc_proc ? spc_i->alloc_proc->pid : 0,
                       spc_i->alloc_proc);
@@ -867,12 +899,12 @@ void print_proc_prov(struct proc *p)
        struct sched_pcore *spc_i;
        if (!p)
                return;
-       printk("Prov cores alloced to proc %d (%08p)\n----------\n", p->pid, p);
+       printk("Prov cores alloced to proc %d (%p)\n----------\n", p->pid, p);
        TAILQ_FOREACH(spc_i, &p->ksched_data.prov_alloc_me, prov_next)
                printk("Pcore %d\n", spc2pcoreid(spc_i));
-       printk("Prov cores not alloced to proc %d (%08p)\n----------\n", p->pid, p);
+       printk("Prov cores not alloced to proc %d (%p)\n----------\n", p->pid, p);
        TAILQ_FOREACH(spc_i, &p->ksched_data.prov_not_alloc_me, prov_next)
-               printk("Pcore %d (alloced to %d (%08p))\n", spc2pcoreid(spc_i),
+               printk("Pcore %d (alloced to %d (%p))\n", spc2pcoreid(spc_i),
                       spc_i->alloc_proc ? spc_i->alloc_proc->pid : 0,
                       spc_i->alloc_proc);
 }