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