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
24 static struct timeval tv;
25 static struct itimerval *value, *ovalue;
26 static volatile unsigned long sigcnt;
27 static long time_step;
28 static long time_sec;
29 static long time_usec;
30
31 static struct tcase {
32 int which;
33 char *des;
34 int signo;
35 } tcases[] = {
36 {ITIMER_REAL, "ITIMER_REAL", SIGALRM},
37 {ITIMER_VIRTUAL, "ITIMER_VIRTUAL", SIGVTALRM},
38 {ITIMER_PROF, "ITIMER_PROF", SIGPROF},
39 };
40
sys_setitimer(int which,void * new_value,void * old_value)41 static int sys_setitimer(int which, void *new_value, void *old_value)
42 {
43 return tst_syscall(__NR_setitimer, which, new_value, old_value);
44 }
45
sig_routine(int signo LTP_ATTRIBUTE_UNUSED)46 static void sig_routine(int signo LTP_ATTRIBUTE_UNUSED)
47 {
48 sigcnt++;
49 }
50
set_setitimer_value(int sec,int usec)51 static void set_setitimer_value(int sec, int usec)
52 {
53 value->it_value.tv_sec = sec;
54 value->it_value.tv_usec = usec;
55 value->it_interval.tv_sec = sec;
56 value->it_interval.tv_usec = usec;
57 }
58
verify_setitimer(unsigned int i)59 static void verify_setitimer(unsigned int i)
60 {
61 pid_t pid;
62 int status;
63 long margin;
64 struct tcase *tc = &tcases[i];
65
66 tst_res(TINFO, "tc->which = %s", tc->des);
67
68 if (tc->which == ITIMER_REAL) {
69 if (gettimeofday(&tv, NULL) == -1)
70 tst_brk(TBROK | TERRNO, "gettimeofday(&tv1, NULL) failed");
71 else
72 tst_res(TINFO, "Test begin time: %ld.%lds", tv.tv_sec, tv.tv_usec);
73 }
74
75 pid = SAFE_FORK();
76
77 if (pid == 0) {
78 tst_no_corefile(0);
79
80 set_setitimer_value(time_sec, time_usec);
81 TST_EXP_PASS(sys_setitimer(tc->which, value, NULL));
82
83 set_setitimer_value(5 * time_sec, 7 * time_usec);
84 TST_EXP_PASS(sys_setitimer(tc->which, value, ovalue));
85
86 TST_EXP_EQ_LI(ovalue->it_interval.tv_sec, time_sec);
87 TST_EXP_EQ_LI(ovalue->it_interval.tv_usec, time_usec);
88
89 tst_res(TINFO, "ovalue->it_value.tv_sec=%ld, ovalue->it_value.tv_usec=%ld",
90 ovalue->it_value.tv_sec, ovalue->it_value.tv_usec);
91
92 /*
93 * ITIMER_VIRTUAL and ITIMER_PROF timers always expire a
94 * time_step afterward the elapsed time to make sure that
95 * at least counters take effect.
96 */
97 margin = tc->which == ITIMER_REAL ? 0 : time_step;
98
99 if (ovalue->it_value.tv_sec == time_sec) {
100 if (ovalue->it_value.tv_usec < 0 ||
101 ovalue->it_value.tv_usec > time_usec + margin)
102 tst_res(TFAIL, "ovalue->it_value.tv_usec is out of range: %ld",
103 ovalue->it_value.tv_usec);
104 } else {
105 if (ovalue->it_value.tv_sec < 0 ||
106 ovalue->it_value.tv_sec > time_sec)
107 tst_res(TFAIL, "ovalue->it_value.tv_sec is out of range: %ld",
108 ovalue->it_value.tv_sec);
109 }
110
111 SAFE_SIGNAL(tc->signo, sig_routine);
112
113 set_setitimer_value(0, time_usec);
114 TST_EXP_PASS(sys_setitimer(tc->which, value, NULL));
115
116 while (sigcnt <= 10UL)
117 ;
118
119 SAFE_SIGNAL(tc->signo, SIG_DFL);
120
121 while (1)
122 ;
123 }
124
125 SAFE_WAITPID(pid, &status, 0);
126
127 if (WIFSIGNALED(status) && WTERMSIG(status) == tc->signo)
128 tst_res(TPASS, "Child received signal: %s", tst_strsig(tc->signo));
129 else
130 tst_res(TFAIL, "Child: %s", tst_strstatus(status));
131
132 if (tc->which == ITIMER_REAL) {
133 if (gettimeofday(&tv, NULL) == -1)
134 tst_brk(TBROK | TERRNO, "gettimeofday(&tv1, NULL) failed");
135 else
136 tst_res(TINFO, "Test end time: %ld.%lds", tv.tv_sec, tv.tv_usec);
137 }
138 }
139
setup(void)140 static void setup(void)
141 {
142 struct timespec time_res;
143
144 /*
145 * Use CLOCK_MONOTONIC_COARSE resolution for all timers, since its value is
146 * bigger than CLOCK_MONOTONIC and therefore can used for both realtime and
147 * virtual/prof timers resolutions.
148 */
149 SAFE_CLOCK_GETRES(CLOCK_MONOTONIC_COARSE, &time_res);
150
151 time_step = time_res.tv_nsec / 1000;
152 if (time_step <= 0)
153 time_step = 1000;
154
155 tst_res(TINFO, "clock low-resolution: %luns, time step: %luus",
156 time_res.tv_nsec, time_step);
157
158 time_sec = 9 + time_step / 1000;
159 time_usec = 3 * time_step;
160 }
161
162 static struct tst_test test = {
163 .tcnt = ARRAY_SIZE(tcases),
164 .forks_child = 1,
165 .setup = setup,
166 .test = verify_setitimer,
167 .bufs = (struct tst_buffers[]) {
168 {&value, .size = sizeof(struct itimerval)},
169 {&ovalue, .size = sizeof(struct itimerval)},
170 {}
171 }
172 };
173