alternate approach to timer inaccuracy due to cached times

Marc Lehmann schmorp at
Sat Oct 15 10:39:09 CEST 2011

On Sat, Oct 15, 2011 at 01:40:25PM +0700, Denis Bilenko <denis.bilenko at> wrote:
> I know about ev_now_update(). In fact, I've suggested to Shaun on
> gevent mailing list
> to call ev_now_update() periodically via setitimer. This only helps
> with timeouts bigger than
> the setitimer period though.

IT's also, of course, not safe to call it from a signal handler.

> Note, that inserting ev_now_update() manually is possible with gevent
> but is not a good suggestion
> in general, because it's hard to predict which operation is long and
> blocking. For example, GC can
> kick in at any moment.

Well, the solution to a bad gc is a good gc that doesn't have this problem.

I sitll think its a perfectly ok solution though - most event libraries do
that internally, and I see no reason why this is inherently bad.

Note that the ev_time() solution from the ev manpage is likely faster because
often is fully handled in userspace.

> What does "take timestamps more often" means?

If you read data then you only know it was rceeived between ev_now and
ev_time. ev_now is what you get almost for free, if you want ev_time
instead, you have to call it to get a newer timestamp.

> What are proper timeouts?

Timeouts larger then any internal processing times - timeouts usually
concern external behaviour, and should not fire for purely internal
causes, e.g. when you have network conenctions then it (usually) makes no
sense to time them out just because you are too slow to respond to them
sendign data.

> 1) The computation takes place for 200ms.
>    (We don't know that in advance, so

> simply inserting ev_now_update() call is not an option.)

And why is that so? It's the most common solution to this in the world

> 2) A new non-blocking connect() is made. An I/O watcher is set up.
> 3) A timeout of 100ms is set up.
> what would be a good implementation of timeouts in 3) ?

depends on what you want do achieve.

> Apparently using ev_timer is naive and does not work. That's, in fact,
> what we do in gevent.
> How do we fix it?

As described in the manpage and on this list - again, what exactly don't you
not understand?

I have yet to hear any substantial response to the solutions given that
doesn't amount to "we obviously can't do that".

> Giving the IO watcher higher priority than ev_timer's would not work
> here, would it?

A timeout of 100ms does not work in any case when you do processing
for 200ms. If your loop can take 200ms then you will get lots of false
timeouts regardless of how libev behaves.

> IIRC, priorities only matter within the same loop iteration, here the
> issue occurs when
> the timer has got an event but the IO hasn't yet.

Right - you have to give operations enough time to complete.

If you only occasionally use 20ms then either put this slow operation
somewhere else, or use one of the methods described to deal with them, such
as using ev_time instead of ev_now as timebase (see manual), or call

> > (2) It can be fixed the lazy but correct way - if you don't whne *when* an
> > event occured, you have to ask the OS. If gettimefday (usually a fast
> > userspace function) is good enough for you, you can just call it when the
> > other event occurs and base your timeout on that.
> Can you elaborate on how to do that, provided it is applicable to the
> scenario above?

The scenario above is not the original problem. The scenario above can
only be fixed by using sensible timeouts.

> That seems like it would give us the kind of timers we need. I still wonder
> how (1) "the good way" or (2) "the correct way" can be applied to the
> example above.

See "The special problem of time updates" in the docs fo (2). (1) assumes
a working design in the first place. Putting 100ms timeouts on operations
that regularly can take more than that is the problem in your example.

> If it can not, then I wonder why don't we just start all timers in
> ev_prepare callback.

It's a valid solution...

> > No, becauase Coro doesn't do I/O the same way, it uses design (2) from my
> > previous mails for actual I/O events.
> I was talking about sleep() without I/O (for simplicity). I installed
> Coro and it seems
> to do the same thing gevent does - it implements sleep() with bare ev_timer.

Coro doesn't implement I/O timeouts with sleep. To me, thats an insane
idea :)

> Here's the gevent example ported to Perl/Coro:

Bad design ported to Coro still stays a bad design.

> Sleep() is documented as "block the current thread for **at least**
> the given number of seconds".
> But it sleeps, like gevent.sleep(), for only 3 seconds instead of 10.

Look, you already know you are comparing the wrong clokcs here. If I create a
timer and then reset the system clock to a few years earlier it will even
elapse in the effective past.

A 10 second timer started at ev_now will not elapse before ev_now () + 10.

If ev_now is the wrong clock for your problem, use ev_time as clock.

I could understand your behaviour if libev *forced* you to use ev_now as
timebase, but it doesn't, and even documents how you can use ev_time (or
even other clocks).

Whats your point in repeating thiese falsehoods then? libev does what you
want, you just have some philosophical problem with the solution. Why
don't you say what problem you *really* have?

> In my opinion, Coro::AnyEvent::sleep is clearly broken according to
> its own documentation, would you agree with that?

In my opinion, one shouldn't give much on your opinion, it's obviously
flawed, and that has been explained a number of times already :/

                The choice of a       Deliantra, the free code+content MORPG
      -----==-     _GNU_    
      ----==-- _       generation
      ---==---(_)__  __ ____  __      Marc Lehmann
      --==---/ / _ \/ // /\ \/ /      schmorp at
      -=====/_/_//_/\_,_/ /_/\_\

More information about the libev mailing list