1 /* $NetBSD: t_sleep.c,v 1.5 2012/11/09 20:13:24 pgoyette Exp $ */ 2 3 /*- 4 * Copyright (c) 2006 Frank Kardel 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <atf-c.h> 30 #include <errno.h> 31 #include <poll.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <time.h> 36 #include <unistd.h> 37 38 #include <sys/cdefs.h> 39 #include <sys/event.h> 40 #include <sys/signal.h> 41 42 #define BILLION 1000000000LL /* nano-seconds per second */ 43 #define MILLION 1000000LL /* nano-seconds per milli-second */ 44 45 #define ALARM 6 /* SIGALRM after this many seconds */ 46 #define MAXSLEEP 22 /* Maximum delay in seconds */ 47 #define KEVNT_TIMEOUT 10300 /* measured in milli-seconds */ 48 #define FUZZ (40 * MILLION) /* scheduling fuzz accepted - 40 ms */ 49 50 /* 51 * Timer notes 52 * 53 * Most tests use FUZZ as their initial delay value, but 'sleep' 54 * starts at 1sec (since it cannot handle sub-second intervals). 55 * Subsequent passes double the previous interval, up to MAXSLEEP. 56 * 57 * The current values result in 5 passes for the 'sleep' test (at 1, 58 * 2, 4, 8, and 16 seconds) and 10 passes for the other tests (at 59 * 0.04, 0.08, 0.16, 0.32, 0.64, 1.28, 2.56, 5.12, 10.24, and 20.48 60 * seconds). 61 * 62 * The ALARM is only set if the current pass's delay is longer, and 63 * only if the ALARM has not already been triggered. 64 * 65 * The 'kevent' test needs the ALARM to be set on a different pass 66 * from when the KEVNT_TIMEOUT fires. So set ALARM to fire on the 67 * penultimate pass, and the KEVNT_TIMEOUT on the final pass. We 68 * set KEVNT_TIMEOUT just barely long enough to put it into the 69 * last test pass, and set MAXSLEEP a couple seconds longer than 70 * necessary,in order to avoid a QEMU bug which nearly doubles 71 * some timers. 72 */ 73 74 static volatile int sig; 75 76 int sleeptest(int (*)(struct timespec *, struct timespec *), bool, bool); 77 int do_nanosleep(struct timespec *, struct timespec *); 78 int do_select(struct timespec *, struct timespec *); 79 int do_poll(struct timespec *, struct timespec *); 80 int do_sleep(struct timespec *, struct timespec *); 81 int do_kevent(struct timespec *, struct timespec *); 82 void sigalrm(int); 83 84 void 85 sigalrm(int s) 86 { 87 88 sig++; 89 } 90 91 int 92 do_nanosleep(struct timespec *delay, struct timespec *remain) 93 { 94 int ret; 95 96 if (nanosleep(delay, remain) == -1) 97 ret = (errno == EINTR ? 0 : errno); 98 else 99 ret = 0; 100 return ret; 101 } 102 103 int 104 do_select(struct timespec *delay, struct timespec *remain) 105 { 106 int ret; 107 struct timeval tv; 108 109 TIMESPEC_TO_TIMEVAL(&tv, delay); 110 if (select(0, NULL, NULL, NULL, &tv) == -1) 111 ret = (errno == EINTR ? 0 : errno); 112 else 113 ret = 0; 114 return ret; 115 } 116 117 int 118 do_poll(struct timespec *delay, struct timespec *remain) 119 { 120 int ret; 121 struct timeval tv; 122 123 TIMESPEC_TO_TIMEVAL(&tv, delay); 124 if (pollts(NULL, 0, delay, NULL) == -1) 125 ret = (errno == EINTR ? 0 : errno); 126 else 127 ret = 0; 128 return ret; 129 } 130 131 int 132 do_sleep(struct timespec *delay, struct timespec *remain) 133 { 134 struct timeval tv; 135 136 TIMESPEC_TO_TIMEVAL(&tv, delay); 137 remain->tv_sec = sleep(delay->tv_sec); 138 remain->tv_nsec = 0; 139 140 return 0; 141 } 142 143 int 144 do_kevent(struct timespec *delay, struct timespec *remain) 145 { 146 struct kevent ktimer; 147 struct kevent kresult; 148 int rtc, kq, kerrno; 149 int tmo; 150 151 ATF_REQUIRE_MSG((kq = kqueue()) != -1, "kqueue: %s", strerror(errno)); 152 153 tmo = KEVNT_TIMEOUT; 154 155 /* 156 * If we expect the KEVNT_TIMEOUT to fire, and we're running 157 * under QEMU, make sure the delay is long enough to account 158 * for the effects of PR kern/43997 ! 159 */ 160 if (system("cpuctl identify 0 | grep -q QEMU") == 0 && 161 tmo/1000 < delay->tv_sec && tmo/500 > delay->tv_sec) 162 delay->tv_sec = MAXSLEEP; 163 164 EV_SET(&ktimer, 1, EVFILT_TIMER, EV_ADD, 0, tmo, 0); 165 166 rtc = kevent(kq, &ktimer, 1, &kresult, 1, delay); 167 kerrno = errno; 168 169 (void)close(kq); 170 171 if (rtc == -1) { 172 ATF_REQUIRE_MSG(kerrno == EINTR, "kevent: %s", strerror(errno)); 173 return 0; 174 } 175 176 if (delay->tv_sec * BILLION + delay->tv_nsec > tmo * MILLION) 177 ATF_REQUIRE_MSG(rtc > 0, 178 "kevent: KEVNT_TIMEOUT did not cause EVFILT_TIMER event"); 179 180 return 0; 181 } 182 183 ATF_TC(nanosleep); 184 ATF_TC_HEAD(nanosleep, tc) 185 { 186 187 atf_tc_set_md_var(tc, "descr", "Test nanosleep(2) timing"); 188 atf_tc_set_md_var(tc, "timeout", "65"); 189 } 190 191 ATF_TC_BODY(nanosleep, tc) 192 { 193 194 sleeptest(do_nanosleep, true, false); 195 } 196 197 ATF_TC(select); 198 ATF_TC_HEAD(select, tc) 199 { 200 201 atf_tc_set_md_var(tc, "descr", "Test select(2) timing"); 202 atf_tc_set_md_var(tc, "timeout", "65"); 203 } 204 205 ATF_TC_BODY(select, tc) 206 { 207 208 sleeptest(do_select, true, true); 209 } 210 211 ATF_TC(poll); 212 ATF_TC_HEAD(poll, tc) 213 { 214 215 atf_tc_set_md_var(tc, "descr", "Test poll(2) timing"); 216 atf_tc_set_md_var(tc, "timeout", "65"); 217 } 218 219 ATF_TC_BODY(poll, tc) 220 { 221 222 sleeptest(do_poll, true, true); 223 } 224 225 ATF_TC(sleep); 226 ATF_TC_HEAD(sleep, tc) 227 { 228 229 atf_tc_set_md_var(tc, "descr", "Test sleep(3) timing"); 230 atf_tc_set_md_var(tc, "timeout", "65"); 231 } 232 233 ATF_TC_BODY(sleep, tc) 234 { 235 236 sleeptest(do_sleep, false, false); 237 } 238 239 ATF_TC(kevent); 240 ATF_TC_HEAD(kevent, tc) 241 { 242 243 atf_tc_set_md_var(tc, "descr", "Test kevent(2) timing"); 244 atf_tc_set_md_var(tc, "timeout", "65"); 245 } 246 247 ATF_TC_BODY(kevent, tc) 248 { 249 250 sleeptest(do_kevent, true, true); 251 } 252 253 int 254 sleeptest(int (*test)(struct timespec *, struct timespec *), 255 bool subsec, bool sim_remain) 256 { 257 struct timespec tsa, tsb, tslp, tremain; 258 int64_t delta1, delta2, delta3, round; 259 260 sig = 0; 261 signal(SIGALRM, sigalrm); 262 263 if (subsec) { 264 round = 1; 265 delta3 = FUZZ; 266 } else { 267 round = 1000000000; 268 delta3 = round; 269 } 270 271 tslp.tv_sec = delta3 / 1000000000; 272 tslp.tv_nsec = delta3 % 1000000000; 273 274 while (tslp.tv_sec <= MAXSLEEP) { 275 /* 276 * disturb sleep by signal on purpose 277 */ 278 if (tslp.tv_sec > ALARM && sig == 0) 279 alarm(ALARM); 280 281 clock_gettime(CLOCK_REALTIME, &tsa); 282 (*test)(&tslp, &tremain); 283 clock_gettime(CLOCK_REALTIME, &tsb); 284 285 if (sim_remain) { 286 timespecsub(&tsb, &tsa, &tremain); 287 timespecsub(&tslp, &tremain, &tremain); 288 } 289 290 delta1 = (int64_t)tsb.tv_sec - (int64_t)tsa.tv_sec; 291 delta1 *= BILLION; 292 delta1 += (int64_t)tsb.tv_nsec - (int64_t)tsa.tv_nsec; 293 294 delta2 = (int64_t)tremain.tv_sec * BILLION; 295 delta2 += (int64_t)tremain.tv_nsec; 296 297 delta3 = (int64_t)tslp.tv_sec * BILLION; 298 delta3 += (int64_t)tslp.tv_nsec - delta1 - delta2; 299 300 delta3 /= round; 301 delta3 *= round; 302 303 if (delta3 > FUZZ || delta3 < -FUZZ) { 304 if (!sim_remain && 305 system("cpuctl identify 0 | grep -q QEMU") == 0) 306 atf_tc_expect_fail("Long reschedule latency " 307 "due to PR kern/43997"); 308 309 atf_tc_fail("Reschedule latency %"PRId64" exceeds " 310 "allowable fuzz %lld", delta3, FUZZ); 311 } 312 delta3 = (int64_t)tslp.tv_sec * 2 * BILLION; 313 delta3 += (int64_t)tslp.tv_nsec * 2; 314 315 delta3 /= round; 316 delta3 *= round; 317 if (delta3 < FUZZ) 318 break; 319 tslp.tv_sec = delta3 / BILLION; 320 tslp.tv_nsec = delta3 % BILLION; 321 } 322 ATF_REQUIRE_MSG(sig == 1, "Alarm did not fire!"); 323 324 atf_tc_pass(); 325 } 326 327 ATF_TP_ADD_TCS(tp) 328 { 329 ATF_TP_ADD_TC(tp, nanosleep); 330 ATF_TP_ADD_TC(tp, select); 331 ATF_TP_ADD_TC(tp, poll); 332 ATF_TP_ADD_TC(tp, sleep); 333 ATF_TP_ADD_TC(tp, kevent); 334 335 return atf_no_error(); 336 } 337