More thoroughly detect preemptions
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 13 Oct 2011 00:50:23 +0000 (17:50 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 15 Dec 2011 22:48:40 +0000 (14:48 -0800)
MCS-PDR code checks for preemptions via preempt_tf_valid.  If you don't
you can accidentally think a yielded vcore is preempted.  Either way, it
is unmapped.  In the future, it'll be safe to restart them, but right
now we don't handle preemption messages, so processes can run into
issues.  Also, you don't really want to restart a yielded vcore.  Next
time you spin in the MCS code, you will (hopefully!) get a different
vcore (reread lockholder, etc).

Also, we were a bit sloppy about the use of preempt_tf_valid.  It's
actually an ancient seq_ctr instead of a bool.  The 2 year old reason
for that was to help us detect changes to the preempt tf for remote
recovery, but I have a feeling it might not be strong enough.

kern/src/process.c
user/parlib/include/vcore.h
user/parlib/mcs.c

index 9107d75..c6bb9ed 100644 (file)
@@ -1552,7 +1552,8 @@ void proc_change_to_vcore(struct proc *p, uint32_t new_vcoreid,
                 * __startcore, to make the caller look like it was preempted. */
                caller_vcpd->preempt_tf = *current_tf;
                save_fp_state(&caller_vcpd->preempt_anc);
-               caller_vcpd->preempt_tf_valid = TRUE;
+               /* Signal a preemption, like __preempt does with this... (TODO) */
+               __seq_start_write(&caller_vcpd->preempt_tf_valid);
        }
        /* Either way, unmap and offline our current vcore */
        /* Move the caller from online to inactive */
index 2706a24..3e0fdaa 100644 (file)
@@ -47,6 +47,7 @@ static inline void __enable_notifs(uint32_t vcoreid);
 static inline void __disable_notifs(uint32_t vcoreid);
 static inline bool notif_is_enabled(uint32_t vcoreid);
 static inline bool vcore_is_mapped(uint32_t vcoreid);
+static inline bool vcore_is_preempted(uint32_t vcoreid);
 int vcore_init(void);
 int vcore_request(size_t k);
 void vcore_yield(bool preempt_pending);
@@ -102,6 +103,14 @@ static inline bool vcore_is_mapped(uint32_t vcoreid)
        return __procinfo.vcoremap[vcoreid].valid;
 }
 
+/* For now, preempt_tf is a seq_ctr, and when it is locked, we think the vcore
+ * is preempted.  Needs work... */
+static inline bool vcore_is_preempted(uint32_t vcoreid)
+{
+       struct preempt_data *vcpd = &__procdata.vcore_preempt_data[vcoreid];
+       return seq_is_locked(vcpd->preempt_tf_valid);
+}
+
 #ifdef __cplusplus
 }
 #endif
index 9a68c63..7cc4818 100644 (file)
@@ -192,7 +192,9 @@ void mcs_pdr_fini(struct mcs_pdr_lock *lock)
  * wastefully spin, we're okay. */
 void __ensure_qnode_runs(struct mcs_pdr_qnode *qnode)
 {
-       if (!vcore_is_mapped(qnode->vcoreid)) {
+       assert(qnode);
+       if (vcore_is_preempted(qnode->vcoreid)) {
+               assert(!vcore_is_mapped(qnode->vcoreid));
                /* We want to recover them from preemption.  Since we know they have
                 * notifs disabled, they will need to be directly restarted, so we can
                 * skip the other logic and cut straight to the sys_change_vcore() */