NetBSD-5.0.2/regress/sys/kern/sleeping/sleeptest.c
/* $NetBSD: sleeptest.c,v 1.2 2006/07/16 22:18:46 kardel Exp $ */
/*-
* Copyright (c) 2006 Frank Kardel
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/event.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>
#include <sys/signal.h>
#include <string.h>
#include <err.h>
#define FUZZ 30000000LL /* scheduling fuzz accepted - 30 ms */
#define MAXSLEEP 32000000000LL /* 32 seconds */
#define ALARM 11 /* SIGALRM after this time */
#define KEVNT_TIMEOUT 13200
static int sig, sigs;
static char *sleepers[] = {
"nanosleep",
"select",
"poll",
"sleep",
"kevent"
};
#define N_SLEEPERS (sizeof(sleepers)/sizeof(sleepers[0]))
void
sigalrm()
{
sig++;
}
int
main(int argc, char *argv[])
{
struct timespec tsa, tsb, tslp, tslplast, tremain;
struct timeval tv;
int64_t delta1, delta2, delta3, round;
int errors = 0, i;
char *rtype;
printf("Testing sleep/timeout implementations\n");
printf("accepted scheduling delta %lld ms\n", FUZZ/ 1000000LL);
printf("testing up to %lld ms for %d interfaces\n", MAXSLEEP / 1000000LL, N_SLEEPERS);
printf("ALARM interrupt after %d sec once per run\n", ALARM);
printf("kevent timer will fire after %d ms\n", KEVNT_TIMEOUT);
signal(SIGALRM, sigalrm);
for (i = 0; i < N_SLEEPERS; i++) {
switch (i) {
case 3: /* sleep has only second resolution */
round = 1000000000;
delta3 = round;
break;
default:
round = 1;
delta3 = FUZZ;
break;
}
sigs += sig;
sig = 0;
rtype = "simulated";
tslp.tv_sec = delta3 / 1000000000;
tslp.tv_nsec = delta3 % 1000000000;
tslplast = tslp;
while (delta3 <= MAXSLEEP) {
printf("[%s] sleeping %lld nsec ... ", sleepers[i], delta3);
/*
* disturb sleep by signal on purpose
*/
if (delta3 > ALARM * 1000000000LL && sig == 0)
alarm(ALARM);
fflush(stdout);
clock_gettime(CLOCK_REALTIME, &tsa);
switch (i) {
case 0: /* nanosleep */
rtype = "returned";
if (nanosleep(&tslp, &tremain) == -1) {
if (errno != EINTR)
errors++;
printf("- errno=%s (%s) - ", strerror(errno), (errno == EINTR) ? "OK" : "ERROR");
}
clock_gettime(CLOCK_REALTIME, &tsb);
break;
case 1: /* select */
TIMESPEC_TO_TIMEVAL(&tv, &tslp);
if (select(0, NULL, NULL, NULL, &tv) == -1) {
if (errno != EINTR)
errors++;
printf("- errno=%s (%s) - ", strerror(errno), (errno == EINTR) ? "OK" : "ERROR");
}
/* simulate remaining time */
clock_gettime(CLOCK_REALTIME, &tsb);
timespecsub(&tsb, &tsa, &tremain);
timespecsub(&tslp, &tremain, &tremain);
break;
case 2: /* poll */
TIMESPEC_TO_TIMEVAL(&tv, &tslp);
if (pollts(NULL, 0, &tslp, NULL) == -1) {
if (errno != EINTR)
errors++;
printf("- errno=%s (%s) - ", strerror(errno), (errno == EINTR) ? "OK" : "ERROR");
}
/* simulate remaining time */
clock_gettime(CLOCK_REALTIME, &tsb);
timespecsub(&tsb, &tsa, &tremain);
timespecsub(&tslp, &tremain, &tremain);
break;
case 3: /* sleep */
rtype = "returned";
tremain.tv_sec = sleep(tslp.tv_sec);
tremain.tv_nsec = 0;
clock_gettime(CLOCK_REALTIME, &tsb);
break;
case 4: /* kevent */
{
struct kevent ktimer;
struct kevent kresult;
int rtc, timeout = KEVNT_TIMEOUT;
int kq = kqueue();
if (kq == -1) {
err(EXIT_FAILURE, "kqueue");
}
EV_SET(&ktimer, 1, EVFILT_TIMER, EV_ADD, 0, timeout, 0);
rtc = kevent(kq, &ktimer, 1, &kresult, 1, &tslp);
if (rtc == -1) {
if (errno != EINTR)
errors++;
printf("- errno=%s (%s) - ", strerror(errno), (errno == EINTR) ? "OK" : "ERROR");
}
clock_gettime(CLOCK_REALTIME, &tsb);
if (rtc == 0) {
printf("- not fired");
if (tslp.tv_sec * 1000000000LL + tslp.tv_nsec -
timeout * 1000000LL > 0) {
printf(" - TIMING ERROR");
errors++;
}
printf(" - ");
} else if (rtc > 0) {
printf("- fired - ");
}
timespecsub(&tsb, &tsa, &tremain);
timespecsub(&tslp, &tremain, &tremain);
(void)close(kq);
}
break;
default:
errx(EXIT_FAILURE, "programming error - sleep method to test not implemented\n");
}
delta1 = ((int64_t)tsb.tv_sec - (int64_t)tsa.tv_sec) * 1000000000LL + (int64_t)tsb.tv_nsec - (int64_t)tsa.tv_nsec;
delta2 = (((int64_t)tremain.tv_sec * 1000000000LL) + (int64_t)tremain.tv_nsec);
delta3 = (int64_t)tslp.tv_sec * 1000000000LL + (int64_t)tslp.tv_nsec - delta1 - delta2;
printf("sig %d, real time sleep %lld nsec, remain(%s) %lld nsec, diff to supposed sleep %lld nsec (rounded %lld nsec)",
sigs + sig, delta1, rtype, delta2, delta3, (delta3 / round) * round);
fflush(stdout);
delta3 /= round;
delta3 *= round;
if (delta3 > FUZZ || delta3 < -FUZZ) {
errors++;
printf(" ERROR\n");
delta3 = ((int64_t)tslp.tv_sec + (int64_t)tslplast.tv_sec) * 1000000000LL + (int64_t)tslplast.tv_nsec
+ (int64_t)tslp.tv_nsec;
delta3 /= 2;
} else {
printf(" OK\n");
tslplast = tslp;
delta3 = ((int64_t)tslp.tv_sec + (int64_t)tslplast.tv_sec) * 1000000000LL + (int64_t)tslplast.tv_nsec
+ (int64_t)tslp.tv_nsec;
}
delta3 /= round;
delta3 *= round;
if (delta3 < FUZZ)
break;
tslp.tv_sec = delta3 / 1000000000LL;
tslp.tv_nsec = delta3 % 1000000000LL;
}
}
sigs += sig;
if (errors || sigs != N_SLEEPERS) {
printf("TEST FAIL (%d errors, %d alarms, %d interfaces)\n", errors, sigs, N_SLEEPERS);
return 1;
} else {
printf("TEST SUCCESSFUL\n");
return 0;
}
}