Allow thread0 uthreads to block
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 11 Aug 2015 19:17:20 +0000 (15:17 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 28 Sep 2015 19:14:00 +0000 (15:14 -0400)
Thread0 uthreads could block on syscalls, but they couldn't block on
things like mutexes or other constructs that are outside the 2LS, such
as event queues.

The initialization of thread0_info from uthread_lib_init() could be done
statically, but we'll need this init function at some point.

user/parlib/thread0_sched.c
user/parlib/uthread.c

index 926d6e8..6246dc6 100644 (file)
@@ -20,24 +20,50 @@ static void thread0_thread_blockon_sysc(struct uthread *uthread, void *sysc);
 static void thread0_thread_refl_fault(struct uthread *uthread,
                                       unsigned int trap_nr, unsigned int err,
                                       unsigned long aux);
+static void thread0_thread_runnable(struct uthread *uth);
+static void thread0_thread_has_blocked(struct uthread *uth, int flags);
 
 /* externed into uthread.c */
 struct schedule_ops thread0_2ls_ops = {
        .sched_entry = thread0_sched_entry,
        .thread_blockon_sysc = thread0_thread_blockon_sysc,
        .thread_refl_fault = thread0_thread_refl_fault,
+       .thread_runnable = thread0_thread_runnable,
+       .thread_has_blocked = thread0_thread_has_blocked,
 };
 
 /* externed into uthread.c */
 struct uthread *thread0_uth;
 
+/* Our thread0 is actually allocated in uthread as just a struct uthread, so we
+ * don't actually attach this mgmt info to it.  But since we just have one
+ * thread, it doesn't matter. */
+struct thread0_info {
+       bool                                            is_blocked;
+};
+static struct thread0_info thread0_info;
+
+void thread0_lib_init(void)
+{
+       memset(&thread0_info, 0, sizeof(thread0_info));
+}
+
 /* Thread0 scheduler ops (for processes that haven't linked in a full 2LS) */
 static void thread0_sched_entry(void)
 {
-       if (current_uthread)
+       /* TODO: support signal handling whenever we run a uthread */
+       if (current_uthread) {
                run_current_uthread();
-       else
-               run_uthread(thread0_uth);
+               assert(0);
+       }
+       while (1) {
+               if (!thread0_info.is_blocked) {
+                       run_uthread(thread0_uth);
+                       assert(0);
+               }
+               sys_yield(FALSE);
+               handle_events(0);
+       }
 }
 
 static void thread0_thread_blockon_sysc(struct uthread *uthread, void *arg)
@@ -79,3 +105,13 @@ static void thread0_thread_refl_fault(struct uthread *uthread,
        printf("Turn on printx to spew unhandled, malignant trap info\n");
        exit(-1);
 }
+
+static void thread0_thread_runnable(struct uthread *uth)
+{
+       thread0_info.is_blocked = FALSE;
+}
+
+static void thread0_thread_has_blocked(struct uthread *uth, int flags)
+{
+       thread0_info.is_blocked = TRUE;
+}
index 22ab2fd..645317e 100644 (file)
@@ -200,6 +200,7 @@ void __attribute__((constructor)) uthread_lib_init(void)
 {
        /* Use the thread0 sched's uth */
        extern struct uthread *thread0_uth;
+       extern void thread0_lib_init(void);
        int ret;
 
        /* Only run once, but make sure that vcore_lib_init() has run already. */
@@ -210,7 +211,9 @@ void __attribute__((constructor)) uthread_lib_init(void)
                             sizeof(struct uthread));
        assert(!ret);
        memset(thread0_uth, 0, sizeof(struct uthread)); /* aggressively 0 for bugs*/
+       /* Init the 2LS, which sets up current_uthread, before thread0 lib */
        uthread_2ls_init(thread0_uth, &thread0_2ls_ops);
+       thread0_lib_init();
        scp_vcctx_ready();
        /* Change our blockon from glibc's internal one to the regular one, which
         * uses vcore context and works for SCPs (with or without 2LS) and MCPs.