vmm: Use VMM_CTL to set VMM flags (XCC)
[akaros.git] / tests / eventfd.c
1 /* Copyright (c) 2015 Google Inc
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * #eventfd test, using the glibc interface mostly. */
6
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <parlib/parlib.h>
10 #include <unistd.h>
11 #include <pthread.h>
12
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <fcntl.h>
16 #include <sys/eventfd.h>
17 #include <sys/epoll.h>
18
19
20 #define handle_error(msg) \
21         do { perror(msg); exit(-1); } while (0)
22
23 static void epoll_on_efd(int efd)
24 {
25         #define EP_SET_SZ 10    /* this is actually the ID of the largest FD */
26         int epfd = epoll_create(EP_SET_SZ);
27         struct epoll_event ep_ev;
28         struct epoll_event results[EP_SET_SZ];
29
30         if (epfd < 0)
31                 handle_error("epoll_create");
32         ep_ev.events = EPOLLIN | EPOLLET;
33         ep_ev.data.fd = efd;
34         if (epoll_ctl(epfd, EPOLL_CTL_ADD, efd, &ep_ev))
35                 handle_error("epoll_ctl_add eventfd");
36         if (epoll_wait(epfd, results, EP_SET_SZ, -1) != 1)
37                 handle_error("epoll_wait");
38         close(epfd);
39 }
40
41 static pthread_attr_t pth_attrs;
42 static bool upped;
43
44 static void *upper_thread(void *arg)
45 {
46         int efd = (int)(long)arg;
47         uthread_sleep(1);
48         if (eventfd_write(efd, 1))
49                 handle_error("upper write");
50         upped = TRUE;
51         return 0;
52 }
53
54 int main(int argc, char **argv)
55 {
56         int ret;
57         eventfd_t efd_val = 0;
58         int efd;
59         pthread_t child;
60
61         parlib_wants_to_be_mcp = FALSE; /* Make us an SCP with a 2LS */
62         pthread_attr_init(&pth_attrs);
63         if (pthread_attr_setdetachstate(&pth_attrs, PTHREAD_CREATE_DETACHED))
64                 handle_error("pth attrs");
65
66         /* Semaphore counter, nonblocking */
67         efd = eventfd(2, EFD_SEMAPHORE | EFD_NONBLOCK);
68         if (efd < 0)
69                 handle_error("open sem");
70         if (eventfd_read(efd, &efd_val))
71                 handle_error("first read");
72         assert(efd_val == 1);
73         if (eventfd_read(efd, &efd_val))
74                 handle_error("second read");
75         assert(efd_val == 1);   /* always get 1 back from the SEM */
76         ret = eventfd_read(efd, &efd_val);
77         if ((ret != -1) && (errno != EAGAIN))
78                 handle_error("third read should be EAGAIN");
79
80         if (pthread_create(&child, &pth_attrs, &upper_thread, (void*)(long)efd))
81                 handle_error("pth_create failed");
82         epoll_on_efd(efd);
83         if (eventfd_read(efd, &efd_val))
84                 handle_error("final read");
85         assert(efd_val == 1);
86         close(efd);
87
88         /* Regular counter */
89         efd = eventfd(2, 0);
90         if (efd < 0)
91                 handle_error("open nonsem");
92         if (eventfd_read(efd, &efd_val))
93                 handle_error("first read nonsem");
94         assert(efd_val == 2);
95
96         /* Will try to block in the kernel.  Using 'upped' to catch any quick
97          * returns.  It's not full-proof, but it can catch an O_NONBLOCK */
98         if (pthread_create(&child, &pth_attrs, &upper_thread, (void*)(long)efd))
99                 handle_error("pth_create failed");
100         upped = FALSE;
101         if (eventfd_read(efd, &efd_val))
102                 handle_error("blocking read nonsem");
103         cmb();
104         assert(upped && efd_val == 1);
105
106         /* Should still be 0.  Add 1 and then extract to see if it was. */
107         if (eventfd_write(efd, 1))
108                 handle_error("write nonsem +1");
109         if (eventfd_read(efd, &efd_val))
110                 handle_error("final read nonsem");
111         /* 1 means it was 0 before we added 1.  it's 0 again, since we read. */
112         assert(efd_val == 1);
113         /* Test the max_val + 1 write */
114         ret = eventfd_write(efd, -1);
115         if ((ret != -1) && (errno != EINVAL))
116                 handle_error("write nonsem should have failed");
117         if (eventfd_write(efd, 0xfffffffffffffffe))
118                 handle_error("largest legal write");
119         close(efd);
120
121         return 0;
122 }