Tracks proc's vcoreids in pcpu info
[akaros.git] / kern / src / process.c
index 05a4fe0..4a4366a 100644 (file)
@@ -473,6 +473,7 @@ void proc_run_s(struct proc *p)
                         * for now.  can simply clear_owning if we want to. */
                        assert(!pcpui->owning_proc);
                        pcpui->owning_proc = p;
+                       pcpui->owning_vcoreid = 0; /* TODO (VC#) */
                        /* TODO: (HSS) set silly state here (__startcore does it instantly) */
                        /* similar to the old __startcore, start them in vcore context if
                         * they have notifs and aren't already in vcore context.  o/w, start
@@ -566,7 +567,8 @@ void __proc_run_m(struct proc *p)
                                 * turn online */
                                TAILQ_FOREACH(vc_i, &p->online_vcs, list) {
                                        send_kernel_message(vc_i->pcoreid, __startcore, (long)p,
-                                                           0, 0, KMSG_IMMEDIATE);
+                                                           (long)vcore2vcoreid(p, vc_i), 0,
+                                                           KMSG_IMMEDIATE);
                                }
                        } else {
                                warn("Tried to proc_run() an _M with no vcores!");
@@ -1046,7 +1048,7 @@ void proc_yield(struct proc *SAFE p, bool being_nice)
        }
        spin_unlock(&p->proc_lock);
        /* Hand the now-idle core to the ksched */
-       put_idle_core(pcoreid);
+       put_idle_core(p, pcoreid);
        goto out_yield_core;
 out_failed:
        /* for some reason we just want to return, either to take a KMSG that cleans
@@ -1247,7 +1249,7 @@ void proc_preempt_core(struct proc *p, uint32_t pcoreid, uint64_t usec)
        }
        spin_unlock(&p->proc_lock);
        if (preempted)
-               put_idle_core(pcoreid);
+               put_idle_core(p, pcoreid);
 }
 
 /* Warns and preempts all from p.  No delaying / alarming, or anything.  The
@@ -1272,7 +1274,7 @@ void proc_preempt_all(struct proc *p, uint64_t usec)
        spin_unlock(&p->proc_lock);
        /* Return the cores to the ksched */
        if (num_revoked)
-               put_idle_cores(pc_arr, num_revoked);
+               put_idle_cores(p, pc_arr, num_revoked);
 }
 
 /* Give the specific pcore to proc p.  Lots of assumptions, so don't really use
@@ -1291,25 +1293,8 @@ void proc_give(struct proc *p, uint32_t pcoreid)
  * out). */
 uint32_t proc_get_vcoreid(struct proc *SAFE p, uint32_t pcoreid)
 {
-       uint32_t vcoreid;
-       // TODO: the code currently doesn't track the vcoreid properly for _S (VC#)
-       spin_lock(&p->proc_lock);
-       switch (p->state) {
-               case PROC_RUNNING_S:
-                       spin_unlock(&p->proc_lock);
-                       return 0; // TODO: here's the ugly part
-               case PROC_RUNNING_M:
-                       vcoreid = get_vcoreid(p, pcoreid);
-                       spin_unlock(&p->proc_lock);
-                       return vcoreid;
-               case PROC_DYING: // death message is on the way
-                       spin_unlock(&p->proc_lock);
-                       return 0;
-               default:
-                       spin_unlock(&p->proc_lock);
-                       panic("Weird state(%s) in %s()", procstate2str(p->state),
-                             __FUNCTION__);
-       }
+       struct per_cpu_info *pcpui = &per_cpu_info[pcoreid];
+       return pcpui->owning_vcoreid;
 }
 
 /* TODO: make all of these static inlines when we gut the env crap */
@@ -1332,9 +1317,10 @@ struct vcore *vcoreid2vcore(struct proc *p, uint32_t vcoreid)
 /********** Core granting (bulk and single) ***********/
 
 /* Helper: gives pcore to the process, mapping it to the next available vcore
- * from list vc_list.  Returns TRUE if we succeeded (non-empty). */
+ * from list vc_list.  Returns TRUE if we succeeded (non-empty).  If you pass in
+ * **vc, we'll tell you which vcore it was. */
 static bool __proc_give_a_pcore(struct proc *p, uint32_t pcore,
-                                struct vcore_tailq *vc_list)
+                                struct vcore_tailq *vc_list, struct vcore **vc)
 {
        struct vcore *new_vc;
        new_vc = TAILQ_FIRST(vc_list);
@@ -1345,6 +1331,8 @@ static bool __proc_give_a_pcore(struct proc *p, uint32_t pcore,
        TAILQ_REMOVE(vc_list, new_vc, list);
        TAILQ_INSERT_TAIL(&p->online_vcs, new_vc, list);
        __map_vcore(p, vcore2vcoreid(p, new_vc), pcore);
+       if (vc)
+               *vc = new_vc;
        return TRUE;
 }
 
@@ -1358,12 +1346,12 @@ static void __proc_give_cores_runnable(struct proc *p, uint32_t *pc_arr,
        p->procinfo->num_vcores += num;
        for (int i = 0; i < num; i++) {
                /* Try from the bulk list first */
-               if (__proc_give_a_pcore(p, pc_arr[i], &p->bulk_preempted_vcs))
+               if (__proc_give_a_pcore(p, pc_arr[i], &p->bulk_preempted_vcs, 0))
                        continue;
                /* o/w, try from the inactive list.  at one point, i thought there might
                 * be a legit way in which the inactive list could be empty, but that i
                 * wanted to catch it via an assert. */
-               assert(__proc_give_a_pcore(p, pc_arr[i], &p->inactive_vcs));
+               assert(__proc_give_a_pcore(p, pc_arr[i], &p->inactive_vcs, 0));
        }
        __seq_end_write(&p->procinfo->coremap_seqctr);
 }
@@ -1371,6 +1359,7 @@ static void __proc_give_cores_runnable(struct proc *p, uint32_t *pc_arr,
 static void __proc_give_cores_running(struct proc *p, uint32_t *pc_arr,
                                       uint32_t num)
 {
+       struct vcore *vc_i;
        /* Up the refcnt, since num cores are going to start using this
         * process and have it loaded in their owning_proc and 'current'. */
        proc_incref(p, num * 2);        /* keep in sync with __startcore */
@@ -1378,9 +1367,9 @@ static void __proc_give_cores_running(struct proc *p, uint32_t *pc_arr,
        p->procinfo->num_vcores += num;
        assert(TAILQ_EMPTY(&p->bulk_preempted_vcs));
        for (int i = 0; i < num; i++) {
-               assert(__proc_give_a_pcore(p, pc_arr[i], &p->inactive_vcs));
-               send_kernel_message(pc_arr[i], __startcore, (long)p, 0, 0,
-                                   KMSG_IMMEDIATE);
+               assert(__proc_give_a_pcore(p, pc_arr[i], &p->inactive_vcs, &vc_i));
+               send_kernel_message(pc_arr[i], __startcore, (long)p,
+                                   (long)vcore2vcoreid(p, vc_i), 0, KMSG_IMMEDIATE);
        }
        __seq_end_write(&p->procinfo->coremap_seqctr);
 }
@@ -1590,6 +1579,7 @@ void clear_owning_proc(uint32_t coreid)
        struct proc *p = pcpui->owning_proc;
        assert(!irq_is_enabled());
        pcpui->owning_proc = 0;
+       pcpui->owning_vcoreid = 0xdeadbeef;
        pcpui->cur_tf = 0;                      /* catch bugs for now (will go away soon) */
        if (p);
                proc_decref(p);
@@ -1725,6 +1715,7 @@ void proc_change_to_vcore(struct proc *p, uint32_t new_vcoreid,
                           bool enable_my_notif)
 {
        uint32_t caller_vcoreid, pcoreid = core_id();
+       struct per_cpu_info *pcpui = &per_cpu_info[pcoreid];
        struct preempt_data *caller_vcpd;
        struct vcore *caller_vc, *new_vc;
        struct event_msg preempt_msg = {0};
@@ -1754,7 +1745,8 @@ void proc_change_to_vcore(struct proc *p, uint32_t new_vcoreid,
        if (!is_mapped_vcore(p, pcoreid))
                goto out_failed;
        /* Get all our info */
-       caller_vcoreid = get_vcoreid(p, pcoreid);
+       caller_vcoreid = get_vcoreid(p, pcoreid);       /* holding lock, we can check */
+       assert(caller_vcoreid == pcpui->owning_vcoreid);
        caller_vcpd = &p->procdata->vcore_preempt_data[caller_vcoreid];
        caller_vc = vcoreid2vcore(p, caller_vcoreid);
        /* Should only call from vcore context */
@@ -1797,6 +1789,8 @@ void proc_change_to_vcore(struct proc *p, uint32_t new_vcoreid,
        __unmap_vcore(p, caller_vcoreid);
        __map_vcore(p, new_vcoreid, pcoreid);
        __seq_end_write(&p->procinfo->coremap_seqctr);
+       /* So this core knows which vcore is here: */
+       pcpui->owning_vcoreid = new_vcoreid;
        /* Send either a PREEMPT msg or a CHECK_MSGS msg.  If they said to
         * enable_my_notif, then all userspace needs is to check messages, not a
         * full preemption recovery. */
@@ -1816,7 +1810,8 @@ out_failed:
  * Interrupts are disabled. */
 void __startcore(struct trapframe *tf, uint32_t srcid, long a0, long a1, long a2)
 {
-       uint32_t vcoreid, coreid = core_id();
+       uint32_t vcoreid = (uint32_t)a1;
+       uint32_t coreid = core_id();
        struct per_cpu_info *pcpui = &per_cpu_info[coreid];
        struct proc *p_to_run = (struct proc *CT(1))a0;
 
@@ -1825,6 +1820,7 @@ void __startcore(struct trapframe *tf, uint32_t srcid, long a0, long a1, long a2
        assert(!pcpui->owning_proc);
        /* the sender of the amsg increfed already for this saved ref to p_to_run */
        pcpui->owning_proc = p_to_run;
+       pcpui->owning_vcoreid = vcoreid;
        /* sender increfed again, assuming we'd install to cur_proc.  only do this
         * if no one else is there.  this is an optimization, since we expect to
         * send these __startcores to idles cores, and this saves a scramble to
@@ -1837,7 +1833,6 @@ void __startcore(struct trapframe *tf, uint32_t srcid, long a0, long a1, long a2
                proc_decref(p_to_run);          /* can't install, decref the extra one */
        }
        /* Note we are not necessarily in the cr3 of p_to_run */
-       vcoreid = get_vcoreid(p_to_run, coreid);
        /* Now that we sorted refcnts and know p / which vcore it should be, set up
         * pcpui->cur_tf so that it will run that particular vcore */
        __set_curtf_to_vcoreid(p_to_run, vcoreid);
@@ -1859,10 +1854,8 @@ void __notify(struct trapframe *tf, uint32_t srcid, long a0, long a1, long a2)
        /* Common cur_tf sanity checks.  Note cur_tf could be an _S's env_tf */
        assert(pcpui->cur_tf);
        assert(!in_kernel(pcpui->cur_tf));
-       /* We shouldn't need to lock here, since unmapping happens on the pcore and
-        * mapping would only happen if the vcore was free, which it isn't until
-        * after we unmap. */
-       vcoreid = get_vcoreid(p, coreid);
+       vcoreid = pcpui->owning_vcoreid;
+       assert(vcoreid == get_vcoreid(p, coreid));
        vcpd = &p->procdata->vcore_preempt_data[vcoreid];
        /* for SCPs that haven't (and might never) call vc_event_init, like rtld.
         * this is harmless for MCPS to check this */
@@ -1899,10 +1892,8 @@ void __preempt(struct trapframe *tf, uint32_t srcid, long a0, long a1, long a2)
        assert(pcpui->cur_tf);
        assert(pcpui->cur_tf == &pcpui->actual_tf);
        assert(!in_kernel(pcpui->cur_tf));
-       /* We shouldn't need to lock here, since unmapping happens on the pcore and
-        * mapping would only happen if the vcore was free, which it isn't until
-        * after we unmap. */
-       vcoreid = get_vcoreid(p, coreid);
+       vcoreid = pcpui->owning_vcoreid;
+       assert(vcoreid == get_vcoreid(p, coreid));
        p->procinfo->vcoremap[vcoreid].preempt_served = FALSE;
        /* either __preempt or proc_yield() ends the preempt phase. */
        p->procinfo->vcoremap[vcoreid].preempt_pending = 0;
@@ -1940,7 +1931,8 @@ void __death(struct trapframe *tf, uint32_t srcid, long a0, long a1, long a2)
        struct per_cpu_info *pcpui = &per_cpu_info[coreid];
        struct proc *p = pcpui->owning_proc;
        if (p) {
-               vcoreid = get_vcoreid(p, coreid);
+               vcoreid = pcpui->owning_vcoreid;
+               assert(vcoreid == get_vcoreid(p, coreid));
                printd("[kernel] death on physical core %d for process %d's vcore %d\n",
                       coreid, p->pid, vcoreid);
                __unmap_vcore(p, vcoreid);