t_sleep.c revision 313535
139215Sgibbs/* $NetBSD: t_sleep.c,v 1.11 2017/01/10 15:43:59 maya Exp $ */
2107178Snjl
339215Sgibbs/*-
4107178Snjl * Copyright (c) 2006 Frank Kardel
539215Sgibbs * All rights reserved.
639215Sgibbs *
739215Sgibbs * Redistribution and use in source and binary forms, with or without
839215Sgibbs * modification, are permitted provided that the following conditions
939215Sgibbs * are met:
1039215Sgibbs * 1. Redistributions of source code must retain the above copyright
1139215Sgibbs *    notice, this list of conditions and the following disclaimer.
1239215Sgibbs * 2. Redistributions in binary form must reproduce the above copyright
1339215Sgibbs *    notice, this list of conditions and the following disclaimer in the
1439215Sgibbs *    documentation and/or other materials provided with the distribution.
1539215Sgibbs *
1639215Sgibbs * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1739215Sgibbs * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1839215Sgibbs * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1939215Sgibbs * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2039215Sgibbs * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2139215Sgibbs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2239215Sgibbs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2339215Sgibbs * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2439215Sgibbs * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2539215Sgibbs * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2639215Sgibbs * POSSIBILITY OF SUCH DAMAGE.
2739215Sgibbs */
2850476Speter
2939215Sgibbs#ifdef __FreeBSD__
3039215Sgibbs#include <sys/types.h>
3139215Sgibbs#endif
32121184Ssimokawa#include <sys/cdefs.h>
3344498Sgibbs#include <sys/event.h>
34107178Snjl#include <sys/signal.h>
3539215Sgibbs#include <sys/time.h>		/* for TIMESPEC_TO_TIMEVAL on FreeBSD */
3644498Sgibbs
3739215Sgibbs#include <atf-c.h>
3839215Sgibbs#include <errno.h>
3939215Sgibbs#include <inttypes.h>
40107178Snjl#include <poll.h>
4139215Sgibbs#include <stdio.h>
4239215Sgibbs#include <stdlib.h>
43107178Snjl#include <string.h>
44109161Snjl#include <time.h>
45107178Snjl#include <unistd.h>
46107178Snjl
47107178Snjl#include "isqemu.h"
48107178Snjl
49120428Ssimokawa#define BILLION		1000000000LL	/* nano-seconds per second */
50107178Snjl#define MILLION		1000000LL	/* nano-seconds per milli-second */
5139215Sgibbs
52107178Snjl#define ALARM		6		/* SIGALRM after this many seconds */
5339215Sgibbs#define MAXSLEEP	22		/* Maximum delay in seconds */
54107178Snjl#define KEVNT_TIMEOUT	10300		/* measured in milli-seconds */
5539215Sgibbs#define FUZZ		(40 * MILLION)	/* scheduling fuzz accepted - 40 ms */
56107178Snjl
57107178Snjl/*
58107178Snjl * Timer notes
59162704Smjacob *
60107178Snjl * Most tests use FUZZ as their initial delay value, but 'sleep'
61107178Snjl * starts at 1sec (since it cannot handle sub-second intervals).
62107178Snjl * Subsequent passes double the previous interval, up to MAXSLEEP.
63107178Snjl *
64107178Snjl * The current values result in 5 passes for the 'sleep' test (at 1,
65162704Smjacob * 2, 4, 8, and 16 seconds) and 10 passes for the other tests (at
66121184Ssimokawa * 0.04, 0.08, 0.16, 0.32, 0.64, 1.28, 2.56, 5.12, 10.24, and 20.48
67121184Ssimokawa * seconds).
68107178Snjl *
69107178Snjl * The ALARM is only set if the current pass's delay is longer, and
70107178Snjl * only if the ALARM has not already been triggered.
71107178Snjl *
72107178Snjl * The 'kevent' test needs the ALARM to be set on a different pass
73107178Snjl * from when the KEVNT_TIMEOUT fires.  So set ALARM to fire on the
74107178Snjl * penultimate pass, and the KEVNT_TIMEOUT on the final pass.  We
75107178Snjl * set KEVNT_TIMEOUT just barely long enough to put it into the
76107178Snjl * last test pass, and set MAXSLEEP a couple seconds longer than
77107178Snjl * necessary, in order to avoid a QEMU bug which nearly doubles
7844498Sgibbs * some timers.
7944498Sgibbs */
8044498Sgibbs
8144498Sgibbsstatic volatile int sig;
8239215Sgibbs
83107178Snjlint sleeptest(int (*)(struct timespec *, struct timespec *), bool, bool);
84107178Snjlint do_nanosleep(struct timespec *, struct timespec *);
85107178Snjlint do_select(struct timespec *, struct timespec *);
86107178Snjl#ifdef __NetBSD__
87107178Snjlint do_poll(struct timespec *, struct timespec *);
88107178Snjl#endif
89107178Snjlint do_sleep(struct timespec *, struct timespec *);
90162704Smjacobint do_kevent(struct timespec *, struct timespec *);
91237601Skenvoid sigalrm(int);
92107178Snjl
93107178Snjlvoid
94107178Snjlsigalrm(int s)
95107178Snjl{
96107178Snjl
97107178Snjl	sig++;
98107178Snjl}
9939215Sgibbs
10039215Sgibbsint
10139215Sgibbsdo_nanosleep(struct timespec *delay, struct timespec *remain)
10239215Sgibbs{
103228481Sed	int ret;
104228481Sed
105107178Snjl	if (nanosleep(delay, remain) == -1)
106107178Snjl		ret = (errno == EINTR ? 0 : errno);
10739215Sgibbs	else
108107178Snjl		ret = 0;
109107178Snjl	return ret;
110107178Snjl}
111107178Snjl
112107178Snjlint
113107178Snjldo_select(struct timespec *delay, struct timespec *remain)
114107178Snjl{
115107178Snjl	int ret;
116107178Snjl	struct timeval tv;
117107178Snjl
118107178Snjl	TIMESPEC_TO_TIMEVAL(&tv, delay);
119107178Snjl	if (select(0, NULL, NULL, NULL, &tv) == -1)
120107178Snjl		ret = (errno == EINTR ? 0 : errno);
121162704Smjacob	else
12239215Sgibbs		ret = 0;
123107178Snjl	return ret;
124107178Snjl}
12539215Sgibbs
126107178Snjl#ifdef __NetBSD__
127107178Snjlint
12839215Sgibbsdo_poll(struct timespec *delay, struct timespec *remain)
129107178Snjl{
130107178Snjl	int ret;
13144498Sgibbs	struct timeval tv;
132107178Snjl
133107178Snjl	TIMESPEC_TO_TIMEVAL(&tv, delay);
13444498Sgibbs	if (pollts(NULL, 0, delay, NULL) == -1)
135107178Snjl		ret = (errno == EINTR ? 0 : errno);
136107178Snjl	else
137107178Snjl		ret = 0;
138107178Snjl	return ret;
13944498Sgibbs}
140107178Snjl#endif
141107178Snjl
142107178Snjlint
143107178Snjldo_sleep(struct timespec *delay, struct timespec *remain)
14463185Smjacob{
145107178Snjl	struct timeval tv;
146121184Ssimokawa
147121184Ssimokawa	TIMESPEC_TO_TIMEVAL(&tv, delay);
148121184Ssimokawa	remain->tv_sec = sleep(delay->tv_sec);
149121184Ssimokawa	remain->tv_nsec = 0;
150121184Ssimokawa
151121184Ssimokawa	return 0;
152121184Ssimokawa}
153121184Ssimokawa
154121184Ssimokawaint
155121184Ssimokawado_kevent(struct timespec *delay, struct timespec *remain)
156121184Ssimokawa{
157121184Ssimokawa	struct kevent ktimer;
158121184Ssimokawa	struct kevent kresult;
159121184Ssimokawa	int rtc, kq, kerrno;
160121184Ssimokawa	int tmo;
161121184Ssimokawa
162121184Ssimokawa	ATF_REQUIRE_MSG((kq = kqueue()) != -1, "kqueue: %s", strerror(errno));
163121184Ssimokawa
164121184Ssimokawa	tmo = KEVNT_TIMEOUT;
165121184Ssimokawa
166121184Ssimokawa	/*
167121184Ssimokawa	 * If we expect the KEVNT_TIMEOUT to fire, and we're running
168121184Ssimokawa	 * under QEMU, make sure the delay is long enough to account
169121184Ssimokawa	 * for the effects of PR kern/43997 !
170121184Ssimokawa	 */
171121184Ssimokawa	if (isQEMU() &&
172121184Ssimokawa	    tmo/1000 < delay->tv_sec && tmo/500 > delay->tv_sec)
173107178Snjl		delay->tv_sec = MAXSLEEP;
174121184Ssimokawa
175107178Snjl	EV_SET(&ktimer, 1, EVFILT_TIMER, EV_ADD, 0, tmo, 0);
176107178Snjl
177107178Snjl	rtc = kevent(kq, &ktimer, 1, &kresult, 1, delay);
178121184Ssimokawa	kerrno = errno;
179107178Snjl
180107178Snjl	(void)close(kq);
181107178Snjl
182107178Snjl	if (rtc == -1) {
183107178Snjl		ATF_REQUIRE_MSG(kerrno == EINTR, "kevent: %s",
184107178Snjl		    strerror(kerrno));
185107178Snjl		return 0;
186107178Snjl	}
187107178Snjl
188107178Snjl	if (delay->tv_sec * BILLION + delay->tv_nsec > tmo * MILLION)
189107178Snjl		ATF_REQUIRE_MSG(rtc > 0,
190107178Snjl		    "kevent: KEVNT_TIMEOUT did not cause EVFILT_TIMER event");
191107178Snjl
192107178Snjl	return 0;
193107178Snjl}
194107178Snjl
195107178SnjlATF_TC(nanosleep);
196107178SnjlATF_TC_HEAD(nanosleep, tc)
197162704Smjacob{
198162704Smjacob
199162704Smjacob	atf_tc_set_md_var(tc, "descr", "Test nanosleep(2) timing");
20039215Sgibbs	atf_tc_set_md_var(tc, "timeout", "65");
20139215Sgibbs}
20239215Sgibbs
20339215SgibbsATF_TC_BODY(nanosleep, tc)
20439215Sgibbs{
20539215Sgibbs
20639215Sgibbs	sleeptest(do_nanosleep, true, false);
207107178Snjl}
208107178Snjl
20939215SgibbsATF_TC(select);
21039215SgibbsATF_TC_HEAD(select, tc)
211107178Snjl{
212107178Snjl
213107178Snjl	atf_tc_set_md_var(tc, "descr", "Test select(2) timing");
214107178Snjl	atf_tc_set_md_var(tc, "timeout", "65");
215107178Snjl}
216107178Snjl
217107178SnjlATF_TC_BODY(select, tc)
218107178Snjl{
21944498Sgibbs
22044498Sgibbs	sleeptest(do_select, true, true);
22144498Sgibbs}
222107178Snjl
223107178Snjl#ifdef __NetBSD__
224107178SnjlATF_TC(poll);
22544498SgibbsATF_TC_HEAD(poll, tc)
226107178Snjl{
227107178Snjl
228107178Snjl	atf_tc_set_md_var(tc, "descr", "Test poll(2) timing");
229196955Ssbruno	atf_tc_set_md_var(tc, "timeout", "65");
23044498Sgibbs}
231107178Snjl
232107178SnjlATF_TC_BODY(poll, tc)
233107178Snjl{
234107178Snjl
235107178Snjl	sleeptest(do_poll, true, true);
236107178Snjl}
237120428Ssimokawa#endif
238120428Ssimokawa
239120428SsimokawaATF_TC(sleep);
240120428SsimokawaATF_TC_HEAD(sleep, tc)
241120428Ssimokawa{
242120428Ssimokawa
243120428Ssimokawa	atf_tc_set_md_var(tc, "descr", "Test sleep(3) timing");
244120428Ssimokawa	atf_tc_set_md_var(tc, "timeout", "65");
245120428Ssimokawa}
246120428Ssimokawa
247120428SsimokawaATF_TC_BODY(sleep, tc)
248120428Ssimokawa{
249107178Snjl
250107178Snjl	sleeptest(do_sleep, false, false);
25144498Sgibbs}
252121184Ssimokawa
253162704SmjacobATF_TC(kevent);
254121184SsimokawaATF_TC_HEAD(kevent, tc)
255121184Ssimokawa{
256107178Snjl
257107178Snjl	atf_tc_set_md_var(tc, "descr", "Test kevent(2) timing");
25844498Sgibbs	atf_tc_set_md_var(tc, "timeout", "65");
259162704Smjacob}
260109161Snjl
261109161SnjlATF_TC_BODY(kevent, tc)
262162704Smjacob{
263109161Snjl
264109161Snjl	sleeptest(do_kevent, true, true);
265109161Snjl}
266109161Snjl
267109161Snjlint
268109161Snjlsleeptest(int (*test)(struct timespec *, struct timespec *),
269109161Snjl	   bool subsec, bool sim_remain)
270109161Snjl{
271109161Snjl	struct timespec tsa, tsb, tslp, tremain;
272162704Smjacob	int64_t delta1, delta2, delta3, round;
273162704Smjacob
274162704Smjacob	sig = 0;
275162704Smjacob	signal(SIGALRM, sigalrm);
276162704Smjacob
277162704Smjacob	if (subsec) {
278162704Smjacob		round = 1;
279162704Smjacob		delta3 = FUZZ;
280109161Snjl	} else {
281109161Snjl		round = 1000000000;
282162704Smjacob		delta3 = round;
283109161Snjl	}
284109161Snjl
285109161Snjl	tslp.tv_sec = delta3 / 1000000000;
286228481Sed	tslp.tv_nsec = delta3 % 1000000000;
287107178Snjl
288228481Sed	while (tslp.tv_sec <= MAXSLEEP) {
289196955Ssbruno		/*
290228481Sed		 * disturb sleep by signal on purpose
29163185Smjacob		 */
292107178Snjl		if (tslp.tv_sec > ALARM && sig == 0)
293107178Snjl			alarm(ALARM);
294107178Snjl
295107178Snjl		clock_gettime(CLOCK_REALTIME, &tsa);
296107178Snjl		(*test)(&tslp, &tremain);
297107178Snjl		clock_gettime(CLOCK_REALTIME, &tsb);
298107178Snjl
299107178Snjl		if (sim_remain) {
30039215Sgibbs			timespecsub(&tsb, &tsa, &tremain);
301107178Snjl			timespecsub(&tslp, &tremain, &tremain);
302107178Snjl		}
303107178Snjl
304107178Snjl		delta1 = (int64_t)tsb.tv_sec - (int64_t)tsa.tv_sec;
305107178Snjl		delta1 *= BILLION;
306107178Snjl		delta1 += (int64_t)tsb.tv_nsec - (int64_t)tsa.tv_nsec;
307107178Snjl
308107178Snjl		delta2 = (int64_t)tremain.tv_sec * BILLION;
309107178Snjl		delta2 += (int64_t)tremain.tv_nsec;
310107178Snjl
311162704Smjacob		delta3 = (int64_t)tslp.tv_sec * BILLION;
31239215Sgibbs		delta3 += (int64_t)tslp.tv_nsec - delta1 - delta2;
31339215Sgibbs
314107178Snjl		delta3 /= round;
315107178Snjl		delta3 *= round;
316107178Snjl
317196955Ssbruno		if (delta3 > FUZZ || delta3 < -FUZZ) {
318107178Snjl			if (!sim_remain)
319107178Snjl				atf_tc_expect_fail("Long reschedule latency "
32044498Sgibbs				    "due to PR kern/43997");
321107178Snjl
322107178Snjl			atf_tc_fail("Reschedule latency %"PRId64" exceeds "
323107178Snjl			    "allowable fuzz %lld", delta3, FUZZ);
32449935Sgibbs		}
325107178Snjl		delta3 = (int64_t)tslp.tv_sec * 2 * BILLION;
326107178Snjl		delta3 += (int64_t)tslp.tv_nsec * 2;
327196955Ssbruno
328107178Snjl		delta3 /= round;
32939215Sgibbs		delta3 *= round;
330107178Snjl		if (delta3 < FUZZ)
33149935Sgibbs			break;
33249935Sgibbs		tslp.tv_sec = delta3 / BILLION;
33349935Sgibbs		tslp.tv_nsec = delta3 % BILLION;
33449935Sgibbs	}
33549935Sgibbs	ATF_REQUIRE_MSG(sig == 1, "Alarm did not fire!");
336107178Snjl
337107178Snjl	atf_tc_pass();
33863290Smjacob}
339107178Snjl
34063290SmjacobATF_TP_ADD_TCS(tp)
341107178Snjl{
34263290Smjacob	ATF_TP_ADD_TC(tp, nanosleep);
343107178Snjl	ATF_TP_ADD_TC(tp, select);
344107178Snjl#ifdef __NetBSD__
345107178Snjl	ATF_TP_ADD_TC(tp, poll);
346107178Snjl#endif
347107178Snjl	ATF_TP_ADD_TC(tp, sleep);
348107178Snjl	ATF_TP_ADD_TC(tp, kevent);
34944498Sgibbs
350107178Snjl	return atf_no_error();
351107178Snjl}
352107178Snjl