Adds devalarm (#A)
[akaros.git] / tests / alarm.c
1 /* Copyright (c) 2013 The Regents of the University of California
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * alarm: basic functionality test for the #A device */
6
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <parlib.h>
10 #include <unistd.h>
11 #include <event.h>
12 #include <measure.h>
13 #include <uthread.h>
14
15 /* Am I the only one annoyed at how open has different includes than
16  * close/read/write? */
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <fcntl.h>
20
21 static void handle_alarm(struct event_msg *ev_msg, unsigned int ev_type)
22 {
23         assert(ev_type == EV_ALARM);
24         printf("\tAlarm fired!\n");
25 }
26
27 int main(int argc, char **argv)
28 {
29         int ctlfd, timerfd, alarm_nr, ret, srvfd;
30         char buf[20];
31         char path[32];
32         struct event_queue *ev_q;
33
34         printf("Starting alarm test\n");
35         /* standard 9ns stuff: clone and read it to get our path, ending up with the
36          * ctlfd and timerfd for #A/aN/{ctl,timer}.  if you plan to fork, you can
37          * open CLOEXEC. */
38         ctlfd = open("#A/clone", O_RDWR | O_CLOEXEC);
39         if (ctlfd < 0) {
40                 perror("Can't clone an alarm");
41                 exit(-1);
42         }
43         ret = read(ctlfd, buf, sizeof(buf) - 1);
44         if (ret <= 0) {
45                 if (!ret)
46                         printf("Got early EOF from ctl\n");
47                 else
48                         perror("Can't read ctl");
49                 exit(-1);
50         }
51         buf[ret] = 0;
52         snprintf(path, sizeof(path), "#A/a%s/timer", buf);
53         /* Don't open CLOEXEC if you want to post it to srv later */
54         timerfd = open(path, O_RDWR);
55         if (timerfd < 0) {
56                 perror("Can't open timer");
57                 exit(-1);
58         }
59         /* Since we're doing SPAM_PUBLIC later, we actually don't need a big ev_q.
60          * But someone might copy/paste this and change a flag. */
61         ev_handlers[EV_ALARM] = handle_alarm;
62         if (!(ev_q = get_big_event_q())) {
63                 perror("Failed ev_q");  /* it'll actually PF if malloc fails */
64                 exit(-1);
65         }
66         ev_q->ev_vcore = 0;
67         /* I think this is all the flags we need; gotta write that dissertation
68          * chapter (and event how-to)! */
69         ev_q->ev_flags = EVENT_IPI | EVENT_NOMSG | EVENT_SPAM_PUBLIC;
70         /* Register the ev_q for our alarm */
71         ret = snprintf(path, sizeof(path), "evq %llx", ev_q);
72         ret = write(ctlfd, path, ret);
73         if (ret <= 0) {
74                 perror("Failed to write ev_q");
75                 exit(-1);
76         }
77         /* Try to set, then cancel before it should go off */
78         ret = snprintf(buf, sizeof(buf), "%llx", read_tsc() + sec2tsc(1));
79         ret = write(timerfd, buf, ret);
80         if (ret <= 0) {
81                 perror("Failed to set timer");
82                 exit(-1);
83         }
84         ret = snprintf(buf, sizeof(buf), "cancel");
85         ret = write(ctlfd, buf, ret);
86         if (ret <= 0) {
87                 perror("Failed to cancel timer");
88                 exit(-1);
89         }
90         uthread_sleep(2);
91         printf("No alarm should have fired yet\n");
92         /* Try to set and receive */
93         ret = snprintf(buf, sizeof(buf), "%llx", read_tsc() + sec2tsc(1));
94         ret = write(timerfd, buf, ret);
95         if (ret <= 0) {
96                 perror("Failed to set timer");
97                 exit(-1);
98         }
99         uthread_sleep(2);
100         close(ctlfd);
101         /* get crazy: post the timerfd to #s, then sleep (or even try to exit), and
102          * then echo into it remotely!  A few limitations:
103          * - if the process is DYING, you won't be able to send an event to it.
104          * - the process won't leave DYING til the srv file is removed. */
105         srvfd = open("#s/alarmtest", O_WRONLY | O_CREAT | O_EXCL, 0666);
106         if (srvfd < 0) {
107                 perror("Failed to open srv file");
108                 exit(-1);
109         }
110         ret = snprintf(buf, sizeof(buf), "%d", timerfd);
111         ret = write(srvfd, buf, ret);
112         if (ret <= 0) {
113                 perror("Failed to post timerfd");
114                 exit(-1);
115         }
116         printf("Sleeping for 10 sec, try to echo 111 > '#s/alarmtest' now!\n");
117         uthread_sleep(10);
118         ret = unlink("#s/alarmtest");
119         if (ret < 0) {
120                 perror("Failed to remove timerfd from #s, proc will never be freed");
121                 exit(-1);
122         }
123         printf("Done\n");
124         return 0;
125 }