Alias "e" to monitor's "exit"
[akaros.git] / kern / src / schedule.c
index 280e74f..8512851 100644 (file)
@@ -4,10 +4,6 @@
  *
  * Scheduling and dispatching. */
 
-#ifdef __SHARC__
-#pragma nosharc
-#endif
-
 #include <schedule.h>
 #include <process.h>
 #include <monitor.h>
@@ -19,6 +15,7 @@
 #include <alarm.h>
 #include <sys/queue.h>
 #include <kmalloc.h>
+#include <arsc_server.h>
 
 /* Process Lists.  'unrunnable' is a holding list for SCPs that are running or
  * waiting or otherwise not considered for sched decisions. */
@@ -39,7 +36,6 @@ struct sched_pcore_tailq idlecores = TAILQ_HEAD_INITIALIZER(idlecores);
 
 /* Helper, defined below */
 static void __core_request(struct proc *p, uint32_t amt_needed);
-static void __put_idle_cores(struct proc *p, uint32_t *pc_arr, uint32_t num);
 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,
@@ -67,7 +63,7 @@ static uint32_t get_cores_needed(struct proc *p);
  *
  * As the ksched gets smarter, we'll probably embedd this poker in a bigger
  * struct that can handle the posting of different types of work. */
-struct poke_tracker ksched_poker = {0, 0, __run_mcp_ksched};
+struct poke_tracker ksched_poker = POKE_INITIALIZER(__run_mcp_ksched);
 
 /* this 'big ksched lock' protects a bunch of things, which i may make fine
  * grained: */
@@ -122,8 +118,8 @@ void schedule_init(void)
 {
        spin_lock(&sched_lock);
        /* init provisioning stuff */
-       all_pcores = kmalloc(sizeof(struct sched_pcore) * num_cpus, 0);
-       memset(all_pcores, 0, sizeof(struct sched_pcore) * num_cpus);
+       all_pcores = kmalloc(sizeof(struct sched_pcore) * num_cores, 0);
+       memset(all_pcores, 0, sizeof(struct sched_pcore) * num_cores);
        assert(!core_id());             /* want the alarm on core0 for now */
        init_awaiter(&ksched_waiter, __ksched_tick);
        set_ksched_alarm();
@@ -131,24 +127,21 @@ void schedule_init(void)
         * 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
-       for (int i = 1; i < num_cpus; i++)
+       for (int i = 1; i < num_cores; i++)
                TAILQ_INSERT_TAIL(&idlecores, pcoreid2spc(i), alloc_next);
 #else
-       assert(!(num_cpus % 2));
-       for (int i = 1; i < num_cpus; i += 2)
+       assert(!(num_cores % 2));
+       for (int i = 1; i < num_cores; i += 2)
                TAILQ_INSERT_TAIL(&idlecores, pcoreid2spc(i), alloc_next);
 #endif /* CONFIG_DISABLE_SMT */
+       spin_unlock(&sched_lock);
+
 #ifdef CONFIG_ARSC_SERVER
-       struct sched_pcore *a_core = TAILQ_FIRST(&idlecores);
-       assert(a_core);
-       TAILQ_REMOVE(&idlecores, a_core, alloc_next);
-       send_kernel_message(spc2pcoreid(a_core), arsc_server, 0, 0, 0,
-                           KMSG_ROUTINE);
-       warn("Using core %d for the ARSCs - there are probably issues with this.",
-            spc2pcoreid(a_core));
+       int arsc_coreid = get_any_idle_core();
+       assert(arsc_coreid >= 0);
+       send_kernel_message(arsc_coreid, arsc_server, 0, 0, 0, KMSG_ROUTINE);
+       printk("Using core %d for the ARSC server\n", arsc_coreid);
 #endif /* CONFIG_ARSC_SERVER */
-       spin_unlock(&sched_lock);
-       return;
 }
 
 static uint32_t spc2pcoreid(struct sched_pcore *spc)
@@ -269,10 +262,8 @@ void __sched_proc_destroy(struct proc *p, uint32_t *pc_arr, uint32_t nr_cores)
        /* Remove from whatever list we are on (if any - might not be on one if it
         * was in the middle of __run_mcp_sched) */
        remove_from_any_list(p);
-       if (nr_cores) {
-               __put_idle_cores(p, pc_arr, nr_cores);
+       if (nr_cores)
                __prov_track_dealloc_bulk(p, pc_arr, nr_cores);
-       }
        spin_unlock(&sched_lock);
        /* Drop the cradle-to-the-grave reference, jet-li */
        proc_decref(p);
@@ -332,30 +323,14 @@ void __sched_put_idle_core(struct proc *p, uint32_t coreid)
 {
        struct sched_pcore *spc = pcoreid2spc(coreid);
        spin_lock(&sched_lock);
-       TAILQ_INSERT_TAIL(&idlecores, spc, alloc_next);
        __prov_track_dealloc(p, coreid);
        spin_unlock(&sched_lock);
 }
 
-/* Helper for put_idle and core_req.  Note this does not track_dealloc.  When we
- * get rid of / revise proc_preempt_all and put_idle_cores, we can get rid of
- * this.  (the ksched will never need it - only external callers). */
-static void __put_idle_cores(struct proc *p, uint32_t *pc_arr, uint32_t num)
-{
-       struct sched_pcore *spc_i;
-       for (int i = 0; i < num; i++) {
-               spc_i = pcoreid2spc(pc_arr[i]);
-               TAILQ_INSERT_TAIL(&idlecores, spc_i, alloc_next);
-       }
-}
-
-/* Callback, bulk interface for put_idle.  Note this one also calls track_dealloc,
- * which the internal version does not.  The proclock is held for this. */
+/* Callback, bulk interface for put_idle. The proclock is held for this. */
 void __sched_put_idle_cores(struct proc *p, uint32_t *pc_arr, uint32_t num)
 {
        spin_lock(&sched_lock);
-       /* TODO: when we revise this func, look at __put_idle */
-       __put_idle_cores(p, pc_arr, num);
        __prov_track_dealloc_bulk(p, pc_arr, num);
        spin_unlock(&sched_lock);
        /* could trigger a sched decision here */
@@ -396,7 +371,10 @@ 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# */
+                       vcore_account_offline(pcpui->owning_proc, 0);
+                       __seq_start_write(&p->procinfo->coremap_seqctr);
+                       __unmap_vcore(p, 0);
+                       __seq_end_write(&p->procinfo->coremap_seqctr);
                        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);
@@ -610,11 +588,11 @@ static bool __spc_is_idle(struct sched_pcore *spc)
        return FALSE;
 }
 
-int get_this_idle_core(int coreid)
+int get_specific_idle_core(int coreid)
 {
        struct sched_pcore *spc = pcoreid2spc(coreid);
        int ret = -1;
-       assert((0 <= coreid) && (coreid < num_cpus));
+       assert((0 <= coreid) && (coreid < num_cores));
        spin_lock(&sched_lock);
        if (__spc_is_idle(pcoreid2spc(coreid)) && !spc->prov_proc) {
                assert(!spc->alloc_proc);
@@ -629,7 +607,7 @@ int get_this_idle_core(int coreid)
 void put_idle_core(int coreid)
 {
        struct sched_pcore *spc = pcoreid2spc(coreid);
-       assert((0 <= coreid) && (coreid < num_cpus));
+       assert((0 <= coreid) && (coreid < num_cores));
        spin_lock(&sched_lock);
        TAILQ_INSERT_TAIL(&idlecores, spc, alloc_next);
        spin_unlock(&sched_lock);
@@ -640,12 +618,25 @@ uint32_t max_vcores(struct proc *p)
 {
 /* TODO: (CG/LL) */
 #ifdef CONFIG_DISABLE_SMT
-       return num_cpus >> 1;
+       return num_cores >> 1;
 #else
-       return num_cpus - 1;    /* reserving core 0 */
+       return num_cores - 1;   /* reserving core 0 */
 #endif /* CONFIG_DISABLE_SMT */
 }
 
+/* Find the best core to give to p. First check p's list of cores
+ * provisioned to it, but not yet allocated. If no cores are found, try and
+ * pull from the idle list.  If no cores found on either list, return NULL.
+ * */
+struct sched_pcore *find_best_core(struct proc *p)
+{
+       struct sched_pcore *spc_i = NULL;
+       spc_i = TAILQ_FIRST(&p->ksched_data.prov_not_alloc_me);
+       if (!spc_i)
+               spc_i = TAILQ_FIRST(&idlecores);
+       return spc_i;
+}
+
 /* 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).
@@ -658,7 +649,7 @@ uint32_t max_vcores(struct proc *p)
 static void __core_request(struct proc *p, uint32_t amt_needed)
 {
        uint32_t nr_to_grant = 0;
-       uint32_t corelist[num_cpus];
+       uint32_t corelist[num_cores];
        struct sched_pcore *spc_i, *temp;
        struct proc *proc_to_preempt;
        bool success;
@@ -667,14 +658,18 @@ static void __core_request(struct proc *p, uint32_t amt_needed)
        /* get all available cores from their prov_not_alloc list.  the list might
         * change when we unlock (new cores added to it, or the entire list emptied,
         * but no core allocations will happen (we hold the poke)). */
-       while (!TAILQ_EMPTY(&p->ksched_data.prov_not_alloc_me)) {
-               if (nr_to_grant == 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(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)
                        break;
-               /* picking the next victim (first on the not_alloc list) */
-               spc_i = TAILQ_FIRST(&p->ksched_data.prov_not_alloc_me);
-               /* someone else has this proc's pcore, so we need to try to preempt.
-                * after this block, the core will be tracked dealloc'd and on the idle
-                * list (regardless of whether we had to preempt or not) */
+               /* 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 (spc_i->alloc_proc) {
                        proc_to_preempt = spc_i->alloc_proc;
                        /* would break both preemption and maybe the later decref */
@@ -697,9 +692,6 @@ static void __core_request(struct proc *p, uint32_t amt_needed)
                                 * to note its dealloc.  we are doing some excessive checking of
                                 * p == prov_proc, but using this helper is a lot clearer. */
                                __prov_track_dealloc(proc_to_preempt, spc2pcoreid(spc_i));
-                               /* here, we rely on the fact that we are the only preemptor.  we
-                                * assume no one else preempted it, so we know it is available*/
-                               TAILQ_INSERT_TAIL(&idlecores, spc_i, alloc_next);
                        } else {
                                /* the preempt failed, which should only happen if the pcore was
                                 * unmapped (could be dying, could be yielding, but NOT
@@ -731,27 +723,15 @@ static void __core_request(struct proc *p, uint32_t amt_needed)
                        if (spc_i->prov_proc != p)
                                continue;
                }
-               /* at this point, the pcore is idle, regardless of how we got here
+               /* At this point, the pcore is idle, regardless of how we got here
                 * (successful preempt, failed preempt, or it was idle in the first
-                * place.  the core is still provisioned.  lets pull from the idle list
-                * and add it to the pc_arr for p.  here, we rely on the fact that we
-                * are the only allocator (spc_i is still idle, despite unlocking). */
-               TAILQ_REMOVE(&idlecores, spc_i, alloc_next);
-               /* At this point, we have the core, ready to try to give it to the proc.
-                * It is on no alloc lists, and is track_dealloc'd() (regardless of how
-                * we got here).
-                *
-                * We'll give p its cores via a bulk list, which is better for the proc
-                * mgmt code (when going from runnable to running). */
-               corelist[nr_to_grant] = spc2pcoreid(spc_i);
-               nr_to_grant++;
-               __prov_track_alloc(p, spc2pcoreid(spc_i));
-       }
-       /* Try to get cores from the idle list that aren't prov to me (FCFS) */
-       TAILQ_FOREACH_SAFE(spc_i, &idlecores, alloc_next, temp) {
-               if (nr_to_grant == amt_needed)
-                       break;
-               TAILQ_REMOVE(&idlecores, spc_i, alloc_next);
+                * 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
+                * 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);
                nr_to_grant++;
                __prov_track_alloc(p, spc2pcoreid(spc_i));
@@ -776,7 +756,6 @@ static void __core_request(struct proc *p, uint32_t amt_needed)
                        /* we failed, put the cores and track their dealloc.  lock is
                         * protecting those structures. */
                        spin_lock(&sched_lock);
-                       __put_idle_cores(p, corelist, nr_to_grant);
                        __prov_track_dealloc_bulk(p, corelist, nr_to_grant);
                } else {
                        /* at some point after giving cores, call proc_run_m() (harmless on
@@ -808,7 +787,7 @@ static bool is_ll_core(uint32_t pcoreid)
 static void __prov_track_alloc(struct proc *p, uint32_t pcoreid)
 {
        struct sched_pcore *spc;
-       assert(pcoreid < num_cpus);             /* catch bugs */
+       assert(pcoreid < num_cores);    /* catch bugs */
        spc = pcoreid2spc(pcoreid);
        assert(spc->alloc_proc != p);   /* corruption or double-alloc */
        spc->alloc_proc = p;
@@ -817,6 +796,8 @@ static void __prov_track_alloc(struct proc *p, uint32_t pcoreid)
                TAILQ_REMOVE(&p->ksched_data.prov_not_alloc_me, spc, prov_next);
                TAILQ_INSERT_TAIL(&p->ksched_data.prov_alloc_me, spc, prov_next);
        }
+       /* Actually allocate the core, removing it from the idle core list. */
+       TAILQ_REMOVE(&idlecores, spc, alloc_next);
 }
 
 /* Helper, makes sure the prov/alloc structures track the pcore properly when it
@@ -824,7 +805,7 @@ static void __prov_track_alloc(struct proc *p, uint32_t pcoreid)
 static void __prov_track_dealloc(struct proc *p, uint32_t pcoreid)
 {
        struct sched_pcore *spc;
-       assert(pcoreid < num_cpus);             /* catch bugs */
+       assert(pcoreid < num_cores);    /* catch bugs */
        spc = pcoreid2spc(pcoreid);
        spc->alloc_proc = 0;
        /* if the pcore is prov to them and now deallocated, move lists */
@@ -836,6 +817,8 @@ static void __prov_track_dealloc(struct proc *p, uint32_t pcoreid)
                 * victim. */
                TAILQ_INSERT_HEAD(&p->ksched_data.prov_not_alloc_me, spc, prov_next);
        }
+       /* Actually dealloc the core, putting it back on the idle core list. */
+       TAILQ_INSERT_TAIL(&idlecores, spc, alloc_next);
 }
 
 /* Bulk interface for __prov_track_dealloc */
@@ -853,7 +836,7 @@ int provision_core(struct proc *p, uint32_t pcoreid)
        struct sched_pcore_tailq *prov_list;
        /* Make sure we aren't asking for something that doesn't exist (bounds check
         * on the pcore array) */
-       if (!(pcoreid < num_cpus)) {
+       if (!(pcoreid < num_cores)) {
                set_errno(ENXIO);
                return -1;
        }
@@ -948,7 +931,7 @@ void print_prov_map(void)
        struct sched_pcore *spc_i;
        /* Doing this unlocked, which is dangerous, but won't deadlock */
        printk("Which cores are provisioned to which procs:\n------------------\n");
-       for (int i = 0; i < num_cpus; i++) {
+       for (int i = 0; i < num_cores; i++) {
                spc_i = pcoreid2spc(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,