Pthread syscall ev_qs no longer use VCPD mboxes
authorBarret Rhoden <brho@cs.berkeley.edu>
Fri, 29 Jul 2011 23:47:02 +0000 (16:47 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:36:05 +0000 (17:36 -0700)
2LSs (and anyone) should not use the VCPD ev_mboxes.  Message delivery
to the VCPD should be for messages meant to go to that specific vcore,
about that vcore's business.

One such bit of business is the indirection event EV_EVENT, telling it
the reason for an IPI is to check a particular event queue (such as the
syscall queue).

You want to decouple these so that different vcores can handle
unblocking threads that slept on a separate vcore, which is necessary if
you want a vcore to yield when it has no work to do but when there are
outstanding syscalls/uthreads.  If we used the VCPD, then another core
would have to process messages of another core's VCPD, which would
include messages that were not meant for the running core - such as
"preempt pending".

Also note that a 2LS could easily have one ev_q for all blocking
syscalls, or even multiple ev_qs (so you can specify IPI targets) but
with one global ev_mbox that all the ev_qs point to (and contend on).
This assumes there are no bugs (which there are).

user/pthread/pthread.c
user/pthread/pthread.h

index 224cee9..4217ee3 100644 (file)
@@ -15,6 +15,7 @@
 #include <sys/mman.h>
 #include <assert.h>
 #include <event.h>
+#include <ucq.h>
 
 struct pthread_queue ready_queue = TAILQ_HEAD_INITIALIZER(ready_queue);
 struct pthread_queue active_queue = TAILQ_HEAD_INITIALIZER(active_queue);
@@ -68,6 +69,7 @@ static int __pthread_allocate_stack(struct pthread_tcb *pt);
  * main()) */
 struct uthread *pth_init(void)
 {
+       uintptr_t mmap_block;
        struct mcs_lock_qnode local_qn = {0};
        /* Tell the kernel where and how we want to receive events.  This is just an
         * example of what to do to have a notification turned on.  We're turning on
@@ -82,14 +84,24 @@ struct uthread *pth_init(void)
        /* Set up the per-vcore structs to track outstanding syscalls */
        sysc_mgmt = malloc(sizeof(struct sysc_mgmt) * max_vcores());
        assert(sysc_mgmt);
+       /* Get a block of pages for our per-vcore (but non-VCPD) ev_qs */
+       mmap_block = (uintptr_t)mmap(0, PGSIZE * 2 * max_vcores(),
+                                    PROT_WRITE | PROT_READ,
+                                    MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
+       assert(mmap_block);
+       /* Could be smarter and do this on demand (in case we don't actually want
+        * max_vcores()). */
        for (int i = 0; i < max_vcores(); i++) {
-               /* Set up each of the per-vcore syscall event queues so that they point
-                * to the VCPD/default vcore mailbox (for now)  Note you'll need the
-                * vcore to be online to get the events (for now). */
-               sysc_mgmt[i].ev_q.ev_mbox =  &__procdata.vcore_preempt_data[i].ev_mbox;
-               sysc_mgmt[i].ev_q.ev_flags = EVENT_IPI;         /* totally up to you */
-               sysc_mgmt[i].ev_q.ev_vcore = i;
+               /* Each vcore needs to point to a non-VCPD ev_q */
+               sysc_mgmt[i].ev_q = get_big_event_q_raw();
+               sysc_mgmt[i].ev_q->ev_flags = EVENT_IPI;                /* totally up to you */
+               sysc_mgmt[i].ev_q->ev_vcore = i;
+               ucq_init_raw(&sysc_mgmt[i].ev_q->ev_mbox->ev_msgs, 
+                            mmap_block + (2 * i    ) * PGSIZE, 
+                            mmap_block + (2 * i + 1) * PGSIZE); 
        }
+       /* Technically, we should munmap and free what we've alloc'd, but the
+        * kernel will clean it up for us when we exit. */
        /* Create a pthread_tcb for the main thread */
        pthread_t t = (pthread_t)calloc(1, sizeof(struct pthread_tcb));
        assert(t);
@@ -294,7 +306,7 @@ void pth_blockon_sysc(struct syscall *sysc)
        /* Set things up so we can wake this thread up later */
        sysc->u_data = current_uthread;
        /* Register our vcore's syscall ev_q to hear about this syscall. */
-       if (!register_evq(sysc, &sysc_mgmt[vcoreid].ev_q)) {
+       if (!register_evq(sysc, sysc_mgmt[vcoreid].ev_q)) {
                /* Lost the race with the call being done.  The kernel won't send the
                 * event.  Just restart him. */
                restart_thread(sysc);
index d8295db..49553d7 100644 (file)
@@ -31,7 +31,7 @@ TAILQ_HEAD(pthread_queue, pthread_tcb);
  * kernel to signal us.  We don't need a lock since this is per-vcore and
  * accessed in vcore context. */
 struct sysc_mgmt {
-       struct event_queue                      ev_q;
+       struct event_queue                      *ev_q;
 };
 
 #define PTHREAD_ONCE_INIT 0