What about adding uv_break(uv_loop_t *) ?

125 views
Skip to first unread message

Saúl Ibarra Corretgé

unread,
Aug 20, 2012, 4:58:05 AM8/20/12
to li...@googlegroups.com
Hi all,

I'm not sure if this was brought up in the past, sorry about that if it
was :-)

So, I was wondering if a patch adding a way to break the loop would be
welcome. It's functionality would pretty much mirror ev_break but since
we have no concept of depth and so on I guess it would be simpler.

The idea would be to return from uv_run in the next iteration, if
uv_break was called. I haven't thought about all possible cases here
like, what should we do if you do uv_break in a prepare callback (should
we break before poll or not?) but I'd like to get some feedback on the
general idea.

Someone may want to break the loop under certain conditions (probably
mainly errors) and do some extra cleanup before closing all handles, for
example.

Particularly, I would like to have some sort of "debug mode" on pyuv,
where the loop would automatically exited if there is an uncaught
exception in any of the callbacks, and then it's up to the user to do
whatever he wants, ie walk the loop and close all handles, or just exit.


Thoughts?

--
Sa�l Ibarra Corretg�
http://saghul.net/blog | http://about.me/saghul

Ben Noordhuis

unread,
Aug 20, 2012, 7:24:09 AM8/20/12
to li...@googlegroups.com
I'll happily take UVRUN_* patches but I don't particularly want
uv_break(), it adds a lot of complexity for little gain.

Your debug mode could be accomplished by channeling all callbacks
through a 'master callback' that sets an error flag. In pseudo-code:

static int exception_flag = 0;

static void master_cb(uv_handle_t* h, int status) {
if (exception_flag) return;
struct your_state* s = h->data;
s->cb(s, status);
if (have_exception()) exception_flag = 1;
}

void run(uv_loop_t* loop) {
while (uv_run_once(loop) && !exception_flag);
if (exception_flag) reraise_exception();
}

Saúl Ibarra Corretgé

unread,
Aug 20, 2012, 7:34:36 AM8/20/12
to li...@googlegroups.com
Hi Ben,

>
> I'll happily take UVRUN_* patches but I don't particularly want
> uv_break(), it adds a lot of complexity for little gain.
>

Ok, I'll see if I can provide those UV_RUN patches then.

> Your debug mode could be accomplished by channeling all callbacks
> through a 'master callback' that sets an error flag. In pseudo-code:
>
> static int exception_flag = 0;
>
> static void master_cb(uv_handle_t* h, int status) {
> if (exception_flag) return;
> struct your_state* s = h->data;
> s->cb(s, status);
> if (have_exception()) exception_flag = 1;
> }
>
> void run(uv_loop_t* loop) {
> while (uv_run_once(loop)&& !exception_flag);
> if (exception_flag) reraise_exception();
> }
>

Hum, that could work, I need to think about it :-) I wonder if anyone
has other requirements that would involve a ev_break replacement,
though. What is the recommendation in such a case? I mean, if someone
calls uv_run and he want uv_run to return there is no other way to do it
but to walk the loop and close everything, is there?

Thanks!

Keno Fischer

unread,
Aug 20, 2012, 8:16:54 AM8/20/12
to li...@googlegroups.com
We had to deal with a similar problem for Julia (julialang.org) and we started off by patching uv_break into libuv, though we recently realized that we didn't really need it and instead opted for something similar to Ben's mater_cb approach. However, that didn't really work on Windows because uv_run_once can block even after a callback has been called. I don't know if that's a bug or intended and If've wanted to ask about that for a while, but haven't really had the time to. We ended up creating a temporary workaround for that, but of course and official libuv solution would be even better. 



--
Saúl Ibarra Corretgé
http://saghul.net/blog | http://about.me/saghul

--
You received this message because you are subscribed to the Google Groups "libuv" group.
To post to this group, send email to li...@googlegroups.com.
Visit this group at http://groups.google.com/group/libuv?hl=en-US.



Bert Belder

unread,
Sep 20, 2012, 9:08:31 PM9/20/12
to li...@googlegroups.com


On Monday, August 20, 2012 2:16:54 PM UTC+2, loladiro wrote:
We had to deal with a similar problem for Julia (julialang.org) and we started off by patching uv_break into libuv, though we recently realized that we didn't really need it and instead opted for something similar to Ben's mater_cb approach. However, that didn't really work on Windows because uv_run_once can block even after a callback has been called. I don't know if that's a bug or intended and If've wanted to ask about that for a while, but haven't really had the time to. We ended up creating a temporary workaround for that, but of course and official libuv solution would be even better. 

Keno, is this still an issue for you guys? With the advent of uv_run_once we should probably standardize on a particular order that uv_run_once does things. It's true that windows will sometimes block after dispatching events, because as it stands it flushes the pending request queue before asking the OS for new events.

- Bert

Keno Fischer

unread,
Sep 21, 2012, 12:29:34 AM9/21/12
to li...@googlegroups.com
We're currently still on a rather old version of libuv (with this
being patched and the different pipe API), but unless something has
changed significantly, this is probably still an issue.

Saúl Ibarra Corretgé

unread,
Sep 21, 2012, 2:44:42 AM9/21/12
to li...@googlegroups.com
Hi,

I found myself again in the need for this... I did a quick prototype of replacing Tornado's (a Python web framework) pollers with pyuv, but it's a bit troublesome due to some slightly weird use case: the IOLoop in Tornado can be stopped and started at any time.

So, if I want to do this with libuv I'd have to make the loop stop while keeping the handles intact. I guess one way would be to unref() everything, but remembering their previous state, and restore it when the loop is run again.

However, Tornado wraps your callbacks and may create new watchers *after* running your callback so if you are trying to stop the loop but a new handle is created right after you are out of luck.

tldr: uv_break could come useful here as well.

As the libev readme says, returning from run because "we are done" is a beauty, but IMHO breaking out by force would make some people's life easier.


Regards,

Fedor Indutny

unread,
Sep 21, 2012, 3:26:58 AM9/21/12
to li...@googlegroups.com
I think uv_wait() and uv_run_once() may solve this problem, see our discussion on this mailing list.

Cheers,
Fedor.



Saúl Ibarra Corretgé

unread,
Sep 21, 2012, 4:05:14 AM9/21/12
to li...@googlegroups.com
Fedor Indutny wrote:
> I think uv_wait() and uv_run_once() may solve this problem, see our
> discussion on this mailing list.
>

Indeed. I guess you could do:

while (1) {
if (need_to_break)
break;
uv_wait(loop, 0);
if (!uv_run_once(loop))
break;
}

Or something similar.


Cheers,

Bert Belder

unread,
Sep 21, 2012, 8:55:11 AM9/21/12
to li...@googlegroups.com
On Friday, September 21, 2012 10:05:17 AM UTC+2, Saúl Ibarra Corretgé wrote:
Fedor Indutny wrote:
> I think uv_wait() and uv_run_once() may solve this problem, see our
> discussion on this mailing list.
>

Indeed. I guess you could do:

while (1) {
     if (need_to_break)
         break;
      uv_wait(loop, 0);
      if (!uv_run_once(loop))
         break;
}

Or something similar.

Although it'd work, it's not ideal because now you're making 2 kevent/epoll_wait syscalls per loop iteration. It's good as a workaround but it's not really good enough to be the "suggested" way.

- Bert

Saúl Ibarra Corretgé

unread,
Sep 21, 2012, 9:46:01 AM9/21/12
to li...@googlegroups.com

>
> Although it'd work, it's not ideal because now you're making 2
> kevent/epoll_wait syscalls per loop iteration. It's good as a workaround
> but it's not really good enough to be the "suggested" way.
>

I see. I didn't think of that. Then can we please have uv_break? I could
make a patch for it :-)

Bert Belder

unread,
Sep 21, 2012, 10:48:13 AM9/21/12
to li...@googlegroups.com
On Friday, September 21, 2012 3:46:04 PM UTC+2, Saúl Ibarra Corretgé wrote:

>
> Although it'd work, it's not ideal because now you're making 2
> kevent/epoll_wait syscalls per loop iteration. It's good as a workaround
> but it's not really good enough to be the "suggested" way.
>

I see. I didn't think of that. Then can we please have uv_break? I could
make a patch for it :-)

I don't mind uv_break, but it depends on what you expect it to do.

1. Return from uv_run soon, and don't block any more. This is easy.
2. Return from uv_run immediately, without making *any* more callbacks. This would be painful and invasive.

- Bert

Saúl Ibarra Corretgé

unread,
Sep 21, 2012, 11:05:01 AM9/21/12
to li...@googlegroups.com
Option 1 was what I had in mind. Break in the next loop iteration, basically, and if we didn't block for polling yet, do a 0 timeout poll.

> - Bert

Ben Noordhuis

unread,
Sep 21, 2012, 11:45:42 AM9/21/12
to li...@googlegroups.com
On Fri, Sep 21, 2012 at 5:05 PM, Saúl Ibarra Corretgé <sag...@gmail.com> wrote:
> Bert Belder wrote:
>> I don't mind uv_break, but it depends on what you expect it to do.
>>
>> 1. Return from uv_run soon, and don't block any more. This is easy.
>> 2. Return from uv_run immediately, without making *any* more callbacks.
>> This would be painful and invasive.
>
> Option 1 was what I had in mind. Break in the next loop iteration,
> basically, and if we didn't block for polling yet, do a 0 timeout poll.

Would `void uv_run(long timeout)` accomplish that? timeout == -1,
block indefinitely, timeout == 0, don't block, timeout > 0, block for
(at most) that many milliseconds.

Saúl Ibarra Corretgé

unread,
Sep 21, 2012, 11:55:00 AM9/21/12
to li...@googlegroups.com
Interesting. I guess some might find it useful, in order to poll the uv loop from another one, for example. What I have in mind, however, requires forcing uv_run to return even if it was called with -1.

I know it can be done with a combination of uv_run_once, a flag and a async handle to wakeup the loop in case it was sleeping, but when writing bindings, there is overhead in going back and forth to C, so it would help if the library itself implemented it.

Btw, uv_run(0) is basically the "nowait" thing, right?

Reply all
Reply to author
Forward
0 new messages