ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/libev/ev.c
Revision: 1.8
Committed: Wed Oct 31 00:32:33 2007 UTC (16 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.7: +44 -1 lines
Log Message:
implement primitive hook management

File Contents

# User Rev Content
1 root 1.1 #include <math.h>
2     #include <stdlib.h>
3 root 1.7 #include <unistd.h>
4     #include <fcntl.h>
5     #include <signal.h>
6 root 1.1
7     #include <stdio.h>
8    
9 root 1.4 #include <assert.h>
10 root 1.1 #include <errno.h>
11     #include <sys/time.h>
12     #include <time.h>
13    
14     #ifdef CLOCK_MONOTONIC
15     # define HAVE_MONOTONIC 1
16     #endif
17    
18 root 1.6 #define HAVE_REALTIME 1
19 root 1.1 #define HAVE_EPOLL 1
20 root 1.5 #define HAVE_SELECT 1
21 root 1.1
22 root 1.4 #define MIN_TIMEJUMP 1. /* minimum timejump that gets detected (if monotonic clock available) */
23 root 1.1 #define MAX_BLOCKTIME 60.
24    
25     #include "ev.h"
26    
27     struct ev_watcher {
28     EV_WATCHER (ev_watcher);
29     };
30    
31     struct ev_watcher_list {
32     EV_WATCHER_LIST (ev_watcher_list);
33     };
34    
35 root 1.4 static ev_tstamp now, diff; /* monotonic clock */
36 root 1.1 ev_tstamp ev_now;
37     int ev_method;
38    
39     static int have_monotonic; /* runtime */
40    
41     static ev_tstamp method_fudge; /* stupid epoll-returns-early bug */
42 root 1.5 static void (*method_modify)(int fd, int oev, int nev);
43 root 1.1 static void (*method_poll)(ev_tstamp timeout);
44    
45 root 1.8 /*****************************************************************************/
46    
47 root 1.1 ev_tstamp
48     ev_time (void)
49     {
50     #if HAVE_REALTIME
51     struct timespec ts;
52     clock_gettime (CLOCK_REALTIME, &ts);
53     return ts.tv_sec + ts.tv_nsec * 1e-9;
54     #else
55     struct timeval tv;
56     gettimeofday (&tv, 0);
57     return tv.tv_sec + tv.tv_usec * 1e-6;
58     #endif
59     }
60    
61     static ev_tstamp
62     get_clock (void)
63     {
64     #if HAVE_MONOTONIC
65     if (have_monotonic)
66     {
67     struct timespec ts;
68     clock_gettime (CLOCK_MONOTONIC, &ts);
69     return ts.tv_sec + ts.tv_nsec * 1e-9;
70     }
71     #endif
72    
73     return ev_time ();
74     }
75    
76     #define array_needsize(base,cur,cnt,init) \
77     if ((cnt) > cur) \
78     { \
79 root 1.2 int newcnt = cur ? cur << 1 : 16; \
80 root 1.1 fprintf (stderr, "resize(" # base ") from %d to %d\n", cur, newcnt);\
81     base = realloc (base, sizeof (*base) * (newcnt)); \
82     init (base + cur, newcnt - cur); \
83     cur = newcnt; \
84     }
85    
86 root 1.8 /*****************************************************************************/
87    
88 root 1.1 typedef struct
89     {
90     struct ev_io *head;
91     unsigned char wev, rev; /* want, received event set */
92     } ANFD;
93    
94     static ANFD *anfds;
95     static int anfdmax;
96    
97     static int *fdchanges;
98     static int fdchangemax, fdchangecnt;
99    
100     static void
101     anfds_init (ANFD *base, int count)
102     {
103     while (count--)
104     {
105     base->head = 0;
106     base->wev = base->rev = EV_NONE;
107     ++base;
108     }
109     }
110    
111     typedef struct
112     {
113     struct ev_watcher *w;
114     int events;
115     } ANPENDING;
116    
117     static ANPENDING *pendings;
118     static int pendingmax, pendingcnt;
119    
120     static void
121     event (struct ev_watcher *w, int events)
122     {
123     w->pending = ++pendingcnt;
124     array_needsize (pendings, pendingmax, pendingcnt, );
125     pendings [pendingcnt - 1].w = w;
126     pendings [pendingcnt - 1].events = events;
127     }
128    
129     static void
130     fd_event (int fd, int events)
131     {
132     ANFD *anfd = anfds + fd;
133     struct ev_io *w;
134    
135     for (w = anfd->head; w; w = w->next)
136     {
137     int ev = w->events & events;
138    
139     if (ev)
140     event ((struct ev_watcher *)w, ev);
141     }
142     }
143    
144 root 1.8 /*****************************************************************************/
145    
146 root 1.4 static struct ev_timer **atimers;
147     static int atimermax, atimercnt;
148    
149     static struct ev_timer **rtimers;
150     static int rtimermax, rtimercnt;
151 root 1.1
152     static void
153 root 1.4 upheap (struct ev_timer **timers, int k)
154 root 1.1 {
155     struct ev_timer *w = timers [k];
156    
157     while (k && timers [k >> 1]->at > w->at)
158     {
159     timers [k] = timers [k >> 1];
160     timers [k]->active = k + 1;
161     k >>= 1;
162     }
163    
164     timers [k] = w;
165     timers [k]->active = k + 1;
166    
167     }
168    
169     static void
170 root 1.4 downheap (struct ev_timer **timers, int N, int k)
171 root 1.1 {
172     struct ev_timer *w = timers [k];
173    
174 root 1.4 while (k < (N >> 1))
175 root 1.1 {
176     int j = k << 1;
177    
178 root 1.4 if (j + 1 < N && timers [j]->at > timers [j + 1]->at)
179 root 1.1 ++j;
180    
181     if (w->at <= timers [j]->at)
182     break;
183    
184     timers [k] = timers [j];
185 root 1.2 timers [k]->active = k + 1;
186 root 1.1 k = j;
187     }
188    
189     timers [k] = w;
190     timers [k]->active = k + 1;
191     }
192    
193 root 1.8 /*****************************************************************************/
194    
195 root 1.7 typedef struct
196     {
197     struct ev_signal *head;
198     sig_atomic_t gotsig;
199     } ANSIG;
200    
201     static ANSIG *signals;
202 root 1.4 static int signalmax;
203 root 1.1
204 root 1.7 static int sigpipe [2];
205     static sig_atomic_t gotsig;
206     static struct ev_io sigev;
207    
208 root 1.1 static void
209 root 1.7 signals_init (ANSIG *base, int count)
210 root 1.1 {
211     while (count--)
212 root 1.7 {
213     base->head = 0;
214     base->gotsig = 0;
215     ++base;
216     }
217     }
218    
219     static void
220     sighandler (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    
231     static void
232     sigcb (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    
250     static void
251     siginit (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 root 1.1 }
263    
264 root 1.8 /*****************************************************************************/
265    
266 root 1.1 #if HAVE_EPOLL
267     # include "ev_epoll.c"
268     #endif
269     #if HAVE_SELECT
270     # include "ev_select.c"
271     #endif
272    
273     int ev_init (int flags)
274     {
275     #if HAVE_MONOTONIC
276     {
277     struct timespec ts;
278     if (!clock_gettime (CLOCK_MONOTONIC, &ts))
279     have_monotonic = 1;
280     }
281     #endif
282    
283     ev_now = ev_time ();
284 root 1.4 now = get_clock ();
285     diff = ev_now - now;
286 root 1.1
287 root 1.7 if (pipe (sigpipe))
288     return 0;
289    
290     ev_method = EVMETHOD_NONE;
291 root 1.1 #if HAVE_EPOLL
292 root 1.7 if (ev_method == EVMETHOD_NONE) epoll_init (flags);
293 root 1.1 #endif
294     #if HAVE_SELECT
295 root 1.7 if (ev_method == EVMETHOD_NONE) select_init (flags);
296 root 1.1 #endif
297    
298 root 1.7 if (ev_method)
299     {
300     evw_init (&sigev, sigcb, 0);
301     siginit ();
302     }
303    
304 root 1.1 return ev_method;
305     }
306    
307 root 1.8 /*****************************************************************************/
308    
309 root 1.1 void ev_prefork (void)
310     {
311     }
312    
313     void ev_postfork_parent (void)
314     {
315     }
316    
317     void ev_postfork_child (void)
318     {
319     #if HAVE_EPOLL
320 root 1.5 if (ev_method == EVMETHOD_EPOLL)
321     epoll_postfork_child ();
322 root 1.1 #endif
323 root 1.7
324     evio_stop (&sigev);
325     close (sigpipe [0]);
326     close (sigpipe [1]);
327     pipe (sigpipe);
328     siginit ();
329 root 1.1 }
330    
331 root 1.8 /*****************************************************************************/
332    
333     static ev_hook hooks [EVHOOK_NUM];
334    
335     void
336     ev_hook_register (int type, ev_hook hook)
337     {
338     hooks [type] = hook;
339     }
340    
341     void
342     ev_hook_unregister (int type, ev_hook hook)
343     {
344     hooks [type] = 0;
345     }
346    
347     static void
348     hook_call (int type)
349     {
350     if (hooks [type])
351     hooks [type] ();
352     }
353    
354 root 1.1 static void
355 root 1.5 fd_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;
378     }
379    
380     static void
381 root 1.1 call_pending ()
382     {
383     int i;
384    
385     for (i = 0; i < pendingcnt; ++i)
386     {
387     ANPENDING *p = pendings + i;
388    
389     if (p->w)
390     {
391     p->w->pending = 0;
392     p->w->cb (p->w, p->events);
393     }
394     }
395    
396     pendingcnt = 0;
397     }
398    
399     static void
400 root 1.4 timers_reify (struct ev_timer **timers, int timercnt, ev_tstamp now)
401 root 1.1 {
402 root 1.4 while (timercnt && timers [0]->at <= now)
403 root 1.1 {
404     struct ev_timer *w = timers [0];
405    
406 root 1.4 /* first reschedule or stop timer */
407 root 1.1 if (w->repeat)
408     {
409     if (w->is_abs)
410 root 1.4 w->at += floor ((now - w->at) / w->repeat + 1.) * w->repeat;
411 root 1.1 else
412 root 1.4 w->at = now + w->repeat;
413    
414     assert (w->at > now);
415 root 1.1
416 root 1.4 downheap (timers, timercnt, 0);
417 root 1.1 }
418     else
419 root 1.4 {
420     evtimer_stop (w); /* nonrepeating: stop timer */
421     --timercnt; /* maybe pass by reference instead? */
422     }
423 root 1.1
424     event ((struct ev_watcher *)w, EV_TIMEOUT);
425     }
426     }
427    
428 root 1.4 static void
429     time_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    
468 root 1.1 int ev_loop_done;
469    
470 root 1.4 void ev_loop (int flags)
471 root 1.1 {
472     double block;
473     ev_loop_done = flags & EVLOOP_ONESHOT;
474    
475     do
476     {
477 root 1.8 hook_call (EVHOOK_PREPOLL);
478    
479 root 1.1 /* update fd-related kernel structures */
480 root 1.5 fd_reify ();
481 root 1.1
482     /* calculate blocking time */
483     if (flags & EVLOOP_NONBLOCK)
484     block = 0.;
485     else
486     {
487 root 1.4 block = MAX_BLOCKTIME;
488    
489     if (rtimercnt)
490     {
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    
501 root 1.1 if (block < 0.) block = 0.;
502     }
503    
504     method_poll (block);
505    
506 root 1.4 /* update ev_now, do magic */
507     time_update ();
508    
509 root 1.8 hook_call (EVHOOK_POSTPOLL);
510    
511 root 1.1 /* put pending timers into pendign queue and reschedule them */
512 root 1.4 /* absolute timers first */
513     timers_reify (atimers, atimercnt, ev_now);
514     /* relative timers second */
515     timers_reify (rtimers, rtimercnt, now);
516 root 1.1
517     call_pending ();
518     }
519     while (!ev_loop_done);
520     }
521    
522 root 1.8 /*****************************************************************************/
523    
524 root 1.1 static void
525     wlist_add (struct ev_watcher_list **head, struct ev_watcher_list *elem)
526     {
527     elem->next = *head;
528     *head = elem;
529     }
530    
531     static void
532     wlist_del (struct ev_watcher_list **head, struct ev_watcher_list *elem)
533     {
534     while (*head)
535     {
536     if (*head == elem)
537     {
538     *head = elem->next;
539     return;
540     }
541    
542     head = &(*head)->next;
543     }
544     }
545    
546     static void
547     ev_start (struct ev_watcher *w, int active)
548     {
549     w->pending = 0;
550     w->active = active;
551     }
552    
553     static void
554     ev_stop (struct ev_watcher *w)
555     {
556     if (w->pending)
557     pendings [w->pending - 1].w = 0;
558    
559     w->active = 0;
560     /* nop */
561     }
562    
563 root 1.8 /*****************************************************************************/
564    
565 root 1.1 void
566     evio_start (struct ev_io *w)
567     {
568     if (ev_is_active (w))
569     return;
570    
571     int fd = w->fd;
572    
573     ev_start ((struct ev_watcher *)w, 1);
574     array_needsize (anfds, anfdmax, fd + 1, anfds_init);
575     wlist_add ((struct ev_watcher_list **)&anfds[fd].head, (struct ev_watcher_list *)w);
576    
577     ++fdchangecnt;
578     array_needsize (fdchanges, fdchangemax, fdchangecnt, );
579     fdchanges [fdchangecnt - 1] = fd;
580     }
581    
582     void
583     evio_stop (struct ev_io *w)
584     {
585     if (!ev_is_active (w))
586     return;
587    
588     wlist_del ((struct ev_watcher_list **)&anfds[w->fd].head, (struct ev_watcher_list *)w);
589     ev_stop ((struct ev_watcher *)w);
590    
591     ++fdchangecnt;
592     array_needsize (fdchanges, fdchangemax, fdchangecnt, );
593     fdchanges [fdchangecnt - 1] = w->fd;
594     }
595    
596     void
597     evtimer_start (struct ev_timer *w)
598     {
599     if (ev_is_active (w))
600     return;
601    
602     if (w->is_abs)
603     {
604 root 1.2 /* this formula differs from the one in timer_reify becuse we do not round up */
605 root 1.1 if (w->repeat)
606     w->at += ceil ((ev_now - w->at) / w->repeat) * w->repeat;
607 root 1.4
608     ev_start ((struct ev_watcher *)w, ++atimercnt);
609     array_needsize (atimers, atimermax, atimercnt, );
610     atimers [atimercnt - 1] = w;
611     upheap (atimers, atimercnt - 1);
612 root 1.1 }
613     else
614 root 1.4 {
615     w->at += now;
616    
617     ev_start ((struct ev_watcher *)w, ++rtimercnt);
618     array_needsize (rtimers, rtimermax, rtimercnt, );
619     rtimers [rtimercnt - 1] = w;
620     upheap (rtimers, rtimercnt - 1);
621     }
622 root 1.1
623     }
624    
625     void
626     evtimer_stop (struct ev_timer *w)
627     {
628     if (!ev_is_active (w))
629     return;
630    
631 root 1.4 if (w->is_abs)
632 root 1.2 {
633 root 1.4 if (w->active < atimercnt--)
634     {
635     atimers [w->active - 1] = atimers [atimercnt];
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 root 1.2 }
647    
648 root 1.1 ev_stop ((struct ev_watcher *)w);
649     }
650    
651     void
652     evsignal_start (struct ev_signal *w)
653     {
654     if (ev_is_active (w))
655     return;
656    
657     ev_start ((struct ev_watcher *)w, 1);
658     array_needsize (signals, signalmax, w->signum, signals_init);
659 root 1.7 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     }
669 root 1.1 }
670    
671     void
672     evsignal_stop (struct ev_signal *w)
673     {
674     if (!ev_is_active (w))
675     return;
676    
677 root 1.7 wlist_del ((struct ev_watcher_list **)&signals [w->signum - 1].head, (struct ev_watcher_list *)w);
678 root 1.1 ev_stop ((struct ev_watcher *)w);
679 root 1.7
680     if (!signals [w->signum - 1].head)
681     signal (w->signum, SIG_DFL);
682 root 1.1 }
683    
684     /*****************************************************************************/
685     #if 1
686    
687     static void
688     sin_cb (struct ev_io *w, int revents)
689     {
690     fprintf (stderr, "sin %d, revents %d\n", w->fd, revents);
691     }
692    
693     static void
694     ocb (struct ev_timer *w, int revents)
695     {
696 root 1.4 //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 root 1.1 }
700    
701 root 1.7 static void
702     scb (struct ev_signal *w, int revents)
703     {
704     fprintf (stderr, "signal %x,%d\n", revents, w->signum);
705     }
706    
707 root 1.1 int main (void)
708     {
709     struct ev_io sin;
710    
711     ev_init (0);
712    
713     evw_init (&sin, sin_cb, 55);
714     evio_set (&sin, 0, EV_READ);
715     evio_start (&sin);
716    
717 root 1.4 struct ev_timer t[10000];
718 root 1.2
719 root 1.8 #if 1
720 root 1.2 int i;
721 root 1.4 for (i = 0; i < 10000; ++i)
722 root 1.2 {
723     struct ev_timer *w = t + i;
724     evw_init (w, ocb, i);
725 root 1.4 evtimer_set_abs (w, drand48 (), 0.99775533);
726 root 1.2 evtimer_start (w);
727     if (drand48 () < 0.5)
728     evtimer_stop (w);
729     }
730 root 1.4 #endif
731    
732     struct ev_timer t1;
733     evw_init (&t1, ocb, 0);
734     evtimer_set_abs (&t1, 5, 10);
735     evtimer_start (&t1);
736 root 1.1
737 root 1.7 struct ev_signal sig;
738     evw_init (&sig, scb, 65535);
739     evsignal_set (&sig, SIGQUIT);
740     evsignal_start (&sig);
741    
742 root 1.1 ev_loop (0);
743    
744     return 0;
745     }
746    
747     #endif
748    
749    
750    
751