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

# Content
1 #include <math.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <fcntl.h>
5 #include <signal.h>
6
7 #include <stdio.h>
8
9 #include <assert.h>
10 #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 #define HAVE_REALTIME 1
19 #define HAVE_EPOLL 1
20 #define HAVE_SELECT 1
21
22 #define MIN_TIMEJUMP 1. /* minimum timejump that gets detected (if monotonic clock available) */
23 #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 static ev_tstamp now, diff; /* monotonic clock */
36 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 static void (*method_modify)(int fd, int oev, int nev);
43 static void (*method_poll)(ev_tstamp timeout);
44
45 /*****************************************************************************/
46
47 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 int newcnt = cur ? cur << 1 : 16; \
80 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 /*****************************************************************************/
87
88 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 /*****************************************************************************/
145
146 static struct ev_timer **atimers;
147 static int atimermax, atimercnt;
148
149 static struct ev_timer **rtimers;
150 static int rtimermax, rtimercnt;
151
152 static void
153 upheap (struct ev_timer **timers, int k)
154 {
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 downheap (struct ev_timer **timers, int N, int k)
171 {
172 struct ev_timer *w = timers [k];
173
174 while (k < (N >> 1))
175 {
176 int j = k << 1;
177
178 if (j + 1 < N && timers [j]->at > timers [j + 1]->at)
179 ++j;
180
181 if (w->at <= timers [j]->at)
182 break;
183
184 timers [k] = timers [j];
185 timers [k]->active = k + 1;
186 k = j;
187 }
188
189 timers [k] = w;
190 timers [k]->active = k + 1;
191 }
192
193 /*****************************************************************************/
194
195 typedef struct
196 {
197 struct ev_signal *head;
198 sig_atomic_t gotsig;
199 } ANSIG;
200
201 static ANSIG *signals;
202 static int signalmax;
203
204 static int sigpipe [2];
205 static sig_atomic_t gotsig;
206 static struct ev_io sigev;
207
208 static void
209 signals_init (ANSIG *base, int count)
210 {
211 while (count--)
212 {
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 }
263
264 /*****************************************************************************/
265
266 #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 now = get_clock ();
285 diff = ev_now - now;
286
287 if (pipe (sigpipe))
288 return 0;
289
290 ev_method = EVMETHOD_NONE;
291 #if HAVE_EPOLL
292 if (ev_method == EVMETHOD_NONE) epoll_init (flags);
293 #endif
294 #if HAVE_SELECT
295 if (ev_method == EVMETHOD_NONE) select_init (flags);
296 #endif
297
298 if (ev_method)
299 {
300 evw_init (&sigev, sigcb, 0);
301 siginit ();
302 }
303
304 return ev_method;
305 }
306
307 /*****************************************************************************/
308
309 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 if (ev_method == EVMETHOD_EPOLL)
321 epoll_postfork_child ();
322 #endif
323
324 evio_stop (&sigev);
325 close (sigpipe [0]);
326 close (sigpipe [1]);
327 pipe (sigpipe);
328 siginit ();
329 }
330
331 /*****************************************************************************/
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 static void
355 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 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 timers_reify (struct ev_timer **timers, int timercnt, ev_tstamp now)
401 {
402 while (timercnt && timers [0]->at <= now)
403 {
404 struct ev_timer *w = timers [0];
405
406 /* first reschedule or stop timer */
407 if (w->repeat)
408 {
409 if (w->is_abs)
410 w->at += floor ((now - w->at) / w->repeat + 1.) * w->repeat;
411 else
412 w->at = now + w->repeat;
413
414 assert (w->at > now);
415
416 downheap (timers, timercnt, 0);
417 }
418 else
419 {
420 evtimer_stop (w); /* nonrepeating: stop timer */
421 --timercnt; /* maybe pass by reference instead? */
422 }
423
424 event ((struct ev_watcher *)w, EV_TIMEOUT);
425 }
426 }
427
428 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 int ev_loop_done;
469
470 void ev_loop (int flags)
471 {
472 double block;
473 ev_loop_done = flags & EVLOOP_ONESHOT;
474
475 do
476 {
477 hook_call (EVHOOK_PREPOLL);
478
479 /* update fd-related kernel structures */
480 fd_reify ();
481
482 /* calculate blocking time */
483 if (flags & EVLOOP_NONBLOCK)
484 block = 0.;
485 else
486 {
487 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 if (block < 0.) block = 0.;
502 }
503
504 method_poll (block);
505
506 /* update ev_now, do magic */
507 time_update ();
508
509 hook_call (EVHOOK_POSTPOLL);
510
511 /* put pending timers into pendign queue and reschedule them */
512 /* absolute timers first */
513 timers_reify (atimers, atimercnt, ev_now);
514 /* relative timers second */
515 timers_reify (rtimers, rtimercnt, now);
516
517 call_pending ();
518 }
519 while (!ev_loop_done);
520 }
521
522 /*****************************************************************************/
523
524 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 /*****************************************************************************/
564
565 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 /* this formula differs from the one in timer_reify becuse we do not round up */
605 if (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);
612 }
613 else
614 {
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
623 }
624
625 void
626 evtimer_stop (struct ev_timer *w)
627 {
628 if (!ev_is_active (w))
629 return;
630
631 if (w->is_abs)
632 {
633 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 }
647
648 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 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 }
670
671 void
672 evsignal_stop (struct ev_signal *w)
673 {
674 if (!ev_is_active (w))
675 return;
676
677 wlist_del ((struct ev_watcher_list **)&signals [w->signum - 1].head, (struct ev_watcher_list *)w);
678 ev_stop ((struct ev_watcher *)w);
679
680 if (!signals [w->signum - 1].head)
681 signal (w->signum, SIG_DFL);
682 }
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 //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
701 static void
702 scb (struct ev_signal *w, int revents)
703 {
704 fprintf (stderr, "signal %x,%d\n", revents, w->signum);
705 }
706
707 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 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
732 struct ev_timer t1;
733 evw_init (&t1, ocb, 0);
734 evtimer_set_abs (&t1, 5, 10);
735 evtimer_start (&t1);
736
737 struct ev_signal sig;
738 evw_init (&sig, scb, 65535);
739 evsignal_set (&sig, SIGQUIT);
740 evsignal_start (&sig);
741
742 ev_loop (0);
743
744 return 0;
745 }
746
747 #endif
748
749
750
751