ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/libev/ev.c
(Generate patch)

Comparing libev/ev.c (file contents):
Revision 1.3 by root, Tue Oct 30 21:45:00 2007 UTC vs.
Revision 1.6 by root, Tue Oct 30 23:55:29 2007 UTC

1#include <math.h> 1#include <math.h>
2#include <stdlib.h> 2#include <stdlib.h>
3 3
4#include <stdio.h> 4#include <stdio.h>
5 5
6#include <assert.h>
6#include <errno.h> 7#include <errno.h>
7#include <sys/time.h> 8#include <sys/time.h>
8#include <time.h> 9#include <time.h>
9 10
10#ifdef CLOCK_MONOTONIC 11#ifdef CLOCK_MONOTONIC
11# define HAVE_MONOTONIC 1 12# define HAVE_MONOTONIC 1
12#endif 13#endif
13 14
15#define HAVE_REALTIME 1
14#define HAVE_EPOLL 1 16#define HAVE_EPOLL 1
15#define HAVE_REALTIME 1
16#define HAVE_SELECT 0 17#define HAVE_SELECT 1
17 18
19#define MIN_TIMEJUMP 1. /* minimum timejump that gets detected (if monotonic clock available) */
18#define MAX_BLOCKTIME 60. 20#define MAX_BLOCKTIME 60.
19 21
20#include "ev.h" 22#include "ev.h"
21 23
22struct ev_watcher { 24struct ev_watcher {
25 27
26struct ev_watcher_list { 28struct ev_watcher_list {
27 EV_WATCHER_LIST (ev_watcher_list); 29 EV_WATCHER_LIST (ev_watcher_list);
28}; 30};
29 31
32static ev_tstamp now, diff; /* monotonic clock */
30ev_tstamp ev_now; 33ev_tstamp ev_now;
31int ev_method; 34int ev_method;
32 35
33static int have_monotonic; /* runtime */ 36static int have_monotonic; /* runtime */
34 37
35static ev_tstamp method_fudge; /* stupid epoll-returns-early bug */ 38static ev_tstamp method_fudge; /* stupid epoll-returns-early bug */
36static void (*method_reify)(void); 39static void (*method_modify)(int fd, int oev, int nev);
37static void (*method_poll)(ev_tstamp timeout); 40static void (*method_poll)(ev_tstamp timeout);
38 41
39ev_tstamp 42ev_tstamp
40ev_time (void) 43ev_time (void)
41{ 44{
129 if (ev) 132 if (ev)
130 event ((struct ev_watcher *)w, ev); 133 event ((struct ev_watcher *)w, ev);
131 } 134 }
132} 135}
133 136
134static struct ev_timer **timers; 137static struct ev_timer **atimers;
135static int timermax, timercnt; 138static int atimermax, atimercnt;
136 139
140static struct ev_timer **rtimers;
141static int rtimermax, rtimercnt;
142
137static void 143static void
138upheap (int k) 144upheap (struct ev_timer **timers, int k)
139{ 145{
140 struct ev_timer *w = timers [k]; 146 struct ev_timer *w = timers [k];
141 147
142 while (k && timers [k >> 1]->at > w->at) 148 while (k && timers [k >> 1]->at > w->at)
143 { 149 {
150 timers [k]->active = k + 1; 156 timers [k]->active = k + 1;
151 157
152} 158}
153 159
154static void 160static void
155downheap (int k) 161downheap (struct ev_timer **timers, int N, int k)
156{ 162{
157 struct ev_timer *w = timers [k]; 163 struct ev_timer *w = timers [k];
158 164
159 while (k < (timercnt >> 1)) 165 while (k < (N >> 1))
160 { 166 {
161 int j = k << 1; 167 int j = k << 1;
162 168
163 if (j + 1 < timercnt && timers [j]->at > timers [j + 1]->at) 169 if (j + 1 < N && timers [j]->at > timers [j + 1]->at)
164 ++j; 170 ++j;
165 171
166 if (w->at <= timers [j]->at) 172 if (w->at <= timers [j]->at)
167 break; 173 break;
168 174
174 timers [k] = w; 180 timers [k] = w;
175 timers [k]->active = k + 1; 181 timers [k]->active = k + 1;
176} 182}
177 183
178static struct ev_signal **signals; 184static struct ev_signal **signals;
179static int signalmax, signalcnt; 185static int signalmax;
180 186
181static void 187static void
182signals_init (struct ev_signal **base, int count) 188signals_init (struct ev_signal **base, int count)
183{ 189{
184 while (count--) 190 while (count--)
201 have_monotonic = 1; 207 have_monotonic = 1;
202 } 208 }
203#endif 209#endif
204 210
205 ev_now = ev_time (); 211 ev_now = ev_time ();
212 now = get_clock ();
213 diff = ev_now - now;
206 214
207#if HAVE_EPOLL 215#if HAVE_EPOLL
208 if (epoll_init (flags)) 216 if (epoll_init (flags))
209 return ev_method; 217 return ev_method;
210#endif 218#endif
226} 234}
227 235
228void ev_postfork_child (void) 236void ev_postfork_child (void)
229{ 237{
230#if HAVE_EPOLL 238#if HAVE_EPOLL
239 if (ev_method == EVMETHOD_EPOLL)
231 epoll_postfork_child (); 240 epoll_postfork_child ();
232#endif 241#endif
242}
243
244static void
245fd_reify (void)
246{
247 int i;
248
249 for (i = 0; i < fdchangecnt; ++i)
250 {
251 int fd = fdchanges [i];
252 ANFD *anfd = anfds + fd;
253 struct ev_io *w;
254
255 int wev = 0;
256
257 for (w = anfd->head; w; w = w->next)
258 wev |= w->events;
259
260 if (anfd->wev != wev)
261 {
262 method_modify (fd, anfd->wev, wev);
263 anfd->wev = wev;
264 }
265 }
266
267 fdchangecnt = 0;
233} 268}
234 269
235static void 270static void
236call_pending () 271call_pending ()
237{ 272{
250 285
251 pendingcnt = 0; 286 pendingcnt = 0;
252} 287}
253 288
254static void 289static void
255timer_reify (void) 290timers_reify (struct ev_timer **timers, int timercnt, ev_tstamp now)
256{ 291{
257 while (timercnt && timers [0]->at <= ev_now) 292 while (timercnt && timers [0]->at <= now)
258 { 293 {
259 struct ev_timer *w = timers [0]; 294 struct ev_timer *w = timers [0];
260 295
261 /* first reschedule timer */ 296 /* first reschedule or stop timer */
262 if (w->repeat) 297 if (w->repeat)
263 { 298 {
264 if (w->is_abs) 299 if (w->is_abs)
265 w->at += ceil ((ev_now - w->at) / w->repeat + 1.) * w->repeat; 300 w->at += floor ((now - w->at) / w->repeat + 1.) * w->repeat;
266 else 301 else
267 w->at = ev_now + w->repeat; 302 w->at = now + w->repeat;
268 303
269 downheap (0); 304 assert (w->at > now);
305
306 downheap (timers, timercnt, 0);
270 } 307 }
271 else 308 else
309 {
272 evtimer_stop (w); /* nonrepeating: stop timer */ 310 evtimer_stop (w); /* nonrepeating: stop timer */
311 --timercnt; /* maybe pass by reference instead? */
312 }
273 313
274 event ((struct ev_watcher *)w, EV_TIMEOUT); 314 event ((struct ev_watcher *)w, EV_TIMEOUT);
275 } 315 }
276} 316}
277 317
318static void
319time_update ()
320{
321 int i;
322 ev_now = ev_time ();
323
324 if (have_monotonic)
325 {
326 ev_tstamp odiff = diff;
327
328 /* detecting time jumps is much more difficult */
329 for (i = 2; --i; ) /* loop a few times, before making important decisions */
330 {
331 now = get_clock ();
332 diff = ev_now - now;
333
334 if (fabs (odiff - diff) < MIN_TIMEJUMP)
335 return; /* all is well */
336
337 ev_now = ev_time ();
338 }
339
340 /* time jump detected, reschedule atimers */
341 for (i = 0; i < atimercnt; ++i)
342 {
343 struct ev_timer *w = atimers [i];
344 w->at += ceil ((ev_now - w->at) / w->repeat + 1.) * w->repeat;
345 }
346 }
347 else
348 {
349 if (now > ev_now || now < ev_now - MAX_BLOCKTIME - MIN_TIMEJUMP)
350 /* time jump detected, adjust rtimers */
351 for (i = 0; i < rtimercnt; ++i)
352 rtimers [i]->at += ev_now - now;
353
354 now = ev_now;
355 }
356}
357
278int ev_loop_done; 358int ev_loop_done;
279 359
280int ev_loop (int flags) 360void ev_loop (int flags)
281{ 361{
282 double block; 362 double block;
283 ev_loop_done = flags & EVLOOP_ONESHOT; 363 ev_loop_done = flags & EVLOOP_ONESHOT;
284 364
285 do 365 do
286 { 366 {
287 /* update fd-related kernel structures */ 367 /* update fd-related kernel structures */
288 method_reify (); fdchangecnt = 0; 368 fd_reify ();
289 369
290 /* calculate blocking time */ 370 /* calculate blocking time */
291 ev_now = ev_time ();
292
293 if (flags & EVLOOP_NONBLOCK) 371 if (flags & EVLOOP_NONBLOCK)
294 block = 0.; 372 block = 0.;
295 else if (!timercnt)
296 block = MAX_BLOCKTIME;
297 else 373 else
298 { 374 {
375 block = MAX_BLOCKTIME;
376
377 if (rtimercnt)
378 {
299 block = timers [0]->at - ev_now + method_fudge; 379 ev_tstamp to = rtimers [0]->at - get_clock () + method_fudge;
380 if (block > to) block = to;
381 }
382
383 if (atimercnt)
384 {
385 ev_tstamp to = atimers [0]->at - ev_time () + method_fudge;
386 if (block > to) block = to;
387 }
388
300 if (block < 0.) block = 0.; 389 if (block < 0.) block = 0.;
301 else if (block > MAX_BLOCKTIME) block = MAX_BLOCKTIME;
302 } 390 }
303 391
304 method_poll (block); 392 method_poll (block);
305 393
394 /* update ev_now, do magic */
395 time_update ();
396
306 /* put pending timers into pendign queue and reschedule them */ 397 /* put pending timers into pendign queue and reschedule them */
307 timer_reify (); 398 /* absolute timers first */
399 timers_reify (atimers, atimercnt, ev_now);
400 /* relative timers second */
401 timers_reify (rtimers, rtimercnt, now);
308 402
309 ev_now = ev_time ();
310 call_pending (); 403 call_pending ();
311 } 404 }
312 while (!ev_loop_done); 405 while (!ev_loop_done);
313} 406}
314 407
391 if (w->is_abs) 484 if (w->is_abs)
392 { 485 {
393 /* this formula differs from the one in timer_reify becuse we do not round up */ 486 /* this formula differs from the one in timer_reify becuse we do not round up */
394 if (w->repeat) 487 if (w->repeat)
395 w->at += ceil ((ev_now - w->at) / w->repeat) * w->repeat; 488 w->at += ceil ((ev_now - w->at) / w->repeat) * w->repeat;
489
490 ev_start ((struct ev_watcher *)w, ++atimercnt);
491 array_needsize (atimers, atimermax, atimercnt, );
492 atimers [atimercnt - 1] = w;
493 upheap (atimers, atimercnt - 1);
396 } 494 }
397 else 495 else
496 {
398 w->at += ev_now; 497 w->at += now;
399 498
400 ev_start ((struct ev_watcher *)w, ++timercnt); 499 ev_start ((struct ev_watcher *)w, ++rtimercnt);
401 array_needsize (timers, timermax, timercnt, ); 500 array_needsize (rtimers, rtimermax, rtimercnt, );
402 timers [timercnt - 1] = w; 501 rtimers [rtimercnt - 1] = w;
403 upheap (timercnt - 1); 502 upheap (rtimers, rtimercnt - 1);
503 }
504
404} 505}
405 506
406void 507void
407evtimer_stop (struct ev_timer *w) 508evtimer_stop (struct ev_timer *w)
408{ 509{
409 if (!ev_is_active (w)) 510 if (!ev_is_active (w))
410 return; 511 return;
411 512
513 if (w->is_abs)
514 {
412 if (w->active < timercnt--) 515 if (w->active < atimercnt--)
413 { 516 {
414 timers [w->active - 1] = timers [timercnt]; 517 atimers [w->active - 1] = atimers [atimercnt];
415 downheap (w->active - 1); 518 downheap (atimers, atimercnt, w->active - 1);
519 }
520 }
521 else
522 {
523 if (w->active < rtimercnt--)
524 {
525 rtimers [w->active - 1] = rtimers [rtimercnt];
526 downheap (rtimers, rtimercnt, w->active - 1);
527 }
416 } 528 }
417 529
418 ev_stop ((struct ev_watcher *)w); 530 ev_stop ((struct ev_watcher *)w);
419} 531}
420 532
449} 561}
450 562
451static void 563static void
452ocb (struct ev_timer *w, int revents) 564ocb (struct ev_timer *w, int revents)
453{ 565{
454 fprintf (stderr, "timer %f,%f (%x) (%f) d%p\n", w->at, w->repeat, revents, w->at - ev_time (), w->data); 566 //fprintf (stderr, "timer %f,%f (%x) (%f) d%p\n", w->at, w->repeat, revents, w->at - ev_time (), w->data);
567 evtimer_stop (w);
568 evtimer_start (w);
455} 569}
456 570
457int main (void) 571int main (void)
458{ 572{
459 struct ev_io sin; 573 struct ev_io sin;
462 576
463 evw_init (&sin, sin_cb, 55); 577 evw_init (&sin, sin_cb, 55);
464 evio_set (&sin, 0, EV_READ); 578 evio_set (&sin, 0, EV_READ);
465 evio_start (&sin); 579 evio_start (&sin);
466 580
467 struct ev_timer t[1000]; 581 struct ev_timer t[10000];
468 582
583#if 1
469 int i; 584 int i;
470 for (i = 0; i < 1000; ++i) 585 for (i = 0; i < 10000; ++i)
471 { 586 {
472 struct ev_timer *w = t + i; 587 struct ev_timer *w = t + i;
473 evw_init (w, ocb, i); 588 evw_init (w, ocb, i);
474 evtimer_set_rel (w, drand48 (), 0); 589 evtimer_set_abs (w, drand48 (), 0.99775533);
475 evtimer_start (w); 590 evtimer_start (w);
476 if (drand48 () < 0.5) 591 if (drand48 () < 0.5)
477 evtimer_stop (w); 592 evtimer_stop (w);
478 } 593 }
594#endif
595
596 struct ev_timer t1;
597 evw_init (&t1, ocb, 0);
598 evtimer_set_abs (&t1, 5, 10);
599 evtimer_start (&t1);
479 600
480 ev_loop (0); 601 ev_loop (0);
481 602
482 return 0; 603 return 0;
483} 604}

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines