1313535Sngie/* $NetBSD: t_sleep.c,v 1.11 2017/01/10 15:43:59 maya 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 29313535Sngie#include <sys/cdefs.h> 30313535Sngie#include <sys/event.h> 31313535Sngie#include <sys/signal.h> 32313535Sngie#include <sys/time.h> /* for TIMESPEC_TO_TIMEVAL on FreeBSD */ 33313535Sngie 34272343Sngie#include <atf-c.h> 35272343Sngie#include <errno.h> 36313535Sngie#include <inttypes.h> 37272343Sngie#include <poll.h> 38272343Sngie#include <stdio.h> 39272343Sngie#include <stdlib.h> 40272343Sngie#include <string.h> 41272343Sngie#include <time.h> 42272343Sngie#include <unistd.h> 43272343Sngie 44272343Sngie#include "isqemu.h" 45272343Sngie 46272343Sngie#define BILLION 1000000000LL /* nano-seconds per second */ 47272343Sngie#define MILLION 1000000LL /* nano-seconds per milli-second */ 48272343Sngie 49272343Sngie#define ALARM 6 /* SIGALRM after this many seconds */ 50272343Sngie#define MAXSLEEP 22 /* Maximum delay in seconds */ 51272343Sngie#define KEVNT_TIMEOUT 10300 /* measured in milli-seconds */ 52272343Sngie#define FUZZ (40 * MILLION) /* scheduling fuzz accepted - 40 ms */ 53272343Sngie 54272343Sngie/* 55272343Sngie * Timer notes 56272343Sngie * 57272343Sngie * Most tests use FUZZ as their initial delay value, but 'sleep' 58272343Sngie * starts at 1sec (since it cannot handle sub-second intervals). 59272343Sngie * Subsequent passes double the previous interval, up to MAXSLEEP. 60272343Sngie * 61272343Sngie * The current values result in 5 passes for the 'sleep' test (at 1, 62272343Sngie * 2, 4, 8, and 16 seconds) and 10 passes for the other tests (at 63272343Sngie * 0.04, 0.08, 0.16, 0.32, 0.64, 1.28, 2.56, 5.12, 10.24, and 20.48 64272343Sngie * seconds). 65272343Sngie * 66272343Sngie * The ALARM is only set if the current pass's delay is longer, and 67272343Sngie * only if the ALARM has not already been triggered. 68272343Sngie * 69272343Sngie * The 'kevent' test needs the ALARM to be set on a different pass 70272343Sngie * from when the KEVNT_TIMEOUT fires. So set ALARM to fire on the 71272343Sngie * penultimate pass, and the KEVNT_TIMEOUT on the final pass. We 72272343Sngie * set KEVNT_TIMEOUT just barely long enough to put it into the 73272343Sngie * last test pass, and set MAXSLEEP a couple seconds longer than 74272343Sngie * necessary, in order to avoid a QEMU bug which nearly doubles 75272343Sngie * some timers. 76272343Sngie */ 77272343Sngie 78272343Sngiestatic volatile int sig; 79272343Sngie 80272343Sngieint sleeptest(int (*)(struct timespec *, struct timespec *), bool, bool); 81272343Sngieint do_nanosleep(struct timespec *, struct timespec *); 82272343Sngieint do_select(struct timespec *, struct timespec *); 83276478Sngie#ifdef __NetBSD__ 84272343Sngieint do_poll(struct timespec *, struct timespec *); 85276478Sngie#endif 86272343Sngieint do_sleep(struct timespec *, struct timespec *); 87272343Sngieint do_kevent(struct timespec *, struct timespec *); 88272343Sngievoid sigalrm(int); 89272343Sngie 90272343Sngievoid 91272343Sngiesigalrm(int s) 92272343Sngie{ 93272343Sngie 94272343Sngie sig++; 95272343Sngie} 96272343Sngie 97272343Sngieint 98272343Sngiedo_nanosleep(struct timespec *delay, struct timespec *remain) 99272343Sngie{ 100272343Sngie int ret; 101272343Sngie 102272343Sngie if (nanosleep(delay, remain) == -1) 103272343Sngie ret = (errno == EINTR ? 0 : errno); 104272343Sngie else 105272343Sngie ret = 0; 106272343Sngie return ret; 107272343Sngie} 108272343Sngie 109272343Sngieint 110272343Sngiedo_select(struct timespec *delay, struct timespec *remain) 111272343Sngie{ 112272343Sngie int ret; 113272343Sngie struct timeval tv; 114272343Sngie 115272343Sngie TIMESPEC_TO_TIMEVAL(&tv, delay); 116272343Sngie if (select(0, NULL, NULL, NULL, &tv) == -1) 117272343Sngie ret = (errno == EINTR ? 0 : errno); 118272343Sngie else 119272343Sngie ret = 0; 120272343Sngie return ret; 121272343Sngie} 122272343Sngie 123276478Sngie#ifdef __NetBSD__ 124272343Sngieint 125272343Sngiedo_poll(struct timespec *delay, struct timespec *remain) 126272343Sngie{ 127272343Sngie int ret; 128272343Sngie struct timeval tv; 129272343Sngie 130272343Sngie TIMESPEC_TO_TIMEVAL(&tv, delay); 131272343Sngie if (pollts(NULL, 0, delay, NULL) == -1) 132272343Sngie ret = (errno == EINTR ? 0 : errno); 133272343Sngie else 134272343Sngie ret = 0; 135272343Sngie return ret; 136272343Sngie} 137276478Sngie#endif 138272343Sngie 139272343Sngieint 140272343Sngiedo_sleep(struct timespec *delay, struct timespec *remain) 141272343Sngie{ 142272343Sngie struct timeval tv; 143272343Sngie 144272343Sngie TIMESPEC_TO_TIMEVAL(&tv, delay); 145272343Sngie remain->tv_sec = sleep(delay->tv_sec); 146272343Sngie remain->tv_nsec = 0; 147272343Sngie 148272343Sngie return 0; 149272343Sngie} 150272343Sngie 151272343Sngieint 152272343Sngiedo_kevent(struct timespec *delay, struct timespec *remain) 153272343Sngie{ 154272343Sngie struct kevent ktimer; 155272343Sngie struct kevent kresult; 156272343Sngie int rtc, kq, kerrno; 157272343Sngie int tmo; 158272343Sngie 159272343Sngie ATF_REQUIRE_MSG((kq = kqueue()) != -1, "kqueue: %s", strerror(errno)); 160272343Sngie 161272343Sngie tmo = KEVNT_TIMEOUT; 162272343Sngie 163272343Sngie /* 164272343Sngie * If we expect the KEVNT_TIMEOUT to fire, and we're running 165272343Sngie * under QEMU, make sure the delay is long enough to account 166272343Sngie * for the effects of PR kern/43997 ! 167272343Sngie */ 168272343Sngie if (isQEMU() && 169272343Sngie tmo/1000 < delay->tv_sec && tmo/500 > delay->tv_sec) 170272343Sngie delay->tv_sec = MAXSLEEP; 171272343Sngie 172272343Sngie EV_SET(&ktimer, 1, EVFILT_TIMER, EV_ADD, 0, tmo, 0); 173272343Sngie 174272343Sngie rtc = kevent(kq, &ktimer, 1, &kresult, 1, delay); 175272343Sngie kerrno = errno; 176272343Sngie 177272343Sngie (void)close(kq); 178272343Sngie 179272343Sngie if (rtc == -1) { 180313498Sngie ATF_REQUIRE_MSG(kerrno == EINTR, "kevent: %s", 181313498Sngie strerror(kerrno)); 182272343Sngie return 0; 183272343Sngie } 184272343Sngie 185272343Sngie if (delay->tv_sec * BILLION + delay->tv_nsec > tmo * MILLION) 186272343Sngie ATF_REQUIRE_MSG(rtc > 0, 187272343Sngie "kevent: KEVNT_TIMEOUT did not cause EVFILT_TIMER event"); 188272343Sngie 189272343Sngie return 0; 190272343Sngie} 191272343Sngie 192272343SngieATF_TC(nanosleep); 193272343SngieATF_TC_HEAD(nanosleep, tc) 194272343Sngie{ 195272343Sngie 196272343Sngie atf_tc_set_md_var(tc, "descr", "Test nanosleep(2) timing"); 197272343Sngie atf_tc_set_md_var(tc, "timeout", "65"); 198272343Sngie} 199272343Sngie 200272343SngieATF_TC_BODY(nanosleep, tc) 201272343Sngie{ 202272343Sngie 203272343Sngie sleeptest(do_nanosleep, true, false); 204272343Sngie} 205272343Sngie 206272343SngieATF_TC(select); 207272343SngieATF_TC_HEAD(select, tc) 208272343Sngie{ 209272343Sngie 210272343Sngie atf_tc_set_md_var(tc, "descr", "Test select(2) timing"); 211272343Sngie atf_tc_set_md_var(tc, "timeout", "65"); 212272343Sngie} 213272343Sngie 214272343SngieATF_TC_BODY(select, tc) 215272343Sngie{ 216272343Sngie 217272343Sngie sleeptest(do_select, true, true); 218272343Sngie} 219272343Sngie 220276478Sngie#ifdef __NetBSD__ 221272343SngieATF_TC(poll); 222272343SngieATF_TC_HEAD(poll, tc) 223272343Sngie{ 224272343Sngie 225272343Sngie atf_tc_set_md_var(tc, "descr", "Test poll(2) timing"); 226272343Sngie atf_tc_set_md_var(tc, "timeout", "65"); 227272343Sngie} 228272343Sngie 229272343SngieATF_TC_BODY(poll, tc) 230272343Sngie{ 231272343Sngie 232272343Sngie sleeptest(do_poll, true, true); 233272343Sngie} 234276478Sngie#endif 235272343Sngie 236272343SngieATF_TC(sleep); 237272343SngieATF_TC_HEAD(sleep, tc) 238272343Sngie{ 239272343Sngie 240272343Sngie atf_tc_set_md_var(tc, "descr", "Test sleep(3) timing"); 241272343Sngie atf_tc_set_md_var(tc, "timeout", "65"); 242272343Sngie} 243272343Sngie 244272343SngieATF_TC_BODY(sleep, tc) 245272343Sngie{ 246272343Sngie 247272343Sngie sleeptest(do_sleep, false, false); 248272343Sngie} 249272343Sngie 250272343SngieATF_TC(kevent); 251272343SngieATF_TC_HEAD(kevent, tc) 252272343Sngie{ 253272343Sngie 254272343Sngie atf_tc_set_md_var(tc, "descr", "Test kevent(2) timing"); 255272343Sngie atf_tc_set_md_var(tc, "timeout", "65"); 256272343Sngie} 257272343Sngie 258272343SngieATF_TC_BODY(kevent, tc) 259272343Sngie{ 260272343Sngie 261272343Sngie sleeptest(do_kevent, true, true); 262272343Sngie} 263272343Sngie 264272343Sngieint 265272343Sngiesleeptest(int (*test)(struct timespec *, struct timespec *), 266272343Sngie bool subsec, bool sim_remain) 267272343Sngie{ 268272343Sngie struct timespec tsa, tsb, tslp, tremain; 269272343Sngie int64_t delta1, delta2, delta3, round; 270272343Sngie 271272343Sngie sig = 0; 272272343Sngie signal(SIGALRM, sigalrm); 273272343Sngie 274272343Sngie if (subsec) { 275272343Sngie round = 1; 276272343Sngie delta3 = FUZZ; 277272343Sngie } else { 278272343Sngie round = 1000000000; 279272343Sngie delta3 = round; 280272343Sngie } 281272343Sngie 282272343Sngie tslp.tv_sec = delta3 / 1000000000; 283272343Sngie tslp.tv_nsec = delta3 % 1000000000; 284272343Sngie 285272343Sngie while (tslp.tv_sec <= MAXSLEEP) { 286272343Sngie /* 287272343Sngie * disturb sleep by signal on purpose 288272343Sngie */ 289272343Sngie if (tslp.tv_sec > ALARM && sig == 0) 290272343Sngie alarm(ALARM); 291272343Sngie 292272343Sngie clock_gettime(CLOCK_REALTIME, &tsa); 293272343Sngie (*test)(&tslp, &tremain); 294272343Sngie clock_gettime(CLOCK_REALTIME, &tsb); 295272343Sngie 296272343Sngie if (sim_remain) { 297272343Sngie timespecsub(&tsb, &tsa, &tremain); 298272343Sngie timespecsub(&tslp, &tremain, &tremain); 299272343Sngie } 300272343Sngie 301272343Sngie delta1 = (int64_t)tsb.tv_sec - (int64_t)tsa.tv_sec; 302272343Sngie delta1 *= BILLION; 303272343Sngie delta1 += (int64_t)tsb.tv_nsec - (int64_t)tsa.tv_nsec; 304272343Sngie 305272343Sngie delta2 = (int64_t)tremain.tv_sec * BILLION; 306272343Sngie delta2 += (int64_t)tremain.tv_nsec; 307272343Sngie 308272343Sngie delta3 = (int64_t)tslp.tv_sec * BILLION; 309272343Sngie delta3 += (int64_t)tslp.tv_nsec - delta1 - delta2; 310272343Sngie 311272343Sngie delta3 /= round; 312272343Sngie delta3 *= round; 313272343Sngie 314272343Sngie if (delta3 > FUZZ || delta3 < -FUZZ) { 315272343Sngie if (!sim_remain) 316272343Sngie atf_tc_expect_fail("Long reschedule latency " 317272343Sngie "due to PR kern/43997"); 318272343Sngie 319272343Sngie atf_tc_fail("Reschedule latency %"PRId64" exceeds " 320272343Sngie "allowable fuzz %lld", delta3, FUZZ); 321272343Sngie } 322272343Sngie delta3 = (int64_t)tslp.tv_sec * 2 * BILLION; 323272343Sngie delta3 += (int64_t)tslp.tv_nsec * 2; 324272343Sngie 325272343Sngie delta3 /= round; 326272343Sngie delta3 *= round; 327272343Sngie if (delta3 < FUZZ) 328272343Sngie break; 329272343Sngie tslp.tv_sec = delta3 / BILLION; 330272343Sngie tslp.tv_nsec = delta3 % BILLION; 331272343Sngie } 332272343Sngie ATF_REQUIRE_MSG(sig == 1, "Alarm did not fire!"); 333272343Sngie 334272343Sngie atf_tc_pass(); 335272343Sngie} 336272343Sngie 337272343SngieATF_TP_ADD_TCS(tp) 338272343Sngie{ 339272343Sngie ATF_TP_ADD_TC(tp, nanosleep); 340272343Sngie ATF_TP_ADD_TC(tp, select); 341276478Sngie#ifdef __NetBSD__ 342272343Sngie ATF_TP_ADD_TC(tp, poll); 343276478Sngie#endif 344272343Sngie ATF_TP_ADD_TC(tp, sleep); 345272343Sngie ATF_TP_ADD_TC(tp, kevent); 346272343Sngie 347272343Sngie return atf_no_error(); 348272343Sngie} 349