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.
