1 /* $NetBSD: vtwrapper.c,v 1.4 2014/12/10 04:37:54 christos 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
46 static struct timeval epoch = { 0, 0 };
47 static int _init_called = 0;
48
49 void
_init(void)50 _init(void) {
51 (void)syscall(SYS_gettimeofday, &epoch, NULL);
52 _init_called = 1;
53 }
54
55 static void
absolute_inflate(struct timeval * vt,struct timeval * rt)56 absolute_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
94 static void
absolute_deflate(struct timeval * rt,struct timeval * vt)95 absolute_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
133 static void
interval_inflate(struct timeval * vt,struct timeval * rt)134 interval_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
159 static void
interval_deflate(struct timeval * rt,struct timeval * vt)160 interval_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
194 int
gettimeofday(struct timeval * tv,struct timezone * tz)195 gettimeofday(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
215 int
select(int nfds,fd_set * rfds,fd_set * wfds,fd_set * xfds,struct timeval * timeout)216 select(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
237 int
poll(struct pollfd fds[],nfds_t nfds,int timeout)238 poll(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
259 int
kevent(int kq,struct kevent * changelist,int nchanges,struct kevent * eventlist,int nevents,const struct timespec * timeout)260 kevent(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
289 int
epoll_wait(int fd,struct epoll_event * events,int maxevents,int timeout)290 epoll_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