• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
24 static struct tcase {
25 	int id;
26 	char const *name;
27 } tcases[] = {
28 	{CLOCK_MONOTONIC, "CLOCK MONOTONIC"},
29 	{CLOCK_REALTIME, "CLOCK REALTIME"},
30 };
31 
32 static 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 
getustime(int clockid)42 static 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 
settime(int tfd,struct tst_its * tmr,int tflags,unsigned long long tvalue,int tinterval)55 static 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 
waittmr(int tfd,unsigned int exp_ticks)67 static 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 
run(unsigned int n)93 static 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 
setup(void)151 static void setup(void)
152 {
153 	tst_res(TINFO, "Testing variant: %s", variants[tst_variant].desc);
154 }
155 
156 static struct tst_test test = {
157 	.test = run,
158 	.tcnt = ARRAY_SIZE(tcases),
159 	.test_variants = ARRAY_SIZE(variants),
160 	.setup = setup,
161 	.min_kver = "2.6.25",
162 };
163