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.8 by root, Wed Oct 31 00:32:33 2007 UTC

1#include <math.h> 1#include <math.h>
2#include <stdlib.h> 2#include <stdlib.h>
3#include <unistd.h>
4#include <fcntl.h>
5#include <signal.h>
3 6
4#include <stdio.h> 7#include <stdio.h>
5 8
9#include <assert.h>
6#include <errno.h> 10#include <errno.h>
7#include <sys/time.h> 11#include <sys/time.h>
8#include <time.h> 12#include <time.h>
9 13
10#ifdef CLOCK_MONOTONIC 14#ifdef CLOCK_MONOTONIC
11# define HAVE_MONOTONIC 1 15# define HAVE_MONOTONIC 1
12#endif 16#endif
13 17
18#define HAVE_REALTIME 1
14#define HAVE_EPOLL 1 19#define HAVE_EPOLL 1
15#define HAVE_REALTIME 1
16#define HAVE_SELECT 0 20#define HAVE_SELECT 1
17 21
22#define MIN_TIMEJUMP 1. /* minimum timejump that gets detected (if monotonic clock available) */
18#define MAX_BLOCKTIME 60. 23#define MAX_BLOCKTIME 60.
19 24
20#include "ev.h" 25#include "ev.h"
21 26
22struct ev_watcher { 27struct ev_watcher {
25 30
26struct ev_watcher_list { 31struct ev_watcher_list {
27 EV_WATCHER_LIST (ev_watcher_list); 32 EV_WATCHER_LIST (ev_watcher_list);
28}; 33};
29 34
35static ev_tstamp now, diff; /* monotonic clock */
30ev_tstamp ev_now; 36ev_tstamp ev_now;
31int ev_method; 37int ev_method;
32 38
33static int have_monotonic; /* runtime */ 39static int have_monotonic; /* runtime */
34 40
35static ev_tstamp method_fudge; /* stupid epoll-returns-early bug */ 41static ev_tstamp method_fudge; /* stupid epoll-returns-early bug */
36static void (*method_reify)(void); 42static void (*method_modify)(int fd, int oev, int nev);
37static void (*method_poll)(ev_tstamp timeout); 43static void (*method_poll)(ev_tstamp timeout);
44
45/*****************************************************************************/
38 46
39ev_tstamp 47ev_tstamp
40ev_time (void) 48ev_time (void)
41{ 49{
42#if HAVE_REALTIME 50#if HAVE_REALTIME
66} 74}
67 75
68#define array_needsize(base,cur,cnt,init) \ 76#define array_needsize(base,cur,cnt,init) \
69 if ((cnt) > cur) \ 77 if ((cnt) > cur) \
70 { \ 78 { \
71 int newcnt = cur; \ 79 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);\ 80 fprintf (stderr, "resize(" # base ") from %d to %d\n", cur, newcnt);\
78 base = realloc (base, sizeof (*base) * (newcnt)); \ 81 base = realloc (base, sizeof (*base) * (newcnt)); \
79 init (base + cur, newcnt - cur); \ 82 init (base + cur, newcnt - cur); \
80 cur = newcnt; \ 83 cur = newcnt; \
81 } 84 }
82 85
86/*****************************************************************************/
87
83typedef struct 88typedef struct
84{ 89{
85 struct ev_io *head; 90 struct ev_io *head;
86 unsigned char wev, rev; /* want, received event set */ 91 unsigned char wev, rev; /* want, received event set */
87} ANFD; 92} ANFD;
134 if (ev) 139 if (ev)
135 event ((struct ev_watcher *)w, ev); 140 event ((struct ev_watcher *)w, ev);
136 } 141 }
137} 142}
138 143
144/*****************************************************************************/
145
139static struct ev_timer **timers; 146static struct ev_timer **atimers;
140static int timermax, timercnt; 147static int atimermax, atimercnt;
141 148
149static struct ev_timer **rtimers;
150static int rtimermax, rtimercnt;
151
142static void 152static void
143upheap (int k) 153upheap (struct ev_timer **timers, int k)
144{ 154{
145 struct ev_timer *w = timers [k]; 155 struct ev_timer *w = timers [k];
146 156
147 while (k && timers [k >> 1]->at > w->at) 157 while (k && timers [k >> 1]->at > w->at)
148 { 158 {
155 timers [k]->active = k + 1; 165 timers [k]->active = k + 1;
156 166
157} 167}
158 168
159static void 169static void
160downheap (int k) 170downheap (struct ev_timer **timers, int N, int k)
161{ 171{
162 struct ev_timer *w = timers [k]; 172 struct ev_timer *w = timers [k];
163 173
164 while (k <= (timercnt >> 1)) 174 while (k < (N >> 1))
165 { 175 {
166 int j = k << 1; 176 int j = k << 1;
167 177
168 if (j + 1 < timercnt && timers [j]->at > timers [j + 1]->at) 178 if (j + 1 < N && timers [j]->at > timers [j + 1]->at)
169 ++j; 179 ++j;
170 180
171 if (w->at <= timers [j]->at) 181 if (w->at <= timers [j]->at)
172 break; 182 break;
173 183
174 timers [k] = timers [j]; 184 timers [k] = timers [j];
175 timers [k]->active = k; 185 timers [k]->active = k + 1;
176 k = j; 186 k = j;
177 } 187 }
178 188
179 timers [k] = w; 189 timers [k] = w;
180 timers [k]->active = k + 1; 190 timers [k]->active = k + 1;
181} 191}
182 192
183static struct ev_signal **signals; 193/*****************************************************************************/
194
195typedef struct
196{
197 struct ev_signal *head;
198 sig_atomic_t gotsig;
199} ANSIG;
200
201static ANSIG *signals;
184static int signalmax, signalcnt; 202static int signalmax;
185 203
204static int sigpipe [2];
205static sig_atomic_t gotsig;
206static struct ev_io sigev;
207
186static void 208static void
187signals_init (struct ev_signal **base, int count) 209signals_init (ANSIG *base, int count)
188{ 210{
189 while (count--) 211 while (count--)
190 *base++ = 0; 212 {
213 base->head = 0;
214 base->gotsig = 0;
215 ++base;
216 }
191} 217}
218
219static void
220sighandler (int signum)
221{
222 signals [signum - 1].gotsig = 1;
223
224 if (!gotsig)
225 {
226 gotsig = 1;
227 write (sigpipe [1], &gotsig, 1);
228 }
229}
230
231static void
232sigcb (struct ev_io *iow, int revents)
233{
234 struct ev_signal *w;
235 int sig;
236
237 gotsig = 0;
238 read (sigpipe [0], &revents, 1);
239
240 for (sig = signalmax; sig--; )
241 if (signals [sig].gotsig)
242 {
243 signals [sig].gotsig = 0;
244
245 for (w = signals [sig].head; w; w = w->next)
246 event ((struct ev_watcher *)w, EV_SIGNAL);
247 }
248}
249
250static void
251siginit (void)
252{
253 fcntl (sigpipe [0], F_SETFD, FD_CLOEXEC);
254 fcntl (sigpipe [1], F_SETFD, FD_CLOEXEC);
255
256 /* rather than sort out wether we really need nb, set it */
257 fcntl (sigpipe [0], F_SETFL, O_NONBLOCK);
258 fcntl (sigpipe [1], F_SETFL, O_NONBLOCK);
259
260 evio_set (&sigev, sigpipe [0], EV_READ);
261 evio_start (&sigev);
262}
263
264/*****************************************************************************/
192 265
193#if HAVE_EPOLL 266#if HAVE_EPOLL
194# include "ev_epoll.c" 267# include "ev_epoll.c"
195#endif 268#endif
196#if HAVE_SELECT 269#if HAVE_SELECT
206 have_monotonic = 1; 279 have_monotonic = 1;
207 } 280 }
208#endif 281#endif
209 282
210 ev_now = ev_time (); 283 ev_now = ev_time ();
284 now = get_clock ();
285 diff = ev_now - now;
211 286
287 if (pipe (sigpipe))
288 return 0;
289
290 ev_method = EVMETHOD_NONE;
212#if HAVE_EPOLL 291#if HAVE_EPOLL
213 if (epoll_init (flags)) 292 if (ev_method == EVMETHOD_NONE) epoll_init (flags);
214 return ev_method;
215#endif 293#endif
216#if HAVE_SELECT 294#if HAVE_SELECT
217 if (select_init (flags)) 295 if (ev_method == EVMETHOD_NONE) select_init (flags);
218 return ev_method;
219#endif 296#endif
220 297
221 ev_method = EVMETHOD_NONE; 298 if (ev_method)
299 {
300 evw_init (&sigev, sigcb, 0);
301 siginit ();
302 }
303
222 return ev_method; 304 return ev_method;
223} 305}
224 306
307/*****************************************************************************/
308
225void ev_prefork (void) 309void ev_prefork (void)
226{ 310{
227} 311}
228 312
229void ev_postfork_parent (void) 313void ev_postfork_parent (void)
231} 315}
232 316
233void ev_postfork_child (void) 317void ev_postfork_child (void)
234{ 318{
235#if HAVE_EPOLL 319#if HAVE_EPOLL
320 if (ev_method == EVMETHOD_EPOLL)
236 epoll_postfork_child (); 321 epoll_postfork_child ();
237#endif 322#endif
323
324 evio_stop (&sigev);
325 close (sigpipe [0]);
326 close (sigpipe [1]);
327 pipe (sigpipe);
328 siginit ();
329}
330
331/*****************************************************************************/
332
333static ev_hook hooks [EVHOOK_NUM];
334
335void
336ev_hook_register (int type, ev_hook hook)
337{
338 hooks [type] = hook;
339}
340
341void
342ev_hook_unregister (int type, ev_hook hook)
343{
344 hooks [type] = 0;
345}
346
347static void
348hook_call (int type)
349{
350 if (hooks [type])
351 hooks [type] ();
352}
353
354static void
355fd_reify (void)
356{
357 int i;
358
359 for (i = 0; i < fdchangecnt; ++i)
360 {
361 int fd = fdchanges [i];
362 ANFD *anfd = anfds + fd;
363 struct ev_io *w;
364
365 int wev = 0;
366
367 for (w = anfd->head; w; w = w->next)
368 wev |= w->events;
369
370 if (anfd->wev != wev)
371 {
372 method_modify (fd, anfd->wev, wev);
373 anfd->wev = wev;
374 }
375 }
376
377 fdchangecnt = 0;
238} 378}
239 379
240static void 380static void
241call_pending () 381call_pending ()
242{ 382{
255 395
256 pendingcnt = 0; 396 pendingcnt = 0;
257} 397}
258 398
259static void 399static void
260timer_reify (void) 400timers_reify (struct ev_timer **timers, int timercnt, ev_tstamp now)
261{ 401{
262 while (timercnt && timers [0]->at <= ev_now) 402 while (timercnt && timers [0]->at <= now)
263 { 403 {
264 struct ev_timer *w = timers [0]; 404 struct ev_timer *w = timers [0];
265 405
266 /* first reschedule timer */ 406 /* first reschedule or stop timer */
267 if (w->repeat) 407 if (w->repeat)
268 { 408 {
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) 409 if (w->is_abs)
271 w->at += floor ((ev_now - w->at) / w->repeat + 1.) * w->repeat; 410 w->at += floor ((now - w->at) / w->repeat + 1.) * w->repeat;
272 else 411 else
273 w->at = ev_now + w->repeat; 412 w->at = now + w->repeat;
274 413
275 fprintf (stderr, "b %f\n", w->at);//D 414 assert (w->at > now);
276 415
277 downheap (0); 416 downheap (timers, timercnt, 0);
278 } 417 }
279 else 418 else
419 {
280 evtimer_stop (w); /* nonrepeating: stop timer */ 420 evtimer_stop (w); /* nonrepeating: stop timer */
421 --timercnt; /* maybe pass by reference instead? */
422 }
281 423
282 event ((struct ev_watcher *)w, EV_TIMEOUT); 424 event ((struct ev_watcher *)w, EV_TIMEOUT);
283 } 425 }
284} 426}
285 427
428static void
429time_update ()
430{
431 int i;
432 ev_now = ev_time ();
433
434 if (have_monotonic)
435 {
436 ev_tstamp odiff = diff;
437
438 /* detecting time jumps is much more difficult */
439 for (i = 2; --i; ) /* loop a few times, before making important decisions */
440 {
441 now = get_clock ();
442 diff = ev_now - now;
443
444 if (fabs (odiff - diff) < MIN_TIMEJUMP)
445 return; /* all is well */
446
447 ev_now = ev_time ();
448 }
449
450 /* time jump detected, reschedule atimers */
451 for (i = 0; i < atimercnt; ++i)
452 {
453 struct ev_timer *w = atimers [i];
454 w->at += ceil ((ev_now - w->at) / w->repeat + 1.) * w->repeat;
455 }
456 }
457 else
458 {
459 if (now > ev_now || now < ev_now - MAX_BLOCKTIME - MIN_TIMEJUMP)
460 /* time jump detected, adjust rtimers */
461 for (i = 0; i < rtimercnt; ++i)
462 rtimers [i]->at += ev_now - now;
463
464 now = ev_now;
465 }
466}
467
286int ev_loop_done; 468int ev_loop_done;
287 469
288int ev_loop (int flags) 470void ev_loop (int flags)
289{ 471{
290 double block; 472 double block;
291 ev_loop_done = flags & EVLOOP_ONESHOT; 473 ev_loop_done = flags & EVLOOP_ONESHOT;
292 474
293 do 475 do
294 { 476 {
477 hook_call (EVHOOK_PREPOLL);
478
295 /* update fd-related kernel structures */ 479 /* update fd-related kernel structures */
296 method_reify (); fdchangecnt = 0; 480 fd_reify ();
297 481
298 /* calculate blocking time */ 482 /* calculate blocking time */
299 ev_now = ev_time ();
300
301 if (flags & EVLOOP_NONBLOCK) 483 if (flags & EVLOOP_NONBLOCK)
302 block = 0.; 484 block = 0.;
303 else if (!timercnt)
304 block = MAX_BLOCKTIME;
305 else 485 else
306 { 486 {
487 block = MAX_BLOCKTIME;
488
489 if (rtimercnt)
490 {
307 block = timers [0]->at - ev_now + method_fudge; 491 ev_tstamp to = rtimers [0]->at - get_clock () + method_fudge;
492 if (block > to) block = to;
493 }
494
495 if (atimercnt)
496 {
497 ev_tstamp to = atimers [0]->at - ev_time () + method_fudge;
498 if (block > to) block = to;
499 }
500
308 if (block < 0.) block = 0.; 501 if (block < 0.) block = 0.;
309 else if (block > MAX_BLOCKTIME) block = MAX_BLOCKTIME;
310 } 502 }
311 503
312 fprintf (stderr, "block %f\n", block);//D
313 method_poll (block); 504 method_poll (block);
314 505
506 /* update ev_now, do magic */
507 time_update ();
508
509 hook_call (EVHOOK_POSTPOLL);
510
315 /* put pending timers into pendign queue and reschedule them */ 511 /* put pending timers into pendign queue and reschedule them */
316 timer_reify (); 512 /* absolute timers first */
513 timers_reify (atimers, atimercnt, ev_now);
514 /* relative timers second */
515 timers_reify (rtimers, rtimercnt, now);
317 516
318 ev_now = ev_time ();
319 call_pending (); 517 call_pending ();
320 } 518 }
321 while (!ev_loop_done); 519 while (!ev_loop_done);
322} 520}
521
522/*****************************************************************************/
323 523
324static void 524static void
325wlist_add (struct ev_watcher_list **head, struct ev_watcher_list *elem) 525wlist_add (struct ev_watcher_list **head, struct ev_watcher_list *elem)
326{ 526{
327 elem->next = *head; 527 elem->next = *head;
357 pendings [w->pending - 1].w = 0; 557 pendings [w->pending - 1].w = 0;
358 558
359 w->active = 0; 559 w->active = 0;
360 /* nop */ 560 /* nop */
361} 561}
562
563/*****************************************************************************/
362 564
363void 565void
364evio_start (struct ev_io *w) 566evio_start (struct ev_io *w)
365{ 567{
366 if (ev_is_active (w)) 568 if (ev_is_active (w))
395evtimer_start (struct ev_timer *w) 597evtimer_start (struct ev_timer *w)
396{ 598{
397 if (ev_is_active (w)) 599 if (ev_is_active (w))
398 return; 600 return;
399 601
400 fprintf (stderr, "t1 %f a %d\n", w->at, w->is_abs);//D
401 if (w->is_abs) 602 if (w->is_abs)
402 { 603 {
604 /* this formula differs from the one in timer_reify becuse we do not round up */
403 if (w->repeat) 605 if (w->repeat)
404 w->at += ceil ((ev_now - w->at) / w->repeat) * w->repeat; 606 w->at += ceil ((ev_now - w->at) / w->repeat) * w->repeat;
607
608 ev_start ((struct ev_watcher *)w, ++atimercnt);
609 array_needsize (atimers, atimermax, atimercnt, );
610 atimers [atimercnt - 1] = w;
611 upheap (atimers, atimercnt - 1);
405 } 612 }
406 else 613 else
614 {
407 w->at += ev_now; 615 w->at += now;
408 fprintf (stderr, "t2 %f a %d\n", w->at, w->is_abs);//D
409 616
410 ev_start ((struct ev_watcher *)w, ++timercnt); 617 ev_start ((struct ev_watcher *)w, ++rtimercnt);
411 array_needsize (timers, timermax, timercnt, ); 618 array_needsize (rtimers, rtimermax, rtimercnt, );
412 timers [timercnt - 1] = w; 619 rtimers [rtimercnt - 1] = w;
413 upheap (timercnt - 1); 620 upheap (rtimers, rtimercnt - 1);
621 }
622
414} 623}
415 624
416void 625void
417evtimer_stop (struct ev_timer *w) 626evtimer_stop (struct ev_timer *w)
418{ 627{
419 if (!ev_is_active (w)) 628 if (!ev_is_active (w))
420 return; 629 return;
421 630
631 if (w->is_abs)
632 {
633 if (w->active < atimercnt--)
634 {
422 timers [w->active - 1] = timers [--timercnt]; 635 atimers [w->active - 1] = atimers [atimercnt];
423 downheap (w->active - 1); 636 downheap (atimers, atimercnt, w->active - 1);
637 }
638 }
639 else
640 {
641 if (w->active < rtimercnt--)
642 {
643 rtimers [w->active - 1] = rtimers [rtimercnt];
644 downheap (rtimers, rtimercnt, w->active - 1);
645 }
646 }
647
424 ev_stop ((struct ev_watcher *)w); 648 ev_stop ((struct ev_watcher *)w);
425} 649}
426 650
427void 651void
428evsignal_start (struct ev_signal *w) 652evsignal_start (struct ev_signal *w)
430 if (ev_is_active (w)) 654 if (ev_is_active (w))
431 return; 655 return;
432 656
433 ev_start ((struct ev_watcher *)w, 1); 657 ev_start ((struct ev_watcher *)w, 1);
434 array_needsize (signals, signalmax, w->signum, signals_init); 658 array_needsize (signals, signalmax, w->signum, signals_init);
435 wlist_add ((struct ev_watcher_list **)&signals [w->signum - 1], (struct ev_watcher_list *)w); 659 wlist_add ((struct ev_watcher_list **)&signals [w->signum - 1].head, (struct ev_watcher_list *)w);
660
661 if (!w->next)
662 {
663 struct sigaction sa;
664 sa.sa_handler = sighandler;
665 sigfillset (&sa.sa_mask);
666 sa.sa_flags = 0;
667 sigaction (w->signum, &sa, 0);
668 }
436} 669}
437 670
438void 671void
439evsignal_stop (struct ev_signal *w) 672evsignal_stop (struct ev_signal *w)
440{ 673{
441 if (!ev_is_active (w)) 674 if (!ev_is_active (w))
442 return; 675 return;
443 676
444 wlist_del ((struct ev_watcher_list **)&signals [w->signum - 1], (struct ev_watcher_list *)w); 677 wlist_del ((struct ev_watcher_list **)&signals [w->signum - 1].head, (struct ev_watcher_list *)w);
445 ev_stop ((struct ev_watcher *)w); 678 ev_stop ((struct ev_watcher *)w);
679
680 if (!signals [w->signum - 1].head)
681 signal (w->signum, SIG_DFL);
446} 682}
447 683
448/*****************************************************************************/ 684/*****************************************************************************/
449#if 1 685#if 1
450 686
455} 691}
456 692
457static void 693static void
458ocb (struct ev_timer *w, int revents) 694ocb (struct ev_timer *w, int revents)
459{ 695{
460 fprintf (stderr, "timer %f,%f (%x) (%f) d%p\n", w->at, w->repeat, revents, w->at - ev_time (), w->data); 696 //fprintf (stderr, "timer %f,%f (%x) (%f) d%p\n", w->at, w->repeat, revents, w->at - ev_time (), w->data);
697 evtimer_stop (w);
698 evtimer_start (w);
699}
700
701static void
702scb (struct ev_signal *w, int revents)
703{
704 fprintf (stderr, "signal %x,%d\n", revents, w->signum);
461} 705}
462 706
463int main (void) 707int main (void)
464{ 708{
465 struct ev_io sin; 709 struct ev_io sin;
468 712
469 evw_init (&sin, sin_cb, 55); 713 evw_init (&sin, sin_cb, 55);
470 evio_set (&sin, 0, EV_READ); 714 evio_set (&sin, 0, EV_READ);
471 evio_start (&sin); 715 evio_start (&sin);
472 716
717 struct ev_timer t[10000];
718
719#if 1
720 int i;
721 for (i = 0; i < 10000; ++i)
722 {
723 struct ev_timer *w = t + i;
724 evw_init (w, ocb, i);
725 evtimer_set_abs (w, drand48 (), 0.99775533);
726 evtimer_start (w);
727 if (drand48 () < 0.5)
728 evtimer_stop (w);
729 }
730#endif
731
473 struct ev_timer t1; 732 struct ev_timer t1;
474 evw_init (&t1, ocb, 1); 733 evw_init (&t1, ocb, 0);
475 evtimer_set_rel (&t1, 1, 0); 734 evtimer_set_abs (&t1, 5, 10);
476 evtimer_start (&t1); 735 evtimer_start (&t1);
477 736
478 struct ev_timer t2; 737 struct ev_signal sig;
479 evw_init (&t2, ocb, 2); 738 evw_init (&sig, scb, 65535);
480 evtimer_set_abs (&t2, ev_time () + 2, 0); 739 evsignal_set (&sig, SIGQUIT);
481 evtimer_start (&t2); 740 evsignal_start (&sig);
482 741
483 ev_loop (0); 742 ev_loop (0);
484 743
485 return 0; 744 return 0;
486} 745}

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines