1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) Linux Test Project, 2002-2022
4 * Copyright (c) International Business Machines Corp., 2001
5 * 03/2001 - Written by Wayne Boyer
6 */
7
8 /*\
9 * [Description]
10 *
11 * Spawn a child, verify that setitimer() syscall passes and it ends up
12 * counting inside expected boundaries. Then verify from the parent that
13 * the syscall sent the correct signal to the child.
14 */
15
16 #include <time.h>
17 #include <errno.h>
18 #include <sys/time.h>
19 #include <stdlib.h>
20 #include "tst_test.h"
21 #include "lapi/syscalls.h"
22 #include "tst_safe_clocks.h"
23 #include "tst_timer.h"
24
25 static struct timeval tv;
26 static struct __kernel_old_itimerval *value, *ovalue;
27 static volatile unsigned long sigcnt;
28 static long time_step;
29 static long time_sec;
30 static long time_usec;
31
32 static struct tcase {
33 int which;
34 char *des;
35 int signo;
36 } tcases[] = {
37 {ITIMER_REAL, "ITIMER_REAL", SIGALRM},
38 {ITIMER_VIRTUAL, "ITIMER_VIRTUAL", SIGVTALRM},
39 {ITIMER_PROF, "ITIMER_PROF", SIGPROF},
40 };
41
sig_routine(int signo LTP_ATTRIBUTE_UNUSED)42 static void sig_routine(int signo LTP_ATTRIBUTE_UNUSED)
43 {
44 sigcnt++;
45 }
46
set_setitimer_value(int sec,int usec)47 static void set_setitimer_value(int sec, int usec)
48 {
49 value->it_value.tv_sec = sec;
50 value->it_value.tv_usec = usec;
51 value->it_interval.tv_sec = sec;
52 value->it_interval.tv_usec = usec;
53 }
54
verify_setitimer(unsigned int i)55 static void verify_setitimer(unsigned int i)
56 {
57 pid_t pid;
58 int status;
59 long margin;
60 struct tcase *tc = &tcases[i];
61
62 tst_res(TINFO, "tc->which = %s", tc->des);
63
64 if (tc->which == ITIMER_REAL) {
65 if (gettimeofday(&tv, NULL) == -1)
66 tst_brk(TBROK | TERRNO, "gettimeofday(&tv1, NULL) failed");
67 else
68 tst_res(TINFO, "Test begin time: %ld.%lds", tv.tv_sec, tv.tv_usec);
69 }
70
71 pid = SAFE_FORK();
72
73 if (pid == 0) {
74 tst_no_corefile(0);
75
76 set_setitimer_value(time_sec, time_usec);
77 TST_EXP_PASS(sys_setitimer(tc->which, value, NULL));
78
79 set_setitimer_value(5 * time_sec, 7 * time_usec);
80 TST_EXP_PASS(sys_setitimer(tc->which, value, ovalue));
81
82 TST_EXP_EQ_LI(ovalue->it_interval.tv_sec, time_sec);
83 TST_EXP_EQ_LI(ovalue->it_interval.tv_usec, time_usec);
84
85 tst_res(TINFO, "ovalue->it_value.tv_sec=%ld, ovalue->it_value.tv_usec=%ld",
86 ovalue->it_value.tv_sec, ovalue->it_value.tv_usec);
87
88 /*
89 * ITIMER_VIRTUAL and ITIMER_PROF timers always expire a
90 * time_step afterward the elapsed time to make sure that
91 * at least counters take effect.
92 */
93 margin = tc->which == ITIMER_REAL ? 0 : time_step;
94
95 if (ovalue->it_value.tv_sec == time_sec) {
96 if (ovalue->it_value.tv_usec < 0 ||
97 ovalue->it_value.tv_usec > time_usec + margin)
98 tst_res(TFAIL, "ovalue->it_value.tv_usec is out of range: %ld",
99 ovalue->it_value.tv_usec);
100 } else {
101 if (ovalue->it_value.tv_sec < 0 ||
102 ovalue->it_value.tv_sec > time_sec)
103 tst_res(TFAIL, "ovalue->it_value.tv_sec is out of range: %ld",
104 ovalue->it_value.tv_sec);
105 }
106
107 SAFE_SIGNAL(tc->signo, sig_routine);
108
109 set_setitimer_value(0, time_usec);
110 TST_EXP_PASS(sys_setitimer(tc->which, value, NULL));
111
112 while (sigcnt <= 10UL)
113 ;
114
115 SAFE_SIGNAL(tc->signo, SIG_DFL);
116
117 while (1)
118 ;
119 }
120
121 SAFE_WAITPID(pid, &status, 0);
122
123 if (WIFSIGNALED(status) && WTERMSIG(status) == tc->signo)
124 tst_res(TPASS, "Child received signal: %s", tst_strsig(tc->signo));
125 else
126 tst_res(TFAIL, "Child: %s", tst_strstatus(status));
127
128 if (tc->which == ITIMER_REAL) {
129 if (gettimeofday(&tv, NULL) == -1)
130 tst_brk(TBROK | TERRNO, "gettimeofday(&tv1, NULL) failed");
131 else
132 tst_res(TINFO, "Test end time: %ld.%lds", tv.tv_sec, tv.tv_usec);
133 }
134 }
135
setup(void)136 static void setup(void)
137 {
138 struct timespec time_res;
139
140 /*
141 * Use CLOCK_MONOTONIC_COARSE resolution for all timers, since its value is
142 * bigger than CLOCK_MONOTONIC and therefore can used for both realtime and
143 * virtual/prof timers resolutions.
144 */
145 SAFE_CLOCK_GETRES(CLOCK_MONOTONIC_COARSE, &time_res);
146
147 time_step = time_res.tv_nsec / 1000;
148 if (time_step <= 0)
149 time_step = 1000;
150
151 tst_res(TINFO, "clock low-resolution: %luns, time step: %luus",
152 time_res.tv_nsec, time_step);
153
154 time_sec = 9 + time_step / 1000;
155 time_usec = 3 * time_step;
156 }
157
158 static struct tst_test test = {
159 .tcnt = ARRAY_SIZE(tcases),
160 .forks_child = 1,
161 .setup = setup,
162 .test = verify_setitimer,
163 .bufs = (struct tst_buffers[]) {
164 {&value, .size = sizeof(struct itimerval)},
165 {&ovalue, .size = sizeof(struct itimerval)},
166 {}
167 }
168 };
169