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

Comparing libev/ev.c (file contents):
Revision 1.1 by root, Tue Oct 30 20:59:31 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{
66} 69}
67 70
68#define array_needsize(base,cur,cnt,init) \ 71#define array_needsize(base,cur,cnt,init) \
69 if ((cnt) > cur) \ 72 if ((cnt) > cur) \
70 { \ 73 { \
71 int newcnt = cur; \ 74 int newcnt = cur ? cur << 1 : 16; \
72 do \
73 { \
74 newcnt += (newcnt >> 1) + 16; \
75 } \
76 while ((cnt) > newcnt); \
77 fprintf (stderr, "resize(" # base ") from %d to %d\n", cur, newcnt);\ 75 fprintf (stderr, "resize(" # base ") from %d to %d\n", cur, newcnt);\
78 base = realloc (base, sizeof (*base) * (newcnt)); \ 76 base = realloc (base, sizeof (*base) * (newcnt)); \
79 init (base + cur, newcnt - cur); \ 77 init (base + cur, newcnt - cur); \
80 cur = newcnt; \ 78 cur = newcnt; \
81 } 79 }
134 if (ev) 132 if (ev)
135 event ((struct ev_watcher *)w, ev); 133 event ((struct ev_watcher *)w, ev);
136 } 134 }
137} 135}
138 136
139static struct ev_timer **timers; 137static struct ev_timer **atimers;
140static int timermax, timercnt; 138static int atimermax, atimercnt;
141 139
140static struct ev_timer **rtimers;
141static int rtimermax, rtimercnt;
142
142static void 143static void
143upheap (int k) 144upheap (struct ev_timer **timers, int k)
144{ 145{
145 struct ev_timer *w = timers [k]; 146 struct ev_timer *w = timers [k];
146 147
147 while (k && timers [k >> 1]->at > w->at) 148 while (k && timers [k >> 1]->at > w->at)
148 { 149 {
155 timers [k]->active = k + 1; 156 timers [k]->active = k + 1;
156 157
157} 158}
158 159
159static void 160static void
160downheap (int k) 161downheap (struct ev_timer **timers, int N, int k)
161{ 162{
162 struct ev_timer *w = timers [k]; 163 struct ev_timer *w = timers [k];
163 164
164 while (k <= (timercnt >> 1)) 165 while (k < (N >> 1))
165 { 166 {
166 int j = k << 1; 167 int j = k << 1;
167 168
168 if (j + 1 < timercnt && timers [j]->at > timers [j + 1]->at) 169 if (j + 1 < N && timers [j]->at > timers [j + 1]->at)
169 ++j; 170 ++j;
170 171
171 if (w->at <= timers [j]->at) 172 if (w->at <= timers [j]->at)
172 break; 173 break;
173 174
174 timers [k] = timers [j]; 175 timers [k] = timers [j];
175 timers [k]->active = k; 176 timers [k]->active = k + 1;
176 k = j; 177 k = j;
177 } 178 }
178 179
179 timers [k] = w; 180 timers [k] = w;
180 timers [k]->active = k + 1; 181 timers [k]->active = k + 1;
181} 182}
182 183
183static struct ev_signal **signals; 184static struct ev_signal **signals;
184static int signalmax, signalcnt; 185static int signalmax;
185 186
186static void 187static void
187signals_init (struct ev_signal **base, int count) 188signals_init (struct ev_signal **base, int count)
188{ 189{
189 while (count--) 190 while (count--)
206 have_monotonic = 1; 207 have_monotonic = 1;
207 } 208 }
208#endif 209#endif
209 210
210 ev_now = ev_time (); 211 ev_now = ev_time ();
212 now = get_clock ();
213 diff = ev_now - now;
211 214
212#if HAVE_EPOLL 215#if HAVE_EPOLL
213 if (epoll_init (flags)) 216 if (epoll_init (flags))
214 return ev_method; 217 return ev_method;
215#endif 218#endif
231} 234}
232 235
233void ev_postfork_child (void) 236void ev_postfork_child (void)
234{ 237{
235#if HAVE_EPOLL 238#if HAVE_EPOLL
239 if (ev_method == EVMETHOD_EPOLL)
236 epoll_postfork_child (); 240 epoll_postfork_child ();
237#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;
238} 268}
239 269
240static void 270static void
241call_pending () 271call_pending ()
242{ 272{
255 285
256 pendingcnt = 0; 286 pendingcnt = 0;
257} 287}
258 288
259static void 289static void
260timer_reify (void) 290timers_reify (struct ev_timer **timers, int timercnt, ev_tstamp now)
261{ 291{
262 while (timercnt && timers [0]->at <= ev_now) 292 while (timercnt && timers [0]->at <= now)
263 { 293 {
264 struct ev_timer *w = timers [0]; 294 struct ev_timer *w = timers [0];
265 295
266 /* first reschedule timer */ 296 /* first reschedule or stop timer */
267 if (w->repeat) 297 if (w->repeat)
268 { 298 {
269 fprintf (stderr, "a %f now %f repeat %f, %f\n", w->at, ev_now, w->repeat, w->repeat *1e30);//D
270 if (w->is_abs) 299 if (w->is_abs)
271 w->at += floor ((ev_now - w->at) / w->repeat + 1.) * w->repeat; 300 w->at += floor ((now - w->at) / w->repeat + 1.) * w->repeat;
272 else 301 else
273 w->at = ev_now + w->repeat; 302 w->at = now + w->repeat;
274 303
275 fprintf (stderr, "b %f\n", w->at);//D 304 assert (w->at > now);
276 305
277 downheap (0); 306 downheap (timers, timercnt, 0);
278 } 307 }
279 else 308 else
309 {
280 evtimer_stop (w); /* nonrepeating: stop timer */ 310 evtimer_stop (w); /* nonrepeating: stop timer */
311 --timercnt; /* maybe pass by reference instead? */
312 }
281 313
282 event ((struct ev_watcher *)w, EV_TIMEOUT); 314 event ((struct ev_watcher *)w, EV_TIMEOUT);
283 } 315 }
284} 316}
285 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
286int ev_loop_done; 358int ev_loop_done;
287 359
288int ev_loop (int flags) 360void ev_loop (int flags)
289{ 361{
290 double block; 362 double block;
291 ev_loop_done = flags & EVLOOP_ONESHOT; 363 ev_loop_done = flags & EVLOOP_ONESHOT;
292 364
293 do 365 do
294 { 366 {
295 /* update fd-related kernel structures */ 367 /* update fd-related kernel structures */
296 method_reify (); fdchangecnt = 0; 368 fd_reify ();
297 369
298 /* calculate blocking time */ 370 /* calculate blocking time */
299 ev_now = ev_time ();
300
301 if (flags & EVLOOP_NONBLOCK) 371 if (flags & EVLOOP_NONBLOCK)
302 block = 0.; 372 block = 0.;
303 else if (!timercnt)
304 block = MAX_BLOCKTIME;
305 else 373 else
306 { 374 {
375 block = MAX_BLOCKTIME;
376
377 if (rtimercnt)
378 {
307 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
308 if (block < 0.) block = 0.; 389 if (block < 0.) block = 0.;
309 else if (block > MAX_BLOCKTIME) block = MAX_BLOCKTIME;
310 } 390 }
311 391
312 fprintf (stderr, "block %f\n", block);//D
313 method_poll (block); 392 method_poll (block);
314 393
394 /* update ev_now, do magic */
395 time_update ();
396
315 /* put pending timers into pendign queue and reschedule them */ 397 /* put pending timers into pendign queue and reschedule them */
316 timer_reify (); 398 /* absolute timers first */
399 timers_reify (atimers, atimercnt, ev_now);
400 /* relative timers second */
401 timers_reify (rtimers, rtimercnt, now);
317 402
318 ev_now = ev_time ();
319 call_pending (); 403 call_pending ();
320 } 404 }
321 while (!ev_loop_done); 405 while (!ev_loop_done);
322} 406}
323 407
395evtimer_start (struct ev_timer *w) 479evtimer_start (struct ev_timer *w)
396{ 480{
397 if (ev_is_active (w)) 481 if (ev_is_active (w))
398 return; 482 return;
399 483
400 fprintf (stderr, "t1 %f a %d\n", w->at, w->is_abs);//D
401 if (w->is_abs) 484 if (w->is_abs)
402 { 485 {
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 if (!ev_is_active (w)) 510 if (!ev_is_active (w))
420 return; 511 return;
421 512
513 if (w->is_abs)
514 {
515 if (w->active < atimercnt--)
516 {
422 timers [w->active - 1] = timers [--timercnt]; 517 atimers [w->active - 1] = atimers [atimercnt];
423 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 }
528 }
529
424 ev_stop ((struct ev_watcher *)w); 530 ev_stop ((struct ev_watcher *)w);
425} 531}
426 532
427void 533void
428evsignal_start (struct ev_signal *w) 534evsignal_start (struct ev_signal *w)
455} 561}
456 562
457static void 563static void
458ocb (struct ev_timer *w, int revents) 564ocb (struct ev_timer *w, int revents)
459{ 565{
460 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);
461} 569}
462 570
463int main (void) 571int main (void)
464{ 572{
465 struct ev_io sin; 573 struct ev_io sin;
468 576
469 evw_init (&sin, sin_cb, 55); 577 evw_init (&sin, sin_cb, 55);
470 evio_set (&sin, 0, EV_READ); 578 evio_set (&sin, 0, EV_READ);
471 evio_start (&sin); 579 evio_start (&sin);
472 580
581 struct ev_timer t[10000];
582
583#if 1
584 int i;
585 for (i = 0; i < 10000; ++i)
586 {
587 struct ev_timer *w = t + i;
588 evw_init (w, ocb, i);
589 evtimer_set_abs (w, drand48 (), 0.99775533);
590 evtimer_start (w);
591 if (drand48 () < 0.5)
592 evtimer_stop (w);
593 }
594#endif
595
473 struct ev_timer t1; 596 struct ev_timer t1;
474 evw_init (&t1, ocb, 1); 597 evw_init (&t1, ocb, 0);
475 evtimer_set_rel (&t1, 1, 0); 598 evtimer_set_abs (&t1, 5, 10);
476 evtimer_start (&t1); 599 evtimer_start (&t1);
477 600
478 struct ev_timer t2;
479 evw_init (&t2, ocb, 2);
480 evtimer_set_abs (&t2, ev_time () + 2, 0);
481 evtimer_start (&t2);
482
483 ev_loop (0); 601 ev_loop (0);
484 602
485 return 0; 603 return 0;
486} 604}
487 605

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines