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