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

Comparing libev/ev.c (file contents):
Revision 1.11 by root, Wed Oct 31 07:40:49 2007 UTC vs.
Revision 1.14 by root, Wed Oct 31 11:52:12 2007 UTC

9#include <assert.h> 9#include <assert.h>
10#include <errno.h> 10#include <errno.h>
11#include <sys/time.h> 11#include <sys/time.h>
12#include <time.h> 12#include <time.h>
13 13
14#define HAVE_EPOLL 1
15
14#ifndef HAVE_MONOTONIC 16#ifndef HAVE_MONOTONIC
15# ifdef CLOCK_MONOTONIC 17# ifdef CLOCK_MONOTONIC
16# define HAVE_MONOTONIC 1 18# define HAVE_MONOTONIC 1
17# endif 19# endif
18#endif 20#endif
32#define MIN_TIMEJUMP 1. /* minimum timejump that gets detected (if monotonic clock available) */ 34#define MIN_TIMEJUMP 1. /* minimum timejump that gets detected (if monotonic clock available) */
33#define MAX_BLOCKTIME 60. 35#define MAX_BLOCKTIME 60.
34 36
35#include "ev.h" 37#include "ev.h"
36 38
37struct ev_watcher {
38 EV_WATCHER (ev_watcher);
39};
40
41struct ev_watcher_list {
42 EV_WATCHER_LIST (ev_watcher_list);
43};
44
45typedef struct ev_watcher *W; 39typedef struct ev_watcher *W;
46typedef struct ev_watcher_list *WL; 40typedef struct ev_watcher_list *WL;
41typedef struct ev_watcher_time *WT;
47 42
48static ev_tstamp now, diff; /* monotonic clock */ 43static ev_tstamp now, diff; /* monotonic clock */
49ev_tstamp ev_now; 44ev_tstamp ev_now;
50int ev_method; 45int ev_method;
51 46
163 event (events [i], type); 158 event (events [i], type);
164} 159}
165 160
166/*****************************************************************************/ 161/*****************************************************************************/
167 162
168static struct ev_timer **atimers; 163static struct ev_timer **timers;
169static int atimermax, atimercnt; 164static int timermax, timercnt;
170 165
171static struct ev_timer **rtimers; 166static struct ev_periodic **periodics;
172static int rtimermax, rtimercnt; 167static int periodicmax, periodiccnt;
173 168
174static void 169static void
175upheap (struct ev_timer **timers, int k) 170upheap (WT *timers, int k)
176{ 171{
177 struct ev_timer *w = timers [k]; 172 WT w = timers [k];
178 173
179 while (k && timers [k >> 1]->at > w->at) 174 while (k && timers [k >> 1]->at > w->at)
180 { 175 {
181 timers [k] = timers [k >> 1]; 176 timers [k] = timers [k >> 1];
182 timers [k]->active = k + 1; 177 timers [k]->active = k + 1;
187 timers [k]->active = k + 1; 182 timers [k]->active = k + 1;
188 183
189} 184}
190 185
191static void 186static void
192downheap (struct ev_timer **timers, int N, int k) 187downheap (WT *timers, int N, int k)
193{ 188{
194 struct ev_timer *w = timers [k]; 189 WT w = timers [k];
195 190
196 while (k < (N >> 1)) 191 while (k < (N >> 1))
197 { 192 {
198 int j = k << 1; 193 int j = k << 1;
199 194
325 if (ev_method == EVMETHOD_NONE) select_init (flags); 320 if (ev_method == EVMETHOD_NONE) select_init (flags);
326#endif 321#endif
327 322
328 if (ev_method) 323 if (ev_method)
329 { 324 {
330 evw_init (&sigev, sigcb, 0); 325 evw_init (&sigev, sigcb);
331 siginit (); 326 siginit ();
332 } 327 }
333 328
334 return ev_method; 329 return ev_method;
335} 330}
406 401
407 pendingcnt = 0; 402 pendingcnt = 0;
408} 403}
409 404
410static void 405static void
411timers_reify (struct ev_timer **timers, int timercnt, ev_tstamp now) 406timers_reify ()
412{ 407{
413 while (timercnt && timers [0]->at <= now) 408 while (timercnt && timers [0]->at <= now)
414 { 409 {
415 struct ev_timer *w = timers [0]; 410 struct ev_timer *w = timers [0];
416 411
417 /* first reschedule or stop timer */ 412 /* first reschedule or stop timer */
418 if (w->repeat) 413 if (w->repeat)
419 { 414 {
420 if (w->is_abs)
421 w->at += floor ((now - w->at) / w->repeat + 1.) * w->repeat;
422 else
423 w->at = now + w->repeat; 415 w->at = now + w->repeat;
424 416 assert (("timer timeout in the past, negative repeat?", w->at > now));
425 assert (w->at > now);
426
427 downheap (timers, timercnt, 0); 417 downheap ((WT *)timers, timercnt, 0);
428 } 418 }
429 else 419 else
430 {
431 evtimer_stop (w); /* nonrepeating: stop timer */ 420 evtimer_stop (w); /* nonrepeating: stop timer */
432 --timercnt; /* maybe pass by reference instead? */
433 }
434 421
435 event ((W)w, EV_TIMEOUT); 422 event ((W)w, EV_TIMEOUT);
436 } 423 }
437} 424}
438 425
439static void 426static void
427periodics_reify ()
428{
429 while (periodiccnt && periodics [0]->at <= ev_now)
430 {
431 struct ev_periodic *w = periodics [0];
432
433 /* first reschedule or stop timer */
434 if (w->interval)
435 {
436 w->at += floor ((ev_now - w->at) / w->interval + 1.) * w->interval;
437 assert (("periodic timeout in the past, negative interval?", w->at > ev_now));
438 downheap ((WT *)periodics, periodiccnt, 0);
439 }
440 else
441 evperiodic_stop (w); /* nonrepeating: stop timer */
442
443 event ((W)w, EV_TIMEOUT);
444 }
445}
446
447static void
448periodics_reschedule (ev_tstamp diff)
449{
450 int i;
451
452 /* adjust periodics after time jump */
453 for (i = 0; i < periodiccnt; ++i)
454 {
455 struct ev_periodic *w = periodics [i];
456
457 if (w->interval)
458 {
459 ev_tstamp diff = ceil ((ev_now - w->at) / w->interval) * w->interval;
460
461 if (fabs (diff) >= 1e-4)
462 {
463 evperiodic_stop (w);
464 evperiodic_start (w);
465
466 i = 0; /* restart loop, inefficient, but time jumps should be rare */
467 }
468 }
469 }
470}
471
472static void
440time_update () 473time_update ()
441{ 474{
442 int i; 475 int i;
476
443 ev_now = ev_time (); 477 ev_now = ev_time ();
444 478
445 if (have_monotonic) 479 if (have_monotonic)
446 { 480 {
447 ev_tstamp odiff = diff; 481 ev_tstamp odiff = diff;
448 482
449 /* detecting time jumps is much more difficult */
450 for (i = 2; --i; ) /* loop a few times, before making important decisions */ 483 for (i = 4; --i; ) /* loop a few times, before making important decisions */
451 { 484 {
452 now = get_clock (); 485 now = get_clock ();
453 diff = ev_now - now; 486 diff = ev_now - now;
454 487
455 if (fabs (odiff - diff) < MIN_TIMEJUMP) 488 if (fabs (odiff - diff) < MIN_TIMEJUMP)
456 return; /* all is well */ 489 return; /* all is well */
457 490
458 ev_now = ev_time (); 491 ev_now = ev_time ();
459 } 492 }
460 493
461 /* time jump detected, reschedule atimers */ 494 periodics_reschedule (diff - odiff);
462 for (i = 0; i < atimercnt; ++i) 495 /* no timer adjustment, as the monotonic clock doesn't jump */
463 {
464 struct ev_timer *w = atimers [i];
465 w->at += ceil ((ev_now - w->at) / w->repeat + 1.) * w->repeat;
466 }
467 } 496 }
468 else 497 else
469 { 498 {
470 if (now > ev_now || now < ev_now - MAX_BLOCKTIME - MIN_TIMEJUMP) 499 if (now > ev_now || now < ev_now - MAX_BLOCKTIME - MIN_TIMEJUMP)
471 /* time jump detected, adjust rtimers */ 500 {
501 periodics_reschedule (ev_now - now);
502
503 /* adjust timers. this is easy, as the offset is the same for all */
472 for (i = 0; i < rtimercnt; ++i) 504 for (i = 0; i < timercnt; ++i)
473 rtimers [i]->at += ev_now - now; 505 timers [i]->at += diff;
506 }
474 507
475 now = ev_now; 508 now = ev_now;
476 } 509 }
477} 510}
478 511
479int ev_loop_done; 512int ev_loop_done;
480 513
481void ev_loop (int flags) 514void ev_loop (int flags)
482{ 515{
483 double block; 516 double block;
484 ev_loop_done = flags & EVLOOP_ONESHOT; 517 ev_loop_done = flags & EVLOOP_ONESHOT ? 1 : 0;
485 518
486 if (checkcnt) 519 if (checkcnt)
487 { 520 {
488 queue_events ((W *)checks, checkcnt, EV_CHECK); 521 queue_events ((W *)checks, checkcnt, EV_CHECK);
489 call_pending (); 522 call_pending ();
493 { 526 {
494 /* update fd-related kernel structures */ 527 /* update fd-related kernel structures */
495 fd_reify (); 528 fd_reify ();
496 529
497 /* calculate blocking time */ 530 /* calculate blocking time */
531
532 /* we only need this for !monotonic clock, but as we always have timers, we just calculate it every time */
533 ev_now = ev_time ();
534
498 if (flags & EVLOOP_NONBLOCK || idlecnt) 535 if (flags & EVLOOP_NONBLOCK || idlecnt)
499 block = 0.; 536 block = 0.;
500 else 537 else
501 { 538 {
502 block = MAX_BLOCKTIME; 539 block = MAX_BLOCKTIME;
503 540
504 if (rtimercnt) 541 if (timercnt)
505 { 542 {
506 ev_tstamp to = rtimers [0]->at - get_clock () + method_fudge; 543 ev_tstamp to = timers [0]->at - (have_monotonic ? get_clock () : ev_now) + method_fudge;
507 if (block > to) block = to; 544 if (block > to) block = to;
508 } 545 }
509 546
510 if (atimercnt) 547 if (periodiccnt)
511 { 548 {
512 ev_tstamp to = atimers [0]->at - ev_time () + method_fudge; 549 ev_tstamp to = periodics [0]->at - ev_now + method_fudge;
513 if (block > to) block = to; 550 if (block > to) block = to;
514 } 551 }
515 552
516 if (block < 0.) block = 0.; 553 if (block < 0.) block = 0.;
517 } 554 }
520 557
521 /* update ev_now, do magic */ 558 /* update ev_now, do magic */
522 time_update (); 559 time_update ();
523 560
524 /* queue pending timers and reschedule them */ 561 /* queue pending timers and reschedule them */
525 /* absolute timers first */ 562 periodics_reify (); /* absolute timers first */
526 timers_reify (atimers, atimercnt, ev_now);
527 /* relative timers second */ 563 timers_reify (); /* relative timers second */
528 timers_reify (rtimers, rtimercnt, now);
529 564
530 /* queue idle watchers unless io or timers are pending */ 565 /* queue idle watchers unless io or timers are pending */
531 if (!pendingcnt) 566 if (!pendingcnt)
532 queue_events ((W *)idles, idlecnt, EV_IDLE); 567 queue_events ((W *)idles, idlecnt, EV_IDLE);
533 568
535 queue_events ((W *)checks, checkcnt, EV_CHECK); 570 queue_events ((W *)checks, checkcnt, EV_CHECK);
536 571
537 call_pending (); 572 call_pending ();
538 } 573 }
539 while (!ev_loop_done); 574 while (!ev_loop_done);
575
576 if (ev_loop_done != 2)
577 ev_loop_done = 0;
540} 578}
541 579
542/*****************************************************************************/ 580/*****************************************************************************/
543 581
544static void 582static void
610 ++fdchangecnt; 648 ++fdchangecnt;
611 array_needsize (fdchanges, fdchangemax, fdchangecnt, ); 649 array_needsize (fdchanges, fdchangemax, fdchangecnt, );
612 fdchanges [fdchangecnt - 1] = w->fd; 650 fdchanges [fdchangecnt - 1] = w->fd;
613} 651}
614 652
653
615void 654void
616evtimer_start (struct ev_timer *w) 655evtimer_start (struct ev_timer *w)
617{ 656{
618 if (ev_is_active (w)) 657 if (ev_is_active (w))
619 return; 658 return;
620 659
621 if (w->is_abs) 660 w->at += now;
622 {
623 /* this formula differs from the one in timer_reify becuse we do not round up */
624 if (w->repeat)
625 w->at += ceil ((ev_now - w->at) / w->repeat) * w->repeat;
626 661
662 assert (("timer repeat value less than zero not allowed", w->repeat >= 0.));
663
627 ev_start ((W)w, ++atimercnt); 664 ev_start ((W)w, ++timercnt);
628 array_needsize (atimers, atimermax, atimercnt, ); 665 array_needsize (timers, timermax, timercnt, );
629 atimers [atimercnt - 1] = w; 666 timers [timercnt - 1] = w;
630 upheap (atimers, atimercnt - 1); 667 upheap ((WT *)timers, timercnt - 1);
631 }
632 else
633 {
634 w->at += now;
635
636 ev_start ((W)w, ++rtimercnt);
637 array_needsize (rtimers, rtimermax, rtimercnt, );
638 rtimers [rtimercnt - 1] = w;
639 upheap (rtimers, rtimercnt - 1);
640 }
641
642} 668}
643 669
644void 670void
645evtimer_stop (struct ev_timer *w) 671evtimer_stop (struct ev_timer *w)
646{ 672{
647 if (!ev_is_active (w)) 673 if (!ev_is_active (w))
648 return; 674 return;
649 675
650 if (w->is_abs)
651 {
652 if (w->active < atimercnt--) 676 if (w->active < timercnt--)
653 { 677 {
654 atimers [w->active - 1] = atimers [atimercnt]; 678 timers [w->active - 1] = timers [timercnt];
679 downheap ((WT *)timers, timercnt, w->active - 1);
680 }
681
682 w->at = w->repeat;
683
684 ev_stop ((W)w);
685}
686
687void
688evtimer_again (struct ev_timer *w)
689{
690 if (ev_is_active (w))
691 {
692 if (w->repeat)
693 {
694 w->at = now + w->repeat;
655 downheap (atimers, atimercnt, w->active - 1); 695 downheap ((WT *)timers, timercnt, w->active - 1);
656 }
657 }
658 else
659 {
660 if (w->active < rtimercnt--)
661 { 696 }
662 rtimers [w->active - 1] = rtimers [rtimercnt]; 697 else
663 downheap (rtimers, rtimercnt, w->active - 1); 698 evtimer_stop (w);
664 } 699 }
700 else if (w->repeat)
701 evtimer_start (w);
702}
703
704void
705evperiodic_start (struct ev_periodic *w)
706{
707 if (ev_is_active (w))
708 return;
709
710 assert (("periodic interval value less than zero not allowed", w->interval >= 0.));
711
712 /* this formula differs from the one in periodic_reify because we do not always round up */
713 if (w->interval)
714 w->at += ceil ((ev_now - w->at) / w->interval) * w->interval;
715
716 ev_start ((W)w, ++periodiccnt);
717 array_needsize (periodics, periodicmax, periodiccnt, );
718 periodics [periodiccnt - 1] = w;
719 upheap ((WT *)periodics, periodiccnt - 1);
720}
721
722void
723evperiodic_stop (struct ev_periodic *w)
724{
725 if (!ev_is_active (w))
726 return;
727
728 if (w->active < periodiccnt--)
729 {
730 periodics [w->active - 1] = periodics [periodiccnt];
731 downheap ((WT *)periodics, periodiccnt, w->active - 1);
665 } 732 }
666 733
667 ev_stop ((W)w); 734 ev_stop ((W)w);
668} 735}
669 736
734 801
735/*****************************************************************************/ 802/*****************************************************************************/
736 803
737#if 0 804#if 0
738 805
806struct ev_io wio;
807
739static void 808static void
740sin_cb (struct ev_io *w, int revents) 809sin_cb (struct ev_io *w, int revents)
741{ 810{
742 fprintf (stderr, "sin %d, revents %d\n", w->fd, revents); 811 fprintf (stderr, "sin %d, revents %d\n", w->fd, revents);
743} 812}
752 821
753static void 822static void
754scb (struct ev_signal *w, int revents) 823scb (struct ev_signal *w, int revents)
755{ 824{
756 fprintf (stderr, "signal %x,%d\n", revents, w->signum); 825 fprintf (stderr, "signal %x,%d\n", revents, w->signum);
826 evio_stop (&wio);
827 evio_start (&wio);
757} 828}
758 829
759static void 830static void
760gcb (struct ev_signal *w, int revents) 831gcb (struct ev_signal *w, int revents)
761{ 832{
762 fprintf (stderr, "generic %x\n", revents); 833 fprintf (stderr, "generic %x\n", revents);
834
763} 835}
764 836
765int main (void) 837int main (void)
766{ 838{
767 struct ev_io sin;
768
769 ev_init (0); 839 ev_init (0);
770 840
771 evw_init (&sin, sin_cb, 55);
772 evio_set (&sin, 0, EV_READ); 841 evio_init (&wio, sin_cb, 0, EV_READ);
773 evio_start (&sin); 842 evio_start (&wio);
774 843
775 struct ev_timer t[10000]; 844 struct ev_timer t[10000];
776 845
777#if 0 846#if 0
778 int i; 847 int i;
779 for (i = 0; i < 10000; ++i) 848 for (i = 0; i < 10000; ++i)
780 { 849 {
781 struct ev_timer *w = t + i; 850 struct ev_timer *w = t + i;
782 evw_init (w, ocb, i); 851 evw_init (w, ocb, i);
783 evtimer_set_abs (w, drand48 (), 0.99775533); 852 evtimer_init_abs (w, ocb, drand48 (), 0.99775533);
784 evtimer_start (w); 853 evtimer_start (w);
785 if (drand48 () < 0.5) 854 if (drand48 () < 0.5)
786 evtimer_stop (w); 855 evtimer_stop (w);
787 } 856 }
788#endif 857#endif
789 858
790 struct ev_timer t1; 859 struct ev_timer t1;
791 evw_init (&t1, ocb, 0); 860 evtimer_init (&t1, ocb, 5, 10);
792 evtimer_set_abs (&t1, 5, 10);
793 evtimer_start (&t1); 861 evtimer_start (&t1);
794 862
795 struct ev_signal sig; 863 struct ev_signal sig;
796 evw_init (&sig, scb, 65535);
797 evsignal_set (&sig, SIGQUIT); 864 evsignal_init (&sig, scb, SIGQUIT);
798 evsignal_start (&sig); 865 evsignal_start (&sig);
799 866
800 struct ev_check cw; 867 struct ev_check cw;
801 evw_init (&cw, gcb, 0); 868 evcheck_init (&cw, gcb);
802 evcheck_start (&cw); 869 evcheck_start (&cw);
803 870
804 struct ev_idle iw; 871 struct ev_idle iw;
805 evw_init (&iw, gcb, 0); 872 evidle_init (&iw, gcb);
806 evidle_start (&iw); 873 evidle_start (&iw);
807 874
808 ev_loop (0); 875 ev_loop (0);
809 876
810 return 0; 877 return 0;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines