1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * timerfd() test by Davide Libenzi (test app for timerfd) 4 * Copyright (C) 2007 Davide Libenzi 5 * 6 * Davide Libenzi <davidel@xmailserver.org> 7 * 8 * Description: 9 * Test timerfd with the flags: 10 * 1) CLOCK_MONOTONIC 11 * 2) CLOCK_REALTIME 12 * 13 * HISTORY 14 * 28/05/2008 Initial contribution by Davide Libenzi <davidel@xmailserver.org> 15 * 28/05/2008 Integrated to LTP by Subrata Modak <subrata@linux.vnet.ibm.com> 16 */ 17 18#define _GNU_SOURCE 19#include <poll.h> 20#include "time64_variants.h" 21#include "tst_timer.h" 22#include "tst_safe_timerfd.h" 23 24static struct tcase { 25 int id; 26 char const *name; 27} tcases[] = { 28 {CLOCK_MONOTONIC, "CLOCK MONOTONIC"}, 29 {CLOCK_REALTIME, "CLOCK REALTIME"}, 30}; 31 32static struct time64_variants variants[] = { 33#if (__NR_timerfd_gettime != __LTP__NR_INVALID_SYSCALL) 34 { .clock_gettime = sys_clock_gettime, .tfd_gettime = sys_timerfd_gettime, .tfd_settime = sys_timerfd_settime, .ts_type = TST_KERN_OLD_TIMESPEC, .desc = "syscall with old kernel spec"}, 35#endif 36 37#if (__NR_timerfd_gettime64 != __LTP__NR_INVALID_SYSCALL) 38 { .clock_gettime = sys_clock_gettime64, .tfd_gettime = sys_timerfd_gettime64, .tfd_settime = sys_timerfd_settime64, .ts_type = TST_KERN_TIMESPEC, .desc = "syscall time64 with kernel spec"}, 39#endif 40}; 41 42static unsigned long long getustime(int clockid) 43{ 44 struct time64_variants *tv = &variants[tst_variant]; 45 struct tst_ts tp = {.type = tv->ts_type, }; 46 47 if (tv->clock_gettime((clockid_t) clockid, tst_ts_get(&tp))) { 48 tst_res(TFAIL | TERRNO, "clock_gettime() failed"); 49 return 0; 50 } 51 52 return 1000000ULL * tst_ts_get_sec(tp) + tst_ts_get_nsec(tp) / 1000; 53} 54 55static void settime(int tfd, struct tst_its *tmr, int tflags, 56 unsigned long long tvalue, int tinterval) 57{ 58 struct time64_variants *tv = &variants[tst_variant]; 59 60 tst_its_set_value_from_us(tmr, tvalue); 61 tst_its_set_interval_from_us(tmr, tinterval); 62 63 if (tv->tfd_settime(tfd, tflags, tst_its_get(tmr), NULL)) 64 tst_res(TFAIL | TERRNO, "timerfd_settime() failed"); 65} 66 67static void waittmr(int tfd, unsigned int exp_ticks) 68{ 69 uint64_t ticks; 70 struct pollfd pfd; 71 72 pfd.fd = tfd; 73 pfd.events = POLLIN; 74 pfd.revents = 0; 75 if (poll(&pfd, 1, -1) < 0) { 76 tst_res(TFAIL | TERRNO, "poll() failed"); 77 return; 78 } 79 if ((pfd.revents & POLLIN) == 0) { 80 tst_res(TFAIL, "no ticks happened"); 81 return; 82 } 83 SAFE_READ(0, tfd, &ticks, sizeof(ticks)); 84 85 if (ticks != exp_ticks) { 86 tst_res(TFAIL, "got %u tick(s) expected %u", 87 (unsigned int)ticks, exp_ticks); 88 } else { 89 tst_res(TPASS, "got %u tick(s)", exp_ticks); 90 } 91} 92 93static void run(unsigned int n) 94{ 95 struct time64_variants *tv = &variants[tst_variant]; 96 int tfd; 97 unsigned long long tnow; 98 uint64_t uticks; 99 struct tst_its tmr = {.type = tv->ts_type, }; 100 struct tcase *clks = &tcases[n]; 101 102 tst_res(TINFO, "testing %s", clks->name); 103 104 tfd = SAFE_TIMERFD_CREATE(clks->id, 0); 105 106 tst_res(TINFO, "relative timer (100 ms)"); 107 settime(tfd, &tmr, 0, 100 * 1000, 0); 108 waittmr(tfd, 1); 109 110 tst_res(TINFO, "absolute timer (100 ms)"); 111 tnow = getustime(clks->id); 112 settime(tfd, &tmr, TFD_TIMER_ABSTIME, tnow + 100 * 1000, 0); 113 waittmr(tfd, 1); 114 115 tst_res(TINFO, "sequential timer (50 ms)"); 116 tnow = getustime(clks->id); 117 settime(tfd, &tmr, TFD_TIMER_ABSTIME, tnow + 50 * 1000, 50 * 1000); 118 119 memset(&tmr, 0, sizeof(tmr)); 120 tmr.type = tv->ts_type; 121 122 if (tv->tfd_gettime(tfd, tst_its_get(&tmr))) 123 tst_res(TFAIL | TERRNO, "timerfd_gettime() failed"); 124 125 if (tst_its_get_value_sec(tmr) != 0 || tst_its_get_value_nsec(tmr) > 50 * 1000000) 126 tst_res(TFAIL, "Timer read back value not relative"); 127 else 128 tst_res(TPASS, "Timer read back value is relative"); 129 130 usleep(160000); 131 132 waittmr(tfd, 3); 133 134 tst_res(TINFO, "testing with O_NONBLOCK"); 135 settime(tfd, &tmr, 0, 100 * 1000, 0); 136 waittmr(tfd, 1); 137 138 SAFE_FCNTL(tfd, F_SETFL, fcntl(tfd, F_GETFL, 0) | O_NONBLOCK); 139 140 TEST(read(tfd, &uticks, sizeof(uticks))); 141 if (TST_RET > 0) 142 tst_res(TFAIL, "timer ticks not zero"); 143 else if (TST_ERR != EAGAIN) 144 tst_res(TFAIL | TTERRNO, "read should fail with EAGAIN got"); 145 else 146 tst_res(TPASS | TERRNO, "read failed with"); 147 148 SAFE_CLOSE(tfd); 149} 150 151static void setup(void) 152{ 153 tst_res(TINFO, "Testing variant: %s", variants[tst_variant].desc); 154} 155 156static struct tst_test test = { 157 .test = run, 158 .tcnt = ARRAY_SIZE(tcases), 159 .test_variants = ARRAY_SIZE(variants), 160 .setup = setup, 161}; 162