On Mon, Dec 28, 2015 at 9:36 PM, Darren Smith <[email protected]> wrote:
> Hi,
>
> I cannot figure out how to achieve the following: to add a new uv_tcp_t to
> already active uv loop which is presently blocked on IO.
>
> In detail:
>
> My uv event loop is invoked as UV_RUN_DEFAULT.  This is managing the IO for
> a single TCP connection which was actively established as follows:
>
>   uv_connect_t connect_req;
>   struct sockaddr_in addr;
>   uv_ip4_addr("127.0.0.1", 40001, &addr);
>   uv_tcp_init(uv_default_loop(), &tcp_handle_1);
>   uv_tcp_connect(&connect_req,
>                  &tcp_handle_1,
>                  (const struct sockaddr*) &addr,
>                  connect_cb);
>   uv_run(uv_default_loop(), UV_RUN_DEFAULT);
>
>
> In the connect_cb() the read is enabled:
>
> static void connect_cb(uv_connect_t* req, int status)
> {
>   uv_read_start(req->handle, alloc_buffer, on_read);
> }
>
>
> Nothing surprising so far, and all works ; this is a single actively
> established socket which can read from other side.
>
> Next, slightly later, and in a separate thread, I wish to create a new
> uv_tcp_t handle and add that to the loop, so I do the same (just changing
> the handle variable):
>
>   uv_connect_t connect_req;
>   struct sockaddr_in addr;
>   uv_ip4_addr("127.0.0.1", 40002, &addr);
>   uv_tcp_init(uv_default_loop(), &tcp_handle_2);
>   uv_tcp_connect(&connect_req,
>                  &tcp_handle_2,
>                  (const struct sockaddr*) &addr,
>                  connect_cb);
>
>
> Now the problem I encounter is that while I do see a connection is made to
> 127.0.0.1:40002, this second stream (tcp_handle_2) does not read from the
> socket.  In fact it will read, but only after some bytes have arrived on the
> first connection.
>
> I think the problem is that the uv event loop is blocked in the IO; so when
> tcp_handle_2 is added, the uv loop does not immediately call the
> connect_cb() to set up the stream reading.  The uv loop remains blocked
> until bytes appears on tcp_handle_1, at which point the connect_cb() for
> tcp_handle_2 is called and then reads can take place.
>
> So what's the best approach to resolve this?  I would like to have a single
> uv event loop to manage many actively established connections, but I have
> not found a way to interrupt an io-blocked uv loop so that it can deliver
> the callbacks associated with setting up a new connection.  One possible
> approach would be to use an idler, however if I try that, I see CPU use rise
> to 100%.  Another approach might be to use something like socketpair to
> manually interrupt the uv loop; but I've not yet found that in libuv.
>
> Help appreciated. Thanks,
>
> Darren

The short answer is that you can't do that.  The event loop in libuv
is not thread-safe (with the sole exception of uv_async_send()) and
this is not expected to change anytime soon; maybe in libuv v2.0.

If you have a file descriptor that you want to wrap in uv_tcp_t, you
can try the following:

  1. Create a uv_async_t handle in your main thread.

  2. Start the worker thread.

  3. Call uv_run() in the main thread.

  4. In the worker thread, put the file descriptor in a thread-safe
data structure (e.g. one guarded by a uv_mutex_t) and call
uv_async_send().

  5. In the main thread, in your uv_async_cb callback, pop off the
file descriptor and create a new uv_tcp_t out of it.

Note that uv_async_send() can and will coalesce calls so don't expect
one callback for every call to uv_async_send().

-- 
You received this message because you are subscribed to the Google Groups 
"libuv" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/libuv.
For more options, visit https://groups.google.com/d/optout.

Reply via email to