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

Comparing libev/ev.c (file contents):
Revision 1.3 by root, Tue Oct 30 21:45:00 2007 UTC vs.
Revision 1.4 by root, Tue Oct 30 23:10:33 2007 UTC

1#include <math.h> 1#include <math.h>
2#include <stdlib.h> 2#include <stdlib.h>
3 3
4#include <stdio.h> 4#include <stdio.h>
5 5
6#include <assert.h>
6#include <errno.h> 7#include <errno.h>
7#include <sys/time.h> 8#include <sys/time.h>
8#include <time.h> 9#include <time.h>
9 10
10#ifdef CLOCK_MONOTONIC 11#ifdef CLOCK_MONOTONIC
13 14
14#define HAVE_EPOLL 1 15#define HAVE_EPOLL 1
15#define HAVE_REALTIME 1 16#define HAVE_REALTIME 1
16#define HAVE_SELECT 0 17#define HAVE_SELECT 0
17 18
19#define MIN_TIMEJUMP 1. /* minimum timejump that gets detected (if monotonic clock available) */
18#define MAX_BLOCKTIME 60. 20#define MAX_BLOCKTIME 60.
19 21
20#include "ev.h" 22#include "ev.h"
21 23
22struct ev_watcher { 24struct ev_watcher {
25 27
26struct ev_watcher_list { 28struct ev_watcher_list {
27 EV_WATCHER_LIST (ev_watcher_list); 29 EV_WATCHER_LIST (ev_watcher_list);
28}; 30};
29 31
32static ev_tstamp now, diff; /* monotonic clock */
30ev_tstamp ev_now; 33ev_tstamp ev_now;
31int ev_method; 34int ev_method;
32 35
33static int have_monotonic; /* runtime */ 36static int have_monotonic; /* runtime */
34 37
129 if (ev) 132 if (ev)
130 event ((struct ev_watcher *)w, ev); 133 event ((struct ev_watcher *)w, ev);
131 } 134 }
132} 135}
133 136
134static struct ev_timer **timers; 137static struct ev_timer **atimers;
135static int timermax, timercnt; 138static int atimermax, atimercnt;
136 139
140static struct ev_timer **rtimers;
141static int rtimermax, rtimercnt;
142
137static void 143static void
138upheap (int k) 144upheap (struct ev_timer **timers, int k)
139{ 145{
140 struct ev_timer *w = timers [k]; 146 struct ev_timer *w = timers [k];
141 147
142 while (k && timers [k >> 1]->at > w->at) 148 while (k && timers [k >> 1]->at > w->at)
143 { 149 {
150 timers [k]->active = k + 1; 156 timers [k]->active = k + 1;
151 157
152} 158}
153 159
154static void 160static void
155downheap (int k) 161downheap (struct ev_timer **timers, int N, int k)
156{ 162{
157 struct ev_timer *w = timers [k]; 163 struct ev_timer *w = timers [k];
158 164
159 while (k < (timercnt >> 1)) 165 while (k < (N >> 1))
160 { 166 {
161 int j = k << 1; 167 int j = k << 1;
162 168
163 if (j + 1 < timercnt && timers [j]->at > timers [j + 1]->at) 169 if (j + 1 < N && timers [j]->at > timers [j + 1]->at)
164 ++j; 170 ++j;
165 171
166 if (w->at <= timers [j]->at) 172 if (w->at <= timers [j]->at)
167 break; 173 break;
168 174
174 timers [k] = w; 180 timers [k] = w;
175 timers [k]->active = k + 1; 181 timers [k]->active = k + 1;
176} 182}
177 183
178static struct ev_signal **signals; 184static struct ev_signal **signals;
179static int signalmax, signalcnt; 185static int signalmax;
180 186
181static void 187static void
182signals_init (struct ev_signal **base, int count) 188signals_init (struct ev_signal **base, int count)
183{ 189{
184 while (count--) 190 while (count--)
201 have_monotonic = 1; 207 have_monotonic = 1;
202 } 208 }
203#endif 209#endif
204 210
205 ev_now = ev_time (); 211 ev_now = ev_time ();
212 now = get_clock ();
213 diff = ev_now - now;
206 214
207#if HAVE_EPOLL 215#if HAVE_EPOLL
208 if (epoll_init (flags)) 216 if (epoll_init (flags))
209 return ev_method; 217 return ev_method;
210#endif 218#endif
250 258
251 pendingcnt = 0; 259 pendingcnt = 0;
252} 260}
253 261
254static void 262static void
255timer_reify (void) 263timers_reify (struct ev_timer **timers, int timercnt, ev_tstamp now)
256{ 264{
257 while (timercnt && timers [0]->at <= ev_now) 265 while (timercnt && timers [0]->at <= now)
258 { 266 {
259 struct ev_timer *w = timers [0]; 267 struct ev_timer *w = timers [0];
260 268
261 /* first reschedule timer */ 269 /* first reschedule or stop timer */
262 if (w->repeat) 270 if (w->repeat)
263 { 271 {
264 if (w->is_abs) 272 if (w->is_abs)
265 w->at += ceil ((ev_now - w->at) / w->repeat + 1.) * w->repeat; 273 w->at += floor ((now - w->at) / w->repeat + 1.) * w->repeat;
266 else 274 else
267 w->at = ev_now + w->repeat; 275 w->at = now + w->repeat;
268 276
269 downheap (0); 277 assert (w->at > now);
278
279 downheap (timers, timercnt, 0);
270 } 280 }
271 else 281 else
282 {
272 evtimer_stop (w); /* nonrepeating: stop timer */ 283 evtimer_stop (w); /* nonrepeating: stop timer */
284 --timercnt; /* maybe pass by reference instead? */
285 }
273 286
274 event ((struct ev_watcher *)w, EV_TIMEOUT); 287 event ((struct ev_watcher *)w, EV_TIMEOUT);
275 } 288 }
276} 289}
277 290
291static void
292time_update ()
293{
294 int i;
295 ev_now = ev_time ();
296
297 if (have_monotonic)
298 {
299 ev_tstamp odiff = diff;
300
301 /* detecting time jumps is much more difficult */
302 for (i = 2; --i; ) /* loop a few times, before making important decisions */
303 {
304 now = get_clock ();
305 diff = ev_now - now;
306
307 if (fabs (odiff - diff) < MIN_TIMEJUMP)
308 return; /* all is well */
309
310 ev_now = ev_time ();
311 }
312
313 /* time jump detected, reschedule atimers */
314 for (i = 0; i < atimercnt; ++i)
315 {
316 struct ev_timer *w = atimers [i];
317 w->at += ceil ((ev_now - w->at) / w->repeat + 1.) * w->repeat;
318 }
319 }
320 else
321 {
322 if (now > ev_now || now < ev_now - MAX_BLOCKTIME - MIN_TIMEJUMP)
323 /* time jump detected, adjust rtimers */
324 for (i = 0; i < rtimercnt; ++i)
325 rtimers [i]->at += ev_now - now;
326
327 now = ev_now;
328 }
329}
330
278int ev_loop_done; 331int ev_loop_done;
279 332
280int ev_loop (int flags) 333void ev_loop (int flags)
281{ 334{
282 double block; 335 double block;
283 ev_loop_done = flags & EVLOOP_ONESHOT; 336 ev_loop_done = flags & EVLOOP_ONESHOT;
284 337
285 do 338 do
286 { 339 {
287 /* update fd-related kernel structures */ 340 /* update fd-related kernel structures */
288 method_reify (); fdchangecnt = 0; 341 method_reify (); fdchangecnt = 0;
289 342
290 /* calculate blocking time */ 343 /* calculate blocking time */
291 ev_now = ev_time ();
292
293 if (flags & EVLOOP_NONBLOCK) 344 if (flags & EVLOOP_NONBLOCK)
294 block = 0.; 345 block = 0.;
295 else if (!timercnt)
296 block = MAX_BLOCKTIME;
297 else 346 else
298 { 347 {
348 block = MAX_BLOCKTIME;
349
350 if (rtimercnt)
351 {
299 block = timers [0]->at - ev_now + method_fudge; 352 ev_tstamp to = rtimers [0]->at - get_clock () + method_fudge;
353 if (block > to) block = to;
354 }
355
356 if (atimercnt)
357 {
358 ev_tstamp to = atimers [0]->at - ev_time () + method_fudge;
359 if (block > to) block = to;
360 }
361
300 if (block < 0.) block = 0.; 362 if (block < 0.) block = 0.;
301 else if (block > MAX_BLOCKTIME) block = MAX_BLOCKTIME;
302 } 363 }
303 364
304 method_poll (block); 365 method_poll (block);
305 366
367 /* update ev_now, do magic */
368 time_update ();
369
306 /* put pending timers into pendign queue and reschedule them */ 370 /* put pending timers into pendign queue and reschedule them */
307 timer_reify (); 371 /* absolute timers first */
372 timers_reify (atimers, atimercnt, ev_now);
373 /* relative timers second */
374 timers_reify (rtimers, rtimercnt, now);
308 375
309 ev_now = ev_time ();
310 call_pending (); 376 call_pending ();
311 } 377 }
312 while (!ev_loop_done); 378 while (!ev_loop_done);
313} 379}
314 380
391 if (w->is_abs) 457 if (w->is_abs)
392 { 458 {
393 /* this formula differs from the one in timer_reify becuse we do not round up */ 459 /* this formula differs from the one in timer_reify becuse we do not round up */
394 if (w->repeat) 460 if (w->repeat)
395 w->at += ceil ((ev_now - w->at) / w->repeat) * w->repeat; 461 w->at += ceil ((ev_now - w->at) / w->repeat) * w->repeat;
462
463 ev_start ((struct ev_watcher *)w, ++atimercnt);
464 array_needsize (atimers, atimermax, atimercnt, );
465 atimers [atimercnt - 1] = w;
466 upheap (atimers, atimercnt - 1);
396 } 467 }
397 else 468 else
469 {
398 w->at += ev_now; 470 w->at += now;
399 471
400 ev_start ((struct ev_watcher *)w, ++timercnt); 472 ev_start ((struct ev_watcher *)w, ++rtimercnt);
401 array_needsize (timers, timermax, timercnt, ); 473 array_needsize (rtimers, rtimermax, rtimercnt, );
402 timers [timercnt - 1] = w; 474 rtimers [rtimercnt - 1] = w;
403 upheap (timercnt - 1); 475 upheap (rtimers, rtimercnt - 1);
476 }
477
404} 478}
405 479
406void 480void
407evtimer_stop (struct ev_timer *w) 481evtimer_stop (struct ev_timer *w)
408{ 482{
409 if (!ev_is_active (w)) 483 if (!ev_is_active (w))
410 return; 484 return;
411 485
486 if (w->is_abs)
487 {
412 if (w->active < timercnt--) 488 if (w->active < atimercnt--)
413 { 489 {
414 timers [w->active - 1] = timers [timercnt]; 490 atimers [w->active - 1] = atimers [atimercnt];
415 downheap (w->active - 1); 491 downheap (atimers, atimercnt, w->active - 1);
492 }
493 }
494 else
495 {
496 if (w->active < rtimercnt--)
497 {
498 rtimers [w->active - 1] = rtimers [rtimercnt];
499 downheap (rtimers, rtimercnt, w->active - 1);
500 }
416 } 501 }
417 502
418 ev_stop ((struct ev_watcher *)w); 503 ev_stop ((struct ev_watcher *)w);
419} 504}
420 505
449} 534}
450 535
451static void 536static void
452ocb (struct ev_timer *w, int revents) 537ocb (struct ev_timer *w, int revents)
453{ 538{
454 fprintf (stderr, "timer %f,%f (%x) (%f) d%p\n", w->at, w->repeat, revents, w->at - ev_time (), w->data); 539 //fprintf (stderr, "timer %f,%f (%x) (%f) d%p\n", w->at, w->repeat, revents, w->at - ev_time (), w->data);
540 evtimer_stop (w);
541 evtimer_start (w);
455} 542}
456 543
457int main (void) 544int main (void)
458{ 545{
459 struct ev_io sin; 546 struct ev_io sin;
462 549
463 evw_init (&sin, sin_cb, 55); 550 evw_init (&sin, sin_cb, 55);
464 evio_set (&sin, 0, EV_READ); 551 evio_set (&sin, 0, EV_READ);
465 evio_start (&sin); 552 evio_start (&sin);
466 553
467 struct ev_timer t[1000]; 554 struct ev_timer t[10000];
468 555
556#if 1
469 int i; 557 int i;
470 for (i = 0; i < 1000; ++i) 558 for (i = 0; i < 10000; ++i)
471 { 559 {
472 struct ev_timer *w = t + i; 560 struct ev_timer *w = t + i;
473 evw_init (w, ocb, i); 561 evw_init (w, ocb, i);
474 evtimer_set_rel (w, drand48 (), 0); 562 evtimer_set_abs (w, drand48 (), 0.99775533);
475 evtimer_start (w); 563 evtimer_start (w);
476 if (drand48 () < 0.5) 564 if (drand48 () < 0.5)
477 evtimer_stop (w); 565 evtimer_stop (w);
478 } 566 }
567#endif
568
569 struct ev_timer t1;
570 evw_init (&t1, ocb, 0);
571 evtimer_set_abs (&t1, 5, 10);
572 evtimer_start (&t1);
479 573
480 ev_loop (0); 574 ev_loop (0);
481 575
482 return 0; 576 return 0;
483} 577}

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines