x86: Add a turbo mode helper
[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 #alarm device */
6
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <parlib/parlib.h>
10 #include <unistd.h>
11 #include <parlib/event.h>
12 #include <benchutil/measure.h>
13 #include <parlib/alarm.h>
14 #include <parlib/uthread.h>
15 #include <parlib/timing.h>
16
17 /* Am I the only one annoyed at how open has different includes than
18  * close/read/write? */
19 /* NO. Ron. */
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <fcntl.h>
23
24 static void handle_alarm(struct event_msg *ev_msg, unsigned int ev_type,
25                          void *data)
26 {
27         assert(ev_type == EV_ALARM);
28         printf("\tAlarm fired!, id %p\n", devalarm_get_id(ev_msg));
29 }
30
31 int main(int argc, char **argv)
32 {
33         int ctlfd, timerfd, alarm_nr, ret, srvfd;
34         char buf[20];
35         struct event_queue *ev_q;
36
37         printf("Starting alarm test\n");
38         if (devalarm_get_fds(&ctlfd, &timerfd, 0)) {
39                 perror("Alarm setup");
40                 exit(-1);
41         }
42         /* Since we're doing SPAM_PUBLIC later, we actually don't need a big ev_q.
43          * But someone might copy/paste this and change a flag. */
44         register_ev_handler(EV_ALARM, handle_alarm, 0);
45         if (!(ev_q = get_eventq(EV_MBOX_UCQ))) {
46                 perror("Failed ev_q");  /* it'll actually PF if malloc fails */
47                 exit(-1);
48         }
49         ev_q->ev_vcore = 0;
50         /* I think this is all the flags we need; gotta write that dissertation
51          * chapter (and event how-to)!  We may get more than one event per alarm, if
52          * we have concurrent preempts/yields. */
53         ev_q->ev_flags = EVENT_IPI | EVENT_SPAM_PUBLIC | EVENT_WAKEUP;
54         /* Register the ev_q for our alarm */
55         if (devalarm_set_evq(timerfd, ev_q, 0xdeadbeef)) {
56                 perror("Failed to set evq");
57                 exit(-1);
58         }
59         /* Try to set, then cancel before it should go off */
60         if (devalarm_set_time(timerfd, read_tsc() + sec2tsc(1))) {
61                 perror("Failed to set timer");
62                 exit(-1);
63         }
64         if (devalarm_disable(timerfd)) {
65                 perror("Failed to cancel timer");
66                 exit(-1);
67         }
68         uthread_sleep(2);
69         printf("No alarm should have fired yet\n");
70         /* Try to set and receive */
71         if (devalarm_set_time(timerfd, read_tsc() + sec2tsc(1))) {
72                 perror("Failed to set timer");
73                 exit(-1);
74         }
75         uthread_sleep(2);
76         close(ctlfd);
77         /* get crazy: post the timerfd to #srv, then sleep (or even try to exit), and
78          * then echo into it remotely!  A few limitations:
79          * - if the process is DYING, you won't be able to send an event to it.
80          * - the process won't leave DYING til the srv file is removed. */
81         srvfd = open("#srv/alarmtest", O_WRONLY | O_CREAT | O_EXCL, 0666);
82         if (srvfd < 0) {
83                 perror("Failed to open srv file");
84                 exit(-1);
85         }
86         ret = snprintf(buf, sizeof(buf), "%d", timerfd);
87         ret = write(srvfd, buf, ret);
88         if (ret <= 0) {
89                 perror("Failed to post timerfd");
90                 exit(-1);
91         }
92         printf("Sleeping for 10 sec, try to echo 111 > '#srv/alarmtest' now!\n");
93         uthread_sleep(10);
94         ret = unlink("#srv/alarmtest");
95         if (ret < 0) {
96                 perror("Failed to remove timerfd from #srv, proc will never be freed");
97                 exit(-1);
98         }
99         printf("Done\n");
100         return 0;
101 }