Add a helper for blocking a uthread from VC ctx
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 27 Apr 2016 21:35:32 +0000 (17:35 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 2 May 2016 21:11:15 +0000 (17:11 -0400)
All 2LSs perform the same basic thing for page faults: issue an async call,
then block on it.  The blocking process is like a stripped down version of
the normal blockon, since it picks up while the 2LS is already in vcore
context.

This commit adds the helper and uses it for the two exiting 2LSs.  This
actually fixes a minor issue: pthread code that was DONT_MIGRATE would have
had an issue.  Likewise, we weren't handling the PFs for the thread0 sched.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
user/parlib/include/parlib/uthread.h
user/parlib/thread0_sched.c
user/parlib/uthread.c
user/pthread/pthread.c

index 0641aff..cb1519a 100644 (file)
@@ -97,7 +97,8 @@ bool __check_preempt_pending(uint32_t vcoreid);       /* careful: check the code */
 void uth_disable_notifs(void);
 void uth_enable_notifs(void);
 
-/* Helpers, which sched_entry() can call */
+/* Helpers, which the 2LS can call */
+void __block_uthread_on_async_sysc(struct uthread *uth);
 void highjack_current_uthread(struct uthread *uthread);
 struct uthread *stop_current_uthread(void);
 void __attribute__((noreturn)) run_current_uthread(void);
index 953f849..45a47a5 100644 (file)
@@ -96,20 +96,43 @@ static void thread0_thread_blockon_sysc(struct uthread *uthread, void *arg)
                thread0_thread_runnable(uthread);
 }
 
+static void refl_error(struct uthread *uth, unsigned int trap_nr,
+                       unsigned int err, unsigned long aux)
+{
+       printf("Thread has unhandled fault: %d, err: %d, aux: %p\n",
+              trap_nr, err, aux);
+       /* Note that uthread.c already copied out our ctx into the uth
+        * struct */
+       print_user_context(&uth->u_ctx);
+       printf("Turn on printx to spew unhandled, malignant trap info\n");
+       exit(-1);
+}
+
+static bool handle_page_fault(struct uthread *uth, unsigned int err,
+                              unsigned long aux)
+{
+       if (!(err & PF_VMR_BACKED))
+               return FALSE;
+       syscall_async(&uth->local_sysc, SYS_populate_va, aux, 1);
+       __block_uthread_on_async_sysc(uth);
+       return TRUE;
+}
+
 static void thread0_thread_refl_fault(struct uthread *uth,
                                       struct user_context *ctx)
 {
-       switch (ctx->type) {
-       case ROS_HW_CTX:
-               printf("SCP has unhandled fault: %d, err: %d, aux: %p\n",
-                      __arch_refl_get_nr(ctx), __arch_refl_get_err(ctx),
-                      __arch_refl_get_aux(ctx));
-               print_user_context(ctx);
-               printf("Turn on printx to spew unhandled, malignant trap info\n");
-               exit(-1);
+       unsigned int trap_nr = __arch_refl_get_nr(ctx);
+       unsigned int err = __arch_refl_get_err(ctx);
+       unsigned long aux = __arch_refl_get_aux(ctx);
+
+       assert(ctx->type == ROS_HW_CTX);
+       switch (trap_nr) {
+       case HW_TRAP_PAGE_FAULT:
+               if (!handle_page_fault(uth, err, aux))
+                       refl_error(uth, trap_nr, err, aux);
                break;
        default:
-               assert(0);
+               refl_error(uth, trap_nr, err, aux);
        }
 }
 
index 47ce2d2..520c94b 100644 (file)
@@ -541,6 +541,24 @@ static void __ros_uth_syscall_blockon(struct syscall *sysc)
        uthread_yield(TRUE, sched_ops->thread_blockon_sysc, sysc);
 }
 
+/* 2LS helper.  Run this from vcore context.  It will block a uthread on it's
+ * internal syscall struct, which should be an async call.  You'd use this in
+ * e.g. thread_refl_fault when the 2LS initiates a syscall on behalf of the
+ * uthread. */
+void __block_uthread_on_async_sysc(struct uthread *uth)
+{
+       assert(in_vcore_context());
+       uth->sysc = &uth->local_sysc;
+       /* If a DONT_MIGRATE issued a syscall that blocks, we gotta spin, same as
+        * with the usual blockon. */
+       if (uth->flags & UTHREAD_DONT_MIGRATE) {
+               __ros_vcore_ctx_syscall_blockon(uth->sysc);
+               uth->sysc = 0;
+               return;
+       }
+       sched_ops->thread_blockon_sysc(uth, uth->sysc);
+}
+
 /* Simply sets current uthread to be whatever the value of uthread is.  This
  * can be called from outside of sched_entry() to highjack the current context,
  * and make sure that the new uthread struct is used to store this context upon
index 9dd4254..e089ff9 100644 (file)
@@ -288,20 +288,8 @@ static void handle_page_fault(struct uthread *uthread, unsigned int err,
        if (!(err & PF_VMR_BACKED)) {
                __signal_and_restart(uthread, SIGSEGV, SEGV_MAPERR, (void*)aux);
        } else {
-               /* stitching for the event handler.  sysc -> uth, uth -> sysc */
-               uthread->local_sysc.u_data = uthread;
-               uthread->sysc = &uthread->local_sysc;
-               pthread->state = PTH_BLK_SYSC;
-               /* one downside is that we'll never check the return val of the syscall.  if
-                * we errored out, we wouldn't know til we PF'd again, and inspected the old
-                * retval/err and other sysc fields (make sure the PF is on the same addr,
-                * etc).  could run into this issue on truncated files too. */
                syscall_async(&uthread->local_sysc, SYS_populate_va, aux, 1);
-               if (!register_evq(&uthread->local_sysc, sysc_mgmt[vcore_id()].ev_q)) {
-                       /* Lost the race with the call being done.  The kernel won't send the
-                        * event.  Just restart him. */
-                       restart_thread(&uthread->local_sysc);
-               }
+               __block_uthread_on_async_sysc(uthread);
        }
 }