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
47static void
48handler(int signo __unused)
49{
50	/* Nothing. */
51}
52
53static int got_info;
54static void
55info_handler(int signo __unused)
56{
57
58	got_info = 1;
59}
60
61
62ATF_TC(nanosleep_basic);
63ATF_TC_HEAD(nanosleep_basic, tc)
64{
65	atf_tc_set_md_var(tc, "descr", "Test that nanosleep(2) works");
66}
67
68ATF_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
105ATF_TC(nanosleep_err);
106ATF_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
112ATF_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
135ATF_TC(nanosleep_sig);
136ATF_TC_HEAD(nanosleep_sig, tc)
137{
138	atf_tc_set_md_var(tc, "descr", "Test signal for nanosleep(2)");
139}
140
141ATF_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
188ATF_TC(nanosleep_eintr);
189ATF_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
195ATF_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
259ATF_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