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