1 /*
2 * Copyright (c) 2016 Fujitsu Ltd.
3 * Author: Guangwen Feng <fenggw-fnst@cn.fujitsu.com>
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
13 * the 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.
17 */
18
19 /*
20 * Description:
21 * Check that epoll_wait(2) timeouts correctly.
22 */
23
24 #include <sys/epoll.h>
25 #include <unistd.h>
26 #include <errno.h>
27
28 #include "test.h"
29 #include "safe_macros.h"
30
31 char *TCID = "epoll_wait02";
32 int TST_TOTAL = 1;
33
34 static int epfd, fds[2];
35 static char *opt_sleep_ms;
36 static struct epoll_event epevs[1] = {
37 {.events = EPOLLIN}
38 };
39
40 static option_t opts[] = {
41 {"s:", NULL, &opt_sleep_ms},
42 {NULL, NULL, NULL}
43 };
44
45 static void setup(void);
46 static void cleanup(void);
47 static void help(void);
48
main(int ac,char ** av)49 int main(int ac, char **av)
50 {
51 int lc, threshold;
52 long long elapsed_ms, sleep_ms = 100;
53
54 tst_parse_opts(ac, av, opts, help);
55
56 if (opt_sleep_ms) {
57 sleep_ms = atoll(opt_sleep_ms);
58
59 if (sleep_ms == 0) {
60 tst_brkm(TBROK, NULL,
61 "Invalid timeout '%s'", opt_sleep_ms);
62 }
63 }
64
65 threshold = sleep_ms / 100 + 10;
66
67 setup();
68
69 for (lc = 0; TEST_LOOPING(lc); lc++) {
70 tst_count = 0;
71
72 tst_timer_start(CLOCK_MONOTONIC);
73 TEST(epoll_wait(epfd, epevs, 1, sleep_ms));
74 tst_timer_stop();
75
76 if (TEST_RETURN == -1) {
77 tst_resm(TFAIL | TTERRNO, "epoll_wait() failed");
78 continue;
79 }
80
81 if (TEST_RETURN != 0) {
82 tst_resm(TFAIL, "epoll_wait() returned %li, expected 0",
83 TEST_RETURN);
84 continue;
85 }
86
87 elapsed_ms = tst_timer_elapsed_ms();
88
89 if (elapsed_ms < sleep_ms) {
90 tst_resm(TFAIL, "epoll_wait() woken up too early %llims, "
91 "expected %llims", elapsed_ms, sleep_ms);
92 continue;
93 }
94
95 if (elapsed_ms - sleep_ms > threshold) {
96 tst_resm(TFAIL, "epoll_wait() slept too long %llims, "
97 "expected %llims, threshold %i",
98 elapsed_ms, sleep_ms, threshold);
99 continue;
100 }
101
102 tst_resm(TPASS, "epoll_wait() slept %llims, expected %llims, "
103 "threshold %i", elapsed_ms, sleep_ms, threshold);
104 }
105
106 cleanup();
107 tst_exit();
108 }
109
setup(void)110 static void setup(void)
111 {
112 tst_timer_check(CLOCK_MONOTONIC);
113
114 SAFE_PIPE(NULL, fds);
115
116 epfd = epoll_create(1);
117 if (epfd == -1) {
118 tst_brkm(TBROK | TERRNO, cleanup,
119 "failed to create epoll instance");
120 }
121
122 epevs[0].data.fd = fds[0];
123
124 if (epoll_ctl(epfd, EPOLL_CTL_ADD, fds[0], &epevs[0])) {
125 tst_brkm(TBROK | TERRNO, cleanup,
126 "failed to register epoll target");
127 }
128 }
129
cleanup(void)130 static void cleanup(void)
131 {
132 if (epfd > 0 && close(epfd))
133 tst_resm(TWARN | TERRNO, "failed to close epfd");
134
135 if (close(fds[0]))
136 tst_resm(TWARN | TERRNO, "close(fds[0]) failed");
137
138 if (close(fds[1]))
139 tst_resm(TWARN | TERRNO, "close(fds[1]) failed");
140 }
141
help(void)142 static void help(void)
143 {
144 printf(" -s epoll_wait() timeout length in ms\n");
145 }
146