Use FD taps for event delivery for #alarm
[akaros.git] / user / benchutil / pvcalarm.c
index 91b62c0..7affaa9 100644 (file)
@@ -7,16 +7,17 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <errno.h>
-#include <parlib.h>
-#include <vcore.h>
-#include <event.h>
-#include <spinlock.h>
-#include <arch/atomic.h>
-#include <arch/bitmask.h>
+#include <parlib/parlib.h>
+#include <parlib/vcore.h>
+#include <parlib/event.h>
+#include <parlib/spinlock.h>
+#include <parlib/arch/atomic.h>
+#include <parlib/arch/bitmask.h>
 #include <sys/queue.h>
 #include <fcntl.h>
-#include <pvcalarm.h>
-#include <alarm_dispatch.h>
+#include <unistd.h>
+#include <benchutil/pvcalarm.h>
+#include <benchutil/alarm.h>
 
 /* Different states for enabling/disabling the per-vcore alarms. */
 enum {
@@ -42,7 +43,7 @@ struct pvcalarm {
 
        atomic_t state;
        int busy_count;
-       void (*handler) (struct event_msg *ev_msg, unsigned int ev_type);
+       handle_event_t handler;
        struct pvcalarm_data *data;
 };
 
@@ -52,9 +53,12 @@ static struct pvcalarm global_pvcalarm = { .state = (void*)S_DISABLED };
 
 /* Helper functions */
 static void init_pvcalarm(struct pvcalarm_data *pvcalarm_data, int vcoreid);
-static void handle_pvcalarm(struct event_msg *ev_msg, unsigned int ev_type);
-static void handle_alarm_real(struct event_msg *ev_msg, unsigned int ev_type);
-static void handle_alarm_prof(struct event_msg *ev_msg, unsigned int ev_type);
+static void handle_pvcalarm(struct event_msg *ev_msg, unsigned int ev_type,
+                            void *data);
+static void handle_alarm_real(struct event_msg *ev_msg, unsigned int ev_type,
+                              void *data);
+static void handle_alarm_prof(struct event_msg *ev_msg, unsigned int ev_type,
+                              void *data);
 
 /* Initialize the pvcalarm service. Only call this function once */
 static int init_global_pvcalarm()
@@ -75,11 +79,7 @@ static int init_global_pvcalarm()
  * time */
 static void run_pvcalarm(struct pvcalarm_data *pvcalarm_data, uint64_t offset)
 {
-       int ret;
-       char buf[20];
-       ret = snprintf(buf, sizeof(buf), "%llx", read_tsc() + offset);
-       ret = write(pvcalarm_data->timerfd, buf, ret);
-       if (ret <= 0) {
+       if (devalarm_set_time(pvcalarm_data->timerfd, read_tsc() + offset)) {
                perror("Useralarm: Failed to set timer");
                return;
        }
@@ -97,9 +97,7 @@ static void start_pvcalarm(struct pvcalarm_data *pvcalarm_data, uint64_t offset)
 /* Stop the pvc alarm associated with pvcalarm_data */
 static void stop_pvcalarm(struct pvcalarm_data *pvcalarm_data)
 {
-       int ret;
-       ret = write(pvcalarm_data->ctlfd, "cancel", sizeof("cancel"));
-       if (ret <= 0) {
+       if (devalarm_disable(pvcalarm_data->ctlfd)) {
                printf("Useralarm: unable to disarm alarm!\n");
                return;
        }
@@ -175,45 +173,24 @@ int disable_pvcalarms()
  * online and the pvcalarm service is active */
 static void init_pvcalarm(struct pvcalarm_data *pvcalarm_data, int vcoreid)
 {
-       int ctlfd, timerfd, alarmid, ev_flags, ret;
-       char buf[20];
-       char path[32];
+       int ctlfd, timerfd, alarmid, ev_flags;
        struct event_queue *ev_q;
 
-       ctlfd = open("#A/clone", O_RDWR | O_CLOEXEC);
-       if (ctlfd < 0) {
-               perror("Pvcalarm: Can't clone an alarm");
+       if (devalarm_get_fds(&ctlfd, &timerfd, &alarmid)) {
+               perror("Pvcalarm: alarm setup");
                return;
        }
-       ret = read(ctlfd, buf, sizeof(buf) - 1);
-       if (ret <= 0) {
-               if (!ret)
-                       printf("Pvcalarm: Got early EOF from ctl\n");
-               else
-                       perror("Pvcalarm: Can't read ctl");
-               return;
-       }
-       buf[ret] = 0;
-       alarmid = atoi(buf);
-       snprintf(path, sizeof(path), "#A/a%s/timer", buf);
-       timerfd = open(path, O_RDWR | O_CLOEXEC);
-       if (timerfd < 0) {
-               perror("Pvcalarm: Can't open timer");
-               return;
-       }
-       alarm_dispatch_register(alarmid, handle_pvcalarm);
+       register_ev_handler(EV_ALARM, handle_pvcalarm, 0);
        ev_flags = EVENT_IPI | EVENT_VCORE_PRIVATE;
-       ev_q = get_event_q_vcpd(vcoreid, ev_flags);
+       ev_q = get_eventq_vcpd(vcoreid, ev_flags);
        if (!ev_q) {
                perror("Pvcalarm: Failed ev_q");
                return;
        }
        ev_q->ev_vcore = vcoreid;
        ev_q->ev_flags = ev_flags;
-       ret = snprintf(path, sizeof(path), "evq %llx", ev_q);
-       ret = write(ctlfd, path, ret);
-       if (ret <= 0) {
-               perror("Pvcalarm: Failed to write ev_q");
+       if (devalarm_set_evq(timerfd, ev_q, alarmid)) {
+               perror("Pvcalarm: Failed to set evq");
                return;
        }
        /* now the alarm is all set, just need to write the timer whenever we want
@@ -224,7 +201,7 @@ static void init_pvcalarm(struct pvcalarm_data *pvcalarm_data, int vcoreid)
 }
 
 /* TODO: implement a way to completely remove each per-vcore alarm and
- * deregister it from the #A device */
+ * deregister it from the #alarm device */
 
 /* A preamble function to run anytime we are about to do anything on behalf of
  * the pvcalarms while in vcore context.  This preamble is necessary to ensure
@@ -232,11 +209,12 @@ static void init_pvcalarm(struct pvcalarm_data *pvcalarm_data, int vcoreid)
  * service in a running application. */
 static inline bool __vcore_preamble()
 {
+       int state;
        assert(in_vcore_context());
        __sync_fetch_and_add(&global_pvcalarm.busy_count, 1);
-       if (atomic_cas(&global_pvcalarm.state, S_DISABLED, S_DISABLED))
-               goto disabled;
-       if (atomic_cas(&global_pvcalarm.state, S_DISABLING, S_DISABLING))
+       cmb();  /* order the state read after the incref.  __sync provides cpu mb */
+       state = atomic_read(&global_pvcalarm.state);
+       if (state == S_DISABLED || state == S_DISABLING)
                goto disabled;
        return true;
 disabled:
@@ -253,16 +231,22 @@ static inline void __vcore_postamble()
 /* The global handler function.  It simply calls the proper underlying handler
  * function depending on whether the service is set for the REAL or PERF
  * policy. */
-static void handle_pvcalarm(struct event_msg *ev_msg, unsigned int ev_type)
+static void handle_pvcalarm(struct event_msg *ev_msg, unsigned int ev_type,
+                            void *data)
 {
+       struct pvcalarm_data *pvcalarm_data = &global_pvcalarm.data[vcore_id()];
+
+       if (devalarm_get_id(ev_msg) != pvcalarm_data->alarmid)
+               return;
        if (!__vcore_preamble()) return;
-       global_pvcalarm.handler(ev_msg, ev_type);
+       global_pvcalarm.handler(ev_msg, ev_type, data);
        __vcore_postamble();
 }
 
 /* The pvcalarm handler for the REAL policy.  Simply call the registered
  * callback and restart the interval alarm. */
-static void handle_alarm_real(struct event_msg *ev_msg, unsigned int ev_type)
+static void handle_alarm_real(struct event_msg *ev_msg, unsigned int ev_type,
+                              void *data)
 {
        global_pvcalarm.callback();
        start_pvcalarm(&global_pvcalarm.data[vcore_id()], global_pvcalarm.interval);
@@ -272,7 +256,8 @@ static void handle_alarm_real(struct event_msg *ev_msg, unsigned int ev_type)
  * has been offline.  Only when the uptime since the last interval is equal to
  * the interval time do we run the callback function.  Otherwise we restart the
  * alarm to make up the difference. */
-static void handle_alarm_prof(struct event_msg *ev_msg, unsigned int ev_type)
+static void handle_alarm_prof(struct event_msg *ev_msg, unsigned int ev_type,
+                              void *data)
 { 
        int vcoreid = vcore_id();
        struct pvcalarm_data *pvcalarm_data = &global_pvcalarm.data[vcoreid];