SCPs can register ev_qs for syscalls (XCC)
authorBarret Rhoden <brho@cs.berkeley.edu>
Fri, 16 Mar 2012 00:09:22 +0000 (17:09 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Fri, 16 Mar 2012 00:11:40 +0000 (17:11 -0700)
Right now, they just yield and get restarted right away, while waiting
for the event (and actually they just check the sysc flag).  Future
patches will have them become WAITING.

Rebuild your cross compiler/userspace.

kern/include/ros/syscall.h
user/parlib/include/vcore.h
user/parlib/uthread.c
user/parlib/vcore.c

index 5c3d8e9..5ff45a0 100644 (file)
@@ -34,15 +34,16 @@ struct syscall {
 #include <arch/atomic.h>
 
 /* Attempts to block on sysc, returning when it is done or progress has been
- * made. */
+ * made.  (function is in uthread.c) */
 void ros_syscall_blockon(struct syscall *sysc);
 
-/* This weak version is meant to work if there is no 2LS.  For now we just
- * spin, but in the future we could block the whole process. */
+/* No one should be using this - it's meant to allow glibc to compile, and all
+ * apps will link against parlib to get the real function. */
 static inline void __ros_syscall_blockon(struct syscall *sysc)
 {
-       while (!(atomic_read(&sysc->flags) & (SC_DONE | SC_PROGRESS)))
-               cpu_relax();
+       /* My ghetto error message: force a PF */
+       int *x = (int*)0xdeadbeef;
+       *x = 1337;
 }
 weak_alias(__ros_syscall_blockon, ros_syscall_blockon);
 
index bc0f011..645c051 100644 (file)
@@ -31,6 +31,8 @@ extern "C" {
 extern void vcore_entry();
 /* Declared in glibc's start.c */
 extern __thread bool __vcore_context;
+/* Simple ev_q (bits, IPIs, vc0) for scp syscalls, signals, etc */
+struct event_queue *__scp_simple_evq;
 
 /* Utility Functions */
 void *allocate_tls(void);
index 7c2da23..c791200 100644 (file)
@@ -295,27 +295,50 @@ void uthread_cleanup(struct uthread *uthread)
        __uthread_free_tls(uthread);
 }
 
+static void __ros_syscall_spinon(struct syscall *sysc)
+{
+       while (!(atomic_read(&sysc->flags) & (SC_DONE | SC_PROGRESS)))
+               cpu_relax();
+}
+
+static void __ros_syscall_scp_blockon(struct syscall *sysc)
+{
+       /* Until we're ready (advertised via the *evq), we must spin */
+       if (!__scp_simple_evq) {
+               __ros_syscall_spinon(sysc);
+               return;
+       }
+       /* Ask for a SYSCALL event when the sysc is done.  We don't need a handler,
+        * we just need the kernel to restart us from proc_yield.  If register
+        * fails, we're already done. */
+       if (register_evq(sysc, __scp_simple_evq)) {
+               /* Sending false for now - we want to signal proc code that we want to
+                * wait (piggybacking on the MCP meaning of this variable */
+               sys_yield(FALSE);
+       }
+}
+
 /* Attempts to block on sysc, returning when it is done or progress has been
  * made. */
 void ros_syscall_blockon(struct syscall *sysc)
 {
-       if (in_vcore_context()) {
-               /* vcore's don't know what to do yet, so do the default (spin) */
-               __ros_syscall_blockon(sysc);
+       /* even if we are in 'vcore context', an _S can block */
+       if (!in_multi_mode()) {
+               __ros_syscall_scp_blockon(sysc);
                return;
        }
-       if (!sched_ops->thread_blockon_sysc || !in_multi_mode()) {
-               /* There isn't a 2LS op for blocking, or we're _S.  Spin for now. */
-               __ros_syscall_blockon(sysc);
+       /* MCP vcore's don't know what to do yet, so we have to spin */
+       if (in_vcore_context()) {
+               __ros_syscall_spinon(sysc);
                return;
        }
-       /* At this point, we know we're a uthread.  If we're a DONT_MIGRATE uthread,
-        * then it's disabled notifs and is basically in vcore context, enough so
-        * that it can't call into the 2LS. */
+       /* At this point, we know we're a uthread in an MCP.  If we're a
+        * DONT_MIGRATE uthread, then it's disabled notifs and is basically in
+        * vcore context, enough so that it can't call into the 2LS. */
        assert(current_uthread);
        if (current_uthread->flags & UTHREAD_DONT_MIGRATE) {
                assert(!notif_is_enabled(vcore_id()));  /* catch bugs */
-               __ros_syscall_blockon(sysc);
+               __ros_syscall_spinon(sysc);
        }
        /* double check before doing all this crap */
        if (atomic_read(&sysc->flags) & (SC_DONE | SC_PROGRESS))
index 924acc3..73d8d6e 100644 (file)
@@ -19,6 +19,8 @@
 static size_t _max_vcores_ever_wanted = 1;
 atomic_t nr_new_vcores_wanted;
 atomic_t vc_req_being_handled;
+/* Simple ev_q (bits, IPIs, vc0) for scp syscalls, signals, etc */
+struct event_queue *__scp_simple_evq = 0;
 
 extern void** vcore_thread_control_blocks;
 
@@ -169,6 +171,7 @@ vcore_init_fail:
 void force_parlib_symbols(void)
 {
        vcore_event_init();
+       ros_syscall_blockon(0); /* don't seem to need to force this for now */
        assert(0);
 }
 
@@ -179,7 +182,15 @@ void vcore_event_init(void)
 {
        /* set up our thread0 as a uthread */
        uthread_slim_init();
-       /* TODO: actually register for event handlers and whatnot */
+       /* Set up an ev_q for blocking _Ss on syscalls.  Events will get sent to
+        * vcore0's VCPD public mbox.  We'll get a bit, instead of a full message,
+        * since we don't need to know *sysc.  Also note that the event handler is
+        * 0, until set by a 2LS.  We don't need a handler - just need to get woken
+        * up. */
+       __scp_simple_evq = get_event_q_vcpd(0, EVENT_NOMSG | EVENT_IPI);
+       /* TODO: register for other kevents/signals and whatnot (can probably reuse
+        * the simple ev_q).  Could also do this via explicit functions from the
+        * program. */
 }
 
 /* Helper, picks some sane defaults and changes the process into an MCP */