Re: [libuv] Embedding libuv's event loop inside another loop.

1,637 views
Skip to first unread message

Tim Caswell

unread,
Sep 20, 2012, 5:19:09 PM9/20/12
to li...@googlegroups.com
I don't understand all the technical aspects to this proposal, but I
approve of anything that makes it possible to sanely integrate with
other event loops, especially GUI event loops. I've wanted for years
to write desktop and mobile apps using libuv.

So, the high-level goal of this is to run something like
CoreFoundation's main loop in a thread which notifies the main thread
(libuv based) about events? Or is it the other way around where libuv
runs in the second thread. In either case, the scripting language
with the user supplied callbacks would be in the libuv thread right?

On Thu, Sep 20, 2012 at 8:16 AM, indutny <fedor....@gmail.com> wrote:
> Hi everyone!
>
> I suggest adding APIs for embedding libuv's loop inside another loop. After
> dealing with CFRunLoop/NSRunLoop (on OSX) and looking at APIs of other UI
> event loops (i.e. Qt), it seems that the only way of embedding uv's loop is:
>
> 1. Starting thread that will wait for events to happen.
> 2. Asking main loop to process those events and fire callbacks in it's
> thread.
>
> First part that should be definitely implemented and exposed is
> uv_wait(uv_loop_t*) function that will wait for events to happen (w/o
> dequeing them from backend). As the second part I propose introducing
> following APIs:
>
> uv_run_embedded(uv_loop_t*, uv_embed_t*) // start thread, that waits for
> events to happen. uv_embed_t contains a callback that will be called once
> uv_wait() call ended.
> uv_poll_embedded(uv_embed_t*) // process available events and run callbacks.
> Should be called in main thread.
> uv_stop_embedded(uv_embed_t*) // stops thread.
>
> The code (Pull Request) for those API changes is there:
> https://github.com/joyent/libuv/pull/561
>
> Fedor Indutny.
>
> --
> 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:00:16 PM9/20/12
to li...@googlegroups.com
On Thursday, September 20, 2012 3:16:49 PM UTC+2, indutny wrote:
uv_run_embedded(uv_loop_t*, uv_embed_t*) // start thread, that waits for events to happen. uv_embed_t contains a callback that will be called once uv_wait() call ended.
uv_poll_embedded(uv_embed_t*) // process available events and run callbacks. Should be called in main thread.
uv_stop_embedded(uv_embed_t*) // stops thread.

I agree that we need a solution for this, and I think your API proposal is a good start. However there are some aspects about it that I don't necessarily like:

* The core API (uv_wait) is combined with some high-level plumbing that does inter-thread synchronization. But the entire "api constellation" is not high level at all, it requires users to replace uv_run() with custom plumbing.
* The strawman implementation of uv_run_embedded is not very efficient atm (it creates a new thread every time you call it), but since we don't know what the user is doing it's hard to see how we could make it more efficient.

IMO we should pick either a low-level strategy or a high-level strategy.

* Option: add only uv_wait and clearly define what it does, and what the constraints are. (e.g. it blocks until there are new events; it is threadsafe).
* Option: add an API to replace the core poll function. It would take 2 callbacks, 1 that would be called instead of kevent/epoll_wait, and another that is called (possibly from another thread) when there are new uv events and the "replacement poll" needs to be interrupted.

I also have some concerns about this (not) being possible on windows. It could probably be done in libuv as it is today, but in the future I'd like to use another notification mechanism in some cases (namely, APCs)  because we could make cluster much more efficient with it. Unfortunately APCs are scheduled to a particular thread, and there's no way to wait for them in another thread. So maybe we should keep this unix-only (sadface).

- Bert

Fedor Indutny

unread,
Sep 21, 2012, 12:20:05 AM9/21/12
to li...@googlegroups.com
Lets add uv_wait with no thread-safety guarantee, users can just wrap uv_wait and uv_run_once with mutexes/semaphores/whatever they want. If it'll won't work on windows, that's not a big problem for me, though I think people will complain about it eventually.

And I don't really get what you can do by replacing polling function, but I'm really ok with it.

Cheers,
Fedor.



Saúl Ibarra Corretgé

unread,
Sep 21, 2012, 2:56:36 AM9/21/12
to li...@googlegroups.com
Hi,
I agree that uv_wait looks fine but I had a bit of trouble understanding
uv_run_embeded and friends. (maybe I was just too tired)

So here is a proposal:

Provide a 2 step alternative to uv_run: uv_poll and uv_wait

- uv_poll(uv_loop_t *loop, int timeout): polls the backend for the given
timeout but doesn't handle events. Not thread safe.

- uv_wait(uv_loop_t *loop, int timeout): waits until the given timeout
expires and handles events in the meanwhile. Thread safe.

Usage:

Qt application spawns a thread where libuv event loop will run. Calls
uv_poll there with the help of an async. Calls uv_wait in the main
thread to wait for events.

Hopefully I didn't completely miss the use case while thinking about this.


Regards,

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

Fedor Indutny

unread,
Sep 21, 2012, 3:13:28 AM9/21/12
to li...@googlegroups.com
So to conclude:

- uv_wait(uv_loop_t*, int timeout) blocks until events will be available for loop without dequeing events from backend. I propose it to be not thread safe, users can handle it, it's not really a problem for them!
- uv_run_once(uv_loop_t*) or uv_poll(uv_loop_t*) - if former may block on some platforms.

To embed libuv's loop into another loop (i.e. UI loop), user should start thread that'll call uv_wait() in a loop, and once it returns that thread should interrupt main loop (UI loop) to invoke uv_run_once() or uv_poll() to deque events and invoke callbacks.

Cheers,
Fedor.





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

Saúl Ibarra Corretgé

unread,
Sep 21, 2012, 4:02:06 AM9/21/12
to li...@googlegroups.com
Hi Fedor,

Looks like you and I are using poll and wait the other way around xD

Fedor Indutny wrote:
> So to conclude:
>
> - uv_wait(uv_loop_t*, int timeout) blocks until events will be available
> for loop *without dequeing events* from backend. I propose it to be *not
> thread safe*, users can handle it, it's not really a problem for them!

Sounds ok.

> - uv_run_once(uv_loop_t*) or uv_poll(uv_loop_t*) - if former may block
> on some platforms.
>

If uv_run* can be used, then we can do without uv_poll, since there will
be a uv_run_once which doesn't block in faio (that's what Ben told me :-) ).

> To embed libuv's loop into another loop (i.e. UI loop), user should
> start thread that'll call uv_wait() in a loop, and once it returns that
> thread should interrupt main loop (UI loop) to invoke uv_run_once() or
> uv_poll() to *deque events and invoke callbacks*.
>

I'm nowhere near as knowledgeable as some of you guys, but this looks
fine :-)


Cheers,

Fedor Indutny

unread,
Sep 21, 2012, 7:03:29 AM9/21/12
to li...@googlegroups.com
I've force pushed my pull request: https://github.com/joyent/libuv/pull/561

It works fine on linux and BSD platforms, so far there're no support for solaris and windows (bertje please make it work!). I suppose that should be ok to merge, since it won't break anything.

Also I propose to merge it into v0.8 and release with next node.js stable release ;)

Cheers,
Fedor.





--

Bert Belder

unread,
Sep 21, 2012, 8:42:48 AM9/21/12
to li...@googlegroups.com, fe...@indutny.com
> It works fine on linux and BSD platforms, so far there're no support for solaris and windows (bertje please make it work!). I suppose that should be ok to merge, since it won't break anything.

For windows we're probably out of luck.

> I propose it to be not thread safe, users can handle it, it's not really a problem for them!

Yes, that seems to be better.

- Bert

Reply all
Reply to author
Forward
0 new messages