mlx4: Fix NAPI polling
[akaros.git] / tests / timerfd.c
1 /*
2  *  timerfd() test by Davide Libenzi (test app for timerfd)
3  *  Copyright (C) 2007  Davide Libenzi
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  *  Davide Libenzi <davidel@xmailserver.org>
20  *
21  *
22  *     $ gcc -o timerfd-test2 timerfd-test2.c -lrt
23  *
24  * NAME
25  *      timerfd01.c
26  * HISTORY
27  *      28/05/2008 Initial contribution by Davide Libenzi <davidel@xmailserver.org>
28  *      28/05/2008 Integrated to LTP by Subrata Modak <subrata@linux.vnet.ibm.com>
29  *      2016-04-08 Deintegrated from LTP by Barret Rhoden <brho@cs.berkeley.edu>
30  *              Ported to Akaros.  Added a few more tests.
31  */
32
33 #define _GNU_SOURCE
34 #include <sys/syscall.h>
35 #include <sys/types.h>
36 #include <sys/signal.h>
37 #include <sys/time.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42 #include <signal.h>
43 #include <poll.h>
44 #include <fcntl.h>
45 #include <time.h>
46 #include <errno.h>
47
48 #include <sys/timerfd.h>
49 #include <sys/select.h>
50 #include <parlib/alarm.h>
51 #include <parlib/uthread.h>
52
53 struct tmr_type {
54         int id;
55         char const *name;
56 };
57
58 unsigned long long getustime(int clockid)
59 {
60         struct timespec tp;
61
62         if (clock_gettime((clockid_t) clockid, &tp)) {
63                 perror("clock_gettime");
64                 return 0;
65         }
66
67         return 1000000ULL * tp.tv_sec + tp.tv_nsec / 1000;
68 }
69
70 void set_timespec(struct timespec *tmr, unsigned long long ustime)
71 {
72
73         tmr->tv_sec = (time_t) (ustime / 1000000ULL);
74         tmr->tv_nsec = (long)(1000ULL * (ustime % 1000000ULL));
75 }
76
77
78 long waittmr(int tfd, int timeo)
79 {
80         u_int64_t ticks;
81         fd_set rfds;
82         struct timeval tv, *timeout = 0;
83         int ret;
84
85         FD_ZERO(&rfds);
86         FD_SET(tfd, &rfds);
87         if (timeo != -1) {
88                 tv.tv_sec = timeo / 1000;
89                 tv.tv_usec = (timeo % 1000) * 1000;
90                 timeout = &tv;
91         }
92         ret = select(tfd + 1, &rfds, 0, 0, timeout);
93         if (ret < 0) {
94                 perror("select");
95                 return -1;
96         }
97         if (ret == 0) {
98                 fprintf(stdout, "no ticks happened\n");
99                 return -1;
100         }
101         if (read(tfd, &ticks, sizeof(ticks)) != sizeof(ticks)) {
102                 perror("timerfd read");
103                 return -1;
104         }
105         return ticks;
106 }
107
108 int main(int ac, char **av)
109 {
110         int i, tfd;
111         long ticks;
112         unsigned long long tnow, ttmr;
113         u_int64_t uticks;
114         struct itimerspec tmr;
115         struct tmr_type clks[] = {
116                 {CLOCK_MONOTONIC, "CLOCK MONOTONIC"},
117                 {CLOCK_REALTIME, "CLOCK REALTIME"},
118         };
119
120         for (i = 0; i < sizeof(clks) / sizeof(clks[0]); i++) {
121                 fprintf(stdout,
122                         "\n\n---------------------------------------\n");
123                 fprintf(stdout, "| testing %s\n", clks[i].name);
124                 fprintf(stdout, "---------------------------------------\n\n");
125
126                 fprintf(stdout, "relative timer test (at 500 ms) ...\n");
127                 set_timespec(&tmr.it_value, 500 * 1000);
128                 set_timespec(&tmr.it_interval, 0);
129                 tnow = getustime(clks[i].id);
130                 if ((tfd = timerfd_create(clks[i].id, 0)) == -1) {
131                         perror("timerfd");
132                         return 1;
133                 }
134                 fprintf(stdout, "timerfd = %d\n", tfd);
135
136                 if (timerfd_settime(tfd, 0, &tmr, NULL)) {
137                         perror("timerfd_settime");
138                         return 1;
139                 }
140
141                 fprintf(stdout, "waiting timer ...\n");
142                 ticks = waittmr(tfd, -1);
143                 ttmr = getustime(clks[i].id);
144                 if (ticks <= 0)
145                         fprintf(stdout, "whooops! no timer showed up!\n");
146                 else
147                         fprintf(stdout, "got timer ticks (%ld) after %llu ms\n",
148                                 ticks, (ttmr - tnow) / 1000);
149
150                 fprintf(stdout, "absolute timer test (at 500 ms) ...\n");
151                 tnow = getustime(clks[i].id);
152                 set_timespec(&tmr.it_value, tnow + 500 * 1000);
153                 set_timespec(&tmr.it_interval, 0);
154                 if (timerfd_settime(tfd, TFD_TIMER_ABSTIME, &tmr, NULL)) {
155                         perror("timerfd_settime");
156                         return 1;
157                 }
158
159                 fprintf(stdout, "waiting timer ...\n");
160                 ticks = waittmr(tfd, -1);
161                 ttmr = getustime(clks[i].id);
162                 if (ticks <= 0)
163                         fprintf(stdout, "whooops! no timer showed up!\n");
164                 else
165                         fprintf(stdout, "got timer ticks (%ld) after %llu ms\n",
166                                 ticks, (ttmr - tnow) / 1000);
167
168                 fprintf(stdout, "sequential timer test (100 ms clock) ...\n");
169                 tnow = getustime(clks[i].id);
170                 set_timespec(&tmr.it_value, tnow + 100 * 1000);
171                 set_timespec(&tmr.it_interval, 100 * 1000);
172                 if (timerfd_settime(tfd, TFD_TIMER_ABSTIME, &tmr, NULL)) {
173                         perror("timerfd_settime");
174                         return 1;
175                 }
176
177                 fprintf(stdout, "sleeping 1 second ...\n");
178                 sleep(1);
179                 if (timerfd_gettime(tfd, &tmr)) {
180                         perror("timerfd_gettime");
181                         return 1;
182                 }
183                 fprintf(stdout, "timerfd_gettime returned:\n"
184                         "\tit_value = { %ld, %ld } it_interval = { %ld, %ld }\n",
185                         (long)tmr.it_value.tv_sec, (long)tmr.it_value.tv_nsec,
186                         (long)tmr.it_interval.tv_sec,
187                         (long)tmr.it_interval.tv_nsec);
188                 fprintf(stdout, "sleeping 1 second ...\n");
189                 sleep(1);
190
191                 fprintf(stdout, "waiting timer ...\n");
192                 ticks = waittmr(tfd, -1);
193                 ttmr = getustime(clks[i].id);
194                 if (ticks <= 0)
195                         fprintf(stdout, "whooops! no timer showed up!\n");
196                 else
197                         fprintf(stdout, "got timer ticks (%ld) after %llu ms\n",
198                                 ticks, (ttmr - tnow) / 1000);
199
200                 fprintf(stdout, "O_NONBLOCK test ...\n");
201                 tnow = getustime(clks[i].id);
202                 set_timespec(&tmr.it_value, 100 * 1000);
203                 set_timespec(&tmr.it_interval, 0);
204                 if (timerfd_settime(tfd, 0, &tmr, NULL)) {
205                         perror("timerfd_settime");
206                         return 1;
207                 }
208                 fprintf(stdout, "timerfd = %d\n", tfd);
209
210                 fprintf(stdout, "waiting timer (flush the single tick) ...\n");
211                 ticks = waittmr(tfd, -1);
212                 ttmr = getustime(clks[i].id);
213                 if (ticks <= 0)
214                         fprintf(stdout, "whooops! no timer showed up!\n");
215                 else
216                         fprintf(stdout, "got timer ticks (%ld) after %llu ms\n",
217                                 ticks, (ttmr - tnow) / 1000);
218
219                 fcntl(tfd, F_SETFL, fcntl(tfd, F_GETFL, 0) | O_NONBLOCK);
220
221                 if (read(tfd, &uticks, sizeof(uticks)) > 0)
222                         fprintf(stdout,
223                                 "whooops! timer ticks not zero when should have been\n");
224                 else if (errno != EAGAIN)
225                         fprintf(stdout,
226                                 "whooops! bad errno value (%d = '%s')!\n",
227                                 errno, strerror(errno));
228                 else
229                         fprintf(stdout, "success\n");
230
231                 /* try a select loop with O_NONBLOCK */
232                 fd_set rfds;
233                 bool has_selected = FALSE;
234                 int ret;
235
236                 FD_ZERO(&rfds);
237                 FD_SET(tfd, &rfds);
238                 set_timespec(&tmr.it_value, 1000000);
239                 set_timespec(&tmr.it_interval, 0);
240                 if (timerfd_settime(tfd, 0, &tmr, NULL)) {
241                         perror("timerfd_settime");
242                         exit(-1);
243                 }
244                 while (1) {
245                         ret = read(tfd, &uticks, sizeof(uticks));
246                         if (ret < 0) {
247                                 if (errno != EAGAIN) {
248                                         perror("select read");
249                                         exit(-1);
250                                 }
251                         } else {
252                                 if (ret != sizeof(uticks)) {
253                                         fprintf(stdout, "short read! (bad)\n");
254                                         exit(-1);
255                                 }
256                                 if (uticks)
257                                         break;
258                         }
259                         if (select(tfd + 1, &rfds, 0, 0, 0) < 0) {
260                                 perror("select");
261                                 return -1;
262                         }
263                         has_selected = TRUE;
264                 }
265                 if (!has_selected) {
266                         fprintf(stdout, "Failed to try to select!\n");
267                         exit(-1);
268                 }
269                 fprintf(stdout, "more success\n");
270                 fcntl(tfd, F_SETFL, fcntl(tfd, F_GETFL, 0) & ~O_NONBLOCK);
271
272                 /* let's make sure it actually blocks too. */
273                 struct alarm_waiter waiter;
274
275                 init_awaiter(&waiter, alarm_abort_sysc);
276                 waiter.data = current_uthread;
277                 set_awaiter_rel(&waiter, 1000000);
278
279                 set_timespec(&tmr.it_value, 10000000);
280                 set_timespec(&tmr.it_interval, 0);
281                 if (timerfd_settime(tfd, 0, &tmr, NULL)) {
282                         perror("timerfd_settime");
283                         exit(-1);
284                 }
285                 set_alarm(&waiter);
286                 ret = read(tfd, &uticks, sizeof(uticks));
287                 unset_alarm(&waiter);
288                 if (ret > 0) {
289                         fprintf(stdout, "Failed to block when we should have!\n");
290                         exit(-1);
291                 }
292                 fprintf(stdout, "done (still success)\n");
293
294                 close(tfd);
295         }
296 }