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