1 /* $NetBSD: t_nanosleep.c,v 1.4 2017/01/13 21:15:14 christos Exp $ */
2 
3 /*-
4  * Copyright (c) 2011 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jukka Ruohonen.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: t_nanosleep.c,v 1.4 2017/01/13 21:15:14 christos Exp $");
33 
34 #include <sys/time.h>
35 #include <sys/wait.h>
36 
37 #include <atf-c.h>
38 #include <errno.h>
39 #include <time.h>
40 #include <signal.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <sysexits.h>
45 #include <unistd.h>
46 
47 static void
48 handler(int signo __unused)
49 {
50 	/* Nothing. */
51 }
52 
53 static int got_info;
54 static void
55 info_handler(int signo __unused)
56 {
57 
58 	got_info = 1;
59 }
60 
61 
62 ATF_TC(nanosleep_basic);
63 ATF_TC_HEAD(nanosleep_basic, tc)
64 {
65 	atf_tc_set_md_var(tc, "descr", "Test that nanosleep(2) works");
66 }
67 
68 ATF_TC_BODY(nanosleep_basic, tc)
69 {
70 	static const size_t maxiter = 10;
71 	struct timespec ts1, ts2, tsn;
72 	size_t i;
73 
74 	for (i = 1; i < maxiter; i++) {
75 
76 		tsn.tv_sec = 0;
77 		tsn.tv_nsec = i;
78 
79 		(void)memset(&ts1, 0, sizeof(struct timespec));
80 		(void)memset(&ts2, 0, sizeof(struct timespec));
81 
82 		ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &ts1) == 0);
83 		ATF_REQUIRE(nanosleep(&tsn, NULL) == 0);
84 		ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &ts2) == 0);
85 
86 		/*
87 		 * Verify that we slept at least one nanosecond.
88 		 */
89 		if (timespeccmp(&ts2, &ts1, <=) != 0) {
90 
91 			(void)fprintf(stderr,
92 			    "sleep time:: sec %llu, nsec %lu\n\t\t"
93 			    "ts1: sec %llu, nsec %lu\n\t\t"
94 			    "ts2: sec %llu, nsec %lu\n",
95 			    (unsigned long long)tsn.tv_sec, tsn.tv_nsec,
96 			    (unsigned long long)ts1.tv_sec, ts1.tv_nsec,
97 			    (unsigned long long)ts2.tv_sec, ts2.tv_nsec);
98 
99 			atf_tc_fail_nonfatal("inaccuracies in sleep time "
100 			    "(resolution = %lu nsec)", tsn.tv_nsec);
101 		}
102 	}
103 }
104 
105 ATF_TC(nanosleep_err);
106 ATF_TC_HEAD(nanosleep_err, tc)
107 {
108 	atf_tc_set_md_var(tc, "descr",
109 	    "Test errors from nanosleep(2) (PR bin/14558)");
110 }
111 
112 ATF_TC_BODY(nanosleep_err, tc)
113 {
114 	struct timespec ts;
115 
116 	ts.tv_sec = 1;
117 	ts.tv_nsec = -1;
118 	errno = 0;
119 	ATF_REQUIRE_ERRNO(EINVAL, nanosleep(&ts, NULL) == -1);
120 
121 	ts.tv_sec = 1;
122 	ts.tv_nsec = 1000000000;
123 	errno = 0;
124 	ATF_REQUIRE_ERRNO(EINVAL, nanosleep(&ts, NULL) == -1);
125 
126 	ts.tv_sec = -1;
127 	ts.tv_nsec = 0;
128 	errno = 0;
129 	ATF_REQUIRE_ERRNO(0, nanosleep(&ts, NULL) == 0);
130 
131 	errno = 0;
132 	ATF_REQUIRE_ERRNO(EFAULT, nanosleep((void *)-1, NULL) == -1);
133 }
134 
135 ATF_TC(nanosleep_sig);
136 ATF_TC_HEAD(nanosleep_sig, tc)
137 {
138 	atf_tc_set_md_var(tc, "descr", "Test signal for nanosleep(2)");
139 }
140 
141 ATF_TC_BODY(nanosleep_sig, tc)
142 {
143 	struct timespec tsn, tsr;
144 	pid_t pid;
145 	int sta;
146 
147 	/*
148 	 * Test that a signal interrupts nanosleep(2).
149 	 *
150 	 * (In which case the return value should be -1 and the
151 	 * second parameter should contain the unslept time.)
152 	 */
153 	pid = fork();
154 
155 	ATF_REQUIRE(pid >= 0);
156 	ATF_REQUIRE(signal(SIGINT, handler) == 0);
157 
158 	if (pid == 0) {
159 
160 		tsn.tv_sec = 10;
161 		tsn.tv_nsec = 0;
162 
163 		tsr.tv_sec = 0;
164 		tsr.tv_nsec = 0;
165 
166 		errno = 0;
167 
168 		if (nanosleep(&tsn, &tsr) != -1)
169 			_exit(EXIT_FAILURE);
170 
171 		if (errno != EINTR)
172 			_exit(EXIT_FAILURE);
173 
174 		if (tsr.tv_sec == 0 && tsr.tv_nsec == 0)
175 			_exit(EXIT_FAILURE);
176 
177 		_exit(EXIT_SUCCESS);
178 	}
179 
180 	(void)sleep(1);
181 	(void)kill(pid, SIGINT);
182 	(void)wait(&sta);
183 
184 	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
185 		atf_tc_fail("signal did not interrupt nanosleep(2)");
186 }
187 
188 ATF_TC(nanosleep_eintr);
189 ATF_TC_HEAD(nanosleep_eintr, tc)
190 {
191 	atf_tc_set_md_var(tc, "descr", "Test [EINTR] for nanosleep(2)");
192 	atf_tc_set_md_var(tc, "timeout", "7");
193 }
194 
195 ATF_TC_BODY(nanosleep_eintr, tc)
196 {
197 	struct sigaction act;
198 	struct timespec tso, ts;
199 	pid_t pid;
200 	int sta;
201 
202 	/*
203 	 * Test that [EINTR] properly handles rmtp for nanosleep(2).
204 	 */
205 	pid = fork();
206 
207 	ATF_REQUIRE(pid >= 0);
208 
209 	got_info = 0;
210 
211 	if (pid == 0) {
212 		act.sa_handler = info_handler;
213 		sigemptyset(&act.sa_mask);
214 		act.sa_flags = 0; /* Don't allow restart. */
215 		ATF_REQUIRE(sigaction(SIGINFO, &act, NULL) == 0);
216 
217 		tso.tv_sec = 5;
218 		tso.tv_nsec = 0;
219 
220 		ts.tv_sec = tso.tv_sec;
221 		ts.tv_nsec = tso.tv_nsec;
222 
223 		errno = 0;
224 		while (nanosleep(&ts, &ts) != 0) {
225 			ATF_REQUIRE_MSG(timespeccmp(&ts, &tso, <=),
226 			    "errno=%d ts=%0.9f should be <= last tso=%0.9f\n",
227 			    errno,
228 			    ts.tv_sec + ts.tv_nsec / 1e9,
229 			    tso.tv_sec + tso.tv_nsec / 1e9);
230 			if (errno == EINTR && got_info == 1) {
231 				got_info = 0;
232 				errno = 0;
233 				tso.tv_sec = ts.tv_sec;
234 				tso.tv_nsec = ts.tv_nsec;
235 				continue;
236 			}
237 			_exit(EXIT_FAILURE);
238 		}
239 
240 		if (errno != 0)
241 			_exit(EXIT_FAILURE);
242 
243 		_exit(EXIT_SUCCESS);
244 	}
245 
246 	/* Flood the process with SIGINFO until it exits. */
247 	do {
248 		for (int i = 0; i < 10; i++)
249 			ATF_REQUIRE(kill(pid, SIGINFO) == 0);
250 		ATF_REQUIRE(usleep(10000) == 0);
251 	} while (waitpid(pid, &sta, WNOHANG) == 0);
252 
253 	ATF_REQUIRE(WIFEXITED(sta) == 1);
254 
255 	if (WEXITSTATUS(sta) != EXIT_SUCCESS)
256 		atf_tc_fail("nanosleep(2) handled rtmp incorrectly");
257 }
258 
259 ATF_TP_ADD_TCS(tp)
260 {
261 
262 	ATF_TP_ADD_TC(tp, nanosleep_basic);
263 	ATF_TP_ADD_TC(tp, nanosleep_err);
264 	ATF_TP_ADD_TC(tp, nanosleep_sig);
265 	ATF_TP_ADD_TC(tp, nanosleep_eintr);
266 
267 	return atf_no_error();
268 }
269