Fixes event_q "get" interfaces to work with UCQs
authorBarret Rhoden <brho@cs.berkeley.edu>
Fri, 29 Jul 2011 23:35:19 +0000 (16:35 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:36:05 +0000 (17:36 -0700)
One of the differences betwene UCQs and BCQs is that UCQs need to be
initialized.  I put some code in the kernel to catch uninitialized UCQs
in _M mode, which shouldn't happen, to help debug this.

For the event and ucq init code, the main difference between the raw and
normal functions is whether or not you manage your own memory.  Doing
one big mmap should be faster if you're making lots of big ev_qs (and
therefore lots of ucqs).

kern/src/event.c
kern/src/ucq.c
tests/ucq.c
user/parlib/event.c
user/parlib/include/event.h
user/parlib/include/ucq.h
user/parlib/ucq.c
user/parlib/vcore.c

index 7b5065b..314c333 100644 (file)
@@ -33,7 +33,7 @@ static void post_ev_msg(struct event_mbox *mbox, struct event_msg *msg,
                         int ev_flags)
 {
        struct proc *p = current;
-       printd("Sending event type %d\n", msg->ev_type);
+       printd("[kernel] Sending event type %d to mbox %08p\n", msg->ev_type, mbox);
        /* Sanity check */
        assert(p);
        /* If they just want a bit (NOMSG), just set the bit */
@@ -58,6 +58,7 @@ void send_event(struct proc *p, struct event_queue *ev_q, struct event_msg *msg,
        struct event_mbox *ev_mbox = 0, *vcore_mbox;
        struct event_msg local_msg = {0};
        assert(p);
+       printd("[kernel] sending msg to proc %08p, ev_q %08p\n", p, ev_q);
        if (!ev_q) {
                warn("[kernel] Null ev_q - kernel code should check before sending!");
                return;
index 3e413a3..4ef2ea8 100644 (file)
@@ -20,8 +20,11 @@ void send_ucq_msg(struct ucq *ucq, struct proc *p, struct event_msg *msg)
 
        assert(is_user_rwaddr(ucq, sizeof(struct ucq)));
        /* So we can try to send ucqs to _Ss before they initialize */
-       if (!ucq->ucq_ready)
+       if (!ucq->ucq_ready) {
+               if (p->state & (PROC_RUNNING_M | PROC_RUNNABLE_M))
+                       warn("proc %d is _M with an uninitialized ucq %08p\n", p->pid, ucq);
                return;
+       }
        /* Bypass fetching/incrementing the counter if we're overflowing, helps
         * prevent wraparound issues on the counter (only 12 bits of counter) */
        if (ucq->prod_overflow)
index 43bd8d2..8e2c9de 100644 (file)
@@ -16,9 +16,9 @@ int main(int argc, char** argv)
        assert((uintptr_t)ucq == USTACKTOP);
        /* Now init it */
        uintptr_t two_pages = (uintptr_t)mmap(0, PGSIZE * 2, PROT_WRITE | PROT_READ,
-                                             MAP_POPULATE, -1, 0);
+                                             MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
        assert(two_pages);
-       ucq_init(ucq, two_pages, two_pages + PGSIZE);
+       ucq_init_raw(ucq, two_pages, two_pages + PGSIZE);
        /* try to get a simple message */
        struct event_msg msg;
        /* 1: Spin til we can get a message (0 on success breaks) */
index 9c1d5db..dd35b4e 100644 (file)
 /********* Event_q Setup / Registration  ***********/
 
 /* Get event_qs via these interfaces, since eventually we'll want to either
- * allocate from pinned memory or use some form of a slab allocator.  Also, this
- * stitches up the big_q so its ev_mbox points to its internal mbox.  Never
- * access the internal mbox directly. */
-struct event_queue *get_big_event_q(void)
+ * allocate from pinned memory or use some form of a slab allocator.  Also,
+ * these stitch up the big_q so its ev_mbox points to its internal mbox.  Never
+ * access the internal mbox directly.
+ *
+ * Raw ones need to have their UCQs initialized.  If you're making a lot of
+ * these, you can do one big mmap and init the ucqs on your own, which ought to
+ * perform better.
+ *
+ * Use the 'regular' one for big_qs if you don't want to worry about the ucq
+ * initalization */
+struct event_queue *get_big_event_q_raw(void)
 {
        /* TODO: (PIN) should be pinned memory */
        struct event_queue_big *big_q = malloc(sizeof(struct event_queue_big));
@@ -33,8 +40,17 @@ struct event_queue *get_big_event_q(void)
        return (struct event_queue*)big_q;
 }
 
-/* Give it up */
-void put_big_event_q(struct event_queue *ev_q)
+struct event_queue *get_big_event_q(void)
+{
+       struct event_queue *big_q = get_big_event_q_raw();
+       /* uses the simpler, internally mmapping ucq_init() */
+       ucq_init(&big_q->ev_mbox->ev_msgs);
+       return big_q;
+}
+
+/* Give it up.  I don't recommend calling these unless you're sure the queues
+ * aren't in use (unregistered, etc). (TODO: consider some checks for this) */
+void put_big_event_q_raw(struct event_queue *ev_q)
 {
        /* if we use something other than malloc, we'll need to be aware that ev_q
         * is actually an event_queue_big.  One option is to use the flags, though
@@ -42,6 +58,12 @@ void put_big_event_q(struct event_queue *ev_q)
        free(ev_q);
 }
 
+void put_big_event_q(struct event_queue *ev_q)
+{
+       ucq_free_pgs(&ev_q->ev_mbox->ev_msgs);
+       put_big_event_q_raw(ev_q);
+}
+
 /* Need to point this event_q to an mbox - usually to a vcpd */
 struct event_queue *get_event_q(void)
 {
@@ -62,7 +84,7 @@ struct event_queue *get_event_q_vcpd(uint32_t vcoreid)
 void put_event_q(struct event_queue *ev_q)
 {
        /* if we use something other than malloc, we'll need to be aware that ev_q
-        * is actually an event_queue_big. */
+        * is not an event_queue_big. */
        free(ev_q);
 }
 
@@ -144,7 +166,7 @@ int handle_mbox_msgs(struct event_mbox *ev_mbox)
        /* Try to dequeue, dispatch whatever you get. */
        while (!get_ucq_msg(&ev_mbox->ev_msgs, &local_msg)) {
                ev_type = local_msg.ev_type;
-               printd("UCQ: ev_type: %d\n", ev_type);
+               printd("[event] UCQ (mbox %08p), ev_type: %d\n", ev_mbox, ev_type);
                if (ev_handlers[ev_type])
                        ev_handlers[ev_type](&local_msg, ev_type);
                check_preempt_pending(vcoreid);
@@ -161,6 +183,7 @@ static int handle_mbox(struct event_mbox *ev_mbox, unsigned int flags)
        int retval = 0;
        uint32_t vcoreid = vcore_id();
 
+       printd("[event] handling ev_mbox %08p on vcore %d\n", ev_mbox, vcore_id());
        /* Handle full messages.  Will deal with bits later. */
        retval = handle_mbox_msgs(ev_mbox);
 
@@ -170,7 +193,7 @@ static int handle_mbox(struct event_mbox *ev_mbox, unsigned int flags)
         * TODO: if they have a flag saying "it's okay to overflow", then we'll want
         * to check the bits regardless */
        void bit_handler(unsigned int bit) {
-               printd("Bit: ev_type: %d\n", bit);
+               printd("[event] Bit: ev_type: %d\n", bit);
                cmb();
                if (ev_handlers[bit])
                        ev_handlers[bit](0, bit);
@@ -233,5 +256,6 @@ void handle_event_q(struct event_queue *ev_q)
                }
                return;
        }
+       printd("[event] handling ev_q %08p on vcore %d\n", ev_q, vcore_id());
        handle_mbox(ev_q->ev_mbox, ev_q->ev_flags);
 }
index 316bb26..e6249e6 100644 (file)
@@ -12,7 +12,9 @@
 #include <ros/common.h>
 
 /********* Event_q Setup / Registration  ***********/
+struct event_queue *get_big_event_q_raw(void);
 struct event_queue *get_big_event_q(void);
+void put_big_event_q_raw(struct event_queue *ev_q);
 void put_big_event_q(struct event_queue *ev_q);
 struct event_queue *get_event_q(void);
 struct event_queue *get_event_q_vcpd(uint32_t vcoreid);
index 3d633a9..ce68d78 100644 (file)
@@ -10,7 +10,9 @@
 
 #include <ros/ucq.h>
 
-void ucq_init(struct ucq *ucq, uintptr_t pg1, uintptr_t pg2);
+void ucq_init_raw(struct ucq *ucq, uintptr_t pg1, uintptr_t pg2);
+void ucq_init(struct ucq *ucq);
+void ucq_free_pgs(struct ucq *ucq);
 int get_ucq_msg(struct ucq *ucq, struct event_msg *msg);
 
 #endif /* _UCQ_H */
index 860e850..720a925 100644 (file)
@@ -18,7 +18,7 @@
 /* Initializes a ucq.  You pass in addresses of mmaped pages for the main page
  * (prod_idx) and the spare page.  I recommend mmaping a big chunk and breaking
  * it up over a bunch of ucqs, instead of doing a lot of little mmap() calls. */
-void ucq_init(struct ucq *ucq, uintptr_t pg1, uintptr_t pg2)
+void ucq_init_raw(struct ucq *ucq, uintptr_t pg1, uintptr_t pg2)
 {
        assert(!PGOFF(pg1));
        assert(!PGOFF(pg2));
@@ -34,6 +34,29 @@ void ucq_init(struct ucq *ucq, uintptr_t pg1, uintptr_t pg2)
        ucq->ucq_ready = TRUE;
 }
 
+/* Inits a ucq, where you don't have to bother with the memory allocation.  This
+ * would be appropriate for one or two UCQs, though if you're allocating in
+ * bulk, use the raw version. */
+void ucq_init(struct ucq *ucq)
+{
+       uintptr_t two_pages = (uintptr_t)mmap(0, PGSIZE * 2,
+                                             PROT_WRITE | PROT_READ,
+                                             MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
+       assert(two_pages);
+       ucq_init_raw(ucq, two_pages, two_pages + PGSIZE);
+}
+
+/* Only call this on ucq's made with the simple ucq_init().  And be sure the ucq
+ * is no longer in use. */
+void ucq_free_pgs(struct ucq *ucq)
+{
+       uintptr_t pg1 = atomic_read(&ucq->prod_idx);
+       uintptr_t pg2 = atomic_read(&ucq->spare_pg);
+       assert(pg1 && pg2);
+       munmap((void*)pg1, PGSIZE);
+       munmap((void*)pg2, PGSIZE);
+}
+
 /* Consumer side, returns 0 on success and fills *msg with the ev_msg.  If the
  * ucq is empty, it will return -1. */
 int get_ucq_msg(struct ucq *ucq, struct event_msg *msg)
index e51abd8..79dbb69 100644 (file)
@@ -119,7 +119,7 @@ int vcore_init()
        /* Initialize our VCPD event queues' ucqs, two pages per vcore */
        mmap_block = (uintptr_t)mmap(0, PGSIZE * 2 * max_vcores(),
                                     PROT_WRITE | PROT_READ,
-                                    MAP_POPULATE, -1, 0);
+                                    MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
        /* Yeah, this doesn't fit in the error-handling scheme, but this whole
         * system doesn't really handle failure, and needs a rewrite involving less
         * mmaps/munmaps. */
@@ -128,9 +128,9 @@ int vcore_init()
         * separate ev_q for that. */
        for (int i = 0; i < max_vcores(); i++) {
                /* two pages each from the big block */
-               ucq_init(&__procdata.vcore_preempt_data[i].ev_mbox.ev_msgs,
-                        mmap_block + (2 * i    ) * PGSIZE, 
-                        mmap_block + (2 * i + 1) * PGSIZE); 
+               ucq_init_raw(&__procdata.vcore_preempt_data[i].ev_mbox.ev_msgs,
+                            mmap_block + (2 * i    ) * PGSIZE, 
+                            mmap_block + (2 * i + 1) * PGSIZE); 
        }
        assert(!in_vcore_context());
        initialized = 1;