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