port to arm64
[lnanohttp.git] / ulinux / patterns / epoll_timerfd / epoll_timerfd.c
bloba99ebcbf547ba9b396db387d0965ca4c1fffb852
1 /*
2 * XXX: if you are a heavy user of time related calls, you should use vdso
3 * calls instead of syscalls. That depends on the arch.
4 */
5 #include <stdarg.h>
7 #include <ulinux/compiler_types.h>
8 #include <ulinux/compiler_misc.h>
9 #include <ulinux/sysc.h>
10 #include <ulinux/types.h>
11 #include <ulinux/epoll.h>
12 #include <ulinux/file.h>
13 #include <ulinux/error.h>
14 #include <ulinux/time.h>
16 #include <ulinux/utils/mem.h>
17 #include <ulinux/utils/ascii/string/string.h>
18 #include <ulinux/utils/ascii/string/vsprintf.h>
20 /* ulinux namespace */
21 #define EINTR ULINUX_EINTR
22 #define EAGAIN ULINUX_EAGAIN
23 #define si ulinux_si
24 #define sl ulinux_sl
25 #define u8 ulinux_u8
26 #define u64 ulinux_u64
27 /* kill process, aka thread group */
28 #define exit(code) ulinux_sysc(exit_group,1,code)
29 #define ISERR ULINUX_ISERR
30 #define CLOCK_MONOTONIC ULINUX_CLOCK_MONOTONIC
31 #define clock_gettime(a,b) ulinux_sysc(clock_gettime,2,a,b)
32 #define TFD_NONBLOCK ULINUX_TFD_NONBLOCK
33 #define TFD_TIMER_ABSTIME ULINUX_TFD_TIMER_ABSTIME
34 #define itimerspec ulinux_itimerspec
35 #define timerfd_create(a,b) ulinux_sysc(timerfd_create,2,a,b)
36 #define timerfd_settime(a,b,c,d) ulinux_sysc(timerfd_settime,4,a,b,c,d)
37 #define epoll_create1(a) ulinux_sysc(epoll_create1,1,a)
38 #define epoll_event ulinux_epoll_event
39 #define memset(a,b,c) ulinux_memset((ulinux_u8*)a,b,c)
40 #define EPOLLIN ULINUX_EPOLLIN
41 #define epoll_ctl(a,b,c,d) ulinux_sysc(epoll_ctl,4,a,b,c,d)
42 #define EPOLL_CTL_ADD ULINUX_EPOLL_CTL_ADD
43 /* common to x86_64 and aarch64 */
44 #define epoll_pwait(a,b,c,d,e) ulinux_sysc(epoll_pwait,5,a,b,c,d,e)
45 #define read(a,b,c) ulinux_sysc(read,3,a,b,c)
47 /* convenience macros */
48 #define BUFSIZ 8192
49 static u8 dprint_buf[BUFSIZ];
50 #define POUT(fmt,...) ulinux_dprintf(1,&dprint_buf[0],BUFSIZ-1,fmt,##__VA_ARGS__)
51 #define EPOLL_EVENTS_N 10
52 #define loop for(;;)
54 #define INITIAL_EXPIRATION_SECS 8
56 void _start(void)
58 sl r;
59 si timerfd;
60 struct itimerspec itimerspec;
61 si epfd;
62 struct epoll_event evts[EPOLL_EVENTS_N];
63 sl evt;
65 dprint_buf[BUFSIZ - 1] = 0; /* secure a 0 terminating char */
67 timerfd = (si)timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
68 if (ISERR(timerfd)) {
69 POUT("unable to create the timer fd (%d)\n", timerfd);
70 exit(1);
73 memset(&itimerspec, 0, sizeof(itimerspec));
75 /*--------------------------------------------------------------------*/
77 r = clock_gettime(CLOCK_MONOTONIC, &itimerspec.value);
78 if (ISERR(r)) {
79 POUT("error while getting the current monotonic clock time (%ld)\n", r);
80 exit(2);
82 POUT("current monotonic clock is %ld secs and %ld nsecs\n", itimerspec.value.sec, itimerspec.value.nsec);
84 /*--------------------------------------------------------------------*/
86 /* initial expiration in the futur of current monotonic clock */
87 itimerspec.value.sec += INITIAL_EXPIRATION_SECS;
88 itimerspec.value.nsec = 0;
90 /* we are looking for an absolute initial expiration */
91 r = timerfd_settime(timerfd, TFD_TIMER_ABSTIME, &itimerspec, 0);
92 if (ISERR(r)) {
93 POUT("unable to arm the timer\n");
94 exit(3);
97 epfd = (si)epoll_create1(0);
98 if (ISERR(epfd)) {
99 POUT("unable to create the epoll fd\n");
100 exit(4);
103 memset(evts, 0, sizeof(evts));
104 evts[0].events = EPOLLIN; /* could be EPOLLET too */
105 evts[0].data.fd = timerfd;
106 r = epoll_ctl(epfd, EPOLL_CTL_ADD, timerfd, &evts[0]);
107 if (ISERR(r)) {
108 POUT("unable to add the timer fd to the epoll fd (%ld)\n", r);
109 exit(5);
112 loop {
113 memset(evts, 0, sizeof(evts));
114 r = epoll_pwait(epfd, evts, EPOLL_EVENTS_N, -1, 0);
115 if (r != -EINTR)
116 break;
118 POUT("epoll_pwait was interruped by a signal (we did not set any timeout), restarting\n");
120 if (ISERR(r)) {
121 POUT("epoll_wait error (%ld)\n", r);
122 exit(6);
125 evt = 0;
126 loop {
127 if (evt == r)
128 break;
130 if (evts[evt].data.fd == timerfd) {
131 if ((evts[evt].events & EPOLLIN) != 0) {
132 u64 expirations_n = 0; /* the count of expirations of our timer */
134 loop {/* reads are atomic or err, aka no short reads */
135 r = read(timerfd, &expirations_n, sizeof(u64));
136 if (r != -EINTR);
137 break;
140 if (r == -EAGAIN) { /* for a non blocking fd, means we read it */
141 POUT("something is wrong: we got notified of some timer expirations, but there is no count of expirations!\n");
142 exit(7);
144 if (ISERR(r)) {
145 POUT("something went wrong while reading the count of expirations (%ld)\n", r);
146 exit(8);
148 POUT("count of expirations=%lu\n", expirations_n);
149 } else {
150 POUT("got an unwanted event on the timer fd\n");
151 exit(9);
154 ++evt; /* next epoll event */
157 /*--------------------------------------------------------------------*/
159 memset(&itimerspec, 0, sizeof(itimerspec));
160 r = clock_gettime(CLOCK_MONOTONIC, &itimerspec.value);
161 if (ISERR(r)) {
162 POUT("error while getting the current monotonic clock time at exit time(%ld)\n", r);
163 exit(10);
165 POUT("monotonic clock at exit is %ld secs and %ld nsecs\n", itimerspec.value.sec, itimerspec.value.nsec);
166 exit(0);