1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) International Business Machines  Corp., 2001
4 *	03/2001 - Written by Wayne Boyer
5 * Copyright (c) 2022 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com>
6 */
7
8/*\
9 * [Description]
10 *
11 * Check that a correct call to getitimer() succeeds.
12 */
13
14#include "tst_test.h"
15#include "tst_safe_clocks.h"
16
17#define SEC  100
18#define USEC 10000
19
20static struct timeval tv;
21static struct itimerval *value;
22static long jiffy;
23
24static struct tcase {
25	int which;
26	char *des;
27} tcases[] = {
28	{ITIMER_REAL,    "ITIMER_REAL"},
29	{ITIMER_VIRTUAL, "ITIMER_VIRTUAL"},
30	{ITIMER_PROF,    "ITIMER_PROF"},
31};
32
33static void set_setitimer_value(int sec, int usec)
34{
35	value->it_value.tv_sec = sec;
36	value->it_value.tv_usec = usec;
37	value->it_interval.tv_sec = sec;
38	value->it_interval.tv_usec = usec;
39}
40
41static void verify_getitimer(unsigned int i)
42{
43	struct tcase *tc = &tcases[i];
44
45	tst_res(TINFO, "tc->which = %s", tc->des);
46
47	if (tc->which == ITIMER_REAL) {
48		if (gettimeofday(&tv, NULL) == -1)
49			tst_brk(TBROK | TERRNO, "gettimeofday(&tv1, NULL) failed");
50		else
51			tst_res(TINFO, "Test begin time: %ld.%lds", tv.tv_sec, tv.tv_usec);
52	}
53
54	TST_EXP_PASS(getitimer(tc->which, value));
55	TST_EXP_EQ_LI(value->it_value.tv_sec, 0);
56	TST_EXP_EQ_LI(value->it_value.tv_usec, 0);
57	TST_EXP_EQ_LI(value->it_interval.tv_sec, 0);
58	TST_EXP_EQ_LI(value->it_interval.tv_usec, 0);
59
60	set_setitimer_value(SEC, USEC);
61	TST_EXP_PASS(setitimer(tc->which, value, NULL));
62
63	set_setitimer_value(0, 0);
64	TST_EXP_PASS(getitimer(tc->which, value));
65
66	TST_EXP_EQ_LI(value->it_interval.tv_sec, SEC);
67	TST_EXP_EQ_LI(value->it_interval.tv_usec, USEC);
68
69	tst_res(TINFO, "value->it_value.tv_sec=%ld, value->it_value.tv_usec=%ld",
70			value->it_value.tv_sec, value->it_value.tv_usec);
71
72	/*
73	 * ITIMER_VIRTUAL and ITIMER_PROF timers always expire a
74	 * TICK_NSEC (jiffy) afterward the elapsed time to make
75	 * sure that at least time counters take effect.
76	 */
77	long margin = (tc->which == ITIMER_REAL) ? 0 : jiffy;
78
79	if (value->it_value.tv_sec == SEC) {
80		if (value->it_value.tv_usec < 0 ||
81				value->it_value.tv_usec > USEC + margin)
82			tst_brk(TFAIL, "value->it_value.tv_usec is out of range: %ld",
83				value->it_value.tv_usec);
84	} else {
85		if (value->it_value.tv_sec < 0 ||
86				value->it_value.tv_sec > SEC)
87			tst_brk(TFAIL, "value->it_value.tv_sec is out of range: %ld",
88				value->it_value.tv_sec);
89	}
90
91	tst_res(TPASS, "timer value is within the expected range");
92
93	if (tc->which == ITIMER_REAL) {
94		if (gettimeofday(&tv, NULL) == -1)
95			tst_brk(TBROK | TERRNO, "gettimeofday(&tv1, NULL) failed");
96		else
97			tst_res(TINFO, "Test end time: %ld.%lds", tv.tv_sec, tv.tv_usec);
98	}
99
100	set_setitimer_value(0, 0);
101	TST_EXP_PASS_SILENT(setitimer(tc->which, value, NULL));
102}
103
104static void setup(void)
105{
106	struct timespec time_res;
107
108	SAFE_CLOCK_GETRES(CLOCK_MONOTONIC_COARSE, &time_res);
109	jiffy = (time_res.tv_nsec + 999) / 1000;
110}
111
112static struct tst_test test = {
113	.tcnt = ARRAY_SIZE(tcases),
114	.setup = setup,
115	.test = verify_getitimer,
116	.bufs = (struct tst_buffers[]) {
117		{&value,  .size = sizeof(struct itimerval)},
118		{}
119	}
120};
121