diff options
Diffstat (limited to '')
-rw-r--r-- | bin/tests/virtual-time/vtwrapper.c | 301 |
1 files changed, 301 insertions, 0 deletions
diff --git a/bin/tests/virtual-time/vtwrapper.c b/bin/tests/virtual-time/vtwrapper.c new file mode 100644 index 0000000..36471f2 --- /dev/null +++ b/bin/tests/virtual-time/vtwrapper.c @@ -0,0 +1,301 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + + +#define _GNU_SOURCE +#include <sys/syscall.h> +#include <sys/time.h> +#include <sys/types.h> +#include <math.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#ifdef SYS_select +#include <sys/select.h> +#endif +#ifdef SYS_poll +#include <poll.h> +#endif +#ifdef SYS_kevent +#include <sys/event.h> +#endif +#ifdef SYS_epoll_wait +#include <sys/epoll.h> +#endif + + +#ifdef SYS_gettimeofday +#define VIRTUAL_TIME +#ifdef VIRTUAL_TIME +static struct timeval epoch = { 0, 0 }; +static int _init_called = 0; + +void +_init(void) { + (void)syscall(SYS_gettimeofday, &epoch, NULL); + _init_called = 1; +} + +static void +absolute_inflate(struct timeval *vt, struct timeval *rt) +{ + double d; + + rt->tv_sec = vt->tv_sec; + rt->tv_usec = vt->tv_usec; + + if ((epoch.tv_sec > vt->tv_sec) || + ((epoch.tv_sec == vt->tv_sec) && (epoch.tv_usec > vt->tv_usec))) + return; + + rt->tv_sec -= epoch.tv_sec; + rt->tv_usec -= epoch.tv_usec; + while (rt->tv_usec < 0) { + rt->tv_sec -= 1; + rt->tv_usec += 1000000; + } + + if (rt->tv_sec == 0) + goto done; + + d = (double) (rt->tv_sec - 1); + d += (double) rt->tv_usec / 1000000.; + d = exp(d); + rt->tv_sec = (time_t) d; + d -= (double) rt->tv_sec; + rt->tv_usec = (suseconds_t) (d * 1000000.); + + done: + rt->tv_sec += epoch.tv_sec; + rt->tv_usec += epoch.tv_usec; + while (rt->tv_usec >= 1000000) { + rt->tv_sec += 1; + rt->tv_usec -= 1000000; + } + return; +} + +static void +absolute_deflate(struct timeval *rt, struct timeval *vt) { + double d; + + vt->tv_sec = rt->tv_sec; + vt->tv_usec = rt->tv_usec; + + if ((epoch.tv_sec > rt->tv_sec) || + ((epoch.tv_sec == rt->tv_sec) && (epoch.tv_usec > rt->tv_usec))) + return; + + vt->tv_sec -= epoch.tv_sec; + vt->tv_usec -= epoch.tv_usec; + while (vt->tv_usec < 0) { + vt->tv_sec -= 1; + vt->tv_usec += 1000000; + } + + if (vt->tv_sec == 0) + goto done; + + d = (double) vt->tv_sec; + d += (double) vt->tv_usec / 1000000.; + d = log(d); + vt->tv_sec = (time_t) d; + d -= (double) vt->tv_sec; + vt->tv_sec += 1; + vt->tv_usec = (suseconds_t) (d * 1000000.); + + done: + vt->tv_sec += epoch.tv_sec; + vt->tv_usec += epoch.tv_usec; + while (vt->tv_usec >= 1000000) { + vt->tv_sec += 1; + vt->tv_usec -= 1000000; + } + return; +} + +static void +interval_inflate(struct timeval *vt, struct timeval *rt) { + struct timeval now, tv; + + (void) gettimeofday(&now, NULL); + + absolute_deflate(&now, &tv); + + tv.tv_sec += vt->tv_sec; + tv.tv_usec += vt->tv_usec; + while (tv.tv_usec >= 1000000) { + tv.tv_sec += 1; + tv.tv_usec -= 1000000; + } + + absolute_inflate(&tv, rt); + + rt->tv_sec -= now.tv_sec; + rt->tv_usec -= now.tv_usec; + if (rt->tv_usec < 0) { + rt->tv_sec -= 1; + rt->tv_usec += 1000000; + } + return; +} + +static void +interval_deflate(struct timeval *rt, struct timeval *vt) { + struct timeval now, tv; + + vt->tv_sec = rt->tv_sec; + vt->tv_usec = rt->tv_usec; + + if ((vt->tv_sec == 0) && (vt->tv_usec <= 10000)) + return; + + (void) gettimeofday(&now, NULL); + + tv.tv_sec = now.tv_sec + rt->tv_sec; + tv.tv_usec = now.tv_usec + rt->tv_usec; + while (tv.tv_usec >= 1000000) { + tv.tv_sec += 1; + tv.tv_usec -= 1000000; + } + + absolute_deflate(&now, &now); + absolute_deflate(&tv, vt); + + vt->tv_sec -= now.tv_sec; + vt->tv_usec -= now.tv_usec; + while (vt->tv_usec < 0) { + vt->tv_sec -= 1; + vt->tv_usec += 1000000; + } + + if ((vt->tv_sec == 0) && (vt->tv_usec < 10000)) + vt->tv_usec = 10000; + return; +} +#endif + +int +gettimeofday(struct timeval *tv, struct timezone *tz) { +#ifdef VIRTUAL_TIME + struct timeval now; + int ret; + + if (!_init_called) _init(); + + if (epoch.tv_sec == 0) + return syscall(SYS_gettimeofday, tv, tz); + + ret = syscall(SYS_gettimeofday, &now, tz); + if (ret == 0) + absolute_inflate(&now, tv); + return ret; +#else + return syscall(SYS_gettimeofday, tv, tz); +#endif +} + +#ifdef SYS_select +int +select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *xfds, + struct timeval *timeout) +{ +#ifdef VIRTUAL_TIME + struct timeval tv; + + if (!_init_called) _init(); + + if (epoch.tv_sec == 0 || timeout == NULL || + (timeout->tv_sec == 0 && timeout->tv_usec == 0)) + return syscall(SYS_select, nfds, rfds, wfds, xfds, timeout); + + interval_deflate(timeout, &tv); + return syscall(SYS_select, nfds, rfds, wfds, xfds, &tv); +#else + return syscall(SYS_select, nfds, rfds, wfds, xfds, timeout); +#endif +} +#endif + +#ifdef SYS_poll +int +poll(struct pollfd fds[], nfds_t nfds, int timeout) { +#ifdef VIRTUAL_TIME + struct timeval in, out; + + if (!_init_called) _init(); + + if (timeout <= 0 || epoch.tv_sec == 0) + return syscall(SYS_poll, fds, nfds, timeout); + + in.tv_sec = timeout / 1000; + in.tv_usec = (timeout % 1000) * 1000; + interval_deflate(&in, &out); + timeout = out.tv_sec * 1000 + out.tv_usec / 1000; + return syscall(SYS_poll, fds, nfds, timeout); +#else + return syscall(SYS_poll, fds, nfds, timeout); +#endif +} +#endif + +#ifdef SYS_kevent +int +kevent(int kq, struct kevent *changelist, int nchanges, + struct kevent *eventlist, int nevents, const struct timespec *timeout) +{ +#ifdef VIRTUAL_TIME + struct timeval in, out; + struct timespec ts; + + if (!_init_called) _init(); + + if (epoch.tv_sec == 0 || timeout == NULL || + (timeout->tv_sec == 0 && timeout->tv_nsec == 0)) + return syscall(SYS_kevent, kq, changelist, nchanges, + eventlist, nevents, timeout); + + in.tv_sec = timeout->tv_sec; + in.tv_usec = timeout->tv_nsec / 1000; + interval_deflate(&in, &out); + ts.tv_sec = out.tv_sec; + ts.tv_nsec = out.tv_usec * 1000; + return syscall(SYS_kevent, kq, changelist, nchanges, eventlist, + nevents, &ts); +#else + return syscall(SYS_kevent, kq, changelist, nchanges, eventlist, + nevents, timeout); +#endif +} +#endif + +#ifdef SYS_epoll_wait +int +epoll_wait(int fd, struct epoll_event *events, int maxevents, int timeout) { +#ifdef VIRTUAL_TIME + struct timeval in, out; + + if (!_init_called) _init(); + + if (timeout == 0 || timeout == -1 || epoch.tv_sec == 0) + return syscall(SYS_epoll_wait, fd, events, maxevents, timeout); + + in.tv_sec = timeout / 1000; + in.tv_usec = (timeout % 1000) * 1000; + interval_deflate(&in, &out); + timeout = out.tv_sec * 1000 + out.tv_usec / 1000; + return syscall(SYS_poll, fd, events, maxevents, timeout); +#else + return syscall(SYS_poll, fd, events, maxevents, timeout); +#endif +} +#endif +#endif |