Updated internals manual

This commit is contained in:
Sergey Lyubka 2013-12-16 13:45:13 +00:00
parent 492328474d
commit a69987a711

View File

@ -1,59 +1,21 @@
# Mongoose Internals # Mongoose Internals
<!-- Mongoose has single-threaded, event-driven, asynchronous, non-blocking core.
Mongoose is multithreaded web server. `mg_start()` function allocates When mongoose server instance is created, it contains an information about
web server context (`struct mg_context`), which holds all information the configuration and the state of each connection:
about web server instance:
- configuration options. Note that mongoose makes internal copies of struct mg_server {
passed options. sock_t listening_sock; // Listening socket
- SSL context, if any union socket_address lsa; // Listening socket address
- user-defined callbacks struct linked_list_link active_connections;
- opened listening sockets struct linked_list_link uri_handlers;
- a queue for accepted sockets char *config_options[NUM_OPTIONS];
- mutexes and condition variables for inter-thread synchronization ...
};
When `mg_start()` returns, all initialization is quaranteed to be complete A server instance is capable on listening on only one port. After creation,
(e.g. listening ports are opened, SSL is initialized, etc). `mg_start()` starts a server instance has a list
two threads: a master thread, that accepts new connections, and several of active connections, initially empty. It has a list of URI handlers,
worker threads, that process accepted connections. The number of worker threads initially empty, and configuration parameters. Configuration can be
is configurable via `num_threads` configuration option. That number puts a altered by `mg_set_option()`, and new URI handlers could be added by
limit on number of simultaneous requests that can be handled by mongoose. `mg_add_uri_handler()`.
When master thread accepts new connection, a new accepted socket (described by
`struct socket`) it placed into the accepted sockets queue,
which has size of 20 (see [code](https://github.com/cesanta/mongoose/blob/3892e0199e6ca9613b160535d9d107ede09daa43/mongoose.c#L486)). Any idle worker thread
can grab accepted sockets from that queue. If all worker threads are busy,
master thread can accept and queue up to 20 more TCP connections,
filling up the queue.
In the attempt to queue next accepted connection, master thread blocks
until there is space in a queue. When master thread is blocked on a
full queue, TCP layer in OS can also queue incoming connection.
The number is limited by the `listen()` call parameter on listening socket,
which is `SOMAXCONN` in case of Mongoose, and depends on a platform.
Worker threads are running in an infinite loop, which in simplified form
looks something like this:
static void *worker_thread() {
while (consume_socket()) {
process_new_connection();
}
}
Function `consume_socket()` gets new accepted socket from the mongoose socket
queue, atomically removing it from the queue. If the queue is empty,
`consume_socket()` blocks and waits until new sockets are placed in a queue
by the master thread. `process_new_connection()` actually processes the
connection, i.e. reads the request, parses it, and performs appropriate action
depending on a parsed request.
Master thread uses `poll()` and `accept()` to accept new connections on
listening sockets. `poll()` is used to avoid `FD_SETSIZE` limitation of
`select()`. Since there are only a few listening sockets, there is no reason
to use hi-performance alternatives like `epoll()` or `kqueue()`. Worker
threads use blocking IO on accepted sockets for reading and writing data.
All accepted sockets have `SO_RCVTIMEO` and `SO_SNDTIMEO` socket options set
(controlled by `request_timeout_ms` mongoose option, 30 seconds default) which
specify read/write timeout on client connection.
-->