cur_proc broken up into owning_proc and cur_proc
authorBarret Rhoden <brho@cs.berkeley.edu>
Mon, 3 Oct 2011 23:18:34 +0000 (16:18 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:36:08 +0000 (17:36 -0700)
It's important that our interrup/kmsg handlers do not adjust current out
from under regular kthread code (or whatever was running there before).
This led to splitting up cur_proc.

pcpui->cur_proc (current) is now only what context is loaded, and not
what process owns the core (owning_proc).  This distinction wasn't clear
before.  owning_proc tells us which process to run, and cur_tf tells us
what trapframe to pop/run.

All proc mgmt kmsg handlers now work on owning_proc, instead of some
combination of cur_tf or cur_proc.  cur_tf has no meaning without an
owning proc.  Earlier, we used cur_tf as a signal to run things.  now we
use owning_proc.

Read the documentation for more details.

Documentation/kref.txt
Documentation/process-internals.txt
kern/include/process.h
kern/include/smp.h
kern/src/process.c
kern/src/resource.c
kern/src/smp.c
kern/src/syscall.c

index 81fd564..17e2473 100644 (file)
@@ -11,10 +11,9 @@ To best understand krefs, keep in mind this quote (from their kref.txt): "the
 kref is appropriate when the object doesn't outlive its last external
 reference."  What we want is to know when all "external" references to an object
 are gone.  At which point we can do something (cleanup, free, etc) and be sure
-that no other code can get a reference.  This is similar to what we used to do
-with proc_decref() and a handful of other custom refcounting mechanisms.  We
-want to do this without locks, if possible, so we make use of a variety of
-helpful atomics (though RAMP uses a lock-per-atomic).
+that no other code can get a reference.  We want to do this without locks, if
+possible, so we make use of a variety of helpful atomics (though RAMP uses a
+lock-per-atomic).
 
 This document will ramble about the details and other stuff.
 Here are things to keep in mind, which differ in some of the use cases:
index 1fa8a01..e7d6c05 100644 (file)
@@ -11,7 +11,7 @@ Contents:
 2. When Do We Really Leave "Process Context"?
 3. Leaving the Kernel Stack
 4. Preemption and Notification Issues
-5. Current_tf
+5. current_tf and owning_proc
 6. Locking!
 7. TLB Coherency
 8. Process Management
@@ -52,9 +52,17 @@ meaning.
 current is a pointer to the proc that is currently loaded/running on any given
 core.  It is stored in the per_cpu_info struct, and set/managed by low-level
 process code.  It is necessary for the kernel to quickly figure out who is
-running on its code, especially when servicing interrupts and traps.  current is
+running on its core, especially when servicing interrupts and traps.  current is
 protected by a refcnt.
 
+current does not say which process owns / will-run on a core.  The per-cpu
+variable 'owning_proc' covers that.  'owning_proc' should be treated like
+'current' (aka, 'cur_proc') when it comes to reference counting.  Like all
+refcnts, you can use it, but you can't consume it without atomically either
+upping the refcnt or passing the reference (clearing the variable storing the
+reference).  Don't pass it to a function that will consume it and not return
+without upping it.
+
 1.4 Reference Counting Rules:
 ---------------------------
 +1 for existing.
@@ -81,10 +89,9 @@ protected by a refcnt.
 +1 for current.
 - current counts as someone using it (expressing interest in the core), but is
   also a source of the pointer, so its a bit different.  Note that all kref's
-  are sources of a pointer.  Technically, to even use 'current', we should kref
-  it and pass it around as a proc.  We don't for performance reasons.  When we
-  are running on a core that has current loaded, the ref is both for its usage
-  as well as for being the current process.
+  are sources of a pointer.  When we are running on a core that has current
+  loaded, the ref is both for its usage as well as for being the current
+  process.
 - You have a reference from current and can use it without refcnting, but
   anything that needs to eat a reference or store/use it needs an incref first.
   To be clear, your reference is *NOT* edible.  It protects the cr3, guarantees
@@ -140,12 +147,6 @@ proc_run(pid2proc(55)) works, since pid2proc() increfs for you.  But you cannot
 proc_run(current), unless you incref current in advance.  Incidentally,
 proc_running current doesn't make a lot of sense.
 
-As another example, __proc_startcore() will take your reference and store it
-in current.  Since it is used by both the __startcore and the interrupt return
-paths (proc_restartcore() now, formerly called proc_startcore()), we're
-currently going with the model of "caller makes sure there is a ref for
-current".  Check its comments for details.
-
 1.6 Runnable List:
 ---------------------------
 Procs on the runnable list need to have a refcnt (other than the +1 for
@@ -160,17 +161,20 @@ abandon_core()).
 
 1.7 Internal Details for Specific Functions:
 ---------------------------
-proc_run(): makes sure enough refcnts are in place for all places that will
-install current.  This also makes it easier on the system (one big incref(n),
-instead of n increfs of (1) from multiple cores).  In the off chance current was
-already set for a core receiving the kernel message, __startcore will decref.
+proc_run()/__proc_give_cores(): makes sure enough refcnts are in place for all
+places that will install owning_proc.  This also makes it easier on the system
+(one big incref(n), instead of n increfs of (1) from multiple cores). 
 Also note that while proc_run() consumes your reference, it's not actually
 decreffing, so there's no danger within proc_run() of the process dying /
 __proc_free()ing.
 
-__proc_startcore(): assumes all references to p are sorted.  *p is already
-accounted for as if it was current on the core startcore runs on. (there is only
-one refcnt for both *p and current, not 2 separate ones).
+__set_proc_current() is a helper that makes sure p is the cur_proc.  It will
+incref if installing a new reference to p.  If it removed an old proc, it will
+decref.
+
+__proc_startcore(): assumes all references to p are sorted.  It will not
+return, and you should not pass it a reference you need to decref().  Passing
+it 'owning_proc' works, since you don't want to decref owning_proc.
 
 proc_destroy(): it used to not return, and back then if your reference was
 from 'current', you needed to incref.  Now that proc_destroy() returns, it
@@ -179,8 +183,9 @@ return, there's no way for the function to know if it's passed reference is
 edible.  Even if p == current, proc_destroy() can't tell if you sent it p (and
 had a reference) or current and didn't.
 
-proc_yield(): this never returns, so it eats your reference.  It will also
-decref when it abandon_core()s.
+proc_yield(): when this doesn't return, it eats your reference.  It will also
+decref twice.  Once when it clears_owning_proc, and again when it calls
+abandon_core() (which clears cur_proc).
 
 abandon_core(): it was not given a reference, so it doesn't eat one.  It will
 decref when it unloads the cr3.  Note that this is a potential performance
@@ -259,24 +264,40 @@ it to proc B.
 If no process is running there, current == 0 and boot_cr3 is loaded, meaning no
 process's context is loaded.
 
+All changes to cur_proc, owning_proc, and cur_tf need to be done with
+interrupts disabled, since they change in interrupt handlers.
+
 2.2 Here's how it is done now:
 ---------------------------
-We try to proactively leave, but have the ability to stay in context til
-__proc_startcore() to handle the corner cases (and to maybe cut down the TLB
-flushes later).  To stop proactively leaving, just change abandon_core() to not
-do anything with current/cr3.  You'll see weird things like processes that won't
-die until their old cores are reused.  The reason we proactively leave context
-is to help with sanity for these issues, and also to avoid decref's in
-__startcore().
+All code is capable of 'spamming' cur_proc (with interrupts disabled!).  If it
+is 0, feel free to set it to whatever process you want.  All code that
+requires current to be set will do so (like __proc_startcore()).  The
+smp_idle() path will make sure current is clear when it halts.  So long as you
+don't change other concurrent code's expectations, you're okay.  What I mean
+by that is you don't clear cur_proc while in an interrupt handler.  But if it
+is already 0, __startcore is allowed to set it to it's future proc (which is
+an optimization).  Other code didn't have any expectations of it (it was 0).
+Likewise, kthread code when we sleep_on() doesn't have to keep cur_proc set.
+A kthread is somewhat an isolated block (codewise), and leaving current set
+when it is done is solely to avoid a TLB flush (at the cost of an incref).
+
+In general, we try to proactively leave process context, but have the ability
+to stay in context til __proc_startcore() to handle the corner cases (and to
+maybe cut down the TLB flushes later).  To stop proactively leaving, just
+change abandon_core() to not do anything with current/cr3.  You'll see weird
+things like processes that won't die until their old cores are reused.  The
+reason we proactively leave context is to help with sanity for these issues,
+and also to avoid decref's in __startcore().
 
 A couple other details: __startcore() sorts the extra increfs, and
 __proc_startcore() sorts leaving the old context.  Anytime a __startcore kernel
-message is sent, the sender increfs in advance for the current refcnt.  If that
-was in error, __startcore decrefs.  __proc_startcore(), which the last moment
-before we *must* have the cr3/current issues sorted, does the actual check if
-there was an old process there or not, while it handles the lcr3 (if necessary).
-In general, lcr3's ought to have refcnts near them, or else comments explaining
-why not.
+message is sent, the sender increfs in advance for the owning_proc refcnt.  As
+an optimization, we can also incref to *attempt* to set current.  If current
+was 0, we set it.  If it was already something else, we failed and need to
+decref.  __proc_startcore(), which the last moment before we *must* have the
+cr3/current issues sorted, does the actual check if there was an old process
+there or not, while it handles the lcr3 (if necessary).  In general, lcr3's
+ought to have refcnts near them, or else comments explaining why not.
 
 So we leave process context when told to do so (__death/abandon_core()) or if
 another process is run there.  The _M code is such that a proc will stay on its
@@ -645,7 +666,7 @@ We also considered using the transition stack as a signal that a process is in
 a notification handler.  The kernel can inspect the stack pointer to determine
 this.  It's possible, but unnecessary.
 
-5. current_tf
+5. current_tf and owning_proc
 ===========================
 Originally, current_tf is a per-core macro that returns a struct trapframe *
 that points back on the kernel stack to the user context that was running on
@@ -661,20 +682,24 @@ can be set by an IPI/KMSG (like '__startcore') so that when the kernel wants
 to idle, it will find a cur_tf that it needs to run, even though we never
 trapped in on that context in the first place.
 
-Process management KMSGs now simply modify cur_tf, as if we had interrupted a
-process.  Instead of '__startcore' forcing the kernel to actually run the
-context, it will just mean we will eventually run it.  In the meantime a
-'__notify' or a '__preempt' can come in, and they will apply to the cur_tf.
-This greatly simplifies process code and code calling process code (like the
-scheduler), since we no longer need to worry about whether or not we are
-getting a "stack killing" kernel message.  Before this, code needed to care
-where it was running when managing _Ms.
+Further, we now have 'owning_proc', which tells the kernel which process
+should be run.  'owning_proc' is a bigger deal than 'current_tf', and it is
+what tells us to run cur_tf.
+
+Process management KMSGs now simply modify 'owning_proc' and cur_tf, as if we
+had interrupted a process.  Instead of '__startcore' forcing the kernel to
+actually run the process and trapframe, it will just mean we will eventually
+run it.  In the meantime a '__notify' or a '__preempt' can come in, and they
+will apply to the owning_proc/cur_tf.  This greatly simplifies process code
+and code calling process code (like the scheduler), since we no longer need to
+worry about whether or not we are getting a "stack killing" kernel message.
+Before this, code needed to care where it was running when managing _Ms.
 
-current_tf should go along with current.  It's the current_tf of the current
-process.  Withouth 'current', it has no meaning.  This will probably change
-slightly, since kthreads care about 'current' but not about current_tf.
+Note that neither 'current_tf' nor 'owning_proc' rely on 'current'/'cur_proc'.
+'current' is just what process context we're in, not what process (and which
+trapframe) we will eventually run.
 
-It does not point to kernel trapframes, which is important when we receive an
+cur_tf does not point to kernel trapframes, which is important when we receive an
 interrupt in the kernel.  At one point, we were (hypothetically) clobbering the
 reference to the user trapframe, and were unable to recover.  We can get away
 with this because the kernel always returns to its previous context from a
index 1f66ea4..deb112b 100644 (file)
@@ -135,6 +135,7 @@ void proc_preempt_all(struct proc *p, uint64_t usec);
 struct proc *switch_to(struct proc *new_p);
 void switch_back(struct proc *new_p, struct proc *old_proc);
 void abandon_core(void);
+void clear_owning_proc(uint32_t coreid);
 void proc_tlbshootdown(struct proc *p, uintptr_t start, uintptr_t end);
 
 /* Kernel message handlers for process management */
index 4f20048..9ecf896 100644 (file)
@@ -26,7 +26,8 @@ struct per_cpu_info {
        spinlock_t lock;
        /* Process management */
        // cur_proc should be valid on all cores that are not management cores.
-       struct proc *cur_proc;
+       struct proc *cur_proc;          /* which process context is loaded */
+       struct proc *owning_proc;       /* proc owning the core / cur_tf */
        struct trapframe *cur_tf;       /* user tf we came in on (can be 0) */
        struct trapframe actual_tf;     /* storage for cur_tf */
        struct syscall *cur_sysc;       /* ptr is into cur_proc's address space */
index 4da7a49..a7220af 100644 (file)
@@ -454,8 +454,9 @@ void proc_decref(struct proc *p)
        kref_put(&p->p_kref);
 }
 
-/* Helper, makes p the 'current' process, dropping the old current/cr3.  Don't
- * incref - this assumes the passed in reference already counted 'current'. */
+/* Helper, makes p the 'current' process, dropping the old current/cr3.  This no
+ * longer assumes the passed in reference already counted 'current'.  It will
+ * incref internally when needed. */
 static void __set_proc_current(struct proc *p)
 {
        /* We use the pcpui to access 'current' to cut down on the core_id() calls,
@@ -463,8 +464,7 @@ static void __set_proc_current(struct proc *p)
        struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
        /* If the process wasn't here, then we need to load its address space. */
        if (p != pcpui->cur_proc) {
-               /* Do not incref here.  We were given the reference to current,
-                * pre-upped. */
+               proc_incref(p, 1);
                lcr3(p->env_cr3);
                /* This is "leaving the process context" of the previous proc.  The
                 * previous lcr3 unloaded the previous proc's context.  This should
@@ -517,19 +517,17 @@ void proc_run(struct proc *p)
                         * work. */
                        __map_vcore(p, 0, core_id()); // sort of.  this needs work.
                        __seq_end_write(&p->procinfo->coremap_seqctr);
-                       /* __set_proc_current assumes the reference we give it is for
-                        * current.  Decref if current is already properly set, otherwise
-                        * ensure current is set. */
-                       if (p == current)
-                               proc_decref(p);
-                       else
-                               __set_proc_current(p);
+                       __set_proc_current(p);
                        /* We restartcore, instead of startcore, since startcore is a bit
                         * lower level and we want a chance to process kmsgs before starting
                         * the process. */
                        spin_unlock(&p->proc_lock);
+                       disable_irq();          /* before mucking with cur_tf / owning_proc */
+                       /* this is one of the few times cur_tf != &actual_tf */
                        current_tf = &p->env_tf;        /* no need for irq disable yet */
-                       proc_restartcore();
+                       /* storing the passed in ref of p in owning_proc */
+                       per_cpu_info[core_id()].owning_proc = p;
+                       proc_restartcore();     /* will reenable interrupts */
                        break;
                case (PROC_RUNNABLE_M):
                        /* vcoremap[i] holds the coreid of the physical core allocated to
@@ -616,18 +614,23 @@ void proc_restartcore(void)
 {
        struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
        assert(!pcpui->cur_sysc);
+       /* Try and get any interrupts before we pop back to userspace.  If we didn't
+        * do this, we'd just get them in userspace, but this might save us some
+        * effort/overhead. */
+       enable_irq();
        /* Need ints disabled when we return from processing (race on missing
         * messages/IPIs) */
        disable_irq();
        process_routine_kmsg(pcpui->cur_tf);
-       /* If there is no cur_tf, it is because the old one was already restarted
-        * (and we weren't interrupting another one to finish).  In which case, we
-        * should just smp_idle() */
-       if (!pcpui->cur_tf) {
+       /* If there is no owning process, just idle, since we don't know what to do.
+        * This could be because the process had been restarted a long time ago and
+        * has since left the core, or due to a KMSG like __preempt or __death. */
+       if (!pcpui->owning_proc) {
                abandon_core();
                smp_idle();
        }
-       __proc_startcore(pcpui->cur_proc, pcpui->cur_tf);
+       assert(pcpui->cur_tf);
+       __proc_startcore(pcpui->owning_proc, pcpui->cur_tf);
 }
 
 /*
@@ -775,7 +778,8 @@ void __proc_yield_s(struct proc *p, struct trapframe *tf)
  * yielders). */
 void proc_yield(struct proc *SAFE p, bool being_nice)
 {
-       uint32_t vcoreid = get_vcoreid(p, core_id());
+       uint32_t coreid = core_id();
+       uint32_t vcoreid = get_vcoreid(p, coreid);
        struct vcore *vc = vcoreid2vcore(p, vcoreid);
        struct preempt_data *vcpd = &p->procdata->vcore_preempt_data[vcoreid];
        int8_t state = 0;
@@ -814,7 +818,7 @@ void proc_yield(struct proc *SAFE p, bool being_nice)
                        break;
                case (PROC_RUNNING_M):
                        printd("[K] Process %d (%p) is yielding on vcore %d\n", p->pid, p,
-                              get_vcoreid(p, core_id()));
+                              get_vcoreid(p, coreid));
                        /* Remove from the online list, add to the yielded list, and unmap
                         * the vcore, which gives up the core. */
                        TAILQ_REMOVE(&p->online_vcs, vc, list);
@@ -842,7 +846,7 @@ void proc_yield(struct proc *SAFE p, bool being_nice)
                                p->resources[RES_CORES].amt_wanted = p->procinfo->num_vcores;
                        __seq_end_write(&p->procinfo->coremap_seqctr);
                        // add to idle list
-                       put_idle_core(core_id());       /* TODO: prod the ksched? */
+                       put_idle_core(coreid);  /* TODO: prod the ksched? */
                        // last vcore?  then we really want 1, and to yield the gang
                        if (p->procinfo->num_vcores == 0) {
                                p->resources[RES_CORES].amt_wanted = 1;
@@ -864,14 +868,11 @@ void proc_yield(struct proc *SAFE p, bool being_nice)
        proc_decref(p);                 /* need to eat the ref passed in */
        /* TODO: (RMS) If there was a change to the idle cores, try and give our
         * core to someone who was preempted. */
-       /* Clean up the core and idle.  For mgmt cores, they will ultimately call
-        * manager, which will call schedule() and will repick the yielding proc.
-        *
-        * Need to do this before enabling interrupts, since once we put_idle_core()
-        * and unlock, we could get a startcore. */
+       /* Clean up the core and idle.  Need to do this before enabling interrupts,
+        * since once we put_idle_core() and unlock, we could get a startcore. */
+       clear_owning_proc(coreid);      /* so we don't restart */
        abandon_core();
-       enable_irqsave(&state); /* arguably unnecessary, smp_idle() will recheck */
-       smp_idle();
+       smp_idle();                             /* will reenable interrupts */
 }
 
 /* Sends a notification (aka active notification, aka IPI) to p's vcore.  We
@@ -1319,20 +1320,32 @@ void __unmap_vcore(struct proc *p, uint32_t vcoreid)
 
 /* Stop running whatever context is on this core and load a known-good cr3.
  * Note this leaves no trace of what was running. This "leaves the process's
- * context. */
+ * context.  Also, we want interrupts disabled, to not conflict with kmsgs
+ * (__launch_kthread, proc mgmt, etc).
+ *
+ * This does not clear the owning proc.  Use the other helper for that. */
 void abandon_core(void)
 {
        struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
-       int8_t state = 0;
+       assert(!irq_is_enabled());
        /* Syscalls that don't return will ultimately call abadon_core(), so we need
         * to make sure we don't think we are still working on a syscall. */
        pcpui->cur_sysc = 0;
-       if (pcpui->cur_proc) {
-               disable_irqsave(&state);
-               pcpui->cur_tf = 0;      /* shouldn't have one of these without a proc btw */
+       if (pcpui->cur_proc)
                __abandon_core();
-               enable_irqsave(&state);
-       }
+}
+
+/* Helper to clear the core's owning processor and manage refcnting.  Pass in
+ * core_id() to save a couple core_id() calls. */
+void clear_owning_proc(uint32_t coreid)
+{
+       struct per_cpu_info *pcpui = &per_cpu_info[coreid];
+       struct proc *p = pcpui->owning_proc;
+       assert(!irq_is_enabled());
+       pcpui->owning_proc = 0;
+       pcpui->cur_tf = 0;                      /* catch bugs for now (will go away soon) */
+       if (p);
+               proc_decref(p);
 }
 
 /* Switches to the address space/context of new_p, doing nothing if we are
@@ -1425,17 +1438,10 @@ void __startcore(struct trapframe *tf, uint32_t srcid, long a0, long a1, long a2
 
        assert(p_to_run);
        /* Can not be any TF from a process here already */
-       assert(!pcpui->cur_tf);
-       /* the sender of the amsg increfed, thinking we weren't running current. */
-       if (p_to_run == pcpui->cur_proc)
-               proc_decref(p_to_run); // how does this assumption match kthreading?
-       else
-               if (pcpui->cur_proc)
-                       warn("clobbering current!");
-       /* TODO: assumes no kthreads from other processes, and that we should just
-        * change this immediately.  This will change (along with the warn())
-        * eventually, maybe when we figure out the kthread/CG plan. */
-       __set_proc_current(p_to_run);
+       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;
+       /* Note we are not necessarily in the cr3 of p_to_run */
        vcoreid = get_vcoreid(p_to_run, coreid);
        vcpd = &p_to_run->procdata->vcore_preempt_data[vcoreid];
        /* We could let userspace do this, though they come into vcore entry many
@@ -1490,12 +1496,10 @@ void __notify(struct trapframe *tf, uint32_t srcid, long a0, long a1, long a2)
        struct proc *p = (struct proc*)a0;
 
        /* Not the right proc */
-       if (p != pcpui->cur_proc)
-               return;
-       /* No TF here to notify (could be spurious) */
-       if (!pcpui->cur_tf)
+       if (p != pcpui->owning_proc)
                return;
        /* Common cur_tf sanity checks */
+       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
@@ -1527,9 +1531,9 @@ void __preempt(struct trapframe *tf, uint32_t srcid, long a0, long a1, long a2)
        struct proc *p = (struct proc*)a0;
 
        assert(p);
-       if (p != pcpui->cur_proc) {
-               panic("__preempt arrived for a process (%p) that was not current (%p)!",
-                     p, pcpui->cur_proc);
+       if (p != pcpui->owning_proc) {
+               panic("__preempt arrived for a process (%p) that was not owning (%p)!",
+                     p, pcpui->owning_proc);
        }
        /* Common cur_tf sanity checks */
        assert(pcpui->cur_tf);
@@ -1554,9 +1558,10 @@ void __preempt(struct trapframe *tf, uint32_t srcid, long a0, long a1, long a2)
        save_fp_state(&vcpd->preempt_anc);
        __seq_start_write(&vcpd->preempt_tf_valid);
        __unmap_vcore(p, vcoreid);
-       /* so we no longer run the process.  current gets cleared later when we notice
-        * current_tf is 0 and we have nothing to do (smp_idle, restartcore, etc) */
-       pcpui->cur_tf = 0;
+       /* We won't restart the process later.  current gets cleared later when we
+        * notice there is no owning_proc and we have nothing to do (smp_idle,
+        * restartcore, etc) */
+       clear_owning_proc(coreid);
 }
 
 /* Kernel message handler to clean up the core when a process is dying.
@@ -1567,15 +1572,17 @@ void __death(struct trapframe *tf, uint32_t srcid, long a0, long a1, long a2)
 {
        uint32_t vcoreid, coreid = core_id();
        struct per_cpu_info *pcpui = &per_cpu_info[coreid];
-       if (pcpui->cur_proc) {
-               vcoreid = get_vcoreid(pcpui->cur_proc, coreid);
+       struct proc *p = pcpui->owning_proc;
+       if (p) {
+               vcoreid = get_vcoreid(p, coreid);
                printd("[kernel] death on physical core %d for process %d's vcore %d\n",
-                      coreid, pcpui->cur_proc->pid, vcoreid);
-               __unmap_vcore(pcpui->cur_proc, vcoreid);
+                      coreid, p->pid, vcoreid);
+               __unmap_vcore(p, vcoreid);
+               /* We won't restart the process later.  current gets cleared later when
+                * we notice there is no owning_proc and we have nothing to do
+                * (smp_idle, restartcore, etc) */
+               clear_owning_proc(coreid);
        }
-       /* so we no longer run the process.  current gets cleared later when we notice
-        * current_tf is 0 and we have nothing to do (smp_idle, restartcore, etc) */
-       pcpui->cur_tf = 0;
 }
 
 /* Kernel message handler, usually sent IMMEDIATE, to shoot down virtual
@@ -1681,7 +1688,7 @@ void check_my_owner(void)
                                 * interrupts, which should cause us to skip cpu_halt() */
                                if (!STAILQ_EMPTY(&pcpui->immed_amsgs))
                                        continue;
-                               printk("Owned pcore (%d) has no cur_tf, belong to %08p, vc %d!\n",
+                               printk("Owned pcore (%d) has no owner, by %08p, vc %d!\n",
                                       core_id(), p, vcore2vcoreid(p, vc_i));
                                spin_unlock(&p->proc_lock);
                                spin_unlock(&pid_hash_lock);
@@ -1692,7 +1699,7 @@ void check_my_owner(void)
        }
        assert(!irq_is_enabled());
        extern int booting;
-       if (!booting && !pcpui->cur_tf) {
+       if (!booting && !pcpui->owning_proc) {
                spin_lock(&pid_hash_lock);
                hash_for_each(pid_hash, shazbot);
                spin_unlock(&pid_hash_lock);
index 522dabe..154d632 100644 (file)
@@ -57,7 +57,7 @@ ssize_t core_request(struct proc *p)
                disable_irqsave(&state);        /* protect cur_tf */
                assert(current_tf);
                p->env_tf = *current_tf;
-               current_tf = 0;                 /* Make sure it isn't used in the future */
+               clear_owning_proc(core_id());   /* so we don't restart */
                enable_irqsave(&state);
                env_push_ancillary_state(p); // TODO: (HSS)
                /* sending death, since it's not our job to save contexts or anything in
@@ -128,7 +128,7 @@ ssize_t core_request(struct proc *p)
                                 * since we're _S and locked, we shouldn't have any. */
                                assert(current_tf);
                                vcpd->preempt_tf = *current_tf;
-                               current_tf = 0;                         /* so we don't restart */
+                               clear_owning_proc(core_id());   /* so we don't restart */
                                save_fp_state(&vcpd->preempt_anc);
                                enable_irqsave(&state);
                                __seq_start_write(&vcpd->preempt_tf_valid);
index e4ac29b..a3e051c 100644 (file)
@@ -32,9 +32,8 @@ static void try_run_proc(void)
        struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
 
        disable_irq();
-       /* There was a process running here, and we should return to it */
-       if (pcpui->cur_tf) {                    /* aka, current_tf */
-               assert(pcpui->cur_proc);        /* aka, current */
+       /* There was a process running here, and we should return to it. */
+       if (pcpui->owning_proc) {
                proc_restartcore();
                assert(0);
        }
index c9c664d..c8e7296 100644 (file)
@@ -570,9 +570,10 @@ all_out:
        /* we can't return, since we'd write retvals to the old location of the
         * syscall struct (which has been freed and is in the old userspace) (or has
         * already been written to).*/
+       disable_irq();                  /* abandon_core/clear_own wants irqs disabled */
+       clear_owning_proc(core_id());
        abandon_core();
-       smp_idle();
-       assert(0);
+       smp_idle();                             /* will reenable interrupts */
 }
 
 static ssize_t sys_trywait(env_t* e, pid_t pid, int* status)