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

Comparing libev/ev.c (file contents):
Revision 1.2 by root, Tue Oct 30 21:42:12 2007 UTC vs.
Revision 1.5 by root, Tue Oct 30 23:54:38 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
14#define HAVE_EPOLL 1 15#define HAVE_EPOLL 1
15#define HAVE_REALTIME 1 16#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 fprintf (stderr, "0 %f, %d c%d\n", w->at, w->active, timercnt);//D
262 /* first reschedule timer */ 296 /* first reschedule or stop timer */
263 if (w->repeat) 297 if (w->repeat)
264 { 298 {
265 fprintf (stderr, "a %f now %f repeat %f, %f\n", w->at, ev_now, w->repeat, w->repeat *1e30);//D
266 if (w->is_abs) 299 if (w->is_abs)
267 w->at += ceil ((ev_now - w->at) / w->repeat + 1.) * w->repeat; 300 w->at += floor ((now - w->at) / w->repeat + 1.) * w->repeat;
268 else 301 else
269 w->at = ev_now + w->repeat; 302 w->at = now + w->repeat;
270 303
271 fprintf (stderr, "b %f\n", w->at);//D 304 assert (w->at > now);
272 305
273 downheap (0); 306 downheap (timers, timercnt, 0);
274 } 307 }
275 else 308 else
276 { 309 {
277 fprintf (stderr, "c %f, %d c%d\n", w->at, w->active, timercnt);//D
278 evtimer_stop (w); /* nonrepeating: stop timer */ 310 evtimer_stop (w); /* nonrepeating: stop timer */
311 --timercnt; /* maybe pass by reference instead? */
279 } 312 }
280 313
281 event ((struct ev_watcher *)w, EV_TIMEOUT); 314 event ((struct ev_watcher *)w, EV_TIMEOUT);
282 } 315 }
283} 316}
284 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
285int ev_loop_done; 358int ev_loop_done;
286 359
287int ev_loop (int flags) 360void ev_loop (int flags)
288{ 361{
289 double block; 362 double block;
290 ev_loop_done = flags & EVLOOP_ONESHOT; 363 ev_loop_done = flags & EVLOOP_ONESHOT;
291 364
292 do 365 do
293 { 366 {
294 /* update fd-related kernel structures */ 367 /* update fd-related kernel structures */
295 method_reify (); fdchangecnt = 0; 368 fd_reify ();
296 369
297 /* calculate blocking time */ 370 /* calculate blocking time */
298 ev_now = ev_time ();
299
300 if (flags & EVLOOP_NONBLOCK) 371 if (flags & EVLOOP_NONBLOCK)
301 block = 0.; 372 block = 0.;
302 else if (!timercnt)
303 block = MAX_BLOCKTIME;
304 else 373 else
305 { 374 {
375 block = MAX_BLOCKTIME;
376
377 if (rtimercnt)
378 {
306 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
307 if (block < 0.) block = 0.; 389 if (block < 0.) block = 0.;
308 else if (block > MAX_BLOCKTIME) block = MAX_BLOCKTIME;
309 } 390 }
310 391
311 fprintf (stderr, "block %f\n", block);//D
312 method_poll (block); 392 method_poll (block);
313 393
394 /* update ev_now, do magic */
395 time_update ();
396
314 /* put pending timers into pendign queue and reschedule them */ 397 /* put pending timers into pendign queue and reschedule them */
315 timer_reify (); 398 /* absolute timers first */
399 timers_reify (atimers, atimercnt, ev_now);
400 /* relative timers second */
401 timers_reify (rtimers, rtimercnt, now);
316 402
317 ev_now = ev_time ();
318 call_pending (); 403 call_pending ();
319 } 404 }
320 while (!ev_loop_done); 405 while (!ev_loop_done);
321} 406}
322 407
394evtimer_start (struct ev_timer *w) 479evtimer_start (struct ev_timer *w)
395{ 480{
396 if (ev_is_active (w)) 481 if (ev_is_active (w))
397 return; 482 return;
398 483
399 fprintf (stderr, "t1 %f a %d\n", w->at, w->is_abs);//D
400 if (w->is_abs) 484 if (w->is_abs)
401 { 485 {
402 /* 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 */
403 if (w->repeat) 487 if (w->repeat)
404 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);
405 } 494 }
406 else 495 else
496 {
407 w->at += ev_now; 497 w->at += now;
408 fprintf (stderr, "t2 %f a %d\n", w->at, w->is_abs);//D
409 498
410 ev_start ((struct ev_watcher *)w, ++timercnt); 499 ev_start ((struct ev_watcher *)w, ++rtimercnt);
411 array_needsize (timers, timermax, timercnt, ); 500 array_needsize (rtimers, rtimermax, rtimercnt, );
412 timers [timercnt - 1] = w; 501 rtimers [rtimercnt - 1] = w;
413 upheap (timercnt - 1); 502 upheap (rtimers, rtimercnt - 1);
503 }
504
414} 505}
415 506
416void 507void
417evtimer_stop (struct ev_timer *w) 508evtimer_stop (struct ev_timer *w)
418{ 509{
419 fprintf (stderr, "-topping %d, %d\n", w->active, timercnt);//D
420 if (!ev_is_active (w)) 510 if (!ev_is_active (w))
421 return; 511 return;
422 512
423 fprintf (stderr, "stopping %d, %d\n", w->active, timercnt);//D 513 if (w->is_abs)
514 {
424 if (w->active < timercnt) 515 if (w->active < atimercnt--)
425 { 516 {
426 timers [w->active - 1] = timers [--timercnt]; 517 atimers [w->active - 1] = atimers [atimercnt];
427 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 }
428 } 528 }
429 529
430 ev_stop ((struct ev_watcher *)w); 530 ev_stop ((struct ev_watcher *)w);
431} 531}
432 532
461} 561}
462 562
463static void 563static void
464ocb (struct ev_timer *w, int revents) 564ocb (struct ev_timer *w, int revents)
465{ 565{
466 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);
467} 569}
468 570
469int main (void) 571int main (void)
470{ 572{
471 struct ev_io sin; 573 struct ev_io sin;
474 576
475 evw_init (&sin, sin_cb, 55); 577 evw_init (&sin, sin_cb, 55);
476 evio_set (&sin, 0, EV_READ); 578 evio_set (&sin, 0, EV_READ);
477 evio_start (&sin); 579 evio_start (&sin);
478 580
479 struct ev_timer t[1000]; 581 struct ev_timer t[10000];
480 582
583#if 1
481 int i; 584 int i;
482 for (i = 0; i < 1000; ++i) 585 for (i = 0; i < 10000; ++i)
483 { 586 {
484 struct ev_timer *w = t + i; 587 struct ev_timer *w = t + i;
485 evw_init (w, ocb, i); 588 evw_init (w, ocb, i);
486 evtimer_set_rel (w, drand48 (), 0); 589 evtimer_set_abs (w, drand48 (), 0.99775533);
487 evtimer_start (w); 590 evtimer_start (w);
488 if (drand48 () < 0.5) 591 if (drand48 () < 0.5)
489 evtimer_stop (w); 592 evtimer_stop (w);
490 } 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);
491 600
492 ev_loop (0); 601 ev_loop (0);
493 602
494 return 0; 603 return 0;
495} 604}

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines