Kernel alarms pass the alarm ID
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 26 Nov 2013 02:06:20 +0000 (18:06 -0800)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 16 Jan 2014 21:07:51 +0000 (13:07 -0800)
So userspace can tell which of it's #A alarms is firing.  With this (and
with multiple event handlers per event), we could have multiple alarm
handlers register and run dynamically.  Alternatively, we could switch
based on the ID, if there was one common handler (can do that
statically).

Note that the existing alarm examples can receive multiple events for
the same alarm.  It's up to userspace to handle that (it's easy, and we
do it).  This is a consequence of using SPAM_PUBLIC.  If your alarm
can't handle that, use an INDIR/FALLBACK.  This is part of the reason
why I didn't make a helper to set up all the alarm stuff - people will
want to customize, especially in the realm of the ev_q.  (The other
issue is whether or not CLOEXEC is used.  And there may be other issues
I haven't thought of).

Multiple ev_qs can be registered for different alarms; it's just hard to
share the event handler for them all, hence this patch.  I'll deal with
this more if we ever get someone who wants to use multiple kernel alarms
with different handlers.

kern/drivers/dev/alarm.c
tests/alarm.c
user/benchutil/alarm.c
user/benchutil/include/alarm.h

index 592067b..5b340a5 100644 (file)
@@ -92,6 +92,7 @@ static void proc_alarm_handler(struct alarm_waiter *a_waiter)
        }
        memset(&msg, 0, sizeof(struct event_msg));
        msg.ev_type = EV_ALARM;
+       msg.ev_arg2 = a->id;
        send_event(a->proc, ev_q, &msg, 0);
 }
 
index cf168ae..7b0375e 100644 (file)
@@ -21,7 +21,7 @@
 static void handle_alarm(struct event_msg *ev_msg, unsigned int ev_type)
 {
        assert(ev_type == EV_ALARM);
-       printf("\tAlarm fired!\n");
+       printf("\tAlarm fired!, id %d\n", ev_msg ? ev_msg->ev_arg2 : 55555);
 }
 
 int main(int argc, char **argv)
@@ -65,8 +65,9 @@ int main(int argc, char **argv)
        }
        ev_q->ev_vcore = 0;
        /* I think this is all the flags we need; gotta write that dissertation
-        * chapter (and event how-to)! */
-       ev_q->ev_flags = EVENT_IPI | EVENT_NOMSG | EVENT_SPAM_PUBLIC;
+        * chapter (and event how-to)!  We may get more than one event per alarm, if
+        * we have concurrent preempts/yields. */
+       ev_q->ev_flags = EVENT_IPI | EVENT_SPAM_PUBLIC;
        /* Register the ev_q for our alarm */
        ret = snprintf(path, sizeof(path), "evq %llx", ev_q);
        ret = write(ctlfd, path, ret);
index 4bb1108..64d0557 100644 (file)
@@ -92,6 +92,7 @@ static void init_alarm_service(void)
                return;
        }
        buf[ret] = 0;
+       global_tchain.alarmid = atoi(buf);
        snprintf(path, sizeof(path), "#A/a%s/timer", buf);
        timerfd = open(path, O_RDWR | O_CLOEXEC);
        if (timerfd < 0) {
@@ -106,7 +107,10 @@ static void init_alarm_service(void)
                return;
        }
        ev_q->ev_vcore = 0;
-       ev_q->ev_flags = EVENT_IPI | EVENT_NOMSG | EVENT_SPAM_PUBLIC;
+       /* We could get multiple events for a single alarm.  It's okay, since
+        * __trigger can handle spurious upcalls.  If it ever is not okay, then use
+        * an INDIR/FALLBACK instead of SPAM_PUBLIC. */
+       ev_q->ev_flags = EVENT_IPI | EVENT_SPAM_PUBLIC;
        ret = snprintf(path, sizeof(path), "evq %llx", ev_q);
        ret = write(ctlfd, path, ret);
        if (ret <= 0) {
@@ -251,7 +255,8 @@ static void __trigger_tchain(struct timer_chain *tchain)
 static void handle_user_alarm(struct event_msg *ev_msg, unsigned int ev_type)
 {
        assert(ev_type == EV_ALARM);
-       __trigger_tchain(&global_tchain);
+       if (ev_msg && (ev_msg->ev_arg2 == global_tchain.alarmid))
+               __trigger_tchain(&global_tchain);
 }
 
 /* Helper, inserts the waiter into the tchain, returning TRUE if we still need
index b4cd24e..d250c82 100644 (file)
@@ -56,6 +56,7 @@ struct timer_chain {
        uint64_t                                        latest_time;
        int                                                     ctlfd;
        int                                                     timerfd;
+       int                                                     alarmid;
        struct event_queue                      *ev_q;
 };