1272343Sngie/* $NetBSD: t_sleep.c,v 1.8 2014/07/15 14:56:34 gson Exp $ */
2272343Sngie
3272343Sngie/*-
4272343Sngie * Copyright (c) 2006 Frank Kardel
5272343Sngie * All rights reserved.
6272343Sngie *
7272343Sngie * Redistribution and use in source and binary forms, with or without
8272343Sngie * modification, are permitted provided that the following conditions
9272343Sngie * are met:
10272343Sngie * 1. Redistributions of source code must retain the above copyright
11272343Sngie *    notice, this list of conditions and the following disclaimer.
12272343Sngie * 2. Redistributions in binary form must reproduce the above copyright
13272343Sngie *    notice, this list of conditions and the following disclaimer in the
14272343Sngie *    documentation and/or other materials provided with the distribution.
15272343Sngie *
16272343Sngie * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17272343Sngie * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18272343Sngie * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19272343Sngie * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20272343Sngie * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21272343Sngie * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22272343Sngie * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23272343Sngie * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24272343Sngie * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25272343Sngie * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26272343Sngie * POSSIBILITY OF SUCH DAMAGE.
27272343Sngie */
28272343Sngie
29272343Sngie#include <atf-c.h>
30272343Sngie#include <errno.h>
31272343Sngie#include <poll.h>
32272343Sngie#include <stdio.h>
33272343Sngie#include <stdlib.h>
34272343Sngie#include <string.h>
35272343Sngie#include <time.h>
36272343Sngie#include <unistd.h>
37272343Sngie
38272343Sngie#include <sys/cdefs.h>
39272343Sngie#include <sys/event.h>
40272343Sngie#include <sys/signal.h>
41272343Sngie
42272343Sngie#include "isqemu.h"
43272343Sngie
44272343Sngie#define BILLION		1000000000LL	/* nano-seconds per second */
45272343Sngie#define MILLION		1000000LL	/* nano-seconds per milli-second */
46272343Sngie
47272343Sngie#define ALARM		6		/* SIGALRM after this many seconds */
48272343Sngie#define MAXSLEEP	22		/* Maximum delay in seconds */
49272343Sngie#define KEVNT_TIMEOUT	10300		/* measured in milli-seconds */
50272343Sngie#define FUZZ		(40 * MILLION)	/* scheduling fuzz accepted - 40 ms */
51272343Sngie
52273529Sngie#ifdef __FreeBSD__
53273529Sngie#include <sys/time.h>
54273529Sngie#include <inttypes.h>
55273529Sngie#endif
56273529Sngie
57272343Sngie/*
58272343Sngie * Timer notes
59272343Sngie *
60272343Sngie * Most tests use FUZZ as their initial delay value, but 'sleep'
61272343Sngie * starts at 1sec (since it cannot handle sub-second intervals).
62272343Sngie * Subsequent passes double the previous interval, up to MAXSLEEP.
63272343Sngie *
64272343Sngie * The current values result in 5 passes for the 'sleep' test (at 1,
65272343Sngie * 2, 4, 8, and 16 seconds) and 10 passes for the other tests (at
66272343Sngie * 0.04, 0.08, 0.16, 0.32, 0.64, 1.28, 2.56, 5.12, 10.24, and 20.48
67272343Sngie * seconds).
68272343Sngie *
69272343Sngie * The ALARM is only set if the current pass's delay is longer, and
70272343Sngie * only if the ALARM has not already been triggered.
71272343Sngie *
72272343Sngie * The 'kevent' test needs the ALARM to be set on a different pass
73272343Sngie * from when the KEVNT_TIMEOUT fires.  So set ALARM to fire on the
74272343Sngie * penultimate pass, and the KEVNT_TIMEOUT on the final pass.  We
75272343Sngie * set KEVNT_TIMEOUT just barely long enough to put it into the
76272343Sngie * last test pass, and set MAXSLEEP a couple seconds longer than
77272343Sngie * necessary, in order to avoid a QEMU bug which nearly doubles
78272343Sngie * some timers.
79272343Sngie */
80272343Sngie
81272343Sngiestatic volatile int sig;
82272343Sngie
83272343Sngieint sleeptest(int (*)(struct timespec *, struct timespec *), bool, bool);
84272343Sngieint do_nanosleep(struct timespec *, struct timespec *);
85272343Sngieint do_select(struct timespec *, struct timespec *);
86273529Sngie#ifdef __NetBSD__
87272343Sngieint do_poll(struct timespec *, struct timespec *);
88273529Sngie#endif
89272343Sngieint do_sleep(struct timespec *, struct timespec *);
90272343Sngieint do_kevent(struct timespec *, struct timespec *);
91272343Sngievoid sigalrm(int);
92272343Sngie
93272343Sngievoid
94272343Sngiesigalrm(int s)
95272343Sngie{
96272343Sngie
97272343Sngie	sig++;
98272343Sngie}
99272343Sngie
100272343Sngieint
101272343Sngiedo_nanosleep(struct timespec *delay, struct timespec *remain)
102272343Sngie{
103272343Sngie	int ret;
104272343Sngie
105272343Sngie	if (nanosleep(delay, remain) == -1)
106272343Sngie		ret = (errno == EINTR ? 0 : errno);
107272343Sngie	else
108272343Sngie		ret = 0;
109272343Sngie	return ret;
110272343Sngie}
111272343Sngie
112272343Sngieint
113272343Sngiedo_select(struct timespec *delay, struct timespec *remain)
114272343Sngie{
115272343Sngie	int ret;
116272343Sngie	struct timeval tv;
117272343Sngie
118272343Sngie	TIMESPEC_TO_TIMEVAL(&tv, delay);
119272343Sngie	if (select(0, NULL, NULL, NULL, &tv) == -1)
120272343Sngie		ret = (errno == EINTR ? 0 : errno);
121272343Sngie	else
122272343Sngie		ret = 0;
123272343Sngie	return ret;
124272343Sngie}
125272343Sngie
126273529Sngie#ifdef __NetBSD__
127272343Sngieint
128272343Sngiedo_poll(struct timespec *delay, struct timespec *remain)
129272343Sngie{
130272343Sngie	int ret;
131272343Sngie	struct timeval tv;
132272343Sngie
133272343Sngie	TIMESPEC_TO_TIMEVAL(&tv, delay);
134272343Sngie	if (pollts(NULL, 0, delay, NULL) == -1)
135272343Sngie		ret = (errno == EINTR ? 0 : errno);
136272343Sngie	else
137272343Sngie		ret = 0;
138272343Sngie	return ret;
139272343Sngie}
140273529Sngie#endif
141272343Sngie
142272343Sngieint
143272343Sngiedo_sleep(struct timespec *delay, struct timespec *remain)
144272343Sngie{
145272343Sngie	struct timeval tv;
146272343Sngie
147272343Sngie	TIMESPEC_TO_TIMEVAL(&tv, delay);
148272343Sngie	remain->tv_sec = sleep(delay->tv_sec);
149272343Sngie	remain->tv_nsec = 0;
150272343Sngie
151272343Sngie	return 0;
152272343Sngie}
153272343Sngie
154272343Sngieint
155272343Sngiedo_kevent(struct timespec *delay, struct timespec *remain)
156272343Sngie{
157272343Sngie	struct kevent ktimer;
158272343Sngie	struct kevent kresult;
159272343Sngie	int rtc, kq, kerrno;
160272343Sngie	int tmo;
161272343Sngie
162272343Sngie	ATF_REQUIRE_MSG((kq = kqueue()) != -1, "kqueue: %s", strerror(errno));
163272343Sngie
164272343Sngie	tmo = KEVNT_TIMEOUT;
165272343Sngie
166272343Sngie	/*
167272343Sngie	 * If we expect the KEVNT_TIMEOUT to fire, and we're running
168272343Sngie	 * under QEMU, make sure the delay is long enough to account
169272343Sngie	 * for the effects of PR kern/43997 !
170272343Sngie	 */
171272343Sngie	if (isQEMU() &&
172272343Sngie	    tmo/1000 < delay->tv_sec && tmo/500 > delay->tv_sec)
173272343Sngie		delay->tv_sec = MAXSLEEP;
174272343Sngie
175272343Sngie	EV_SET(&ktimer, 1, EVFILT_TIMER, EV_ADD, 0, tmo, 0);
176272343Sngie
177272343Sngie	rtc = kevent(kq, &ktimer, 1, &kresult, 1, delay);
178272343Sngie	kerrno = errno;
179272343Sngie
180272343Sngie	(void)close(kq);
181272343Sngie
182272343Sngie	if (rtc == -1) {
183272343Sngie		ATF_REQUIRE_MSG(kerrno == EINTR, "kevent: %s", strerror(errno));
184272343Sngie		return 0;
185272343Sngie	}
186272343Sngie
187272343Sngie	if (delay->tv_sec * BILLION + delay->tv_nsec > tmo * MILLION)
188272343Sngie		ATF_REQUIRE_MSG(rtc > 0,
189272343Sngie		    "kevent: KEVNT_TIMEOUT did not cause EVFILT_TIMER event");
190272343Sngie
191272343Sngie	return 0;
192272343Sngie}
193272343Sngie
194272343SngieATF_TC(nanosleep);
195272343SngieATF_TC_HEAD(nanosleep, tc)
196272343Sngie{
197272343Sngie
198272343Sngie	atf_tc_set_md_var(tc, "descr", "Test nanosleep(2) timing");
199272343Sngie	atf_tc_set_md_var(tc, "timeout", "65");
200272343Sngie}
201272343Sngie
202272343SngieATF_TC_BODY(nanosleep, tc)
203272343Sngie{
204272343Sngie
205272343Sngie	sleeptest(do_nanosleep, true, false);
206272343Sngie}
207272343Sngie
208272343SngieATF_TC(select);
209272343SngieATF_TC_HEAD(select, tc)
210272343Sngie{
211272343Sngie
212272343Sngie	atf_tc_set_md_var(tc, "descr", "Test select(2) timing");
213272343Sngie	atf_tc_set_md_var(tc, "timeout", "65");
214272343Sngie}
215272343Sngie
216272343SngieATF_TC_BODY(select, tc)
217272343Sngie{
218272343Sngie
219272343Sngie	sleeptest(do_select, true, true);
220272343Sngie}
221272343Sngie
222273529Sngie#ifdef __NetBSD__
223272343SngieATF_TC(poll);
224272343SngieATF_TC_HEAD(poll, tc)
225272343Sngie{
226272343Sngie
227272343Sngie	atf_tc_set_md_var(tc, "descr", "Test poll(2) timing");
228272343Sngie	atf_tc_set_md_var(tc, "timeout", "65");
229272343Sngie}
230272343Sngie
231272343SngieATF_TC_BODY(poll, tc)
232272343Sngie{
233272343Sngie
234272343Sngie	sleeptest(do_poll, true, true);
235272343Sngie}
236273529Sngie#endif
237272343Sngie
238272343SngieATF_TC(sleep);
239272343SngieATF_TC_HEAD(sleep, tc)
240272343Sngie{
241272343Sngie
242272343Sngie	atf_tc_set_md_var(tc, "descr", "Test sleep(3) timing");
243272343Sngie	atf_tc_set_md_var(tc, "timeout", "65");
244272343Sngie}
245272343Sngie
246272343SngieATF_TC_BODY(sleep, tc)
247272343Sngie{
248272343Sngie
249272343Sngie	sleeptest(do_sleep, false, false);
250272343Sngie}
251272343Sngie
252272343SngieATF_TC(kevent);
253272343SngieATF_TC_HEAD(kevent, tc)
254272343Sngie{
255272343Sngie
256272343Sngie	atf_tc_set_md_var(tc, "descr", "Test kevent(2) timing");
257272343Sngie	atf_tc_set_md_var(tc, "timeout", "65");
258272343Sngie}
259272343Sngie
260272343SngieATF_TC_BODY(kevent, tc)
261272343Sngie{
262272343Sngie
263272343Sngie	sleeptest(do_kevent, true, true);
264272343Sngie}
265272343Sngie
266272343Sngieint
267272343Sngiesleeptest(int (*test)(struct timespec *, struct timespec *),
268272343Sngie	   bool subsec, bool sim_remain)
269272343Sngie{
270272343Sngie	struct timespec tsa, tsb, tslp, tremain;
271272343Sngie	int64_t delta1, delta2, delta3, round;
272272343Sngie
273272343Sngie	sig = 0;
274272343Sngie	signal(SIGALRM, sigalrm);
275272343Sngie
276272343Sngie	if (subsec) {
277272343Sngie		round = 1;
278272343Sngie		delta3 = FUZZ;
279272343Sngie	} else {
280272343Sngie		round = 1000000000;
281272343Sngie		delta3 = round;
282272343Sngie	}
283272343Sngie
284272343Sngie	tslp.tv_sec = delta3 / 1000000000;
285272343Sngie	tslp.tv_nsec = delta3 % 1000000000;
286272343Sngie
287272343Sngie	while (tslp.tv_sec <= MAXSLEEP) {
288272343Sngie		/*
289272343Sngie		 * disturb sleep by signal on purpose
290272343Sngie		 */
291272343Sngie		if (tslp.tv_sec > ALARM && sig == 0)
292272343Sngie			alarm(ALARM);
293272343Sngie
294272343Sngie		clock_gettime(CLOCK_REALTIME, &tsa);
295272343Sngie		(*test)(&tslp, &tremain);
296272343Sngie		clock_gettime(CLOCK_REALTIME, &tsb);
297272343Sngie
298272343Sngie		if (sim_remain) {
299272343Sngie			timespecsub(&tsb, &tsa, &tremain);
300272343Sngie			timespecsub(&tslp, &tremain, &tremain);
301272343Sngie		}
302272343Sngie
303272343Sngie		delta1 = (int64_t)tsb.tv_sec - (int64_t)tsa.tv_sec;
304272343Sngie		delta1 *= BILLION;
305272343Sngie		delta1 += (int64_t)tsb.tv_nsec - (int64_t)tsa.tv_nsec;
306272343Sngie
307272343Sngie		delta2 = (int64_t)tremain.tv_sec * BILLION;
308272343Sngie		delta2 += (int64_t)tremain.tv_nsec;
309272343Sngie
310272343Sngie		delta3 = (int64_t)tslp.tv_sec * BILLION;
311272343Sngie		delta3 += (int64_t)tslp.tv_nsec - delta1 - delta2;
312272343Sngie
313272343Sngie		delta3 /= round;
314272343Sngie		delta3 *= round;
315272343Sngie
316272343Sngie		if (delta3 > FUZZ || delta3 < -FUZZ) {
317272343Sngie			if (!sim_remain)
318272343Sngie				atf_tc_expect_fail("Long reschedule latency "
319272343Sngie				    "due to PR kern/43997");
320272343Sngie
321272343Sngie			atf_tc_fail("Reschedule latency %"PRId64" exceeds "
322272343Sngie			    "allowable fuzz %lld", delta3, FUZZ);
323272343Sngie		}
324272343Sngie		delta3 = (int64_t)tslp.tv_sec * 2 * BILLION;
325272343Sngie		delta3 += (int64_t)tslp.tv_nsec * 2;
326272343Sngie
327272343Sngie		delta3 /= round;
328272343Sngie		delta3 *= round;
329272343Sngie		if (delta3 < FUZZ)
330272343Sngie			break;
331272343Sngie		tslp.tv_sec = delta3 / BILLION;
332272343Sngie		tslp.tv_nsec = delta3 % BILLION;
333272343Sngie	}
334272343Sngie	ATF_REQUIRE_MSG(sig == 1, "Alarm did not fire!");
335272343Sngie
336272343Sngie	atf_tc_pass();
337272343Sngie}
338272343Sngie
339272343SngieATF_TP_ADD_TCS(tp)
340272343Sngie{
341272343Sngie	ATF_TP_ADD_TC(tp, nanosleep);
342272343Sngie	ATF_TP_ADD_TC(tp, select);
343273529Sngie#ifdef __NetBSD__
344272343Sngie	ATF_TP_ADD_TC(tp, poll);
345273529Sngie#endif
346272343Sngie	ATF_TP_ADD_TC(tp, sleep);
347272343Sngie	ATF_TP_ADD_TC(tp, kevent);
348272343Sngie
349272343Sngie	return atf_no_error();
350272343Sngie}
351