Ok, after reading more on of the source code, watching the Google Tech Talk on Node.js and considering your answers, this is a rough attemp to make sense of what happens in libuv when you have, for instance, a HTTP request asking for a file (assume Node.js using libuv):
1) The default event loop listening to TCP connections will run the callback for accepting the connection. 2) The connection is accepted, and the OS notifies that there's data to be read in the socket. [default loop dealing with other requests...] 3) The request (data) will be read in the main thread up to a certain limit to avoid starvation (32 iterations, as in `uv__read`). 4) The user callback will be called inside this libuv callback, still in the main thread. It will parse the request, and upon finding that it should read a file, will call the FS abstraction asking for that file. If we assume Node.js here, this callback means a V8 invocation running in the main thread, and no other requests can be served in the mean time. 5) The call to read a file will spawn asynchronous work by calling `uv__work_submit`. The task will be performed in another thread, and `uv_sync_asend` will send the file contents through a socket (pipe?) when it's done. [async request running and default loop dealing with other requests...] 6) The file contents will be received by a watcher in the main thread, and the default event loop will read it all and call the user callback with the file contents. No requests can be served while we're doing that. 7) The user callback (still running in the main thread) will write the response to the client. No requests can be served while we're doing that. I think I may have mistaken some parts, especially in step 4 and in the parts where requests can't be served in steps 6 and 7. I'm assuming a small request and a small file. Is this more or less correct or did I get it all wrong? Thank you for the patience :) Allan On Wednesday, January 22, 2014 9:18:06 AM UTC-2, Fedor Indutny wrote: > > I mean using the same TCP server fd in multiple threads each with it's > own libuv loop. You'll still need to send the `uv_tcp_t` server handle > to other threads using IPC pipe (see `uv_pipe_open`). > > On Wed, Jan 22, 2014 at 3:14 PM, <[email protected] <javascript:>> > wrote: > > What do you mean by listening on the same fd? > > > > I have used the other approach when using libevent (one event loop > giving > > control of the fds to other event loops in other threads). > > > > On Wednesday, January 22, 2014 9:11:29 AM UTC-2, Fedor Indutny wrote: > >> > >> Hello again! > >> > >> Sorry for not answering all of your questions. > >> > >> libuv is a single-threaded library, and everything, except, > >> uv_work_cb's are executed in the same thread, where uv_run() "runs". > >> There are at least two ways, how you could make libuv-based app use > >> all available CPUs: load-balancing incoming sockets via IPC pipes to > >> child process or worker threads (each with it's own libuv loop) or > >> listening on the same fd. > >> > >> Node.js was using latter approach up until v0.11 that will become v0.12 > >> soon. > >> > >> Cheers, > >> Fedor. > >> > >> On Wed, Jan 22, 2014 at 3:02 PM, <[email protected]> wrote: > >> > Thank you for the answers! I used libevent previously, so I was > >> > confused about the different nature of libuv. > >> > > >> > I took a look at the NodeJS source code, and how it uses libuv, and > one > >> > question remains. > >> > > >> > Is the default event loop/main thread used for everything? Assuming a > >> > request comes in, this thread alone will: get notified about the > event, > >> > read the data, run the callback, and then write back a response? All > of > >> > this on a single thread, for any number of requests? > >> > > >> > I read parts of the NodeJS code, but I couldn't find anything that > >> > points to any thread parallelism (except from debugging). It seems > that > >> > even uv_queue_work is not even being called much. > >> > > >> > > >> > If this question is too specific, let me know and I'll ask it in the > >> > NodeJS mailing list. > >> > > >> > > >> > Allan > >> > > >> > On Friday, January 17, 2014 4:35:40 PM UTC-2, Fedor Indutny wrote: > >> >> > >> >> Hello! > >> >> > >> >> You should not call anything except `uv_async_send()` from another > >> >> thread. Many functions are inserting stuff into loop's linked lists > >> >> and the list itself is not thread-safe (not even talking about many > >> >> other internals). > >> >> > >> >> `uv_async_send()` indeed writes to one end of the pipe, and libuv is > >> >> listening on the other end of the pipe, and interrupts loop and > >> >> invokes callback when receives data. > >> >> > >> >> As a way to return data back from uv_work_cb - you could set and > >> >> change req.data safely inside worker thread, it'll be available in > >> >> uv_work_done_cb. > >> >> > >> >> Cheers, > >> >> Fedor. > >> >> > >> >> On Fri, Jan 17, 2014 at 6:19 PM, <[email protected]> wrote: > >> >> > Hi, > >> >> > > >> >> > I've been curious about how libuv works internally regarding > thread > >> >> > communication. > >> >> > > >> >> > This is what I understand: > >> >> > There's a single thread running uv_run. If I spawn some work to be > >> >> > done > >> >> > in another thread I'm supposed to use uv_queue_work. The way to > send > >> >> > the results of this work back to the main thread is through > >> >> > uv_async_send (which is the only thread-safe function in libuv). > >> >> > > >> >> > This is what I want to do: > >> >> > Start listening on a TCP socket, accept incoming connections in > the > >> >> > default loop, and wait for data to be available for reading (using > >> >> > uv_read_start). When it's available for reading, I'd put the work > >> >> > (socket reading) in the queue (with uv_queue_work), and the > callback > >> >> > for this would run in another thread, reading the data and > performing > >> >> > some work based on it, which may involve writing data back to this > or > >> >> > any other socket. > >> >> > > >> >> > So, my questions related to this are: > >> >> > - Is this possible to do? If I call uv_read_start and uv_write in > >> >> > another thread, can this cause trouble, because they should have > been > >> >> > called in the default loop? > >> >> > > >> >> > - If uv_read_start and uv_write should be called in the default > loop, > >> >> > then the main thread will be responsible for reading and writing > all > >> >> > data, right? Wouldn't this impact performance? How does NodeJS > deal > >> >> > with this? > >> >> > > >> >> > - How does uv_async_send work? From a quick glance at the source > >> >> > code, > >> >> > I suspect it sends data in a file descriptor, which will be read > in > >> >> > the > >> >> > default loop. Is this what is happening? > >> >> > > >> >> > > >> >> > Allan > >> >> > > >> >> > -- > >> >> > 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 http://groups.google.com/group/libuv. > >> >> > For more options, visit https://groups.google.com/groups/opt_out. > -- 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 http://groups.google.com/group/libuv. For more options, visit https://groups.google.com/groups/opt_out.
