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.7 by root, Wed Oct 31 00:24:16 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);
38 44
39ev_tstamp 45ev_tstamp
40ev_time (void) 46ev_time (void)
41{ 47{
66} 72}
67 73
68#define array_needsize(base,cur,cnt,init) \ 74#define array_needsize(base,cur,cnt,init) \
69 if ((cnt) > cur) \ 75 if ((cnt) > cur) \
70 { \ 76 { \
71 int newcnt = cur; \ 77 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);\ 78 fprintf (stderr, "resize(" # base ") from %d to %d\n", cur, newcnt);\
78 base = realloc (base, sizeof (*base) * (newcnt)); \ 79 base = realloc (base, sizeof (*base) * (newcnt)); \
79 init (base + cur, newcnt - cur); \ 80 init (base + cur, newcnt - cur); \
80 cur = newcnt; \ 81 cur = newcnt; \
81 } 82 }
134 if (ev) 135 if (ev)
135 event ((struct ev_watcher *)w, ev); 136 event ((struct ev_watcher *)w, ev);
136 } 137 }
137} 138}
138 139
139static struct ev_timer **timers; 140static struct ev_timer **atimers;
140static int timermax, timercnt; 141static int atimermax, atimercnt;
141 142
143static struct ev_timer **rtimers;
144static int rtimermax, rtimercnt;
145
142static void 146static void
143upheap (int k) 147upheap (struct ev_timer **timers, int k)
144{ 148{
145 struct ev_timer *w = timers [k]; 149 struct ev_timer *w = timers [k];
146 150
147 while (k && timers [k >> 1]->at > w->at) 151 while (k && timers [k >> 1]->at > w->at)
148 { 152 {
155 timers [k]->active = k + 1; 159 timers [k]->active = k + 1;
156 160
157} 161}
158 162
159static void 163static void
160downheap (int k) 164downheap (struct ev_timer **timers, int N, int k)
161{ 165{
162 struct ev_timer *w = timers [k]; 166 struct ev_timer *w = timers [k];
163 167
164 while (k <= (timercnt >> 1)) 168 while (k < (N >> 1))
165 { 169 {
166 int j = k << 1; 170 int j = k << 1;
167 171
168 if (j + 1 < timercnt && timers [j]->at > timers [j + 1]->at) 172 if (j + 1 < N && timers [j]->at > timers [j + 1]->at)
169 ++j; 173 ++j;
170 174
171 if (w->at <= timers [j]->at) 175 if (w->at <= timers [j]->at)
172 break; 176 break;
173 177
174 timers [k] = timers [j]; 178 timers [k] = timers [j];
175 timers [k]->active = k; 179 timers [k]->active = k + 1;
176 k = j; 180 k = j;
177 } 181 }
178 182
179 timers [k] = w; 183 timers [k] = w;
180 timers [k]->active = k + 1; 184 timers [k]->active = k + 1;
181} 185}
182 186
183static struct ev_signal **signals; 187typedef struct
188{
189 struct ev_signal *head;
190 sig_atomic_t gotsig;
191} ANSIG;
192
193static ANSIG *signals;
184static int signalmax, signalcnt; 194static int signalmax;
185 195
196static int sigpipe [2];
197static sig_atomic_t gotsig;
198static struct ev_io sigev;
199
186static void 200static void
187signals_init (struct ev_signal **base, int count) 201signals_init (ANSIG *base, int count)
188{ 202{
189 while (count--) 203 while (count--)
190 *base++ = 0; 204 {
205 base->head = 0;
206 base->gotsig = 0;
207 ++base;
208 }
209}
210
211static void
212sighandler (int signum)
213{
214 signals [signum - 1].gotsig = 1;
215
216 if (!gotsig)
217 {
218 gotsig = 1;
219 write (sigpipe [1], &gotsig, 1);
220 }
221}
222
223static void
224sigcb (struct ev_io *iow, int revents)
225{
226 struct ev_signal *w;
227 int sig;
228
229 gotsig = 0;
230 read (sigpipe [0], &revents, 1);
231
232 for (sig = signalmax; sig--; )
233 if (signals [sig].gotsig)
234 {
235 signals [sig].gotsig = 0;
236
237 for (w = signals [sig].head; w; w = w->next)
238 event ((struct ev_watcher *)w, EV_SIGNAL);
239 }
240}
241
242static void
243siginit (void)
244{
245 fcntl (sigpipe [0], F_SETFD, FD_CLOEXEC);
246 fcntl (sigpipe [1], F_SETFD, FD_CLOEXEC);
247
248 /* rather than sort out wether we really need nb, set it */
249 fcntl (sigpipe [0], F_SETFL, O_NONBLOCK);
250 fcntl (sigpipe [1], F_SETFL, O_NONBLOCK);
251
252 evio_set (&sigev, sigpipe [0], EV_READ);
253 evio_start (&sigev);
191} 254}
192 255
193#if HAVE_EPOLL 256#if HAVE_EPOLL
194# include "ev_epoll.c" 257# include "ev_epoll.c"
195#endif 258#endif
206 have_monotonic = 1; 269 have_monotonic = 1;
207 } 270 }
208#endif 271#endif
209 272
210 ev_now = ev_time (); 273 ev_now = ev_time ();
274 now = get_clock ();
275 diff = ev_now - now;
211 276
277 if (pipe (sigpipe))
278 return 0;
279
280 ev_method = EVMETHOD_NONE;
212#if HAVE_EPOLL 281#if HAVE_EPOLL
213 if (epoll_init (flags)) 282 if (ev_method == EVMETHOD_NONE) epoll_init (flags);
214 return ev_method;
215#endif 283#endif
216#if HAVE_SELECT 284#if HAVE_SELECT
217 if (select_init (flags)) 285 if (ev_method == EVMETHOD_NONE) select_init (flags);
218 return ev_method;
219#endif 286#endif
220 287
221 ev_method = EVMETHOD_NONE; 288 if (ev_method)
289 {
290 evw_init (&sigev, sigcb, 0);
291 siginit ();
292 }
293
222 return ev_method; 294 return ev_method;
223} 295}
224 296
225void ev_prefork (void) 297void ev_prefork (void)
226{ 298{
231} 303}
232 304
233void ev_postfork_child (void) 305void ev_postfork_child (void)
234{ 306{
235#if HAVE_EPOLL 307#if HAVE_EPOLL
308 if (ev_method == EVMETHOD_EPOLL)
236 epoll_postfork_child (); 309 epoll_postfork_child ();
237#endif 310#endif
311
312 evio_stop (&sigev);
313 close (sigpipe [0]);
314 close (sigpipe [1]);
315 pipe (sigpipe);
316 siginit ();
317}
318
319static void
320fd_reify (void)
321{
322 int i;
323
324 for (i = 0; i < fdchangecnt; ++i)
325 {
326 int fd = fdchanges [i];
327 ANFD *anfd = anfds + fd;
328 struct ev_io *w;
329
330 int wev = 0;
331
332 for (w = anfd->head; w; w = w->next)
333 wev |= w->events;
334
335 if (anfd->wev != wev)
336 {
337 method_modify (fd, anfd->wev, wev);
338 anfd->wev = wev;
339 }
340 }
341
342 fdchangecnt = 0;
238} 343}
239 344
240static void 345static void
241call_pending () 346call_pending ()
242{ 347{
255 360
256 pendingcnt = 0; 361 pendingcnt = 0;
257} 362}
258 363
259static void 364static void
260timer_reify (void) 365timers_reify (struct ev_timer **timers, int timercnt, ev_tstamp now)
261{ 366{
262 while (timercnt && timers [0]->at <= ev_now) 367 while (timercnt && timers [0]->at <= now)
263 { 368 {
264 struct ev_timer *w = timers [0]; 369 struct ev_timer *w = timers [0];
265 370
266 /* first reschedule timer */ 371 /* first reschedule or stop timer */
267 if (w->repeat) 372 if (w->repeat)
268 { 373 {
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) 374 if (w->is_abs)
271 w->at += floor ((ev_now - w->at) / w->repeat + 1.) * w->repeat; 375 w->at += floor ((now - w->at) / w->repeat + 1.) * w->repeat;
272 else 376 else
273 w->at = ev_now + w->repeat; 377 w->at = now + w->repeat;
274 378
275 fprintf (stderr, "b %f\n", w->at);//D 379 assert (w->at > now);
276 380
277 downheap (0); 381 downheap (timers, timercnt, 0);
278 } 382 }
279 else 383 else
384 {
280 evtimer_stop (w); /* nonrepeating: stop timer */ 385 evtimer_stop (w); /* nonrepeating: stop timer */
386 --timercnt; /* maybe pass by reference instead? */
387 }
281 388
282 event ((struct ev_watcher *)w, EV_TIMEOUT); 389 event ((struct ev_watcher *)w, EV_TIMEOUT);
283 } 390 }
284} 391}
285 392
393static void
394time_update ()
395{
396 int i;
397 ev_now = ev_time ();
398
399 if (have_monotonic)
400 {
401 ev_tstamp odiff = diff;
402
403 /* detecting time jumps is much more difficult */
404 for (i = 2; --i; ) /* loop a few times, before making important decisions */
405 {
406 now = get_clock ();
407 diff = ev_now - now;
408
409 if (fabs (odiff - diff) < MIN_TIMEJUMP)
410 return; /* all is well */
411
412 ev_now = ev_time ();
413 }
414
415 /* time jump detected, reschedule atimers */
416 for (i = 0; i < atimercnt; ++i)
417 {
418 struct ev_timer *w = atimers [i];
419 w->at += ceil ((ev_now - w->at) / w->repeat + 1.) * w->repeat;
420 }
421 }
422 else
423 {
424 if (now > ev_now || now < ev_now - MAX_BLOCKTIME - MIN_TIMEJUMP)
425 /* time jump detected, adjust rtimers */
426 for (i = 0; i < rtimercnt; ++i)
427 rtimers [i]->at += ev_now - now;
428
429 now = ev_now;
430 }
431}
432
286int ev_loop_done; 433int ev_loop_done;
287 434
288int ev_loop (int flags) 435void ev_loop (int flags)
289{ 436{
290 double block; 437 double block;
291 ev_loop_done = flags & EVLOOP_ONESHOT; 438 ev_loop_done = flags & EVLOOP_ONESHOT;
292 439
293 do 440 do
294 { 441 {
295 /* update fd-related kernel structures */ 442 /* update fd-related kernel structures */
296 method_reify (); fdchangecnt = 0; 443 fd_reify ();
297 444
298 /* calculate blocking time */ 445 /* calculate blocking time */
299 ev_now = ev_time ();
300
301 if (flags & EVLOOP_NONBLOCK) 446 if (flags & EVLOOP_NONBLOCK)
302 block = 0.; 447 block = 0.;
303 else if (!timercnt)
304 block = MAX_BLOCKTIME;
305 else 448 else
306 { 449 {
450 block = MAX_BLOCKTIME;
451
452 if (rtimercnt)
453 {
307 block = timers [0]->at - ev_now + method_fudge; 454 ev_tstamp to = rtimers [0]->at - get_clock () + method_fudge;
455 if (block > to) block = to;
456 }
457
458 if (atimercnt)
459 {
460 ev_tstamp to = atimers [0]->at - ev_time () + method_fudge;
461 if (block > to) block = to;
462 }
463
308 if (block < 0.) block = 0.; 464 if (block < 0.) block = 0.;
309 else if (block > MAX_BLOCKTIME) block = MAX_BLOCKTIME;
310 } 465 }
311 466
312 fprintf (stderr, "block %f\n", block);//D
313 method_poll (block); 467 method_poll (block);
314 468
469 /* update ev_now, do magic */
470 time_update ();
471
315 /* put pending timers into pendign queue and reschedule them */ 472 /* put pending timers into pendign queue and reschedule them */
316 timer_reify (); 473 /* absolute timers first */
474 timers_reify (atimers, atimercnt, ev_now);
475 /* relative timers second */
476 timers_reify (rtimers, rtimercnt, now);
317 477
318 ev_now = ev_time ();
319 call_pending (); 478 call_pending ();
320 } 479 }
321 while (!ev_loop_done); 480 while (!ev_loop_done);
322} 481}
323 482
395evtimer_start (struct ev_timer *w) 554evtimer_start (struct ev_timer *w)
396{ 555{
397 if (ev_is_active (w)) 556 if (ev_is_active (w))
398 return; 557 return;
399 558
400 fprintf (stderr, "t1 %f a %d\n", w->at, w->is_abs);//D
401 if (w->is_abs) 559 if (w->is_abs)
402 { 560 {
561 /* this formula differs from the one in timer_reify becuse we do not round up */
403 if (w->repeat) 562 if (w->repeat)
404 w->at += ceil ((ev_now - w->at) / w->repeat) * w->repeat; 563 w->at += ceil ((ev_now - w->at) / w->repeat) * w->repeat;
564
565 ev_start ((struct ev_watcher *)w, ++atimercnt);
566 array_needsize (atimers, atimermax, atimercnt, );
567 atimers [atimercnt - 1] = w;
568 upheap (atimers, atimercnt - 1);
405 } 569 }
406 else 570 else
571 {
407 w->at += ev_now; 572 w->at += now;
408 fprintf (stderr, "t2 %f a %d\n", w->at, w->is_abs);//D
409 573
410 ev_start ((struct ev_watcher *)w, ++timercnt); 574 ev_start ((struct ev_watcher *)w, ++rtimercnt);
411 array_needsize (timers, timermax, timercnt, ); 575 array_needsize (rtimers, rtimermax, rtimercnt, );
412 timers [timercnt - 1] = w; 576 rtimers [rtimercnt - 1] = w;
413 upheap (timercnt - 1); 577 upheap (rtimers, rtimercnt - 1);
578 }
579
414} 580}
415 581
416void 582void
417evtimer_stop (struct ev_timer *w) 583evtimer_stop (struct ev_timer *w)
418{ 584{
419 if (!ev_is_active (w)) 585 if (!ev_is_active (w))
420 return; 586 return;
421 587
588 if (w->is_abs)
589 {
590 if (w->active < atimercnt--)
591 {
422 timers [w->active - 1] = timers [--timercnt]; 592 atimers [w->active - 1] = atimers [atimercnt];
423 downheap (w->active - 1); 593 downheap (atimers, atimercnt, w->active - 1);
594 }
595 }
596 else
597 {
598 if (w->active < rtimercnt--)
599 {
600 rtimers [w->active - 1] = rtimers [rtimercnt];
601 downheap (rtimers, rtimercnt, w->active - 1);
602 }
603 }
604
424 ev_stop ((struct ev_watcher *)w); 605 ev_stop ((struct ev_watcher *)w);
425} 606}
426 607
427void 608void
428evsignal_start (struct ev_signal *w) 609evsignal_start (struct ev_signal *w)
430 if (ev_is_active (w)) 611 if (ev_is_active (w))
431 return; 612 return;
432 613
433 ev_start ((struct ev_watcher *)w, 1); 614 ev_start ((struct ev_watcher *)w, 1);
434 array_needsize (signals, signalmax, w->signum, signals_init); 615 array_needsize (signals, signalmax, w->signum, signals_init);
435 wlist_add ((struct ev_watcher_list **)&signals [w->signum - 1], (struct ev_watcher_list *)w); 616 wlist_add ((struct ev_watcher_list **)&signals [w->signum - 1].head, (struct ev_watcher_list *)w);
617
618 if (!w->next)
619 {
620 struct sigaction sa;
621 sa.sa_handler = sighandler;
622 sigfillset (&sa.sa_mask);
623 sa.sa_flags = 0;
624 sigaction (w->signum, &sa, 0);
625 }
436} 626}
437 627
438void 628void
439evsignal_stop (struct ev_signal *w) 629evsignal_stop (struct ev_signal *w)
440{ 630{
441 if (!ev_is_active (w)) 631 if (!ev_is_active (w))
442 return; 632 return;
443 633
444 wlist_del ((struct ev_watcher_list **)&signals [w->signum - 1], (struct ev_watcher_list *)w); 634 wlist_del ((struct ev_watcher_list **)&signals [w->signum - 1].head, (struct ev_watcher_list *)w);
445 ev_stop ((struct ev_watcher *)w); 635 ev_stop ((struct ev_watcher *)w);
636
637 if (!signals [w->signum - 1].head)
638 signal (w->signum, SIG_DFL);
446} 639}
447 640
448/*****************************************************************************/ 641/*****************************************************************************/
449#if 1 642#if 1
450 643
455} 648}
456 649
457static void 650static void
458ocb (struct ev_timer *w, int revents) 651ocb (struct ev_timer *w, int revents)
459{ 652{
460 fprintf (stderr, "timer %f,%f (%x) (%f) d%p\n", w->at, w->repeat, revents, w->at - ev_time (), w->data); 653 //fprintf (stderr, "timer %f,%f (%x) (%f) d%p\n", w->at, w->repeat, revents, w->at - ev_time (), w->data);
654 evtimer_stop (w);
655 evtimer_start (w);
656}
657
658static void
659scb (struct ev_signal *w, int revents)
660{
661 fprintf (stderr, "signal %x,%d\n", revents, w->signum);
461} 662}
462 663
463int main (void) 664int main (void)
464{ 665{
465 struct ev_io sin; 666 struct ev_io sin;
468 669
469 evw_init (&sin, sin_cb, 55); 670 evw_init (&sin, sin_cb, 55);
470 evio_set (&sin, 0, EV_READ); 671 evio_set (&sin, 0, EV_READ);
471 evio_start (&sin); 672 evio_start (&sin);
472 673
674 struct ev_timer t[10000];
675
676#if 0
677 int i;
678 for (i = 0; i < 10000; ++i)
679 {
680 struct ev_timer *w = t + i;
681 evw_init (w, ocb, i);
682 evtimer_set_abs (w, drand48 (), 0.99775533);
683 evtimer_start (w);
684 if (drand48 () < 0.5)
685 evtimer_stop (w);
686 }
687#endif
688
473 struct ev_timer t1; 689 struct ev_timer t1;
474 evw_init (&t1, ocb, 1); 690 evw_init (&t1, ocb, 0);
475 evtimer_set_rel (&t1, 1, 0); 691 evtimer_set_abs (&t1, 5, 10);
476 evtimer_start (&t1); 692 evtimer_start (&t1);
477 693
478 struct ev_timer t2; 694 struct ev_signal sig;
479 evw_init (&t2, ocb, 2); 695 evw_init (&sig, scb, 65535);
480 evtimer_set_abs (&t2, ev_time () + 2, 0); 696 evsignal_set (&sig, SIGQUIT);
481 evtimer_start (&t2); 697 evsignal_start (&sig);
482 698
483 ev_loop (0); 699 ev_loop (0);
484 700
485 return 0; 701 return 0;
486} 702}

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines