BCQ touch-ups (XCC)
[akaros.git] / kern / src / schedule.c
index a229b5d..ceff708 100644 (file)
@@ -100,17 +100,17 @@ static void set_ksched_alarm(void)
 /* 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)
 {
-       schedule();
+       run_scheduler();
 }
 
-/* Kmsg, to run the scheduler tick (not in interrupt context) and reset the
+/* 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
  * quiescent state. */
-static void __ksched_tick(uint32_t srcid, long a0, long a1, long a2)
+static void __ksched_tick(struct alarm_waiter *waiter)
 {
        /* 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! */
@@ -118,13 +118,6 @@ static void __ksched_tick(uint32_t srcid, long a0, long a1, long a2)
        set_alarm(&per_cpu_info[core_id()].tchain, &ksched_waiter);
 }
 
-/* Interrupt/alarm handler: tells our core to run the scheduler (out of
- * interrupt context). */
-static void __kalarm(struct alarm_waiter *waiter)
-{
-       send_kernel_message(core_id(), __ksched_tick, 0, 0, 0, KMSG_ROUTINE);
-}
-
 void schedule_init(void)
 {
        spin_lock(&sched_lock);
@@ -132,20 +125,20 @@ void schedule_init(void)
        all_pcores = kmalloc(sizeof(struct sched_pcore) * num_cpus, 0);
        memset(all_pcores, 0, sizeof(struct sched_pcore) * num_cpus);
        assert(!core_id());             /* want the alarm on core0 for now */
-       init_awaiter(&ksched_waiter, __kalarm);
+       init_awaiter(&ksched_waiter, __ksched_tick);
        set_ksched_alarm();
        /* 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);
@@ -153,7 +146,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;
 }
@@ -311,6 +304,23 @@ void __sched_scp_wakeup(struct proc *p)
        remove_from_any_list(p);
        add_to_list(p, &runnable_scps);
        spin_unlock(&sched_lock);
+       /* we could be on a CG core, and all the mgmt cores could be halted.  if we
+        * don't tell one of them about the new proc, they will sleep until the
+        * timer tick goes off. */
+       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
+                * different mgmt core could remain idle (and this process would sleep)
+                * until its tick goes off */
+               send_ipi(0, I_POKE_CORE);
+       }
 }
 
 /* Callback to return a core to the ksched, which tracks it as idle and
@@ -386,6 +396,7 @@ static bool __schedule_scp(void)
                         * 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);
+                       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);
@@ -510,8 +521,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. */
@@ -570,11 +584,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
@@ -848,7 +862,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);
 }
 
@@ -881,7 +895,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);
@@ -893,12 +907,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);
 }
@@ -921,3 +935,27 @@ void next_core(uint32_t pcoreid)
        }
        spin_unlock(&sched_lock);
 }
+
+void sort_idles(void)
+{
+       struct sched_pcore *spc_i, *spc_j, *temp;
+       struct sched_pcore_tailq sorter = TAILQ_HEAD_INITIALIZER(sorter);
+       bool added;
+       spin_lock(&sched_lock);
+       TAILQ_CONCAT(&sorter, &idlecores, alloc_next);
+       TAILQ_FOREACH_SAFE(spc_i, &sorter, alloc_next, temp) {
+               TAILQ_REMOVE(&sorter, spc_i, alloc_next);
+               added = FALSE;
+               /* don't need foreach_safe since we break after we muck with the list */
+               TAILQ_FOREACH(spc_j, &idlecores, alloc_next) {
+                       if (spc_i < spc_j) {
+                               TAILQ_INSERT_BEFORE(spc_j, spc_i, alloc_next);
+                               added = TRUE;
+                               break;
+                       }
+               }
+               if (!added)
+                       TAILQ_INSERT_TAIL(&idlecores, spc_i, alloc_next);
+       }
+       spin_unlock(&sched_lock);
+}