master
c 472 lines 11.4 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 timerfd.c
8
9 Abstract:
10
11 This file is a timerfd test.
12
13 --*/
14
15 #include "lxtcommon.h"
16 #include "unittests.h"
17 // #include <sys/timerfd.h>
18 #include <sys/epoll.h>
19 #include <sys/time.h>
20 #include <unistd.h>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 #include <fcntl.h>
24
25 #define LXT_NAME "timerfd"
26 #define LXT_EVENT_ARRAY_SIZE (10)
27 #define LXT_BASIC_TEST_LOOP_COUNT (3)
28
29 int TimerFdBasic(PLXT_ARGS Args);
30
31 int TimerFdEpoll(PLXT_ARGS Args);
32
33 //
34 // Global constants
35 //
36
37 static const LXT_VARIATION g_LxtVariations[] = {{"Timerfd Basic", TimerFdBasic}, {"Timerfd Epoll", TimerFdEpoll}};
38
39 //
40 // Global variables
41 //
42
43 static struct timespec g_SignalTime;
44 static int g_SignalCount;
45
46 int TimerFdTestEntry(int Argc, char* Argv[])
47
48 /*++
49 --*/
50
51 {
52
53 LXT_ARGS Args;
54 int Result;
55
56 LxtCheckResult(LxtInitialize(Argc, Argv, &Args, LXT_NAME));
57 LxtCheckResult(LxtRunVariations(&Args, g_LxtVariations, LXT_COUNT_OF(g_LxtVariations)));
58
59 ErrorExit:
60 LxtUninitialize();
61 return !LXT_SUCCESS(Result);
62 }
63
64 int TimerFdBasic(PLXT_ARGS Args)
65
66 /*++
67 --*/
68
69 {
70
71 struct epoll_event Event;
72 struct epoll_event Events[LXT_EVENT_ARRAY_SIZE];
73 int EpollFd;
74 struct stat FileStat;
75 int Flags;
76 int Index;
77 int LoopIndex;
78 struct itimerspec NewTimer;
79 struct itimerspec OldTimer;
80 int ReadyFdCount;
81 int Result;
82 struct timespec SleepDuration;
83 uint64_t TimerExpirationCount;
84 int TimerFd;
85
86 //
87 // Initialize locals.
88 //
89
90 EpollFd = -1;
91 TimerFd = -1;
92
93 //
94 // Create invalid timers.
95 //
96
97 TimerFd = timerfd_create(-1, O_NONBLOCK);
98 if (TimerFd >= 0)
99 {
100 LxtLogError("timerfd_create was supposed to fail because of invalid parameters but did not fail.");
101 Result = TimerFd;
102 goto ErrorExit;
103 }
104
105 TimerFd = timerfd_create(CLOCK_MONOTONIC, -1);
106 if (TimerFd >= 0)
107 {
108 LxtLogError("timerfd_create was supposed to fail because of invalid parameters but did not fail.");
109 Result = TimerFd;
110 goto ErrorExit;
111 }
112
113 TimerFd = timerfd_create(-1, -1);
114 if (TimerFd >= 0)
115 {
116 LxtLogError("timerfd_create was supposed to fail because of invalid parameters but did not fail.");
117 Result = TimerFd;
118 goto ErrorExit;
119 }
120
121 //
122 // Create a timer fd.
123 //
124
125 TimerFd = timerfd_create(CLOCK_MONOTONIC, O_NONBLOCK);
126 if (TimerFd < 0)
127 {
128 LxtLogError("timerfd_create failed");
129 Result = TimerFd;
130 goto ErrorExit;
131 }
132
133 //
134 // Create epoll fd to monitor the file for read events.
135 //
136
137 EpollFd = epoll_create(LXT_EVENT_ARRAY_SIZE);
138 if (EpollFd < 0)
139 {
140 LxtLogError("epoll create failed");
141 Result = EpollFd;
142 goto ErrorExit;
143 }
144
145 Event.events = EPOLLIN;
146 Event.data.fd = TimerFd;
147 Result = epoll_ctl(EpollFd, EPOLL_CTL_ADD, TimerFd, &Event);
148 if (Result < 0)
149 {
150 LxtLogError("epoll_ctl failed.");
151 goto ErrorExit;
152 }
153
154 //
155 // Set timer fd to expire at one second interval.
156 //
157
158 Flags = 0;
159 NewTimer.it_interval.tv_sec = 1;
160 NewTimer.it_interval.tv_nsec = 0;
161 NewTimer.it_value.tv_sec = 1;
162 NewTimer.it_value.tv_nsec = 0;
163
164 //
165 // Set timer with invalid parameters.
166 //
167
168 Result = timerfd_settime(-1, Flags, &NewTimer, &OldTimer);
169 if (Result >= 0)
170 {
171 LxtLogError("timerfd_settime was supposed to fail because of invalid parameters but did not fail.");
172 goto ErrorExit;
173 }
174
175 //
176 // Set timer with valid parameters.
177 //
178
179 Result = timerfd_settime(TimerFd, Flags, &NewTimer, &OldTimer);
180 if (Result < 0)
181 {
182 LxtLogError("timerfd_settime failed");
183 goto ErrorExit;
184 }
185
186 //
187 // Read with invalid buffer size.
188 //
189
190 Result = read(TimerFd, &TimerExpirationCount, sizeof(TimerExpirationCount) - 1);
191 if (Result >= 0)
192 {
193 LxtLogError("read was supposed to fail because of invalid parameters but did not fail.");
194 goto ErrorExit;
195 }
196
197 //
198 // Loop three times. In each iteration increase the wait time by one seconds.
199 // this should increase the expiration count by one in each iteration.
200 //
201
202 for (LoopIndex = 1; LoopIndex <= LXT_BASIC_TEST_LOOP_COUNT; LoopIndex += 1)
203 {
204
205 //
206 // Sleep for a factor of a second.
207 //
208
209 SleepDuration.tv_sec = LoopIndex;
210 SleepDuration.tv_nsec = 0;
211 nanosleep(&SleepDuration, NULL);
212 ReadyFdCount = epoll_wait(EpollFd, Events, LXT_EVENT_ARRAY_SIZE, 0);
213 if (ReadyFdCount < 0)
214 {
215 LxtLogError("epoll_wait failed.");
216 Result = ReadyFdCount;
217 goto ErrorExit;
218 }
219
220 for (Index = 0; Index < ReadyFdCount; Index += 1)
221 {
222
223 //
224 // Look out for TimerFd.
225 //
226
227 if (Events[Index].data.fd == TimerFd)
228 {
229 TimerExpirationCount = 0;
230 if (read(TimerFd, &TimerExpirationCount, sizeof(TimerExpirationCount)) != -1)
231 {
232 LxtLogInfo("Number of times the timer expired in %d seconds is : %lld", SleepDuration.tv_sec, (long long)TimerExpirationCount);
233 }
234 }
235 }
236 }
237
238 //
239 // Read even before the timer has expired. Set a 10 second expiration window
240 // and do a read after that. The read should fail with EAGAIN.
241 //
242
243 Flags = 0;
244 NewTimer.it_interval.tv_sec = 10;
245 NewTimer.it_interval.tv_nsec = 0;
246 Result = timerfd_settime(TimerFd, Flags, &NewTimer, &OldTimer);
247 if (Result < 0)
248 {
249 LxtLogError("timerfd_settime failed");
250 goto ErrorExit;
251 }
252
253 Result = read(TimerFd, &TimerExpirationCount, sizeof(TimerExpirationCount));
254 if (Result != -1)
255 {
256 LxtLogError("Read was supposed to fail with eagain but it did not %d", Result);
257 }
258
259 //
260 // Call get time with invalid parameters.
261 //
262
263 Result = timerfd_gettime(-1, &OldTimer);
264 if (Result >= 0)
265 {
266 LxtLogError("timerfd_gettime was supposed to fail because of invalid parameters but did not fail.");
267 goto ErrorExit;
268 }
269
270 Result = timerfd_gettime(TimerFd, NULL);
271 if (Result >= 0)
272 {
273 LxtLogError("timerfd_gettime was supposed to fail because of invalid parameters but did not fail.");
274 goto ErrorExit;
275 }
276
277 Result = timerfd_gettime(-1, NULL);
278 if (Result >= 0)
279 {
280 LxtLogError("timerfd_gettime was supposed to fail because of invalid parameters but did not fail.");
281 goto ErrorExit;
282 }
283
284 NewTimer.it_value.tv_sec = 60;
285 NewTimer.it_interval.tv_sec = 60;
286 Result = timerfd_settime(TimerFd, Flags, &NewTimer, &OldTimer);
287 if (Result < 0)
288 {
289 LxtLogError("timerfd_settime failed");
290 goto ErrorExit;
291 }
292
293 Result = timerfd_gettime(TimerFd, &OldTimer);
294 if (Result < 0)
295 {
296 LxtLogError("timerfd_gettime failed.");
297 goto ErrorExit;
298 }
299
300 LxtLogInfo(
301 "Current timer settings: Interval (seconds: %d, nanoseconds: %lu),"
302 "time till next expiration (seconds %d, nanoseconds %ld, %d)",
303 OldTimer.it_interval.tv_sec,
304 OldTimer.it_interval.tv_nsec,
305 OldTimer.it_value.tv_sec,
306 OldTimer.it_value.tv_nsec,
307 OldTimer.it_value.tv_nsec);
308
309 //
310 // Stat on the TimerFd.
311 //
312
313 Result = fstat(TimerFd, &FileStat);
314 if (Result < 0)
315 {
316 LxtLogError("stat on timerfd failed.");
317 goto ErrorExit;
318 }
319
320 LxtLogInfo("File Size: %d bytes", FileStat.st_size);
321 LxtLogInfo("Number of Links: %d", FileStat.st_nlink);
322 LxtLogInfo("File inode: %d", FileStat.st_ino);
323 LxtLogInfo("Symbolic link: %c ", (S_ISLNK(FileStat.st_mode)) ? 'Y' : 'N');
324 LxtLogInfo("Mode: %d", FileStat.st_mode);
325 LxtLogInfo("Mode: %lu", FileStat.st_mode);
326
327 //
328 // Invalid parameter variations.
329 //
330
331 memset(&NewTimer, 0, sizeof(NewTimer));
332 NewTimer.it_value.tv_sec = -1;
333 LxtCheckErrnoFailure(timerfd_settime(TimerFd, 0, &NewTimer, NULL), EINVAL);
334 memset(&NewTimer, 0, sizeof(NewTimer));
335 NewTimer.it_value.tv_nsec = 999999999 + 1;
336 LxtCheckErrnoFailure(timerfd_settime(TimerFd, 0, &NewTimer, NULL), EINVAL);
337 memset(&NewTimer, 0, sizeof(NewTimer));
338 NewTimer.it_interval.tv_sec = -1;
339 LxtCheckErrnoFailure(timerfd_settime(TimerFd, 0, &NewTimer, NULL), EINVAL);
340 memset(&NewTimer, 0, sizeof(NewTimer));
341 NewTimer.it_interval.tv_nsec = 999999999 + 1;
342 LxtCheckErrnoFailure(timerfd_settime(TimerFd, 0, &NewTimer, NULL), EINVAL);
343
344 Result = LXT_RESULT_SUCCESS;
345
346 ErrorExit:
347 if (EpollFd > 0)
348 {
349 LxtClose(EpollFd);
350 }
351
352 if (TimerFd > 0)
353 {
354 LxtClose(TimerFd);
355 }
356
357 return Result;
358 }
359
360 int TimerFdEpoll(PLXT_ARGS Args)
361
362 /*++
363
364 Routine Description:
365
366 This routine validates the various epoll states of timer FD.
367
368 Arguments:
369
370 Args - Supplies the command line arguments.
371
372 Return Value:
373
374 Returns 0 on success, -1 on failure.
375
376 --*/
377
378 {
379
380 struct epoll_event Event;
381 struct epoll_event Events[LXT_EVENT_ARRAY_SIZE];
382 int EpollFd;
383 struct itimerspec NewTimer;
384 struct itimerspec OldTimer;
385 int ReadyFdCount;
386 int Result;
387 struct timespec SleepDuration;
388 uint64_t TimerExpirationCount;
389 int TimerFd;
390
391 //
392 // Initialize locals.
393 //
394
395 EpollFd = -1;
396 TimerFd = -1;
397
398 //
399 // Create a timer fd.
400 //
401
402 LxtCheckErrno((TimerFd = timerfd_create(CLOCK_MONOTONIC, O_NONBLOCK)));
403
404 //
405 // Create epoll fd to monitor the file for read events.
406 //
407
408 LxtCheckErrno((EpollFd = epoll_create(LXT_EVENT_ARRAY_SIZE)));
409
410 //
411 // EPOLLIN is the only interesting event for timer FD.
412 //
413
414 Event.events = EPOLLIN;
415 Event.data.fd = TimerFd;
416 LxtCheckErrno(epoll_ctl(EpollFd, EPOLL_CTL_ADD, TimerFd, &Event));
417
418 //
419 // Soon after creation, there shouldn't be any epoll set on the timer FD.
420 //
421
422 LxtCheckErrno((ReadyFdCount = epoll_wait(EpollFd, &Event, 1, 10)));
423 LxtCheckEqual(ReadyFdCount, 0, "%d");
424
425 //
426 // Set the timer to fire soon (1ms).
427 //
428
429 NewTimer.it_interval.tv_sec = 0;
430 NewTimer.it_interval.tv_nsec = 0;
431 NewTimer.it_value.tv_sec = 0;
432 NewTimer.it_value.tv_nsec = 1000;
433
434 //
435 // Set the timer.
436 //
437
438 LxtCheckErrno(timerfd_settime(TimerFd, 0, &NewTimer, &OldTimer));
439
440 //
441 // Wait for EPOLL for a timeout > timer. `epoll_wait` takes time in ms.
442 //
443
444 LxtCheckErrno((ReadyFdCount = epoll_wait(EpollFd, &Event, 1, 1000)));
445 LxtCheckEqual(ReadyFdCount, 1, "%d");
446
447 //
448 // Setting the timer to 0 should reset the timer and the epoll.
449 //
450
451 NewTimer.it_interval.tv_sec = 0;
452 NewTimer.it_interval.tv_nsec = 0;
453 NewTimer.it_value.tv_sec = 0;
454 NewTimer.it_value.tv_nsec = 0;
455 LxtCheckErrno(timerfd_settime(TimerFd, 0, &NewTimer, &OldTimer));
456 LxtCheckErrno((ReadyFdCount = epoll_wait(EpollFd, &Event, 1, 10)));
457 LxtCheckEqual(ReadyFdCount, 0, "%d");
458 Result = LXT_RESULT_SUCCESS;
459
460 ErrorExit:
461 if (EpollFd > 0)
462 {
463 close(EpollFd);
464 }
465
466 if (TimerFd > 0)
467 {
468 close(TimerFd);
469 }
470
471 return Result;
472 }