Event helpers for userspace
authorBarret Rhoden <brho@cs.berkeley.edu>
Sat, 19 Feb 2011 00:18:15 +0000 (16:18 -0800)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:58 +0000 (17:35 -0700)
Provides helpers for some common tasks, and uses them in the example
code.  Note that you'll often want something more complicated than
enable_kevent() and get_event_type(), so you'll have to build that from
the other functions in event.c.

kern/include/ros/bcq.h
tests/eth_audio.c
tests/mhello.c
tests/msr_dumb_while.c
tests/msr_nice_while.c
user/include/event.h [new file with mode: 0644]
user/parlib/Makefrag
user/parlib/event.c [new file with mode: 0644]
user/parlib/pthread.c

index b5b255b..d2684d3 100644 (file)
@@ -177,6 +177,10 @@ struct bcq_header {
        __retval;                                                                  \
 })
 
        __retval;                                                                  \
 })
 
+/* Checks of a bcq is empty (meaning no work), instead of trying to dequeue */
+#define bcq_empty(_bcq)                                                        \
+       BCQ_NO_WORK((_bcq)->hdr.prod_idx, (_bcq)->hdr.cons_pvt_idx)
+
 #if 0
 /* Original C Code, for posterity / debugging */
 static inline int enqueue(struct __name_bcq *bcq, __elem_t *elem,
 #if 0
 /* Original C Code, for posterity / debugging */
 static inline int enqueue(struct __name_bcq *bcq, __elem_t *elem,
index 57f1ca0..b1e5e34 100644 (file)
@@ -17,6 +17,7 @@
 #include <sys/mman.h>
 #include <timing.h>
 #include <assert.h>
 #include <sys/mman.h>
 #include <timing.h>
 #include <assert.h>
+#include <event.h>
 
 void *core0_tls = 0;
 void *in_buf, *out_buf;
 
 void *core0_tls = 0;
 void *in_buf, *out_buf;
@@ -53,12 +54,7 @@ int main()
                printf("vcore_init() failed, we're fucked!\n");
 
        /* ETHAUD Turn on Free apple pie (which is the network packet) */
                printf("vcore_init() failed, we're fucked!\n");
 
        /* ETHAUD Turn on Free apple pie (which is the network packet) */
-       struct event_queue *ev_q = malloc(sizeof(struct event_queue));
-       ev_q->ev_mbox = &__procdata.vcore_preempt_data[0].ev_mbox;
-       ev_q->ev_flags = EVENT_IPI;
-       ev_q->ev_vcore = 0;     
-       ev_q->ev_handler = 0;
-       __procdata.kernel_evts[EV_FREE_APPLE_PIE] = ev_q;
+       enable_kevent(EV_FREE_APPLE_PIE, 0, TRUE);
 
        /* Need to save this somewhere that you can find it again when restarting
         * core0 */
 
        /* Need to save this somewhere that you can find it again when restarting
         * core0 */
@@ -108,12 +104,11 @@ void vcore_entry(void)
        struct preempt_data *vcpd;
        vcpd = &__procdata.vcore_preempt_data[vcoreid];
        
        struct preempt_data *vcpd;
        vcpd = &__procdata.vcore_preempt_data[vcoreid];
        
-       /* here is how you receive an event message (ought to check overflow) */
-       struct event_msg ev_msg = {0};
-       bcq_dequeue(&vcpd->ev_mbox.ev_msgs, &ev_msg, NR_BCQ_EVENTS);
+       /* Ghetto way to get just an event number */
+       unsigned int ev_type = get_event_type(&vcpd->ev_mbox);
 
        /* ETHAUD app: process the packet if we got a notif */
 
        /* ETHAUD app: process the packet if we got a notif */
-       if (ev_msg.ev_type == EV_FREE_APPLE_PIE)
+       if (ev_type == EV_FREE_APPLE_PIE)
                process_packet();
 
        if (vc->preempt_pending) {
                process_packet();
 
        if (vc->preempt_pending) {
index 765a7bf..7e49cf4 100644 (file)
@@ -10,6 +10,7 @@
 #include <mcs.h>
 #include <timing.h>
 #include <rassert.h>
 #include <mcs.h>
 #include <timing.h>
 #include <rassert.h>
+#include <event.h>
 
 #ifdef __sparc_v8__
 # define udelay(x) udelay((x)/2000)
 
 #ifdef __sparc_v8__
 # define udelay(x) udelay((x)/2000)
@@ -20,7 +21,7 @@ mcs_barrier_t b;
 __thread int temp;
 void *core0_tls = 0;
 
 __thread int temp;
 void *core0_tls = 0;
 
-struct event_queue_big *indirect_q;
+struct event_queue *indirect_q;
 
 int main(int argc, char** argv)
 {
 
 int main(int argc, char** argv)
 {
@@ -29,32 +30,22 @@ int main(int argc, char** argv)
 
        mcs_barrier_init(&b, max_vcores());
 
 
        mcs_barrier_init(&b, max_vcores());
 
-       /* prep indirect ev_q (TODO PIN).  Note we grab a big one */
-       indirect_q = malloc(sizeof(struct event_queue_big));
-       indirect_q->ev_mbox = &indirect_q->ev_imbox;
+       /* prep indirect ev_q.  Note we grab a big one */
+       indirect_q = get_big_event_q();
        indirect_q->ev_flags = EVENT_IPI;
        indirect_q->ev_vcore = 1;                       /* IPI core 1 */
        indirect_q->ev_handler = 0;
        printf("Registering %08p for event type %d\n", indirect_q,
               EV_FREE_APPLE_PIE);
        indirect_q->ev_flags = EVENT_IPI;
        indirect_q->ev_vcore = 1;                       /* IPI core 1 */
        indirect_q->ev_handler = 0;
        printf("Registering %08p for event type %d\n", indirect_q,
               EV_FREE_APPLE_PIE);
-       __procdata.kernel_evts[EV_FREE_APPLE_PIE] = (struct event_queue*)indirect_q;
+       register_kevent_q(indirect_q, EV_FREE_APPLE_PIE);
 
 /* begin: stuff userspace needs to do before switching to multi-mode */
        if (vcore_init())
                printf("vcore_init() failed, we're fucked!\n");
 
 
 /* begin: stuff userspace needs to do before switching to multi-mode */
        if (vcore_init())
                printf("vcore_init() failed, we're fucked!\n");
 
-       /* 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
-        * USER_IPIs, posting events to vcore 0's vcpd, and telling the kernel to
-        * send to vcore 0.
-        * TODO: (PIN) this ev_q needs to be pinned */
-       struct event_queue *ev_q = malloc(sizeof(struct event_queue));
-       ev_q->ev_mbox = &__procdata.vcore_preempt_data[0].ev_mbox;
-       ev_q->ev_flags = EVENT_IPI;     /* we want an IPI */
-       ev_q->ev_vcore = 0;                     /* IPI core 0 */
-       ev_q->ev_handler = 0;
-       /* Now tell the kernel about it */
-       __procdata.kernel_evts[EV_USER_IPI] = ev_q;
+       /* Set up event reception.  For example, this will allow us to receive an
+        * event and IPI for USER_IPIs on vcore 0.  Check event.c for more stuff. */
+       enable_kevent(EV_USER_IPI, 0, TRUE);
 
        /* Need to save this somewhere that you can find it again when restarting
         * core0 */
 
        /* Need to save this somewhere that you can find it again when restarting
         * core0 */
@@ -125,16 +116,18 @@ void vcore_entry(void)
        struct preempt_data *vcpd;
        vcpd = &__procdata.vcore_preempt_data[vcoreid];
        
        struct preempt_data *vcpd;
        vcpd = &__procdata.vcore_preempt_data[vcoreid];
        
-       /* here is how you receive an event (ought to check for overflow, etc) */
+       /* here is how you receive an event */
        struct event_msg ev_msg = {0};
        struct event_msg ev_msg = {0};
-       bcq_dequeue(&vcpd->ev_mbox.ev_msgs, &ev_msg, NR_BCQ_EVENTS);
-       printf("the queue is on vcore %d and has a ne with type %d\n", vcoreid,
-              ev_msg.ev_type);
+       if (event_activity(&vcpd->ev_mbox, 0)) {
+               /* Ought to while loop/dequeue, processing as they come in. */
+               bcq_dequeue(&vcpd->ev_mbox.ev_msgs, &ev_msg, NR_BCQ_EVENTS);
+               printf("the queue is on vcore %d and has a ne with type %d\n", vcoreid,
+                      ev_msg.ev_type);
+               printf("Number of event overflows: %d\n", vcpd->ev_mbox.ev_overflows);
+       }
        /* it might be in bitmask form too: */
        //printf("and the bitmask looks like: ");
        //PRINT_BITMASK(__procdata.vcore_preempt_data[vcoreid].notif_bmask, MAX_NR_NOTIF);
        /* it might be in bitmask form too: */
        //printf("and the bitmask looks like: ");
        //PRINT_BITMASK(__procdata.vcore_preempt_data[vcoreid].notif_bmask, MAX_NR_NOTIF);
-       /* can see how many messages had to be sent as bits */
-       printf("Number of event overflows: %d\n", vcpd->ev_mbox.ev_overflows);
 
        /* How we handle indirection events: */
        struct event_queue_big *ev_q;
 
        /* How we handle indirection events: */
        struct event_queue_big *ev_q;
@@ -142,6 +135,7 @@ void vcore_entry(void)
        if (ev_msg.ev_type == EV_EVENT) {
                ev_q = ev_msg.ev_arg3;  /* convention */
                printf("Detected EV_EVENT, ev_q is %08p (%08p)\n", ev_q, indirect_q);
        if (ev_msg.ev_type == EV_EVENT) {
                ev_q = ev_msg.ev_arg3;  /* convention */
                printf("Detected EV_EVENT, ev_q is %08p (%08p)\n", ev_q, indirect_q);
+               /* Ought to loop/dequeue, processing as they come in. */
                bcq_dequeue(&ev_q->ev_mbox->ev_msgs, &indir_msg, NR_BCQ_EVENTS);
                printf("Message of type: %d (%d)\n", indir_msg.ev_type,
                       EV_FREE_APPLE_PIE);
                bcq_dequeue(&ev_q->ev_mbox->ev_msgs, &indir_msg, NR_BCQ_EVENTS);
                printf("Message of type: %d (%d)\n", indir_msg.ev_type,
                       EV_FREE_APPLE_PIE);
index 2fdfc06..aff755c 100644 (file)
@@ -6,7 +6,7 @@
 #include <rstdio.h>
 #include <vcore.h>
 #include <arch/arch.h>
 #include <rstdio.h>
 #include <vcore.h>
 #include <arch/arch.h>
-#include <ros/bcq.h>
+#include <event.h>
 
 int main(int argc, char** argv)
 {
 
 int main(int argc, char** argv)
 {
@@ -16,14 +16,8 @@ int main(int argc, char** argv)
        struct preempt_data *vcpd = &__procdata.vcore_preempt_data[0];
        vcpd->notif_enabled = TRUE;
 
        struct preempt_data *vcpd = &__procdata.vcore_preempt_data[0];
        vcpd->notif_enabled = TRUE;
 
-       /* Get EV_ALARM on vcore 1, with IPI.
-        * TODO: (PIN) this ev_q needs to be pinned */
-       struct event_queue *ev_q = malloc(sizeof(struct event_queue));
-       ev_q->ev_mbox = &__procdata.vcore_preempt_data[1].ev_mbox;
-       ev_q->ev_flags = EVENT_IPI;
-       ev_q->ev_vcore = 1;
-       ev_q->ev_handler = 0;
-       __procdata.kernel_evts[EV_ALARM] = ev_q;
+       /* Get EV_ALARM on vcore 1, with IPI. */
+       enable_kevent(EV_ALARM, 1, EVENT_IPI);
 
        vcore_request(max_vcores());
 
 
        vcore_request(max_vcores());
 
@@ -36,9 +30,8 @@ void vcore_entry(void)
        struct preempt_data *vcpd = &__procdata.vcore_preempt_data[0];
        vcpd->notif_enabled = TRUE;
 
        struct preempt_data *vcpd = &__procdata.vcore_preempt_data[0];
        vcpd->notif_enabled = TRUE;
 
-       struct event_msg ev_msg = {0};
-       bcq_dequeue(&vcpd->ev_mbox.ev_msgs, &ev_msg, NR_BCQ_EVENTS);
-       if (ev_msg.ev_type == EV_ALARM)
+       unsigned int ev_type = get_event_type(&vcpd->ev_mbox);
+       if (ev_type == EV_ALARM)
                printf("[T]:009:E:%llu\n", read_tsc());
        while(1);
 }
                printf("[T]:009:E:%llu\n", read_tsc());
        while(1);
 }
index fc91bcd..21ef7f7 100644 (file)
@@ -4,11 +4,11 @@
  * userthread.  The pthread code will nicely yield if it detects an incoming
  * preemption. */
 
  * userthread.  The pthread code will nicely yield if it detects an incoming
  * preemption. */
 
-#include <ros/event.h>
 #include <stdlib.h>
 #include <vcore.h>
 #include <pthread.h>
 #include <rassert.h>
 #include <stdlib.h>
 #include <vcore.h>
 #include <pthread.h>
 #include <rassert.h>
+#include <event.h>
 
 void *while_thread(void *arg)
 {
 
 void *while_thread(void *arg)
 {
@@ -20,14 +20,10 @@ int main(int argc, char** argv)
        pthread_t *my_threads = malloc(sizeof(pthread_t) * max_vcores());
 
        /* set up to receive the PREEMPT_PENDING event.  EVENT_VCORE_APPRO tells the
        pthread_t *my_threads = malloc(sizeof(pthread_t) * max_vcores());
 
        /* set up to receive the PREEMPT_PENDING event.  EVENT_VCORE_APPRO tells the
-        * kernel to send the msg to whichever vcore is appropriate. 
-        * TODO: (PIN) this ev_q needs to be pinned */
-       struct event_queue *ev_q = malloc(sizeof(struct event_queue));
-       ev_q->ev_mbox = &__procdata.vcore_preempt_data[0].ev_mbox;
-       ev_q->ev_flags = EVENT_IPI | EVENT_NOMSG | EVENT_VCORE_APPRO;
-       ev_q->ev_vcore = 0;
-       ev_q->ev_handler = 0;
-       __procdata.kernel_evts[EV_PREEMPT_PENDING] = ev_q;
+        * kernel to send the msg to whichever vcore is appropriate.  Pthread code
+        * will see the preemption and yield. */
+       enable_kevent(EV_PREEMPT_PENDING, 0,
+                     EVENT_IPI | EVENT_NOMSG | EVENT_VCORE_APPRO);
 
        /* actually only need one less, since the _S will be pthread 0 */
        for (int i = 0; i < max_vcores() - 1; i++)
 
        /* actually only need one less, since the _S will be pthread 0 */
        for (int i = 0; i < max_vcores() - 1; i++)
diff --git a/user/include/event.h b/user/include/event.h
new file mode 100644 (file)
index 0000000..74867cd
--- /dev/null
@@ -0,0 +1,30 @@
+/* Copyright (c) 2011 The Regents of the University of California
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Userspace utility functions for receiving events and notifications (IPIs).
+ * Some are higher level than others; just use what you need. */ 
+
+#ifndef _EVENT_H
+#define _EVENT_H
+
+#include <ros/event.h>
+#include <ros/common.h>
+
+/********* Event_q Setup / Registration  ***********/
+struct event_queue *get_big_event_q(void);
+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);
+void put_event_q(struct event_queue *ev_q);
+void register_kevent_q(struct event_queue *ev_q, unsigned int ev_type);
+struct event_queue *clear_kevent_q(unsigned int ev_type);
+void enable_kevent(unsigned int ev_type, uint32_t vcoreid, bool ipi);
+void disable_kevent(unsigned int ev_type);
+
+/********* Event Handling / Reception ***********/
+bool event_activity(struct event_mbox *ev_mbox, int flags);
+unsigned int event_clear_overflows(struct event_queue *ev_q);
+unsigned int get_event_type(struct event_mbox *ev_mbox);
+
+#endif /* _EVENT_H */
index 5c310e8..1923ba2 100644 (file)
@@ -19,6 +19,7 @@ USER_PARLIB_SRCFILES := \
                  $(USER_PARLIB_DIR)/debugfmt.c \
                  $(USER_PARLIB_DIR)/timing.c \
                  $(USER_PARLIB_DIR)/debug.c \
                  $(USER_PARLIB_DIR)/debugfmt.c \
                  $(USER_PARLIB_DIR)/timing.c \
                  $(USER_PARLIB_DIR)/debug.c \
+                 $(USER_PARLIB_DIR)/event.c \
                  $(USER_PARLIB_DIR)/asynccall.c
 
 # Only build files if they exist.
                  $(USER_PARLIB_DIR)/asynccall.c
 
 # Only build files if they exist.
diff --git a/user/parlib/event.c b/user/parlib/event.c
new file mode 100644 (file)
index 0000000..115db35
--- /dev/null
@@ -0,0 +1,151 @@
+/* Copyright (c) 2011 The Regents of the University of California
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Userspace utility functions for receiving events and notifications (IPIs).
+ * Some are higher level than others; just use what you need. */ 
+
+#include <ros/event.h>
+#include <ros/procdata.h>
+#include <ros/bcq.h>
+#include <arch/bitmask.h>
+#include <vcore.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <parlib.h>
+#include <event.h>
+
+/********* 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)
+{
+       /* TODO: (PIN) should be pinned memory */
+       struct event_queue_big *big_q = malloc(sizeof(struct event_queue_big));
+       memset(big_q, 0, sizeof(struct event_queue_big));
+       big_q->ev_mbox = &big_q->ev_imbox;
+       return (struct event_queue*)big_q;
+}
+
+/* Give it up */
+void put_big_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.  One option is to use the flags, though
+        * this could be error prone. */
+       free(ev_q);
+}
+
+/* Need to point this event_q to an mbox - usually to a vcpd */
+struct event_queue *get_event_q(void)
+{
+       /* TODO: (PIN) should be pinned memory */
+       struct event_queue *ev_q = malloc(sizeof(struct event_queue));
+       memset(ev_q, 0, sizeof(struct event_queue));
+       return ev_q;
+}
+
+/* Gets a small ev_q, with ev_mbox pointing to the vcpd mbox of vcoreid */
+struct event_queue *get_event_q_vcpd(uint32_t vcoreid)
+{
+       struct event_queue *ev_q = get_event_q();
+       ev_q->ev_mbox = &__procdata.vcore_preempt_data[vcoreid].ev_mbox;
+       return ev_q;
+}
+
+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. */
+       free(ev_q);
+}
+
+/* Sets ev_q to be the receiving end for kernel event ev_type */
+void register_kevent_q(struct event_queue *ev_q, unsigned int ev_type)
+{
+       __procdata.kernel_evts[ev_type] = ev_q;
+}
+
+/* Clears the event, returning an ev_q if there was one there.  You'll need to
+ * free it. */
+struct event_queue *clear_kevent_q(unsigned int ev_type)
+{
+       struct event_queue *ev_q = __procdata.kernel_evts[ev_type];
+       __procdata.kernel_evts[ev_type] = 0;
+       return ev_q;
+}
+
+/* Enables an IPI/event combo for ev_type sent to vcoreid's default mbox.  IPI
+ * if you want one or not.  This is the simplest thing applications may want,
+ * and shows how you can put the other event functions together to get similar
+ * things done. */
+void enable_kevent(unsigned int ev_type, uint32_t vcoreid, bool ipi)
+{
+       struct event_queue *ev_q = get_event_q_vcpd(vcoreid);
+       ev_q->ev_flags = ipi ? EVENT_IPI : 0;
+       ev_q->ev_vcore = vcoreid;
+       ev_q->ev_handler = 0;
+       register_kevent_q(ev_q, ev_type);
+}
+
+/* Stop receiving the events (one could be on the way) */
+void disable_kevent(unsigned int ev_type)
+{
+       struct event_queue *ev_q = clear_kevent_q(ev_type);
+       if (ev_q)
+               put_event_q(ev_q);
+       else
+               printf("Tried to disable but no event_q loaded on ev_type %d", ev_type);
+}
+
+/********* Event Handling / Reception ***********/
+/* Tests the ev_q to see if anything has happened on it.  Up to the caller to do
+ * something with the info, such as try and dequeue or handle an overflow.
+ * Flags is for the ev_q's flags (if you know it), which is to check the NO_MSG
+ * style ev_qs. */
+bool event_activity(struct event_mbox *ev_mbox, int flags)
+{
+       if (!bcq_empty(&ev_mbox->ev_msgs))
+               return TRUE;
+       /* Only need to check the bitmask for activity if we've had overflows or if
+        * we are a NO_MSG.  This means the client can clear its overflows. */
+       if (ev_mbox->ev_overflows || (flags & EVENT_NOMSG)) {
+               if (!BITMASK_IS_CLEAR(&ev_mbox->ev_bitmap, MAX_NR_EVENT))
+                       return TRUE;
+       }
+       return FALSE;
+}
+
+/* Clears the overflows, returning the number of overflows cleared. */
+unsigned int event_clear_overflows(struct event_queue *ev_q)
+{
+       unsigned int retval = ev_q->ev_mbox->ev_overflows;
+       ev_q->ev_mbox->ev_overflows = 0;
+       return retval;
+}
+
+/* Somewhat ghetto helper, for the lazy.  If all you care about is an event
+ * number, this will see if the event happened or not.  It will try for a
+ * message, but if there is none, it will go for a bit.  Note that multiple
+ * messages that overflowed could turn into just one bit. */
+unsigned int get_event_type(struct event_mbox *ev_mbox)
+{
+       struct event_msg local_msg = {0};
+       if (bcq_dequeue(&ev_mbox->ev_msgs, &local_msg, NR_BCQ_EVENTS)) {
+               return local_msg.ev_type;
+       }
+       if (BITMASK_IS_CLEAR(&ev_mbox->ev_bitmap, MAX_NR_EVENT))
+               return EV_NONE; /* aka, 0 */
+       for (int i = 0; i < MAX_NR_EVENT; i++) {
+               if (GET_BITMASK_BIT(ev_mbox->ev_bitmap, i)) {
+                       CLR_BITMASK_BIT_ATOMIC(ev_mbox->ev_bitmap, i);
+                       return i;
+               }
+       }
+       return EV_NONE;
+}
index 291965e..8b58f16 100644 (file)
@@ -14,6 +14,7 @@
 #include <sys/queue.h>
 #include <sys/mman.h>
 #include <assert.h>
 #include <sys/queue.h>
 #include <sys/mman.h>
 #include <assert.h>
+#include <event.h>
 
 struct pthread_queue ready_queue = TAILQ_HEAD_INITIALIZER(ready_queue);
 struct pthread_queue active_queue = TAILQ_HEAD_INITIALIZER(active_queue);
 
 struct pthread_queue ready_queue = TAILQ_HEAD_INITIALIZER(ready_queue);
 struct pthread_queue active_queue = TAILQ_HEAD_INITIALIZER(active_queue);
@@ -38,15 +39,10 @@ void _pthread_init()
        /* 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
         * USER_IPIs, posting events to vcore 0's vcpd, and telling the kernel to
        /* 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
         * USER_IPIs, posting events to vcore 0's vcpd, and telling the kernel to
-        * send to vcore 0.
-        * TODO: (PIN) this ev_q needs to be pinned */
-       struct event_queue *ev_q = malloc(sizeof(struct event_queue));
-       ev_q->ev_mbox = &__procdata.vcore_preempt_data[0].ev_mbox;
-       ev_q->ev_flags = EVENT_IPI;     /* we want an IPI */
-       ev_q->ev_vcore = 0;                     /* IPI core 0 */
-       ev_q->ev_handler = 0;
-       /* Now tell the kernel about it */
-       __procdata.kernel_evts[EV_USER_IPI] = ev_q;
+        * send to vcore 0.  Note sys_self_notify will ignore the vcoreid pref.
+        * Also note that enable_kevent() is just an example, and you probably want
+        * to use parts of event.c to do what you want. */
+       enable_kevent(EV_USER_IPI, 0, EVENT_IPI);
 
        /* don't forget to enable notifs on vcore0.  if you don't, the kernel will
         * restart your _S with notifs disabled, which is a path to confusion. */
 
        /* don't forget to enable notifs on vcore0.  if you don't, the kernel will
         * restart your _S with notifs disabled, which is a path to confusion. */