xref: /openbsd/regress/sys/kern/nanosleep/nanosleep.c (revision d415bd75)
1 /*	$OpenBSD: nanosleep.c,v 1.7 2018/05/22 18:33:41 cheloha Exp $	*/
2 /*
3  *	Written by Artur Grabowski <art@openbsd.org> 2002 Public Domain.
4  */
5 #include <sys/types.h>
6 #include <sys/time.h>
7 #include <sys/wait.h>
8 
9 #include <errno.h>
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <unistd.h>
13 #include <time.h>
14 #include <err.h>
15 #include <signal.h>
16 
17 int invalid_time(void);
18 int trivial(void);
19 int with_signal(void);
20 int time_elapsed(void);
21 int time_elapsed_with_signal(void);
22 
23 int short_time(void);
24 
25 void sighandler(int);
26 
27 int
28 main(int argc, char **argv)
29 {
30 	int ch, ret;
31 
32 	ret = 0;
33 
34 	while ((ch = getopt(argc, argv, "itseES")) != -1) {
35 		switch (ch) {
36 		case 'i':
37 			ret |= invalid_time();
38 			break;
39 		case 't':
40 			ret |= trivial();
41 			break;
42 		case 's':
43 			ret |= with_signal();
44 			break;
45 		case 'e':
46 			ret |= time_elapsed();
47 			break;
48 		case 'E':
49 			ret |= time_elapsed_with_signal();
50 			break;
51 		case 'S':
52 			ret |= short_time();
53 		default:
54 			fprintf(stderr, "Usage: nanosleep [-itseSE]\n");
55 			exit(1);
56 		}
57 	}
58 
59 	return (ret);
60 }
61 
62 void
63 sighandler(int signum)
64 {
65 }
66 
67 int
68 trivial(void)
69 {
70 	struct timespec ts, rts;
71 
72 	ts.tv_sec = 0;
73 	ts.tv_nsec = 30000000;
74 	rts.tv_sec = 4711;	/* Just add to the confusion */
75 	rts.tv_nsec = 4711;
76 	if (nanosleep(&ts, &rts) < 0) {
77 		warn("trivial: nanosleep");
78 		return 1;
79 	}
80 
81 	/*
82 	 * Just check that we don't get any leftover time if we sleep the
83 	 * amount of time we want to sleep.
84 	 * If we receive any signal, something is wrong anyway.
85 	 */
86 	if (rts.tv_sec != 0 || rts.tv_nsec != 0) {
87 		warnx("trivial: non-zero time? %lld/%ld", (long long)rts.tv_sec,
88 		    rts.tv_nsec);
89 		return 1;
90 	}
91 
92 	return 0;
93 }
94 
95 int
96 with_signal(void)
97 {
98 	struct timespec ts, rts;
99 	pid_t pid;
100 	int status;
101 
102 	signal(SIGUSR1, sighandler);
103 
104 	pid = getpid();
105 
106 	switch(fork()) {
107 	case -1:
108 		err(1, "fork");
109 	default:
110 		ts.tv_sec = 1;
111 		ts.tv_nsec = 0;
112 		nanosleep(&ts, NULL);
113 		kill(pid, SIGUSR1);
114 		exit(0);
115 	}
116 
117 	ts.tv_sec = 10;
118 	ts.tv_nsec = 0;
119 	rts.tv_sec = 0;
120 	rts.tv_nsec = 0;
121 	if (nanosleep(&ts, &rts) == 0) {
122 		warnx("with-signal: nanosleep");
123 		return 1;
124 	}
125 	if (rts.tv_sec == 0 && rts.tv_nsec == 0) {
126 		warnx("with-signal: zero time");
127 		return 1;
128 	}
129 
130 	if (wait(&status) < 0)
131 		err(1, "wait");
132 
133 	return 0;
134 }
135 
136 int
137 time_elapsed(void)
138 {
139 	struct timespec ts;
140 	struct timeval stv, etv;
141 
142 	ts.tv_sec = 0;
143 	ts.tv_nsec = 500000000;
144 
145 	if (gettimeofday(&stv, NULL) < 0) {
146 		warn("gettimeofday");
147 		return 1;
148 	}
149 
150 	if (nanosleep(&ts, NULL) < 0) {
151 		warn("nanosleep");
152 		return 1;
153 	}
154 
155 	if (gettimeofday(&etv, NULL) < 0) {
156 		warn("gettimeofday");
157 		return 1;
158 	}
159 
160 	timersub(&etv, &stv, &stv);
161 
162 	if (stv.tv_sec == 0 && stv.tv_usec < 500000) {
163 		warnx("slept less than 0.5 sec");
164 		return 1;
165 	}
166 
167 	return 0;
168 }
169 
170 int
171 time_elapsed_with_signal(void)
172 {
173 	struct timespec ts, rts;
174 	struct timeval stv, etv;
175 	pid_t pid;
176 	int status;
177 
178 	signal(SIGUSR1, sighandler);
179 
180 	pid = getpid();
181 
182 	switch(fork()) {
183 	case -1:
184 		err(1, "fork");
185 	default:
186 		ts.tv_sec = 1;
187 		ts.tv_nsec = 0;
188 		nanosleep(&ts, NULL);
189 		kill(pid, SIGUSR1);
190 		exit(0);
191 	}
192 
193 	ts.tv_sec = 10;
194 	ts.tv_nsec = 0;
195 	rts.tv_sec = 0;
196 	rts.tv_nsec = 0;
197 
198 	if (gettimeofday(&stv, NULL) < 0) {
199 		warn("gettimeofday");
200 		return 1;
201 	}
202 
203 	if (nanosleep(&ts, &rts) == 0) {
204 		warnx("nanosleep");
205 		return 1;
206 	}
207 
208 	if (gettimeofday(&etv, NULL) < 0) {
209 		warn("gettimeofday");
210 		return 1;
211 	}
212 
213 	timersub(&etv, &stv, &stv);
214 
215 	etv.tv_sec = rts.tv_sec;
216 	etv.tv_usec = rts.tv_nsec / 1000 + 1; /* the '+ 1' is a "roundup" */
217 
218 	timeradd(&etv, &stv, &stv);
219 
220 	if (stv.tv_sec < 10) {
221 		warnx("slept time + leftover time < 10 sec");
222 		return 1;
223 	}
224 
225 
226 	if (wait(&status) < 0)
227 		err(1, "wait");
228 
229 	return 0;
230 }
231 
232 int
233 short_time(void)
234 {
235 	struct timespec ts, rts;
236 	pid_t pid;
237 	int status;
238 
239 	signal(SIGUSR1, sighandler);
240 
241 	pid = getpid();
242 
243 	switch(fork()) {
244 	case -1:
245 		err(1, "fork");
246 	default:
247 		/* Sleep two seconds, then shoot parent. */
248 		ts.tv_sec = 2;
249 		ts.tv_nsec = 0;
250 		nanosleep(&ts, NULL);
251 		kill(pid, SIGUSR1);
252 		exit(0);
253 	}
254 
255 	ts.tv_sec = 0;
256 	ts.tv_nsec = 1;
257 	if (nanosleep(&ts, NULL) <= 0) {
258 		warn("short_time: nanosleep");
259 		return 1;
260 	}
261 
262 	if (wait(&status) < 0)
263 		err(1, "wait");
264 
265 	return 0;
266 }
267 
268 int
269 invalid_time(void)
270 {
271 	struct timespec ts[3] = { {-1, 0}, {0, -1}, {0, 1000000000L} };
272 	int i, status;
273 
274 	for (i = 0; i < 3; i++) {
275 		status = nanosleep(&ts[i], NULL);
276 		if (status != -1 || errno != EINVAL) {
277 			warnx("invalid-time: nanosleep %lld %ld",
278 			    (long long)ts[i].tv_sec, ts[i].tv_nsec);
279 			return 1;
280 		}
281 	}
282 	return 0;
283 }
284