1/* $NetBSD: vtwrapper.c,v 1.2.6.1 2012/06/05 21:15:54 bouyer Exp $ */ 2 3/* 4 * Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC") 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 11 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 12 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 13 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 14 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 15 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19/* Id: vtwrapper.c,v 1.4 2010/08/12 09:31:50 fdupont Exp */ 20 21#define _GNU_SOURCE 22#include <sys/syscall.h> 23#include <sys/time.h> 24#include <sys/types.h> 25#include <math.h> 26#include <unistd.h> 27#include <stdlib.h> 28#include <stdio.h> 29#ifdef SYS_select 30#include <sys/select.h> 31#endif 32#ifdef SYS_poll 33#include <poll.h> 34#endif 35#ifdef SYS_kevent 36#include <sys/event.h> 37#endif 38#ifdef SYS_epoll_wait 39#include <sys/epoll.h> 40#endif 41 42 43#ifdef SYS_gettimeofday 44#define VIRTUAL_TIME 45#ifdef VIRTUAL_TIME 46static struct timeval epoch = { 0, 0 }; 47static int _init_called = 0; 48 49void 50_init(void) { 51 (void)syscall(SYS_gettimeofday, &epoch, NULL); 52 _init_called = 1; 53} 54 55static void 56absolute_inflate(struct timeval *vt, struct timeval *rt) 57{ 58 double d; 59 60 rt->tv_sec = vt->tv_sec; 61 rt->tv_usec = vt->tv_usec; 62 63 if ((epoch.tv_sec > vt->tv_sec) || 64 ((epoch.tv_sec == vt->tv_sec) && (epoch.tv_usec > vt->tv_usec))) 65 return; 66 67 rt->tv_sec -= epoch.tv_sec; 68 rt->tv_usec -= epoch.tv_usec; 69 while (rt->tv_usec < 0) { 70 rt->tv_sec -= 1; 71 rt->tv_usec += 1000000; 72 } 73 74 if (rt->tv_sec == 0) 75 goto done; 76 77 d = (double) (rt->tv_sec - 1); 78 d += (double) rt->tv_usec / 1000000.; 79 d = exp(d); 80 rt->tv_sec = (time_t) d; 81 d -= (double) rt->tv_sec; 82 rt->tv_usec = (suseconds_t) (d * 1000000.); 83 84 done: 85 rt->tv_sec += epoch.tv_sec; 86 rt->tv_usec += epoch.tv_usec; 87 while (rt->tv_usec >= 1000000) { 88 rt->tv_sec += 1; 89 rt->tv_usec -= 1000000; 90 } 91 return; 92} 93 94static void 95absolute_deflate(struct timeval *rt, struct timeval *vt) { 96 double d; 97 98 vt->tv_sec = rt->tv_sec; 99 vt->tv_usec = rt->tv_usec; 100 101 if ((epoch.tv_sec > rt->tv_sec) || 102 ((epoch.tv_sec == rt->tv_sec) && (epoch.tv_usec > rt->tv_usec))) 103 return; 104 105 vt->tv_sec -= epoch.tv_sec; 106 vt->tv_usec -= epoch.tv_usec; 107 while (vt->tv_usec < 0) { 108 vt->tv_sec -= 1; 109 vt->tv_usec += 1000000; 110 } 111 112 if (vt->tv_sec == 0) 113 goto done; 114 115 d = (double) vt->tv_sec; 116 d += (double) vt->tv_usec / 1000000.; 117 d = log(d); 118 vt->tv_sec = (time_t) d; 119 d -= (double) vt->tv_sec; 120 vt->tv_sec += 1; 121 vt->tv_usec = (suseconds_t) (d * 1000000.); 122 123 done: 124 vt->tv_sec += epoch.tv_sec; 125 vt->tv_usec += epoch.tv_usec; 126 while (vt->tv_usec >= 1000000) { 127 vt->tv_sec += 1; 128 vt->tv_usec -= 1000000; 129 } 130 return; 131} 132 133static void 134interval_inflate(struct timeval *vt, struct timeval *rt) { 135 struct timeval now, tv; 136 137 (void) gettimeofday(&now, NULL); 138 139 absolute_deflate(&now, &tv); 140 141 tv.tv_sec += vt->tv_sec; 142 tv.tv_usec += vt->tv_usec; 143 while (tv.tv_usec >= 1000000) { 144 tv.tv_sec += 1; 145 tv.tv_usec -= 1000000; 146 } 147 148 absolute_inflate(&tv, rt); 149 150 rt->tv_sec -= now.tv_sec; 151 rt->tv_usec -= now.tv_usec; 152 if (rt->tv_usec < 0) { 153 rt->tv_sec -= 1; 154 rt->tv_usec += 1000000; 155 } 156 return; 157} 158 159static void 160interval_deflate(struct timeval *rt, struct timeval *vt) { 161 struct timeval now, tv; 162 163 vt->tv_sec = rt->tv_sec; 164 vt->tv_usec = rt->tv_usec; 165 166 if ((vt->tv_sec == 0) && (vt->tv_usec <= 10000)) 167 return; 168 169 (void) gettimeofday(&now, NULL); 170 171 tv.tv_sec = now.tv_sec + rt->tv_sec; 172 tv.tv_usec = now.tv_usec + rt->tv_usec; 173 while (tv.tv_usec >= 1000000) { 174 tv.tv_sec += 1; 175 tv.tv_usec -= 1000000; 176 } 177 178 absolute_deflate(&now, &now); 179 absolute_deflate(&tv, vt); 180 181 vt->tv_sec -= now.tv_sec; 182 vt->tv_usec -= now.tv_usec; 183 while (vt->tv_usec < 0) { 184 vt->tv_sec -= 1; 185 vt->tv_usec += 1000000; 186 } 187 188 if ((vt->tv_sec == 0) && (vt->tv_usec < 10000)) 189 vt->tv_usec = 10000; 190 return; 191} 192#endif 193 194int 195gettimeofday(struct timeval *tv, struct timezone *tz) { 196#ifdef VIRTUAL_TIME 197 struct timeval now; 198 int ret; 199 200 if (!_init_called) _init(); 201 202 if (epoch.tv_sec == 0) 203 return syscall(SYS_gettimeofday, tv, tz); 204 205 ret = syscall(SYS_gettimeofday, &now, tz); 206 if (ret == 0) 207 absolute_inflate(&now, tv); 208 return ret; 209#else 210 return syscall(SYS_gettimeofday, tv, tz); 211#endif 212} 213 214#ifdef SYS_select 215int 216select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *xfds, 217 struct timeval *timeout) 218{ 219#ifdef VIRTUAL_TIME 220 struct timeval tv; 221 222 if (!_init_called) _init(); 223 224 if (epoch.tv_sec == 0 || timeout == NULL || 225 (timeout->tv_sec == 0 && timeout->tv_usec == 0)) 226 return syscall(SYS_select, nfds, rfds, wfds, xfds, timeout); 227 228 interval_deflate(timeout, &tv); 229 return syscall(SYS_select, nfds, rfds, wfds, xfds, &tv); 230#else 231 return syscall(SYS_select, nfds, rfds, wfds, xfds, timeout); 232#endif 233} 234#endif 235 236#ifdef SYS_poll 237int 238poll(struct pollfd fds[], nfds_t nfds, int timeout) { 239#ifdef VIRTUAL_TIME 240 struct timeval in, out; 241 242 if (!_init_called) _init(); 243 244 if (timeout <= 0 || epoch.tv_sec == 0) 245 return syscall(SYS_poll, fds, nfds, timeout); 246 247 in.tv_sec = timeout / 1000; 248 in.tv_usec = (timeout % 1000) * 1000; 249 interval_deflate(&in, &out); 250 timeout = out.tv_sec * 1000 + out.tv_usec / 1000; 251 return syscall(SYS_poll, fds, nfds, timeout); 252#else 253 return syscall(SYS_poll, fds, nfds, timeout); 254#endif 255} 256#endif 257 258#ifdef SYS_kevent 259int 260kevent(int kq, struct kevent *changelist, int nchanges, 261 struct kevent *eventlist, int nevents, const struct timespec *timeout) 262{ 263#ifdef VIRTUAL_TIME 264 struct timeval in, out; 265 struct timespec ts; 266 267 if (!_init_called) _init(); 268 269 if (epoch.tv_sec == 0 || timeout == NULL || 270 (timeout->tv_sec == 0 && timeout->tv_nsec == 0)) 271 return syscall(SYS_kevent, kq, changelist, nchanges, 272 eventlist, nevents, timeout); 273 274 in.tv_sec = timeout->tv_sec; 275 in.tv_usec = timeout->tv_nsec / 1000; 276 interval_deflate(&in, &out); 277 ts.tv_sec = out.tv_sec; 278 ts.tv_nsec = out.tv_usec * 1000; 279 return syscall(SYS_kevent, kq, changelist, nchanges, eventlist, 280 nevents, &ts); 281#else 282 return syscall(SYS_kevent, kq, changelist, nchanges, eventlist, 283 nevents, timeout); 284#endif 285} 286#endif 287 288#ifdef SYS_epoll_wait 289int 290epoll_wait(int fd, struct epoll_event *events, int maxevents, int timeout) { 291#ifdef VIRTUAL_TIME 292 struct timeval in, out; 293 294 if (!_init_called) _init(); 295 296 if (timeout == 0 || timeout == -1 || epoch.tv_sec == 0) 297 return syscall(SYS_epoll_wait, fd, events, maxevents, timeout); 298 299 in.tv_sec = timeout / 1000; 300 in.tv_usec = (timeout % 1000) * 1000; 301 interval_deflate(&in, &out); 302 timeout = out.tv_sec * 1000 + out.tv_usec / 1000; 303 return syscall(SYS_poll, fd, events, maxevents, timeout); 304#else 305 return syscall(SYS_poll, fd, events, maxevents, timeout); 306#endif 307} 308#endif 309#endif 310