alarm: Do not hold the tchain lock during handlers
[akaros.git] / kern / src / schedule.c
index 054c878..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. */
@@ -28,17 +29,12 @@ struct proc_list all_mcps_2 = TAILQ_HEAD_INITIALIZER(all_mcps_2);
 struct proc_list *primary_mcps = &all_mcps_1;
 struct proc_list *secondary_mcps = &all_mcps_2;
 
-/* TAILQ of all unallocated, idle (CG) cores.
- * Pulled from corealloc.c at the moment */
-extern struct sched_pcore_tailq idlecores;
-
 /* Helper, defined below */
 static void __core_request(struct proc *p, uint32_t amt_needed);
 static void add_to_list(struct proc *p, struct proc_list *list);
 static void remove_from_list(struct proc *p, struct proc_list *list);
 static void switch_lists(struct proc *p, struct proc_list *old,
                          struct proc_list *new);
-static bool is_ll_core(uint32_t pcoreid);
 static void __run_mcp_ksched(void *arg);       /* don't call directly */
 static uint32_t get_cores_needed(struct proc *p);
 
@@ -47,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
@@ -63,12 +59,10 @@ struct poke_tracker ksched_poker = POKE_INITIALIZER(__run_mcp_ksched);
  * of a proc on those lists.  proc lifetime within the ksched but outside this
  * lock is protected by the proc kref. */
 //spinlock_t proclist_lock = SPINLOCK_INITIALIZER; /* subsumed by bksl */
-/* - protects the provisioning assignment, membership of sched_pcores in
- * provision lists, and the integrity of all prov lists (the lists of each
- * proc).  does NOT protect spc->alloc_proc. */
+/* - protects the provisioning assignment, and the integrity of all prov
+ * lists (the lists of each proc). */
 //spinlock_t prov_lock = SPINLOCK_INITIALIZER;
-/* - protects allocation structures: spc->alloc_proc, the integrity and
- * membership of the idelcores tailq. */
+/* - protects allocation structures */
 //spinlock_t alloc_lock = SPINLOCK_INITIALIZER;
 spinlock_t sched_lock = SPINLOCK_INITIALIZER;
 
@@ -85,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
@@ -99,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);
 }
 
@@ -116,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);
@@ -166,11 +159,11 @@ 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);
-       coreprov_proc_init(p);
+       corealloc_proc_init(p);
        add_to_list(p, &unrunnable_scps);
        spin_unlock(&sched_lock);
 }
@@ -182,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;
        }
@@ -226,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;
        }
@@ -240,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;
        }
@@ -254,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
@@ -274,7 +263,6 @@ void __sched_scp_wakeup(struct proc *p)
  * a scheduling decision (or at least plan to). */
 void __sched_put_idle_core(struct proc *p, uint32_t coreid)
 {
-       struct sched_pcore *spc = pcoreid2spc(coreid);
        spin_lock(&sched_lock);
        __track_core_dealloc(p, coreid);
        spin_unlock(&sched_lock);
@@ -298,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,
@@ -323,7 +305,7 @@ static bool __schedule_scp(void)
                        /* 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);
+                       __proc_save_context_s(pcpui->owning_proc);
                        vcore_account_offline(pcpui->owning_proc, 0);
                        __seq_start_write(&p->procinfo->coremap_seqctr);
                        __unmap_vcore(p, 0);
@@ -338,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;
@@ -432,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
@@ -450,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.
@@ -511,41 +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);
-}
-
-/* Normally it'll be the max number of CG cores ever */
-uint32_t max_vcores(struct proc *p)
-{
-/* TODO: (CG/LL) */
-#ifdef CONFIG_DISABLE_SMT
-       return num_cores >> 1;
-#else
-       return num_cores - 1;   /* reserving core 0 */
-#endif /* CONFIG_DISABLE_SMT */
-}
-
 /* 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).
@@ -559,7 +505,7 @@ static void __core_request(struct proc *p, uint32_t amt_needed)
 {
        uint32_t nr_to_grant = 0;
        uint32_t corelist[num_cores];
-       struct sched_pcore *spc_i, *temp;
+       uint32_t pcoreid;
        struct proc *proc_to_preempt;
        bool success;
        /* we come in holding the ksched lock, and we hold it here to protect
@@ -570,24 +516,24 @@ static void __core_request(struct proc *p, uint32_t amt_needed)
        while (nr_to_grant != amt_needed) {
                /* Find the next best core to allocate to p. It may be a core
                 * provisioned to p, and it might not be. */
-               spc_i = __find_best_core_to_alloc(p);
+               pcoreid = __find_best_core_to_alloc(p);
                /* If no core is returned, we know that there are no more cores to give
                 * out, so we exit the loop. */
-               if (spc_i == NULL)
+               if (pcoreid == -1)
                        break;
                /* If the pcore chosen currently has a proc allocated to it, we know
                 * it must be provisioned to p, but not allocated to it. We need to try
                 * to preempt. After this block, the core will be track_dealloc'd and
                 * on the idle list (regardless of whether we had to preempt or not) */
-               if (get_alloc_proc(spc_i)) {
-                       proc_to_preempt = get_alloc_proc(spc_i);
+               if (get_alloc_proc(pcoreid)) {
+                       proc_to_preempt = get_alloc_proc(pcoreid);
                        /* would break both preemption and maybe the later decref */
                        assert(proc_to_preempt != p);
                        /* need to keep a valid, external ref when we unlock */
                        proc_incref(proc_to_preempt, 1);
                        spin_unlock(&sched_lock);
                        /* sending no warning time for now - just an immediate preempt. */
-                       success = proc_preempt_core(proc_to_preempt, spc2pcoreid(spc_i), 0);
+                       success = proc_preempt_core(proc_to_preempt, pcoreid, 0);
                        /* reaquire locks to protect provisioning and idle lists */
                        spin_lock(&sched_lock);
                        if (success) {
@@ -596,11 +542,11 @@ static void __core_request(struct proc *p, uint32_t amt_needed)
                                 * idle CBs).  the core is not on the idle core list.  (if we
                                 * ever have proc alloc lists, it'll still be on the old proc's
                                 * list). */
-                               assert(get_alloc_proc(spc_i));
+                               assert(get_alloc_proc(pcoreid));
                                /* regardless of whether or not it is still prov to p, we need
                                 * to note its dealloc.  we are doing some excessive checking of
                                 * p == prov_proc, but using this helper is a lot clearer. */
-                               __track_core_dealloc(proc_to_preempt, spc2pcoreid(spc_i));
+                               __track_core_dealloc(proc_to_preempt, pcoreid);
                        } else {
                                /* the preempt failed, which should only happen if the pcore was
                                 * unmapped (could be dying, could be yielding, but NOT
@@ -618,7 +564,7 @@ static void __core_request(struct proc *p, uint32_t amt_needed)
                                 * allocator, the pcore could have been put on the idle list and
                                 * then quickly removed/allocated. */
                                cmb();
-                               while (get_alloc_proc(spc_i)) {
+                               while (get_alloc_proc(pcoreid)) {
                                        /* this loop should be very rare */
                                        spin_unlock(&sched_lock);
                                        udelay(1);
@@ -627,9 +573,9 @@ static void __core_request(struct proc *p, uint32_t amt_needed)
                        }
                        /* no longer need to keep p_to_pre alive */
                        proc_decref(proc_to_preempt);
-                       /* might not be prov to p anymore (rare race).  spc_i is idle - we
+                       /* might not be prov to p anymore (rare race). pcoreid is idle - we
                         * might get it later, or maybe we'll give it to its rightful proc*/
-                       if (get_prov_proc(spc_i) != p)
+                       if (get_prov_proc(pcoreid) != p)
                                continue;
                }
                /* At this point, the pcore is idle, regardless of how we got here
@@ -637,13 +583,13 @@ static void __core_request(struct proc *p, uint32_t amt_needed)
                 * place).  We also know the core is still provisioned to us.  Lets add
                 * it to the corelist for p (so we can give it to p in bulk later), and
                 * track its allocation with p (so our internal data structures stay in
-                * sync). We rely on the fact that we are the only allocator (spc_i is
+                * sync). We rely on the fact that we are the only allocator (pcoreid is
                 * still idle, despite (potentially) unlocking during the preempt
                 * attempt above).  It is guaranteed to be track_dealloc'd()
                 * (regardless of how we got here). */
-               corelist[nr_to_grant] = spc2pcoreid(spc_i);
+               corelist[nr_to_grant] = pcoreid;
                nr_to_grant++;
-               __track_core_alloc(p, spc2pcoreid(spc_i));
+               __track_core_alloc(p, pcoreid);
        }
        /* Now, actually give them out */
        if (nr_to_grant) {
@@ -680,22 +626,10 @@ static void __core_request(struct proc *p, uint32_t amt_needed)
        /* note the ksched lock is still held */
 }
 
-/* TODO: need more thorough CG/LL management.  For now, core0 is the only LL
- * core.  This won't play well with the ghetto shit in schedule_init() if you do
- * anything like 'DEDICATED_MONITOR' or the ARSC server.  All that needs an
- * overhaul. */
-static bool is_ll_core(uint32_t pcoreid)
-{
-       if (pcoreid == 0)
-               return TRUE;
-       return FALSE;
-}
-
 /* Provision a core to a process. This function wraps the primary logic
  * implemented in __provision_core, with a lock, error checking, etc. */
 int provision_core(struct proc *p, uint32_t pcoreid)
 {
-       struct sched_pcore *spc;
        /* Make sure we aren't asking for something that doesn't exist (bounds check
         * on the pcore array) */
        if (!(pcoreid < num_cores)) {
@@ -707,12 +641,11 @@ int provision_core(struct proc *p, uint32_t pcoreid)
                set_errno(EBUSY);
                return -1;
        }
-       spc = pcoreid2spc(pcoreid);
-       /* Note the sched lock protects the spc tailqs for all procs in this code.
+       /* Note the sched lock protects the tailqs for all procs in this code.
         * If we need a finer grained sched lock, this is one place where we could
         * have a different lock */
        spin_lock(&sched_lock);
-       __provision_core(p, spc);
+       __provision_core(p, pcoreid);
        spin_unlock(&sched_lock);
        return 0;
 }