Hey Marc,
thanks for taking your time for replying! And even if you do display a certain
abrasiveness while we're at it, and I do not see a few things your way, I
really do learn alot by our exchange. That is greatly appreciated. Thank you.
On Monday 20 April 2015 00:21:19 Marc Lehmann wrote:
> ev_prepare watchers do queue with other watchers - event handling is the
> same for every watcher type.
Yes, I noticed that. If I read your code correctly, ev_prepare watchers will
in fact almost never be queued together with other watchers, as opposed to
ev_check watchers.
if (expect_false (preparecnt))
{
queue_events (EV_A_ (W *)prepares, preparecnt, EV_PREPARE);
EV_INVOKE_PENDING;
}
Further reading of the code suggests the only time you will have other events
in the queue, is when a watcher from an EV_INVOKE_PENDING call prior to the
queueing of prepares, with lower priority, does an ev_feed_event on a watcher
with higher priority, right before the prepares are queued.
> That's ok, it's no a shame to have to ask the list, but you should listen
> to the replies and not stubbornly repeat the same things over and over.
Hey, you have written the documentation and I keep finding things in the doc
after reading it a second or third time, but in this instance I fail.
I have also reread the section about ev_prepare watchers (which seems to be
together with ev_check watchers)
I kindly ask you, could you point me to where you wrote about limitations on
adding prepare watchers from other prepare watchers?
> ev_prepare watchers have their own manual section which documents their
> limitations.
In the doc I only see:
###
Also, ev_check watchers (and ev_prepare watchers, too) should not activate
("feed") events into libev. While libev fully supports this, they might get
executed before other ev_check watchers did their job. As ev_check watchers
are often used to embed other (non-libev) event loops those other event loops
might be in an unusable state until their ev_check watcher ran (always remind
yourself to coexist peacefully with others).
###
It says "might get executed before other ev_check watchers"... I see nothing
to indicate what happens when you start a prepare watcher from another prepare
watcher.
> That's ok, reading documentation can be hard, especially one one uses code
> in a way that it wasn't meant to be used for. Still, the documentation
> thoroughly describes how events are processed.
I only really started understanding how libev queues watcher events after
actually reading libev code. Specifically, it was interesting to see that fork
event watchers are queued, then EV_INVOKE_PENDING is called, then the prepare
events, then again EV_INVOKE_PENDING.
Most of the documentation discusses how events are queued after the blocking
syscall.
Your documentation is actually a good read. Maybe you did describe all of the
aspects that I've written about just now in this paragraph, in a completely
different section. Oftentimes however these things hide in one sentence that
are easy to miss and one doesn't notice them until one has read the doc the
umpeenth time.
> Your problem certainly isn't to invoke something once per event loop
> iteration - your stated problem was to invoke another callback via your
> event loop, i.e. delayed execution of another callback, as soon as
> possible, without waiting for another iteration.
>
> This is not what ev_prepare does.
Okay.
> Obviously, it is "intuitive" for you if these watchers have very different
> behaviour. I find it more intuitive (and rational) if they have the same
> behaviour, as they have in libev, and the same behaviour as any other
> watcher type in libev, namely triggering on their respective event, not on
> starting them.
Well, the doc says:
###
The rationale behind this is that you do not need to check for recursion in
those watchers, i.e. the sequence will always be ev_prepare, blocking,
ev_check so if you have one watcher of each kind they will always be called in
pairs bracketing the blocking call.
###
"Bracketing" is the key word. Some libev user as naive as me would think:
"hey, the blocking call has not been called yet, so I can start ev_prepare
watchers and they'll always get executed before the blocking" - which is true
when they're started from any any other watcher callback than that of an
ev_prepare watcher.
> Btw, it's dangerous to make up statements such as "any other watcher
> for that matter, will see its execution only after the next poll/select
> syscall", since they are not true - libev works as documented, and making
> your own rules will only get your surprised. Specifically, libev makes no
> guarantee like the one you stated, and current code doesn't ensure that it
> is true either, so it's likely that your code will break if you rely on
> your own advice.
I should have exempted some special watchers, like the fork watcher, and
watchers that were added to pending watchers via ev_feed_event().
At least for fd watchers I think my assumption will always hold true. At this
time timeout callbacks are also only called after the blocking syscall. But
yes, you're right. There's no guarantee for it in the doc.
> > This is not quite as clear for ev_prepare watchers.
>
> Well, that's not the fault of libev or it's documentation though.
Well, here I disagree, obviously :)
> Then ev_prepare watchers are obviously the wrong type of watcher, because
> these run neither soon, nor are they guaranteed to run at all.
Not guaranteed to run at all? How come?
> > While all this is happening, even after the deferral, the timestamp
> > returned by ev_now() must not change, because my code relies on the
> > value returned by ev_now() as a reference time stamp for when a value is
> > generated on some node types. This practically rules out the use of
> > ev_timer and ev_idle.
>
> ev_tstamp event_time = ev_now ();
>
> event_time will not change unless you need it to - problem solved.
event_time will have to be preserved and communicated over multiple function
calls on the off-chance some other function might need it. Kind of a pain but
doable.
And yes, there's no guarantee for ev_now() time not changing until the prepare
watcher. You have convinced me :)
> What about time
> critical code, where real time timestamps are of importance?
>
> ev_idle makes no guarantee whatsoever how many event loop interations
> need to happen before it is first invoked, which is bad.
Time critical code means to me: Execution shall happen as fast as possible. I
wasn't really clear with the "real time timestamps" either: It means the
defer-executed code needs to generate a real time as returned by ev_time() for
further processing, as soon as possible.
I understand now ev_prepare is not the right watcher for this. But ev_idle
definitely is even worse, because here we cannot be sure when that watcher is
ever going to be called.
In this context, I was saying for this time critical code, starting an ev_idle
watcher and waiting for an idle event is really bad.
> > > Indeed, if you want the shortest possible delay, 0 would be simplest
> > > and most succinct.
> >
> > Oh. For some reason, I thought that a timeout value of 0.0 was illegal
> > which it clearly is not. My bad.
>
> Reading documentation really helps.
It was not for lack of reading the documentation that made me think it was
illegal, I assure you. May have been some use case years before that didn't
work as I expected for entirely different reasons. I don't remember. Human
brains just work like that.
> Well, as I wrote, you can queue an event for later. Or use a
> timer. Depending on your needs and correctness. timers have the advantage
> that they don't starve the event loop.
Right, ev_feed_event(). I assume it will work if I use feed event on any
watcher with the same priority as the watcher being currently executed.
Correct?
--
Best regards,
Thilo Schulz
_______________________________________________
libev mailing list
[email protected]
http://lists.schmorp.de/cgi-bin/mailman/listinfo/libev