xref: /unit/src/nxt_runtime.c (revision 53)
120Sigor@sysoev.ru 
220Sigor@sysoev.ru /*
320Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
420Sigor@sysoev.ru  * Copyright (C) Valentin V. Bartenev
520Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
620Sigor@sysoev.ru  */
720Sigor@sysoev.ru 
820Sigor@sysoev.ru #include <nxt_main.h>
920Sigor@sysoev.ru #include <nxt_runtime.h>
1020Sigor@sysoev.ru #include <nxt_port.h>
1120Sigor@sysoev.ru #include <nxt_master_process.h>
1220Sigor@sysoev.ru 
1320Sigor@sysoev.ru 
1420Sigor@sysoev.ru static nxt_int_t nxt_runtime_inherited_listen_sockets(nxt_task_t *task,
1520Sigor@sysoev.ru     nxt_runtime_t *rt);
1620Sigor@sysoev.ru static nxt_int_t nxt_runtime_systemd_listen_sockets(nxt_task_t *task,
1720Sigor@sysoev.ru     nxt_runtime_t *rt);
1820Sigor@sysoev.ru static nxt_int_t nxt_runtime_event_engines(nxt_task_t *task, nxt_runtime_t *rt);
1920Sigor@sysoev.ru static nxt_int_t nxt_runtime_thread_pools(nxt_thread_t *thr, nxt_runtime_t *rt);
2020Sigor@sysoev.ru static void nxt_runtime_start(nxt_task_t *task, void *obj, void *data);
2120Sigor@sysoev.ru static void nxt_runtime_initial_start(nxt_task_t *task);
2220Sigor@sysoev.ru static void nxt_single_process_start(nxt_thread_t *thr, nxt_task_t *task,
2320Sigor@sysoev.ru     nxt_runtime_t *rt);
2420Sigor@sysoev.ru static void nxt_runtime_close_idle_connections(nxt_event_engine_t *engine);
2520Sigor@sysoev.ru static void nxt_runtime_exit(nxt_task_t *task, void *obj, void *data);
2620Sigor@sysoev.ru static nxt_int_t nxt_runtime_event_engine_change(nxt_task_t *task,
2720Sigor@sysoev.ru     nxt_runtime_t *rt);
2820Sigor@sysoev.ru static nxt_int_t nxt_runtime_conf_init(nxt_task_t *task, nxt_runtime_t *rt);
2920Sigor@sysoev.ru static nxt_int_t nxt_runtime_conf_read_cmd(nxt_task_t *task, nxt_runtime_t *rt);
3020Sigor@sysoev.ru static nxt_sockaddr_t *nxt_runtime_sockaddr_parse(nxt_task_t *task,
3120Sigor@sysoev.ru     nxt_mem_pool_t *mp, nxt_str_t *addr);
3220Sigor@sysoev.ru static nxt_sockaddr_t *nxt_runtime_sockaddr_unix_parse(nxt_task_t *task,
3320Sigor@sysoev.ru     nxt_mem_pool_t *mp, nxt_str_t *addr);
3420Sigor@sysoev.ru static nxt_sockaddr_t *nxt_runtime_sockaddr_inet6_parse(nxt_task_t *task,
3520Sigor@sysoev.ru     nxt_mem_pool_t *mp, nxt_str_t *addr);
3620Sigor@sysoev.ru static nxt_sockaddr_t *nxt_runtime_sockaddr_inet_parse(nxt_task_t *task,
3720Sigor@sysoev.ru     nxt_mem_pool_t *mp, nxt_str_t *addr);
3820Sigor@sysoev.ru static nxt_int_t nxt_runtime_hostname(nxt_task_t *task, nxt_runtime_t *rt);
3920Sigor@sysoev.ru static nxt_int_t nxt_runtime_log_files_init(nxt_runtime_t *rt);
4020Sigor@sysoev.ru static nxt_int_t nxt_runtime_log_files_create(nxt_task_t *task,
4120Sigor@sysoev.ru     nxt_runtime_t *rt);
4220Sigor@sysoev.ru static nxt_int_t nxt_runtime_pid_file_create(nxt_task_t *task,
4320Sigor@sysoev.ru     nxt_file_name_t *pid_file);
4420Sigor@sysoev.ru 
4520Sigor@sysoev.ru #if (NXT_THREADS)
4620Sigor@sysoev.ru static void nxt_runtime_thread_pool_destroy(nxt_task_t *task, nxt_runtime_t *rt,
4720Sigor@sysoev.ru     nxt_runtime_cont_t cont);
4820Sigor@sysoev.ru #endif
4920Sigor@sysoev.ru 
5020Sigor@sysoev.ru 
5120Sigor@sysoev.ru nxt_int_t
5220Sigor@sysoev.ru nxt_runtime_create(nxt_task_t *task)
5320Sigor@sysoev.ru {
5420Sigor@sysoev.ru     nxt_int_t       ret;
5520Sigor@sysoev.ru     nxt_array_t     *listen_sockets;
5620Sigor@sysoev.ru     nxt_runtime_t   *rt;
5720Sigor@sysoev.ru     nxt_mem_pool_t  *mp;
5820Sigor@sysoev.ru 
5920Sigor@sysoev.ru     mp = nxt_mem_pool_create(1024);
6020Sigor@sysoev.ru 
6120Sigor@sysoev.ru     if (nxt_slow_path(mp == NULL)) {
6220Sigor@sysoev.ru         return NXT_ERROR;
6320Sigor@sysoev.ru     }
6420Sigor@sysoev.ru 
6520Sigor@sysoev.ru     /* This alloction cannot fail. */
6620Sigor@sysoev.ru     rt = nxt_mem_zalloc(mp, sizeof(nxt_runtime_t));
6720Sigor@sysoev.ru 
6820Sigor@sysoev.ru     task->thread->runtime = rt;
6920Sigor@sysoev.ru     rt->mem_pool = mp;
7020Sigor@sysoev.ru 
7120Sigor@sysoev.ru     rt->prefix = nxt_current_directory(mp);
7220Sigor@sysoev.ru     if (nxt_slow_path(rt->prefix == NULL)) {
7320Sigor@sysoev.ru         goto fail;
7420Sigor@sysoev.ru     }
7520Sigor@sysoev.ru 
7620Sigor@sysoev.ru     rt->conf_prefix = rt->prefix;
7720Sigor@sysoev.ru 
7820Sigor@sysoev.ru     rt->services = nxt_services_init(mp);
7920Sigor@sysoev.ru     if (nxt_slow_path(rt->services == NULL)) {
8020Sigor@sysoev.ru         goto fail;
8120Sigor@sysoev.ru     }
8220Sigor@sysoev.ru 
8320Sigor@sysoev.ru     listen_sockets = nxt_array_create(mp, 1, sizeof(nxt_listen_socket_t));
8420Sigor@sysoev.ru     if (nxt_slow_path(listen_sockets == NULL)) {
8520Sigor@sysoev.ru         goto fail;
8620Sigor@sysoev.ru     }
8720Sigor@sysoev.ru 
8820Sigor@sysoev.ru     rt->listen_sockets = listen_sockets;
8920Sigor@sysoev.ru 
9020Sigor@sysoev.ru     ret = nxt_runtime_inherited_listen_sockets(task, rt);
9120Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
9220Sigor@sysoev.ru         goto fail;
9320Sigor@sysoev.ru     }
9420Sigor@sysoev.ru 
9520Sigor@sysoev.ru     if (nxt_runtime_hostname(task, rt) != NXT_OK) {
9620Sigor@sysoev.ru         goto fail;
9720Sigor@sysoev.ru     }
9820Sigor@sysoev.ru 
9920Sigor@sysoev.ru     if (nxt_slow_path(nxt_runtime_log_files_init(rt) != NXT_OK)) {
10020Sigor@sysoev.ru         goto fail;
10120Sigor@sysoev.ru     }
10220Sigor@sysoev.ru 
10320Sigor@sysoev.ru     if (nxt_runtime_event_engines(task, rt) != NXT_OK) {
10420Sigor@sysoev.ru         goto fail;
10520Sigor@sysoev.ru     }
10620Sigor@sysoev.ru 
10720Sigor@sysoev.ru     if (nxt_slow_path(nxt_runtime_thread_pools(task->thread, rt) != NXT_OK)) {
10820Sigor@sysoev.ru         goto fail;
10920Sigor@sysoev.ru     }
11020Sigor@sysoev.ru 
11120Sigor@sysoev.ru     rt->start = nxt_runtime_initial_start;
11220Sigor@sysoev.ru 
11320Sigor@sysoev.ru     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
11420Sigor@sysoev.ru                        nxt_runtime_start, task, rt, NULL);
11520Sigor@sysoev.ru 
11620Sigor@sysoev.ru     return NXT_OK;
11720Sigor@sysoev.ru 
11820Sigor@sysoev.ru fail:
11920Sigor@sysoev.ru 
12020Sigor@sysoev.ru     nxt_mem_pool_destroy(mp);
12120Sigor@sysoev.ru 
12220Sigor@sysoev.ru     return NXT_ERROR;
12320Sigor@sysoev.ru }
12420Sigor@sysoev.ru 
12520Sigor@sysoev.ru 
12620Sigor@sysoev.ru static nxt_int_t
12720Sigor@sysoev.ru nxt_runtime_inherited_listen_sockets(nxt_task_t *task, nxt_runtime_t *rt)
12820Sigor@sysoev.ru {
12920Sigor@sysoev.ru     u_char               *v, *p;
13020Sigor@sysoev.ru     nxt_int_t            type;
13120Sigor@sysoev.ru     nxt_array_t          *inherited_sockets;
13220Sigor@sysoev.ru     nxt_socket_t         s;
13320Sigor@sysoev.ru     nxt_listen_socket_t  *ls;
13420Sigor@sysoev.ru 
13520Sigor@sysoev.ru     v = (u_char *) getenv("NGINX");
13620Sigor@sysoev.ru 
13720Sigor@sysoev.ru     if (v == NULL) {
13820Sigor@sysoev.ru         return nxt_runtime_systemd_listen_sockets(task, rt);
13920Sigor@sysoev.ru     }
14020Sigor@sysoev.ru 
14120Sigor@sysoev.ru     nxt_log(task, NXT_LOG_CRIT, "using inherited listen sockets: %s", v);
14220Sigor@sysoev.ru 
14320Sigor@sysoev.ru     inherited_sockets = nxt_array_create(rt->mem_pool,
14420Sigor@sysoev.ru                                          1, sizeof(nxt_listen_socket_t));
14520Sigor@sysoev.ru     if (inherited_sockets == NULL) {
14620Sigor@sysoev.ru         return NXT_ERROR;
14720Sigor@sysoev.ru     }
14820Sigor@sysoev.ru 
14920Sigor@sysoev.ru     rt->inherited_sockets = inherited_sockets;
15020Sigor@sysoev.ru 
15120Sigor@sysoev.ru     for (p = v; *p != '\0'; p++) {
15220Sigor@sysoev.ru 
15320Sigor@sysoev.ru         if (*p == ';') {
15420Sigor@sysoev.ru             s = nxt_int_parse(v, p - v);
15520Sigor@sysoev.ru 
15620Sigor@sysoev.ru             if (nxt_slow_path(s < 0)) {
15720Sigor@sysoev.ru                 nxt_log(task, NXT_LOG_CRIT, "invalid socket number "
15820Sigor@sysoev.ru                         "\"%s\" in NGINX environment variable, "
15920Sigor@sysoev.ru                         "ignoring the rest of the variable", v);
16020Sigor@sysoev.ru                 return NXT_ERROR;
16120Sigor@sysoev.ru             }
16220Sigor@sysoev.ru 
16320Sigor@sysoev.ru             v = p + 1;
16420Sigor@sysoev.ru 
16520Sigor@sysoev.ru             ls = nxt_array_zero_add(inherited_sockets);
16620Sigor@sysoev.ru             if (nxt_slow_path(ls == NULL)) {
16720Sigor@sysoev.ru                 return NXT_ERROR;
16820Sigor@sysoev.ru             }
16920Sigor@sysoev.ru 
17020Sigor@sysoev.ru             ls->socket = s;
17120Sigor@sysoev.ru 
17220Sigor@sysoev.ru             ls->sockaddr = nxt_getsockname(task, rt->mem_pool, s);
17320Sigor@sysoev.ru             if (nxt_slow_path(ls->sockaddr == NULL)) {
17420Sigor@sysoev.ru                 return NXT_ERROR;
17520Sigor@sysoev.ru             }
17620Sigor@sysoev.ru 
17720Sigor@sysoev.ru             type = nxt_socket_getsockopt(task, s, SOL_SOCKET, SO_TYPE);
17820Sigor@sysoev.ru             if (nxt_slow_path(type == -1)) {
17920Sigor@sysoev.ru                 return NXT_ERROR;
18020Sigor@sysoev.ru             }
18120Sigor@sysoev.ru 
18220Sigor@sysoev.ru             ls->sockaddr->type = (uint16_t) type;
18320Sigor@sysoev.ru         }
18420Sigor@sysoev.ru     }
18520Sigor@sysoev.ru 
18620Sigor@sysoev.ru     return NXT_OK;
18720Sigor@sysoev.ru }
18820Sigor@sysoev.ru 
18920Sigor@sysoev.ru 
19020Sigor@sysoev.ru static nxt_int_t
19120Sigor@sysoev.ru nxt_runtime_systemd_listen_sockets(nxt_task_t *task, nxt_runtime_t *rt)
19220Sigor@sysoev.ru {
19320Sigor@sysoev.ru     u_char               *nfd, *pid;
19420Sigor@sysoev.ru     nxt_int_t            n;
19520Sigor@sysoev.ru     nxt_array_t          *inherited_sockets;
19620Sigor@sysoev.ru     nxt_socket_t         s;
19720Sigor@sysoev.ru     nxt_listen_socket_t  *ls;
19820Sigor@sysoev.ru 
19920Sigor@sysoev.ru     /*
20020Sigor@sysoev.ru      * Number of listening sockets passed.  The socket
20120Sigor@sysoev.ru      * descriptors start from number 3 and are sequential.
20220Sigor@sysoev.ru      */
20320Sigor@sysoev.ru     nfd = (u_char *) getenv("LISTEN_FDS");
20420Sigor@sysoev.ru     if (nfd == NULL) {
20520Sigor@sysoev.ru         return NXT_OK;
20620Sigor@sysoev.ru     }
20720Sigor@sysoev.ru 
20820Sigor@sysoev.ru     /* The pid of the service process. */
20920Sigor@sysoev.ru     pid = (u_char *) getenv("LISTEN_PID");
21020Sigor@sysoev.ru     if (pid == NULL) {
21120Sigor@sysoev.ru         return NXT_OK;
21220Sigor@sysoev.ru     }
21320Sigor@sysoev.ru 
21420Sigor@sysoev.ru     n = nxt_int_parse(nfd, nxt_strlen(nfd));
21520Sigor@sysoev.ru     if (n < 0) {
21620Sigor@sysoev.ru         return NXT_OK;
21720Sigor@sysoev.ru     }
21820Sigor@sysoev.ru 
21920Sigor@sysoev.ru     if (nxt_pid != nxt_int_parse(pid, nxt_strlen(pid))) {
22020Sigor@sysoev.ru         return NXT_OK;
22120Sigor@sysoev.ru     }
22220Sigor@sysoev.ru 
22320Sigor@sysoev.ru     nxt_log(task, NXT_LOG_INFO, "using %s systemd listen sockets", n);
22420Sigor@sysoev.ru 
22520Sigor@sysoev.ru     inherited_sockets = nxt_array_create(rt->mem_pool,
22620Sigor@sysoev.ru                                          n, sizeof(nxt_listen_socket_t));
22720Sigor@sysoev.ru     if (inherited_sockets == NULL) {
22820Sigor@sysoev.ru         return NXT_ERROR;
22920Sigor@sysoev.ru     }
23020Sigor@sysoev.ru 
23120Sigor@sysoev.ru     rt->inherited_sockets = inherited_sockets;
23220Sigor@sysoev.ru 
23320Sigor@sysoev.ru     for (s = 3; s < n; s++) {
23420Sigor@sysoev.ru         ls = nxt_array_zero_add(inherited_sockets);
23520Sigor@sysoev.ru         if (nxt_slow_path(ls == NULL)) {
23620Sigor@sysoev.ru             return NXT_ERROR;
23720Sigor@sysoev.ru         }
23820Sigor@sysoev.ru 
23920Sigor@sysoev.ru         ls->socket = s;
24020Sigor@sysoev.ru 
24120Sigor@sysoev.ru         ls->sockaddr = nxt_getsockname(task, rt->mem_pool, s);
24220Sigor@sysoev.ru         if (nxt_slow_path(ls->sockaddr == NULL)) {
24320Sigor@sysoev.ru             return NXT_ERROR;
24420Sigor@sysoev.ru         }
24520Sigor@sysoev.ru 
24620Sigor@sysoev.ru         ls->sockaddr->type = SOCK_STREAM;
24720Sigor@sysoev.ru     }
24820Sigor@sysoev.ru 
24920Sigor@sysoev.ru     return NXT_OK;
25020Sigor@sysoev.ru }
25120Sigor@sysoev.ru 
25220Sigor@sysoev.ru 
25320Sigor@sysoev.ru static nxt_int_t
25420Sigor@sysoev.ru nxt_runtime_event_engines(nxt_task_t *task, nxt_runtime_t *rt)
25520Sigor@sysoev.ru {
256*53Sigor@sysoev.ru     nxt_thread_t                 *thread;
257*53Sigor@sysoev.ru     nxt_event_engine_t           *engine;
25820Sigor@sysoev.ru     const nxt_event_interface_t  *interface;
25920Sigor@sysoev.ru 
26020Sigor@sysoev.ru     interface = nxt_service_get(rt->services, "engine", NULL);
26120Sigor@sysoev.ru 
26220Sigor@sysoev.ru     if (nxt_slow_path(interface == NULL)) {
26320Sigor@sysoev.ru         /* TODO: log */
26420Sigor@sysoev.ru         return NXT_ERROR;
26520Sigor@sysoev.ru     }
26620Sigor@sysoev.ru 
26720Sigor@sysoev.ru     engine = nxt_event_engine_create(task, interface,
26820Sigor@sysoev.ru                                      nxt_master_process_signals, 0, 0);
26920Sigor@sysoev.ru 
27020Sigor@sysoev.ru     if (nxt_slow_path(engine == NULL)) {
27120Sigor@sysoev.ru         return NXT_ERROR;
27220Sigor@sysoev.ru     }
27320Sigor@sysoev.ru 
274*53Sigor@sysoev.ru     thread = task->thread;
275*53Sigor@sysoev.ru     thread->engine = engine;
276*53Sigor@sysoev.ru     thread->fiber = &engine->fibers->fiber;
277*53Sigor@sysoev.ru 
27820Sigor@sysoev.ru     engine->id = rt->last_engine_id++;
279*53Sigor@sysoev.ru 
280*53Sigor@sysoev.ru     nxt_queue_init(&rt->engines);
281*53Sigor@sysoev.ru     nxt_queue_insert_tail(&rt->engines, &engine->link);
28220Sigor@sysoev.ru 
28320Sigor@sysoev.ru     return NXT_OK;
28420Sigor@sysoev.ru }
28520Sigor@sysoev.ru 
28620Sigor@sysoev.ru 
28720Sigor@sysoev.ru static nxt_int_t
28820Sigor@sysoev.ru nxt_runtime_thread_pools(nxt_thread_t *thr, nxt_runtime_t *rt)
28920Sigor@sysoev.ru {
29020Sigor@sysoev.ru #if (NXT_THREADS)
29120Sigor@sysoev.ru     nxt_int_t    ret;
29220Sigor@sysoev.ru     nxt_array_t  *thread_pools;
29320Sigor@sysoev.ru 
29420Sigor@sysoev.ru     thread_pools = nxt_array_create(rt->mem_pool, 1,
29520Sigor@sysoev.ru                                     sizeof(nxt_thread_pool_t *));
29620Sigor@sysoev.ru 
29720Sigor@sysoev.ru     if (nxt_slow_path(thread_pools == NULL)) {
29820Sigor@sysoev.ru         return NXT_ERROR;
29920Sigor@sysoev.ru     }
30020Sigor@sysoev.ru 
30120Sigor@sysoev.ru     rt->thread_pools = thread_pools;
30220Sigor@sysoev.ru     ret = nxt_runtime_thread_pool_create(thr, rt, 2, 60000 * 1000000LL);
30320Sigor@sysoev.ru 
30420Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
30520Sigor@sysoev.ru         return NXT_ERROR;
30620Sigor@sysoev.ru     }
30720Sigor@sysoev.ru 
30820Sigor@sysoev.ru #endif
30920Sigor@sysoev.ru 
31020Sigor@sysoev.ru     return NXT_OK;
31120Sigor@sysoev.ru }
31220Sigor@sysoev.ru 
31320Sigor@sysoev.ru 
31420Sigor@sysoev.ru static void
31520Sigor@sysoev.ru nxt_runtime_start(nxt_task_t *task, void *obj, void *data)
31620Sigor@sysoev.ru {
31720Sigor@sysoev.ru     nxt_uint_t     i;
31820Sigor@sysoev.ru     nxt_runtime_t  *rt;
31920Sigor@sysoev.ru 
32020Sigor@sysoev.ru     rt = obj;
32120Sigor@sysoev.ru 
32220Sigor@sysoev.ru     nxt_debug(task, "rt conf done");
32320Sigor@sysoev.ru 
32420Sigor@sysoev.ru     nxt_mem_pool_debug_lock(rt->mem_pool, nxt_thread_tid(task->thread));
32520Sigor@sysoev.ru 
32620Sigor@sysoev.ru     task->thread->log->ctx_handler = NULL;
32720Sigor@sysoev.ru     task->thread->log->ctx = NULL;
32820Sigor@sysoev.ru 
32920Sigor@sysoev.ru     if (nxt_runtime_conf_init(task, rt) != NXT_OK) {
33020Sigor@sysoev.ru         goto fail;
33120Sigor@sysoev.ru     }
33220Sigor@sysoev.ru 
33320Sigor@sysoev.ru     for (i = 0; i < nxt_init_modules_n; i++) {
33420Sigor@sysoev.ru         if (nxt_init_modules[i](task->thread, rt) != NXT_OK) {
33520Sigor@sysoev.ru             goto fail;
33620Sigor@sysoev.ru         }
33720Sigor@sysoev.ru     }
33820Sigor@sysoev.ru 
33920Sigor@sysoev.ru     if (nxt_runtime_log_files_create(task, rt) != NXT_OK) {
34020Sigor@sysoev.ru         goto fail;
34120Sigor@sysoev.ru     }
34220Sigor@sysoev.ru 
34320Sigor@sysoev.ru     if (nxt_runtime_event_engine_change(task, rt) != NXT_OK) {
34420Sigor@sysoev.ru         goto fail;
34520Sigor@sysoev.ru     }
34620Sigor@sysoev.ru 
34720Sigor@sysoev.ru #if (NXT_THREADS)
34820Sigor@sysoev.ru 
34920Sigor@sysoev.ru     /*
35020Sigor@sysoev.ru      * Thread pools should be destroyed before starting worker
35120Sigor@sysoev.ru      * processes, because thread pool semaphores will stick in
35220Sigor@sysoev.ru      * locked state in new processes after fork().
35320Sigor@sysoev.ru      */
35420Sigor@sysoev.ru     nxt_runtime_thread_pool_destroy(task, rt, rt->start);
35520Sigor@sysoev.ru 
35620Sigor@sysoev.ru #else
35720Sigor@sysoev.ru 
35820Sigor@sysoev.ru     rt->start(task->thread, rt);
35920Sigor@sysoev.ru 
36020Sigor@sysoev.ru #endif
36120Sigor@sysoev.ru 
36220Sigor@sysoev.ru     return;
36320Sigor@sysoev.ru 
36420Sigor@sysoev.ru fail:
36520Sigor@sysoev.ru 
36620Sigor@sysoev.ru     nxt_runtime_quit(task);
36720Sigor@sysoev.ru }
36820Sigor@sysoev.ru 
36920Sigor@sysoev.ru 
37020Sigor@sysoev.ru static void
37120Sigor@sysoev.ru nxt_runtime_initial_start(nxt_task_t *task)
37220Sigor@sysoev.ru {
37320Sigor@sysoev.ru     nxt_int_t                    ret;
37420Sigor@sysoev.ru     nxt_thread_t                 *thr;
37520Sigor@sysoev.ru     nxt_runtime_t                *rt;
37620Sigor@sysoev.ru     const nxt_event_interface_t  *interface;
37720Sigor@sysoev.ru 
37820Sigor@sysoev.ru     thr = task->thread;
37920Sigor@sysoev.ru     rt = thr->runtime;
38020Sigor@sysoev.ru 
38120Sigor@sysoev.ru     if (rt->inherited_sockets == NULL && rt->daemon) {
38220Sigor@sysoev.ru 
38320Sigor@sysoev.ru         if (nxt_process_daemon(task) != NXT_OK) {
38420Sigor@sysoev.ru             goto fail;
38520Sigor@sysoev.ru         }
38620Sigor@sysoev.ru 
38720Sigor@sysoev.ru         /*
38820Sigor@sysoev.ru          * An event engine should be updated after fork()
38920Sigor@sysoev.ru          * even if an event facility was not changed because:
39020Sigor@sysoev.ru          * 1) inherited kqueue descriptor is invalid,
39120Sigor@sysoev.ru          * 2) the signal thread is not inherited.
39220Sigor@sysoev.ru          */
39320Sigor@sysoev.ru         interface = nxt_service_get(rt->services, "engine", rt->engine);
39420Sigor@sysoev.ru         if (interface == NULL) {
39520Sigor@sysoev.ru             goto fail;
39620Sigor@sysoev.ru         }
39720Sigor@sysoev.ru 
39820Sigor@sysoev.ru         ret = nxt_event_engine_change(task->thread->engine, interface,
39920Sigor@sysoev.ru                                       rt->batch);
40020Sigor@sysoev.ru         if (ret != NXT_OK) {
40120Sigor@sysoev.ru             goto fail;
40220Sigor@sysoev.ru         }
40320Sigor@sysoev.ru     }
40420Sigor@sysoev.ru 
40520Sigor@sysoev.ru     ret = nxt_runtime_pid_file_create(task, rt->pid_file);
40620Sigor@sysoev.ru     if (ret != NXT_OK) {
40720Sigor@sysoev.ru         goto fail;
40820Sigor@sysoev.ru     }
40920Sigor@sysoev.ru 
41020Sigor@sysoev.ru     if (nxt_runtime_event_engine_change(task, rt) != NXT_OK) {
41120Sigor@sysoev.ru         goto fail;
41220Sigor@sysoev.ru     }
41320Sigor@sysoev.ru 
41420Sigor@sysoev.ru     thr->engine->max_connections = rt->engine_connections;
41520Sigor@sysoev.ru 
41620Sigor@sysoev.ru     if (rt->master_process) {
41720Sigor@sysoev.ru         if (nxt_master_process_start(thr, task, rt) != NXT_ERROR) {
41820Sigor@sysoev.ru             return;
41920Sigor@sysoev.ru         }
42020Sigor@sysoev.ru 
42120Sigor@sysoev.ru     } else {
42220Sigor@sysoev.ru         nxt_single_process_start(thr, task, rt);
42320Sigor@sysoev.ru         return;
42420Sigor@sysoev.ru     }
42520Sigor@sysoev.ru 
42620Sigor@sysoev.ru fail:
42720Sigor@sysoev.ru 
42820Sigor@sysoev.ru     nxt_runtime_quit(task);
42920Sigor@sysoev.ru }
43020Sigor@sysoev.ru 
43120Sigor@sysoev.ru 
43220Sigor@sysoev.ru static void
43320Sigor@sysoev.ru nxt_single_process_start(nxt_thread_t *thr, nxt_task_t *task, nxt_runtime_t *rt)
43420Sigor@sysoev.ru {
43520Sigor@sysoev.ru #if (NXT_THREADS)
43620Sigor@sysoev.ru     nxt_int_t  ret;
43720Sigor@sysoev.ru 
43820Sigor@sysoev.ru     ret = nxt_runtime_thread_pool_create(thr, rt, rt->auxiliary_threads,
43920Sigor@sysoev.ru                                        60000 * 1000000LL);
44020Sigor@sysoev.ru 
44120Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
44220Sigor@sysoev.ru         nxt_runtime_quit(task);
44320Sigor@sysoev.ru         return;
44420Sigor@sysoev.ru     }
44520Sigor@sysoev.ru 
44620Sigor@sysoev.ru #endif
44720Sigor@sysoev.ru 
44820Sigor@sysoev.ru     rt->type = NXT_PROCESS_SINGLE;
44920Sigor@sysoev.ru 
45020Sigor@sysoev.ru     nxt_runtime_listen_sockets_enable(task, rt);
45120Sigor@sysoev.ru 
45220Sigor@sysoev.ru     return;
45320Sigor@sysoev.ru }
45420Sigor@sysoev.ru 
45520Sigor@sysoev.ru 
45620Sigor@sysoev.ru void
45720Sigor@sysoev.ru nxt_runtime_quit(nxt_task_t *task)
45820Sigor@sysoev.ru {
45920Sigor@sysoev.ru     nxt_bool_t          done;
46020Sigor@sysoev.ru     nxt_runtime_t       *rt;
46120Sigor@sysoev.ru     nxt_event_engine_t  *engine;
46220Sigor@sysoev.ru 
46320Sigor@sysoev.ru     rt = task->thread->runtime;
46420Sigor@sysoev.ru     engine = task->thread->engine;
46520Sigor@sysoev.ru 
46620Sigor@sysoev.ru     nxt_debug(task, "exiting");
46720Sigor@sysoev.ru 
46820Sigor@sysoev.ru     done = 1;
46920Sigor@sysoev.ru 
47020Sigor@sysoev.ru     if (!engine->shutdown) {
47120Sigor@sysoev.ru         engine->shutdown = 1;
47220Sigor@sysoev.ru 
47320Sigor@sysoev.ru #if (NXT_THREADS)
47420Sigor@sysoev.ru 
47520Sigor@sysoev.ru         if (!nxt_array_is_empty(rt->thread_pools)) {
47620Sigor@sysoev.ru             nxt_runtime_thread_pool_destroy(task, rt, nxt_runtime_quit);
47720Sigor@sysoev.ru             done = 0;
47820Sigor@sysoev.ru         }
47920Sigor@sysoev.ru 
48020Sigor@sysoev.ru #endif
48120Sigor@sysoev.ru 
48220Sigor@sysoev.ru         if (rt->type == NXT_PROCESS_MASTER) {
48320Sigor@sysoev.ru             nxt_master_stop_worker_processes(task, rt);
48420Sigor@sysoev.ru             done = 0;
48520Sigor@sysoev.ru         }
48620Sigor@sysoev.ru     }
48720Sigor@sysoev.ru 
48820Sigor@sysoev.ru     nxt_runtime_close_idle_connections(engine);
48920Sigor@sysoev.ru 
49020Sigor@sysoev.ru     if (done) {
49120Sigor@sysoev.ru         nxt_work_queue_add(&engine->fast_work_queue, nxt_runtime_exit,
49220Sigor@sysoev.ru                            task, rt, engine);
49320Sigor@sysoev.ru     }
49420Sigor@sysoev.ru }
49520Sigor@sysoev.ru 
49620Sigor@sysoev.ru 
49720Sigor@sysoev.ru static void
49820Sigor@sysoev.ru nxt_runtime_close_idle_connections(nxt_event_engine_t *engine)
49920Sigor@sysoev.ru {
50020Sigor@sysoev.ru     nxt_queue_t       *idle;
50120Sigor@sysoev.ru     nxt_queue_link_t  *link, *next;
50220Sigor@sysoev.ru     nxt_event_conn_t  *c;
50320Sigor@sysoev.ru 
50420Sigor@sysoev.ru     nxt_debug(&engine->task, "close idle connections");
50520Sigor@sysoev.ru 
50620Sigor@sysoev.ru     idle = &engine->idle_connections;
50720Sigor@sysoev.ru 
50820Sigor@sysoev.ru     for (link = nxt_queue_head(idle);
50920Sigor@sysoev.ru          link != nxt_queue_tail(idle);
51020Sigor@sysoev.ru          link = next)
51120Sigor@sysoev.ru     {
51220Sigor@sysoev.ru         next = nxt_queue_next(link);
51320Sigor@sysoev.ru         c = nxt_queue_link_data(link, nxt_event_conn_t, link);
51420Sigor@sysoev.ru 
51520Sigor@sysoev.ru         if (!c->socket.read_ready) {
51620Sigor@sysoev.ru             nxt_queue_remove(link);
51720Sigor@sysoev.ru             nxt_event_conn_close(engine, c);
51820Sigor@sysoev.ru         }
51920Sigor@sysoev.ru     }
52020Sigor@sysoev.ru }
52120Sigor@sysoev.ru 
52220Sigor@sysoev.ru 
52320Sigor@sysoev.ru static void
52420Sigor@sysoev.ru nxt_runtime_exit(nxt_task_t *task, void *obj, void *data)
52520Sigor@sysoev.ru {
52620Sigor@sysoev.ru     nxt_runtime_t         *rt;
52720Sigor@sysoev.ru     nxt_event_engine_t  *engine;
52820Sigor@sysoev.ru 
52920Sigor@sysoev.ru     rt = obj;
53020Sigor@sysoev.ru     engine = data;
53120Sigor@sysoev.ru 
53220Sigor@sysoev.ru #if (NXT_THREADS)
53320Sigor@sysoev.ru 
53420Sigor@sysoev.ru     nxt_debug(task, "thread pools: %d", rt->thread_pools->nelts);
53520Sigor@sysoev.ru 
53620Sigor@sysoev.ru     if (!nxt_array_is_empty(rt->thread_pools)) {
53720Sigor@sysoev.ru         return;
53820Sigor@sysoev.ru     }
53920Sigor@sysoev.ru 
54020Sigor@sysoev.ru #endif
54120Sigor@sysoev.ru 
54220Sigor@sysoev.ru     if (rt->type <= NXT_PROCESS_MASTER) {
54320Sigor@sysoev.ru         if (rt->pid_file != NULL) {
54420Sigor@sysoev.ru             nxt_file_delete(rt->pid_file);
54520Sigor@sysoev.ru         }
54620Sigor@sysoev.ru     }
54720Sigor@sysoev.ru 
54820Sigor@sysoev.ru     if (!engine->event.signal_support) {
54920Sigor@sysoev.ru         nxt_event_engine_signals_stop(engine);
55020Sigor@sysoev.ru     }
55120Sigor@sysoev.ru 
55220Sigor@sysoev.ru     nxt_debug(task, "exit");
55320Sigor@sysoev.ru 
55420Sigor@sysoev.ru     exit(0);
55520Sigor@sysoev.ru     nxt_unreachable();
55620Sigor@sysoev.ru }
55720Sigor@sysoev.ru 
55820Sigor@sysoev.ru 
55920Sigor@sysoev.ru static nxt_int_t
56020Sigor@sysoev.ru nxt_runtime_event_engine_change(nxt_task_t *task, nxt_runtime_t *rt)
56120Sigor@sysoev.ru {
56220Sigor@sysoev.ru     nxt_event_engine_t           *engine;
56320Sigor@sysoev.ru     const nxt_event_interface_t  *interface;
56420Sigor@sysoev.ru 
56520Sigor@sysoev.ru     engine = task->thread->engine;
56620Sigor@sysoev.ru 
56720Sigor@sysoev.ru     if (engine->batch == rt->batch
56820Sigor@sysoev.ru         && nxt_strcmp(engine->event.name, rt->engine) == 0)
56920Sigor@sysoev.ru     {
57020Sigor@sysoev.ru         return NXT_OK;
57120Sigor@sysoev.ru     }
57220Sigor@sysoev.ru 
57320Sigor@sysoev.ru     interface = nxt_service_get(rt->services, "engine", rt->engine);
57420Sigor@sysoev.ru 
57520Sigor@sysoev.ru     if (interface != NULL) {
57620Sigor@sysoev.ru         return nxt_event_engine_change(engine, interface, rt->batch);
57720Sigor@sysoev.ru     }
57820Sigor@sysoev.ru 
57920Sigor@sysoev.ru     return NXT_ERROR;
58020Sigor@sysoev.ru }
58120Sigor@sysoev.ru 
58220Sigor@sysoev.ru 
58320Sigor@sysoev.ru void
58420Sigor@sysoev.ru nxt_runtime_event_engine_free(nxt_runtime_t *rt)
58520Sigor@sysoev.ru {
586*53Sigor@sysoev.ru     nxt_queue_link_t    *link;
587*53Sigor@sysoev.ru     nxt_event_engine_t  *engine;
58820Sigor@sysoev.ru 
589*53Sigor@sysoev.ru     link = nxt_queue_first(&rt->engines);
590*53Sigor@sysoev.ru     nxt_queue_remove(link);
59120Sigor@sysoev.ru 
592*53Sigor@sysoev.ru     engine = nxt_queue_link_data(link, nxt_event_engine_t, link);
59320Sigor@sysoev.ru     nxt_event_engine_free(engine);
59420Sigor@sysoev.ru }
59520Sigor@sysoev.ru 
59620Sigor@sysoev.ru 
59720Sigor@sysoev.ru #if (NXT_THREADS)
59820Sigor@sysoev.ru 
59920Sigor@sysoev.ru static void nxt_runtime_thread_pool_init(void);
60020Sigor@sysoev.ru static void nxt_runtime_thread_pool_exit(nxt_task_t *task, void *obj,
60120Sigor@sysoev.ru     void *data);
60220Sigor@sysoev.ru 
60320Sigor@sysoev.ru 
60420Sigor@sysoev.ru nxt_int_t
60520Sigor@sysoev.ru nxt_runtime_thread_pool_create(nxt_thread_t *thr, nxt_runtime_t *rt,
60620Sigor@sysoev.ru     nxt_uint_t max_threads, nxt_nsec_t timeout)
60720Sigor@sysoev.ru {
60820Sigor@sysoev.ru     nxt_thread_pool_t   *thread_pool, **tp;
60920Sigor@sysoev.ru 
61020Sigor@sysoev.ru     tp = nxt_array_add(rt->thread_pools);
61120Sigor@sysoev.ru     if (tp == NULL) {
61220Sigor@sysoev.ru         return NXT_ERROR;
61320Sigor@sysoev.ru     }
61420Sigor@sysoev.ru 
61520Sigor@sysoev.ru     thread_pool = nxt_thread_pool_create(max_threads, timeout,
61620Sigor@sysoev.ru                                          nxt_runtime_thread_pool_init,
61720Sigor@sysoev.ru                                          thr->engine,
61820Sigor@sysoev.ru                                          nxt_runtime_thread_pool_exit);
61920Sigor@sysoev.ru 
62020Sigor@sysoev.ru     if (nxt_fast_path(thread_pool != NULL)) {
62120Sigor@sysoev.ru         *tp = thread_pool;
62220Sigor@sysoev.ru     }
62320Sigor@sysoev.ru 
62420Sigor@sysoev.ru     return NXT_OK;
62520Sigor@sysoev.ru }
62620Sigor@sysoev.ru 
62720Sigor@sysoev.ru 
62820Sigor@sysoev.ru static void
62920Sigor@sysoev.ru nxt_runtime_thread_pool_destroy(nxt_task_t *task, nxt_runtime_t *rt,
63020Sigor@sysoev.ru     nxt_runtime_cont_t cont)
63120Sigor@sysoev.ru {
63220Sigor@sysoev.ru     nxt_uint_t         n;
63320Sigor@sysoev.ru     nxt_thread_pool_t  **tp;
63420Sigor@sysoev.ru 
63520Sigor@sysoev.ru     rt->continuation = cont;
63620Sigor@sysoev.ru 
63720Sigor@sysoev.ru     n = rt->thread_pools->nelts;
63820Sigor@sysoev.ru 
63920Sigor@sysoev.ru     if (n == 0) {
64020Sigor@sysoev.ru         cont(task);
64120Sigor@sysoev.ru         return;
64220Sigor@sysoev.ru     }
64320Sigor@sysoev.ru 
64420Sigor@sysoev.ru     tp = rt->thread_pools->elts;
64520Sigor@sysoev.ru 
64620Sigor@sysoev.ru     do {
64720Sigor@sysoev.ru         nxt_thread_pool_destroy(*tp);
64820Sigor@sysoev.ru 
64920Sigor@sysoev.ru         tp++;
65020Sigor@sysoev.ru         n--;
65120Sigor@sysoev.ru     } while (n != 0);
65220Sigor@sysoev.ru }
65320Sigor@sysoev.ru 
65420Sigor@sysoev.ru 
65520Sigor@sysoev.ru static void
65620Sigor@sysoev.ru nxt_runtime_thread_pool_init(void)
65720Sigor@sysoev.ru {
65820Sigor@sysoev.ru #if (NXT_REGEX)
65920Sigor@sysoev.ru     nxt_regex_init(0);
66020Sigor@sysoev.ru #endif
66120Sigor@sysoev.ru }
66220Sigor@sysoev.ru 
66320Sigor@sysoev.ru 
66420Sigor@sysoev.ru static void
66520Sigor@sysoev.ru nxt_runtime_thread_pool_exit(nxt_task_t *task, void *obj, void *data)
66620Sigor@sysoev.ru {
66720Sigor@sysoev.ru     nxt_uint_t           i, n;
66820Sigor@sysoev.ru     nxt_runtime_t        *rt;
66920Sigor@sysoev.ru     nxt_thread_pool_t    *tp, **thread_pools;
67020Sigor@sysoev.ru     nxt_thread_handle_t  handle;
67120Sigor@sysoev.ru 
67220Sigor@sysoev.ru     tp = obj;
67320Sigor@sysoev.ru 
67420Sigor@sysoev.ru     if (data != NULL) {
67520Sigor@sysoev.ru         handle = (nxt_thread_handle_t) (uintptr_t) data;
67620Sigor@sysoev.ru         nxt_thread_wait(handle);
67720Sigor@sysoev.ru     }
67820Sigor@sysoev.ru 
67920Sigor@sysoev.ru     rt = task->thread->runtime;
68020Sigor@sysoev.ru 
68120Sigor@sysoev.ru     thread_pools = rt->thread_pools->elts;
68220Sigor@sysoev.ru     n = rt->thread_pools->nelts;
68320Sigor@sysoev.ru 
68420Sigor@sysoev.ru     nxt_debug(task, "thread pools: %ui", n);
68520Sigor@sysoev.ru 
68620Sigor@sysoev.ru     for (i = 0; i < n; i++) {
68720Sigor@sysoev.ru 
68820Sigor@sysoev.ru         if (tp == thread_pools[i]) {
68920Sigor@sysoev.ru             nxt_array_remove(rt->thread_pools, &thread_pools[i]);
69020Sigor@sysoev.ru 
69120Sigor@sysoev.ru             if (n == 1) {
69220Sigor@sysoev.ru                 /* The last thread pool. */
69320Sigor@sysoev.ru                 rt->continuation(task);
69420Sigor@sysoev.ru             }
69520Sigor@sysoev.ru 
69620Sigor@sysoev.ru             return;
69720Sigor@sysoev.ru         }
69820Sigor@sysoev.ru     }
69920Sigor@sysoev.ru }
70020Sigor@sysoev.ru 
70120Sigor@sysoev.ru #endif
70220Sigor@sysoev.ru 
70320Sigor@sysoev.ru 
70420Sigor@sysoev.ru static nxt_int_t
70520Sigor@sysoev.ru nxt_runtime_conf_init(nxt_task_t *task, nxt_runtime_t *rt)
70620Sigor@sysoev.ru {
70720Sigor@sysoev.ru     nxt_int_t                    ret;
70820Sigor@sysoev.ru     nxt_str_t                    *prefix;
70920Sigor@sysoev.ru     nxt_file_t                   *file;
71020Sigor@sysoev.ru     nxt_file_name_str_t          file_name;
71120Sigor@sysoev.ru     const nxt_event_interface_t  *interface;
71220Sigor@sysoev.ru 
71320Sigor@sysoev.ru     rt->daemon = 1;
71420Sigor@sysoev.ru     rt->master_process = 1;
71520Sigor@sysoev.ru     rt->engine_connections = 256;
71620Sigor@sysoev.ru     rt->worker_processes = 1;
71720Sigor@sysoev.ru     rt->auxiliary_threads = 2;
71820Sigor@sysoev.ru     rt->user_cred.user = "nobody";
71920Sigor@sysoev.ru     rt->group = NULL;
72020Sigor@sysoev.ru     rt->pid = "nginext.pid";
72120Sigor@sysoev.ru     rt->error_log = "error.log";
72220Sigor@sysoev.ru 
72320Sigor@sysoev.ru     if (nxt_runtime_conf_read_cmd(task, rt) != NXT_OK) {
72420Sigor@sysoev.ru         return NXT_ERROR;
72520Sigor@sysoev.ru     }
72620Sigor@sysoev.ru 
72720Sigor@sysoev.ru     if (nxt_runtime_controller_socket(task, rt) != NXT_OK) {
72820Sigor@sysoev.ru         return NXT_ERROR;
72920Sigor@sysoev.ru     }
73020Sigor@sysoev.ru 
73120Sigor@sysoev.ru     if (nxt_user_cred_get(task, &rt->user_cred, rt->group) != NXT_OK) {
73220Sigor@sysoev.ru         return NXT_ERROR;
73320Sigor@sysoev.ru     }
73420Sigor@sysoev.ru 
73520Sigor@sysoev.ru     /* An engine's parameters. */
73620Sigor@sysoev.ru 
73720Sigor@sysoev.ru     interface = nxt_service_get(rt->services, "engine", rt->engine);
73820Sigor@sysoev.ru     if (interface == NULL) {
73920Sigor@sysoev.ru         return NXT_ERROR;
74020Sigor@sysoev.ru     }
74120Sigor@sysoev.ru 
74220Sigor@sysoev.ru     rt->engine = interface->name;
74320Sigor@sysoev.ru 
74420Sigor@sysoev.ru     prefix = nxt_file_name_is_absolute(rt->pid) ? NULL : rt->prefix;
74520Sigor@sysoev.ru 
74620Sigor@sysoev.ru     ret = nxt_file_name_create(rt->mem_pool, &file_name, "%V%s%Z",
74720Sigor@sysoev.ru                                prefix, rt->pid);
74820Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
74920Sigor@sysoev.ru         return NXT_ERROR;
75020Sigor@sysoev.ru     }
75120Sigor@sysoev.ru 
75220Sigor@sysoev.ru     rt->pid_file = file_name.start;
75320Sigor@sysoev.ru 
75420Sigor@sysoev.ru     prefix = nxt_file_name_is_absolute(rt->error_log) ? NULL : rt->prefix;
75520Sigor@sysoev.ru 
75620Sigor@sysoev.ru     ret = nxt_file_name_create(rt->mem_pool, &file_name, "%V%s%Z",
75720Sigor@sysoev.ru                                prefix, rt->error_log);
75820Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
75920Sigor@sysoev.ru         return NXT_ERROR;
76020Sigor@sysoev.ru     }
76120Sigor@sysoev.ru 
76220Sigor@sysoev.ru     file = nxt_list_first(rt->log_files);
76320Sigor@sysoev.ru     file->name = file_name.start;
76420Sigor@sysoev.ru 
76520Sigor@sysoev.ru     return NXT_OK;
76620Sigor@sysoev.ru }
76720Sigor@sysoev.ru 
76820Sigor@sysoev.ru 
76920Sigor@sysoev.ru static nxt_int_t
77020Sigor@sysoev.ru nxt_runtime_conf_read_cmd(nxt_task_t *task, nxt_runtime_t *rt)
77120Sigor@sysoev.ru {
77220Sigor@sysoev.ru     char            *p, **argv;
77320Sigor@sysoev.ru     nxt_int_t       n;
77420Sigor@sysoev.ru     nxt_str_t       addr;
77520Sigor@sysoev.ru     nxt_sockaddr_t  *sa;
77620Sigor@sysoev.ru 
77720Sigor@sysoev.ru     argv = nxt_process_argv;
77820Sigor@sysoev.ru 
77920Sigor@sysoev.ru     while (*argv != NULL) {
78020Sigor@sysoev.ru         p = *argv++;
78120Sigor@sysoev.ru 
78220Sigor@sysoev.ru         if (nxt_strcmp(p, "--listen") == 0) {
78320Sigor@sysoev.ru             if (*argv == NULL) {
78420Sigor@sysoev.ru                 nxt_log(task, NXT_LOG_CRIT,
78520Sigor@sysoev.ru                          "no argument for option \"--listen\"");
78620Sigor@sysoev.ru                 return NXT_ERROR;
78720Sigor@sysoev.ru             }
78820Sigor@sysoev.ru 
78920Sigor@sysoev.ru             p = *argv++;
79020Sigor@sysoev.ru 
79120Sigor@sysoev.ru             addr.length = nxt_strlen(p);
79220Sigor@sysoev.ru             addr.start = (u_char *) p;
79320Sigor@sysoev.ru 
79420Sigor@sysoev.ru             sa = nxt_runtime_sockaddr_parse(task, rt->mem_pool, &addr);
79520Sigor@sysoev.ru 
79620Sigor@sysoev.ru             if (sa == NULL) {
79720Sigor@sysoev.ru                 return NXT_ERROR;
79820Sigor@sysoev.ru             }
79920Sigor@sysoev.ru 
80020Sigor@sysoev.ru             rt->controller_listen = sa;
80120Sigor@sysoev.ru 
80220Sigor@sysoev.ru             continue;
80320Sigor@sysoev.ru         }
80420Sigor@sysoev.ru 
80520Sigor@sysoev.ru         if (nxt_strcmp(p, "--upstream") == 0) {
80620Sigor@sysoev.ru             if (*argv == NULL) {
80720Sigor@sysoev.ru                 nxt_log(task, NXT_LOG_CRIT,
80820Sigor@sysoev.ru                               "no argument for option \"--upstream\"");
80920Sigor@sysoev.ru                 return NXT_ERROR;
81020Sigor@sysoev.ru             }
81120Sigor@sysoev.ru 
81220Sigor@sysoev.ru             p = *argv++;
81320Sigor@sysoev.ru 
81420Sigor@sysoev.ru             rt->upstream.length = nxt_strlen(p);
81520Sigor@sysoev.ru             rt->upstream.start = (u_char *) p;
81620Sigor@sysoev.ru 
81720Sigor@sysoev.ru             continue;
81820Sigor@sysoev.ru         }
81920Sigor@sysoev.ru 
82020Sigor@sysoev.ru         if (nxt_strcmp(p, "--workers") == 0) {
82120Sigor@sysoev.ru             if (*argv == NULL) {
82220Sigor@sysoev.ru                 nxt_log(task, NXT_LOG_CRIT,
82320Sigor@sysoev.ru                         "no argument for option \"--workers\"");
82420Sigor@sysoev.ru                 return NXT_ERROR;
82520Sigor@sysoev.ru             }
82620Sigor@sysoev.ru 
82720Sigor@sysoev.ru             p = *argv++;
82820Sigor@sysoev.ru             n = nxt_int_parse((u_char *) p, nxt_strlen(p));
82920Sigor@sysoev.ru 
83020Sigor@sysoev.ru             if (n < 1) {
83120Sigor@sysoev.ru                 nxt_log(task, NXT_LOG_CRIT,
83220Sigor@sysoev.ru                         "invalid number of workers: \"%s\"", p);
83320Sigor@sysoev.ru                 return NXT_ERROR;
83420Sigor@sysoev.ru             }
83520Sigor@sysoev.ru 
83620Sigor@sysoev.ru             rt->worker_processes = n;
83720Sigor@sysoev.ru 
83820Sigor@sysoev.ru             continue;
83920Sigor@sysoev.ru         }
84020Sigor@sysoev.ru 
84120Sigor@sysoev.ru         if (nxt_strcmp(p, "--user") == 0) {
84220Sigor@sysoev.ru             if (*argv == NULL) {
84320Sigor@sysoev.ru                 nxt_log(task, NXT_LOG_CRIT,
84420Sigor@sysoev.ru                         "no argument for option \"--user\"");
84520Sigor@sysoev.ru                 return NXT_ERROR;
84620Sigor@sysoev.ru             }
84720Sigor@sysoev.ru 
84820Sigor@sysoev.ru             p = *argv++;
84920Sigor@sysoev.ru 
85020Sigor@sysoev.ru             rt->user_cred.user = p;
85120Sigor@sysoev.ru 
85220Sigor@sysoev.ru             continue;
85320Sigor@sysoev.ru         }
85420Sigor@sysoev.ru 
85520Sigor@sysoev.ru         if (nxt_strcmp(p, "--group") == 0) {
85620Sigor@sysoev.ru             if (*argv == NULL) {
85720Sigor@sysoev.ru                 nxt_log(task, NXT_LOG_CRIT,
85820Sigor@sysoev.ru                         "no argument for option \"--group\"");
85920Sigor@sysoev.ru                 return NXT_ERROR;
86020Sigor@sysoev.ru             }
86120Sigor@sysoev.ru 
86220Sigor@sysoev.ru             p = *argv++;
86320Sigor@sysoev.ru 
86420Sigor@sysoev.ru             rt->group = p;
86520Sigor@sysoev.ru 
86620Sigor@sysoev.ru             continue;
86720Sigor@sysoev.ru         }
86820Sigor@sysoev.ru 
86920Sigor@sysoev.ru         if (nxt_strcmp(p, "--pid") == 0) {
87020Sigor@sysoev.ru             if (*argv == NULL) {
87120Sigor@sysoev.ru                 nxt_log(task, NXT_LOG_CRIT,
87220Sigor@sysoev.ru                         "no argument for option \"--pid\"");
87320Sigor@sysoev.ru                 return NXT_ERROR;
87420Sigor@sysoev.ru             }
87520Sigor@sysoev.ru 
87620Sigor@sysoev.ru             p = *argv++;
87720Sigor@sysoev.ru 
87820Sigor@sysoev.ru             rt->pid = p;
87920Sigor@sysoev.ru 
88020Sigor@sysoev.ru             continue;
88120Sigor@sysoev.ru         }
88220Sigor@sysoev.ru 
88320Sigor@sysoev.ru         if (nxt_strcmp(p, "--log") == 0) {
88420Sigor@sysoev.ru             if (*argv == NULL) {
88520Sigor@sysoev.ru                 nxt_log(task, NXT_LOG_CRIT,
88620Sigor@sysoev.ru                         "no argument for option \"--log\"");
88720Sigor@sysoev.ru                 return NXT_ERROR;
88820Sigor@sysoev.ru             }
88920Sigor@sysoev.ru 
89020Sigor@sysoev.ru             p = *argv++;
89120Sigor@sysoev.ru 
89220Sigor@sysoev.ru             rt->error_log = p;
89320Sigor@sysoev.ru 
89420Sigor@sysoev.ru             continue;
89520Sigor@sysoev.ru         }
89620Sigor@sysoev.ru 
89720Sigor@sysoev.ru         if (nxt_strcmp(p, "--no-daemonize") == 0) {
89820Sigor@sysoev.ru             rt->daemon = 0;
89920Sigor@sysoev.ru             continue;
90020Sigor@sysoev.ru         }
90120Sigor@sysoev.ru     }
90220Sigor@sysoev.ru 
90320Sigor@sysoev.ru     return NXT_OK;
90420Sigor@sysoev.ru }
90520Sigor@sysoev.ru 
90620Sigor@sysoev.ru 
90720Sigor@sysoev.ru static nxt_sockaddr_t *
90820Sigor@sysoev.ru nxt_runtime_sockaddr_parse(nxt_task_t *task, nxt_mem_pool_t *mp,
90920Sigor@sysoev.ru     nxt_str_t *addr)
91020Sigor@sysoev.ru {
91120Sigor@sysoev.ru     u_char  *p;
91220Sigor@sysoev.ru     size_t  length;
91320Sigor@sysoev.ru 
91420Sigor@sysoev.ru     length = addr->length;
91520Sigor@sysoev.ru     p = addr->start;
91620Sigor@sysoev.ru 
91720Sigor@sysoev.ru     if (length >= 5 && nxt_memcmp(p, (u_char *) "unix:", 5) == 0) {
91820Sigor@sysoev.ru         return nxt_runtime_sockaddr_unix_parse(task, mp, addr);
91920Sigor@sysoev.ru     }
92020Sigor@sysoev.ru 
92120Sigor@sysoev.ru     if (length != 0 && *p == '[') {
92220Sigor@sysoev.ru         return nxt_runtime_sockaddr_inet6_parse(task, mp, addr);
92320Sigor@sysoev.ru     }
92420Sigor@sysoev.ru 
92520Sigor@sysoev.ru     return nxt_runtime_sockaddr_inet_parse(task, mp, addr);
92620Sigor@sysoev.ru }
92720Sigor@sysoev.ru 
92820Sigor@sysoev.ru 
92920Sigor@sysoev.ru static nxt_sockaddr_t *
93020Sigor@sysoev.ru nxt_runtime_sockaddr_unix_parse(nxt_task_t *task, nxt_mem_pool_t *mp,
93120Sigor@sysoev.ru     nxt_str_t *addr)
93220Sigor@sysoev.ru {
93320Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
93420Sigor@sysoev.ru     u_char          *p;
93520Sigor@sysoev.ru     size_t          length, socklen;
93620Sigor@sysoev.ru     nxt_sockaddr_t  *sa;
93720Sigor@sysoev.ru 
93820Sigor@sysoev.ru     /*
93920Sigor@sysoev.ru      * Actual sockaddr_un length can be lesser or even larger than defined
94020Sigor@sysoev.ru      * struct sockaddr_un length (see comment in unix/nxt_socket.h).  So
94120Sigor@sysoev.ru      * limit maximum Unix domain socket address length by defined sun_path[]
94220Sigor@sysoev.ru      * length because some OSes accept addresses twice larger than defined
94320Sigor@sysoev.ru      * struct sockaddr_un.  Also reserve space for a trailing zero to avoid
94420Sigor@sysoev.ru      * ambiguity, since many OSes accept Unix domain socket addresses
94520Sigor@sysoev.ru      * without a trailing zero.
94620Sigor@sysoev.ru      */
94720Sigor@sysoev.ru     const size_t max_len = sizeof(struct sockaddr_un)
94820Sigor@sysoev.ru                            - offsetof(struct sockaddr_un, sun_path) - 1;
94920Sigor@sysoev.ru 
95020Sigor@sysoev.ru     /* cutting "unix:" */
95120Sigor@sysoev.ru     length = addr->length - 5;
95220Sigor@sysoev.ru     p = addr->start + 5;
95320Sigor@sysoev.ru 
95420Sigor@sysoev.ru     if (length == 0) {
95520Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT,
95620Sigor@sysoev.ru                 "unix domain socket \"%V\" name is invalid", addr);
95720Sigor@sysoev.ru         return NULL;
95820Sigor@sysoev.ru     }
95920Sigor@sysoev.ru 
96020Sigor@sysoev.ru     if (length > max_len) {
96120Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT,
96220Sigor@sysoev.ru                 "unix domain socket \"%V\" name is too long", addr);
96320Sigor@sysoev.ru         return NULL;
96420Sigor@sysoev.ru     }
96520Sigor@sysoev.ru 
96620Sigor@sysoev.ru     socklen = offsetof(struct sockaddr_un, sun_path) + length + 1;
96720Sigor@sysoev.ru 
96820Sigor@sysoev.ru #if (NXT_LINUX)
96920Sigor@sysoev.ru 
97020Sigor@sysoev.ru     /*
97120Sigor@sysoev.ru      * Linux unix(7):
97220Sigor@sysoev.ru      *
97320Sigor@sysoev.ru      *   abstract: an abstract socket address is distinguished by the fact
97420Sigor@sysoev.ru      *   that sun_path[0] is a null byte ('\0').  The socket's address in
97520Sigor@sysoev.ru      *   this namespace is given by the additional bytes in sun_path that
97620Sigor@sysoev.ru      *   are covered by the specified length of the address structure.
97720Sigor@sysoev.ru      *   (Null bytes in the name have no special significance.)
97820Sigor@sysoev.ru      */
97920Sigor@sysoev.ru     if (p[0] == '@') {
98020Sigor@sysoev.ru         p[0] = '\0';
98120Sigor@sysoev.ru         socklen--;
98220Sigor@sysoev.ru     }
98320Sigor@sysoev.ru 
98420Sigor@sysoev.ru #endif
98520Sigor@sysoev.ru 
98620Sigor@sysoev.ru     sa = nxt_sockaddr_alloc(mp, socklen, addr->length);
98720Sigor@sysoev.ru 
98820Sigor@sysoev.ru     if (nxt_slow_path(sa == NULL)) {
98920Sigor@sysoev.ru         return NULL;
99020Sigor@sysoev.ru     }
99120Sigor@sysoev.ru 
99220Sigor@sysoev.ru     sa->type = SOCK_STREAM;
99320Sigor@sysoev.ru 
99420Sigor@sysoev.ru     sa->u.sockaddr_un.sun_family = AF_UNIX;
99520Sigor@sysoev.ru     nxt_memcpy(sa->u.sockaddr_un.sun_path, p, length);
99620Sigor@sysoev.ru 
99720Sigor@sysoev.ru     return sa;
99820Sigor@sysoev.ru 
99920Sigor@sysoev.ru #else  /* !(NXT_HAVE_UNIX_DOMAIN) */
100020Sigor@sysoev.ru 
100120Sigor@sysoev.ru     nxt_log(task, NXT_LOG_CRIT, "unix domain socket \"%V\" is not supported",
100220Sigor@sysoev.ru             addr);
100320Sigor@sysoev.ru 
100420Sigor@sysoev.ru     return NULL;
100520Sigor@sysoev.ru 
100620Sigor@sysoev.ru #endif
100720Sigor@sysoev.ru }
100820Sigor@sysoev.ru 
100920Sigor@sysoev.ru 
101020Sigor@sysoev.ru static nxt_sockaddr_t *
101120Sigor@sysoev.ru nxt_runtime_sockaddr_inet6_parse(nxt_task_t *task, nxt_mem_pool_t *mp,
101220Sigor@sysoev.ru     nxt_str_t *addr)
101320Sigor@sysoev.ru {
101420Sigor@sysoev.ru #if (NXT_INET6)
101520Sigor@sysoev.ru     u_char           *p, *addr, *addr_end;
101620Sigor@sysoev.ru     size_t           length;
101720Sigor@sysoev.ru     nxt_int_t        port;
101820Sigor@sysoev.ru     nxt_mem_pool_t   *mp;
101920Sigor@sysoev.ru     nxt_sockaddr_t   *sa;
102020Sigor@sysoev.ru     struct in6_addr  *in6_addr;
102120Sigor@sysoev.ru 
102220Sigor@sysoev.ru     length = addr->length - 1;
102320Sigor@sysoev.ru     p = addr->start + 1;
102420Sigor@sysoev.ru 
102520Sigor@sysoev.ru     addr_end = nxt_memchr(p, ']', length);
102620Sigor@sysoev.ru 
102720Sigor@sysoev.ru     if (addr_end == NULL) {
102820Sigor@sysoev.ru         goto invalid_address;
102920Sigor@sysoev.ru     }
103020Sigor@sysoev.ru 
103120Sigor@sysoev.ru     sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in6));
103220Sigor@sysoev.ru 
103320Sigor@sysoev.ru     if (nxt_slow_path(sa == NULL)) {
103420Sigor@sysoev.ru         return NULL;
103520Sigor@sysoev.ru     }
103620Sigor@sysoev.ru 
103720Sigor@sysoev.ru     in6_addr = &sa->u.sockaddr_in6.sin6_addr;
103820Sigor@sysoev.ru 
103920Sigor@sysoev.ru     if (nxt_inet6_addr(in6_addr, p, addr_end - p) != NXT_OK) {
104020Sigor@sysoev.ru         goto invalid_address;
104120Sigor@sysoev.ru     }
104220Sigor@sysoev.ru 
104320Sigor@sysoev.ru     p = addr_end + 1;
104420Sigor@sysoev.ru     length = (p + length) - p;
104520Sigor@sysoev.ru 
104620Sigor@sysoev.ru     if (length == 0) {
104720Sigor@sysoev.ru         goto found;
104820Sigor@sysoev.ru     }
104920Sigor@sysoev.ru 
105020Sigor@sysoev.ru     if (*p == ':') {
105120Sigor@sysoev.ru         port = nxt_int_parse(p + 1, length - 1);
105220Sigor@sysoev.ru 
105320Sigor@sysoev.ru         if (port >= 1 && port <= 65535) {
105420Sigor@sysoev.ru             goto found;
105520Sigor@sysoev.ru         }
105620Sigor@sysoev.ru     }
105720Sigor@sysoev.ru 
105820Sigor@sysoev.ru     nxt_log(task, NXT_LOG_CRIT, "invalid port in \"%V\"", addr);
105920Sigor@sysoev.ru 
106020Sigor@sysoev.ru     return NULL;
106120Sigor@sysoev.ru 
106220Sigor@sysoev.ru found:
106320Sigor@sysoev.ru 
106420Sigor@sysoev.ru     sa->type = SOCK_STREAM;
106520Sigor@sysoev.ru 
106620Sigor@sysoev.ru     sa->u.sockaddr_in6.sin6_family = AF_INET6;
106720Sigor@sysoev.ru     sa->u.sockaddr_in6.sin6_port = htons((in_port_t) port);
106820Sigor@sysoev.ru 
106920Sigor@sysoev.ru     return sa;
107020Sigor@sysoev.ru 
107120Sigor@sysoev.ru invalid_address:
107220Sigor@sysoev.ru 
107320Sigor@sysoev.ru     nxt_log(task, NXT_LOG_CRIT, "invalid IPv6 address in \"%V\"", addr);
107420Sigor@sysoev.ru 
107520Sigor@sysoev.ru     return NULL;
107620Sigor@sysoev.ru 
107720Sigor@sysoev.ru #else
107820Sigor@sysoev.ru 
107920Sigor@sysoev.ru     nxt_log(task, NXT_LOG_CRIT, "IPv6 socket \"%V\" is not supported", addr);
108020Sigor@sysoev.ru 
108120Sigor@sysoev.ru     return NULL;
108220Sigor@sysoev.ru 
108320Sigor@sysoev.ru #endif
108420Sigor@sysoev.ru }
108520Sigor@sysoev.ru 
108620Sigor@sysoev.ru 
108720Sigor@sysoev.ru static nxt_sockaddr_t *
108820Sigor@sysoev.ru nxt_runtime_sockaddr_inet_parse(nxt_task_t *task, nxt_mem_pool_t *mp,
108926Sigor@sysoev.ru     nxt_str_t *string)
109020Sigor@sysoev.ru {
109120Sigor@sysoev.ru     u_char          *p, *ip;
109220Sigor@sysoev.ru     size_t          length;
109326Sigor@sysoev.ru     in_addr_t       addr;
109420Sigor@sysoev.ru     nxt_int_t       port;
109520Sigor@sysoev.ru     nxt_sockaddr_t  *sa;
109620Sigor@sysoev.ru 
109726Sigor@sysoev.ru     addr = INADDR_ANY;
109820Sigor@sysoev.ru 
109926Sigor@sysoev.ru     length = string->length;
110026Sigor@sysoev.ru     ip = string->start;
110120Sigor@sysoev.ru 
110220Sigor@sysoev.ru     p = nxt_memchr(ip, ':', length);
110320Sigor@sysoev.ru 
110420Sigor@sysoev.ru     if (p == NULL) {
110520Sigor@sysoev.ru 
110620Sigor@sysoev.ru         /* single value port, or address */
110720Sigor@sysoev.ru 
110820Sigor@sysoev.ru         port = nxt_int_parse(ip, length);
110920Sigor@sysoev.ru 
111020Sigor@sysoev.ru         if (port > 0) {
111120Sigor@sysoev.ru             /* "*:XX" */
111220Sigor@sysoev.ru 
111320Sigor@sysoev.ru             if (port < 1 || port > 65535) {
111420Sigor@sysoev.ru                 goto invalid_port;
111520Sigor@sysoev.ru             }
111620Sigor@sysoev.ru 
111720Sigor@sysoev.ru         } else {
111820Sigor@sysoev.ru             /* "x.x.x.x" */
111920Sigor@sysoev.ru 
112026Sigor@sysoev.ru             addr = nxt_inet_addr(ip, length);
112120Sigor@sysoev.ru 
112226Sigor@sysoev.ru             if (addr == INADDR_NONE) {
112320Sigor@sysoev.ru                 goto invalid_port;
112420Sigor@sysoev.ru             }
112520Sigor@sysoev.ru 
112620Sigor@sysoev.ru             port = 8080;
112720Sigor@sysoev.ru         }
112820Sigor@sysoev.ru 
112920Sigor@sysoev.ru     } else {
113020Sigor@sysoev.ru 
113120Sigor@sysoev.ru         /* x.x.x.x:XX */
113220Sigor@sysoev.ru 
113320Sigor@sysoev.ru         p++;
113420Sigor@sysoev.ru         length = (ip + length) - p;
113520Sigor@sysoev.ru         port = nxt_int_parse(p, length);
113620Sigor@sysoev.ru 
113720Sigor@sysoev.ru         if (port < 1 || port > 65535) {
113820Sigor@sysoev.ru             goto invalid_port;
113920Sigor@sysoev.ru         }
114020Sigor@sysoev.ru 
114120Sigor@sysoev.ru         length = (p - 1) - ip;
114220Sigor@sysoev.ru 
114320Sigor@sysoev.ru         if (length != 1 || ip[0] != '*') {
114426Sigor@sysoev.ru             addr = nxt_inet_addr(ip, length);
114520Sigor@sysoev.ru 
114626Sigor@sysoev.ru             if (addr == INADDR_NONE) {
114720Sigor@sysoev.ru                 goto invalid_addr;
114820Sigor@sysoev.ru             }
114920Sigor@sysoev.ru 
115020Sigor@sysoev.ru             /* "x.x.x.x:XX" */
115120Sigor@sysoev.ru         }
115220Sigor@sysoev.ru     }
115320Sigor@sysoev.ru 
115420Sigor@sysoev.ru     sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in),
115520Sigor@sysoev.ru                             NXT_INET_ADDR_STR_LEN);
115620Sigor@sysoev.ru     if (nxt_slow_path(sa == NULL)) {
115720Sigor@sysoev.ru         return NULL;
115820Sigor@sysoev.ru     }
115920Sigor@sysoev.ru 
116020Sigor@sysoev.ru     sa->type = SOCK_STREAM;
116120Sigor@sysoev.ru 
116220Sigor@sysoev.ru     sa->u.sockaddr_in.sin_family = AF_INET;
116320Sigor@sysoev.ru     sa->u.sockaddr_in.sin_port = htons((in_port_t) port);
116426Sigor@sysoev.ru     sa->u.sockaddr_in.sin_addr.s_addr = addr;
116520Sigor@sysoev.ru 
116620Sigor@sysoev.ru     return sa;
116720Sigor@sysoev.ru 
116820Sigor@sysoev.ru invalid_port:
116920Sigor@sysoev.ru 
117026Sigor@sysoev.ru     nxt_log(task, NXT_LOG_CRIT, "invalid port in \"%V\"", string);
117120Sigor@sysoev.ru 
117220Sigor@sysoev.ru     return NULL;
117320Sigor@sysoev.ru 
117420Sigor@sysoev.ru invalid_addr:
117520Sigor@sysoev.ru 
117626Sigor@sysoev.ru     nxt_log(task, NXT_LOG_CRIT, "invalid address in \"%V\"", string);
117720Sigor@sysoev.ru 
117820Sigor@sysoev.ru     return NULL;
117920Sigor@sysoev.ru }
118020Sigor@sysoev.ru 
118120Sigor@sysoev.ru 
118220Sigor@sysoev.ru nxt_listen_socket_t *
118320Sigor@sysoev.ru nxt_runtime_listen_socket_add(nxt_runtime_t *rt, nxt_sockaddr_t *sa)
118420Sigor@sysoev.ru {
118520Sigor@sysoev.ru     nxt_mem_pool_t       *mp;
118620Sigor@sysoev.ru     nxt_listen_socket_t  *ls;
118720Sigor@sysoev.ru 
118820Sigor@sysoev.ru     ls = nxt_array_zero_add(rt->listen_sockets);
118920Sigor@sysoev.ru     if (ls == NULL) {
119020Sigor@sysoev.ru         return NULL;
119120Sigor@sysoev.ru     }
119220Sigor@sysoev.ru 
119320Sigor@sysoev.ru     mp = rt->mem_pool;
119420Sigor@sysoev.ru 
119520Sigor@sysoev.ru     ls->sockaddr = nxt_sockaddr_create(mp, &sa->u.sockaddr, sa->socklen,
119620Sigor@sysoev.ru                                        sa->length);
119720Sigor@sysoev.ru     if (ls->sockaddr == NULL) {
119820Sigor@sysoev.ru         return NULL;
119920Sigor@sysoev.ru     }
120020Sigor@sysoev.ru 
120120Sigor@sysoev.ru     ls->sockaddr->type = sa->type;
120220Sigor@sysoev.ru 
120320Sigor@sysoev.ru     nxt_sockaddr_text(ls->sockaddr);
120420Sigor@sysoev.ru 
120520Sigor@sysoev.ru     ls->socket = -1;
120620Sigor@sysoev.ru     ls->backlog = NXT_LISTEN_BACKLOG;
120720Sigor@sysoev.ru 
120820Sigor@sysoev.ru     return ls;
120920Sigor@sysoev.ru }
121020Sigor@sysoev.ru 
121120Sigor@sysoev.ru 
121220Sigor@sysoev.ru static nxt_int_t
121320Sigor@sysoev.ru nxt_runtime_hostname(nxt_task_t *task, nxt_runtime_t *rt)
121420Sigor@sysoev.ru {
121520Sigor@sysoev.ru     size_t  length;
121620Sigor@sysoev.ru     char    hostname[NXT_MAXHOSTNAMELEN + 1];
121720Sigor@sysoev.ru 
121820Sigor@sysoev.ru     if (gethostname(hostname, NXT_MAXHOSTNAMELEN) != 0) {
121920Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "gethostname() failed %E", nxt_errno);
122020Sigor@sysoev.ru         return NXT_ERROR;
122120Sigor@sysoev.ru     }
122220Sigor@sysoev.ru 
122320Sigor@sysoev.ru     /*
122420Sigor@sysoev.ru      * Linux gethostname(2):
122520Sigor@sysoev.ru      *
122620Sigor@sysoev.ru      *    If the null-terminated hostname is too large to fit,
122720Sigor@sysoev.ru      *    then the name is truncated, and no error is returned.
122820Sigor@sysoev.ru      *
122920Sigor@sysoev.ru      * For this reason an additional byte is reserved in the buffer.
123020Sigor@sysoev.ru      */
123120Sigor@sysoev.ru     hostname[NXT_MAXHOSTNAMELEN] = '\0';
123220Sigor@sysoev.ru 
123320Sigor@sysoev.ru     length = nxt_strlen(hostname);
123420Sigor@sysoev.ru     rt->hostname.length = length;
123520Sigor@sysoev.ru 
123620Sigor@sysoev.ru     rt->hostname.start = nxt_mem_nalloc(rt->mem_pool, length);
123720Sigor@sysoev.ru 
123820Sigor@sysoev.ru     if (rt->hostname.start != NULL) {
123920Sigor@sysoev.ru         nxt_memcpy_lowcase(rt->hostname.start, (u_char *) hostname, length);
124020Sigor@sysoev.ru         return NXT_OK;
124120Sigor@sysoev.ru     }
124220Sigor@sysoev.ru 
124320Sigor@sysoev.ru     return NXT_ERROR;
124420Sigor@sysoev.ru }
124520Sigor@sysoev.ru 
124620Sigor@sysoev.ru 
124720Sigor@sysoev.ru static nxt_int_t
124820Sigor@sysoev.ru nxt_runtime_log_files_init(nxt_runtime_t *rt)
124920Sigor@sysoev.ru {
125020Sigor@sysoev.ru     nxt_file_t  *file;
125120Sigor@sysoev.ru     nxt_list_t  *log_files;
125220Sigor@sysoev.ru 
125320Sigor@sysoev.ru     log_files = nxt_list_create(rt->mem_pool, 1, sizeof(nxt_file_t));
125420Sigor@sysoev.ru 
125520Sigor@sysoev.ru     if (nxt_fast_path(log_files != NULL)) {
125620Sigor@sysoev.ru         rt->log_files = log_files;
125720Sigor@sysoev.ru 
125820Sigor@sysoev.ru         /* Preallocate the main error_log.  This allocation cannot fail. */
125920Sigor@sysoev.ru         file = nxt_list_zero_add(log_files);
126020Sigor@sysoev.ru 
126120Sigor@sysoev.ru         file->fd = NXT_FILE_INVALID;
126220Sigor@sysoev.ru         file->log_level = NXT_LOG_CRIT;
126320Sigor@sysoev.ru 
126420Sigor@sysoev.ru         return NXT_OK;
126520Sigor@sysoev.ru     }
126620Sigor@sysoev.ru 
126720Sigor@sysoev.ru     return NXT_ERROR;
126820Sigor@sysoev.ru }
126920Sigor@sysoev.ru 
127020Sigor@sysoev.ru 
127120Sigor@sysoev.ru nxt_file_t *
127220Sigor@sysoev.ru nxt_runtime_log_file_add(nxt_runtime_t *rt, nxt_str_t *name)
127320Sigor@sysoev.ru {
127420Sigor@sysoev.ru     nxt_int_t            ret;
127520Sigor@sysoev.ru     nxt_str_t            *prefix;
127620Sigor@sysoev.ru     nxt_file_t           *file;
127720Sigor@sysoev.ru     nxt_file_name_str_t  file_name;
127820Sigor@sysoev.ru 
127920Sigor@sysoev.ru     prefix = nxt_file_name_is_absolute(name->start) ? NULL : rt->prefix;
128020Sigor@sysoev.ru 
128120Sigor@sysoev.ru     ret = nxt_file_name_create(rt->mem_pool, &file_name, "%V%V%Z",
128220Sigor@sysoev.ru                                prefix, name);
128320Sigor@sysoev.ru 
128420Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
128520Sigor@sysoev.ru         return NULL;
128620Sigor@sysoev.ru     }
128720Sigor@sysoev.ru 
128820Sigor@sysoev.ru     nxt_list_each(file, rt->log_files) {
128920Sigor@sysoev.ru 
129020Sigor@sysoev.ru         /* STUB: hardecoded case sensitive/insensitive. */
129120Sigor@sysoev.ru 
129220Sigor@sysoev.ru         if (file->name != NULL
129320Sigor@sysoev.ru             && nxt_file_name_eq(file->name, file_name.start))
129420Sigor@sysoev.ru         {
129520Sigor@sysoev.ru             return file;
129620Sigor@sysoev.ru         }
129720Sigor@sysoev.ru 
129820Sigor@sysoev.ru     } nxt_list_loop;
129920Sigor@sysoev.ru 
130020Sigor@sysoev.ru     file = nxt_list_zero_add(rt->log_files);
130120Sigor@sysoev.ru 
130220Sigor@sysoev.ru     if (nxt_slow_path(file == NULL)) {
130320Sigor@sysoev.ru         return NULL;
130420Sigor@sysoev.ru     }
130520Sigor@sysoev.ru 
130620Sigor@sysoev.ru     file->fd = NXT_FILE_INVALID;
130720Sigor@sysoev.ru     file->log_level = NXT_LOG_CRIT;
130820Sigor@sysoev.ru     file->name = file_name.start;
130920Sigor@sysoev.ru 
131020Sigor@sysoev.ru     return file;
131120Sigor@sysoev.ru }
131220Sigor@sysoev.ru 
131320Sigor@sysoev.ru 
131420Sigor@sysoev.ru static nxt_int_t
131520Sigor@sysoev.ru nxt_runtime_log_files_create(nxt_task_t *task, nxt_runtime_t *rt)
131620Sigor@sysoev.ru {
131720Sigor@sysoev.ru     nxt_int_t   ret;
131820Sigor@sysoev.ru     nxt_file_t  *file;
131920Sigor@sysoev.ru 
132020Sigor@sysoev.ru     nxt_list_each(file, rt->log_files) {
132120Sigor@sysoev.ru 
132220Sigor@sysoev.ru         ret = nxt_file_open(task, file, O_WRONLY | O_APPEND, O_CREAT,
132320Sigor@sysoev.ru                             NXT_FILE_OWNER_ACCESS);
132420Sigor@sysoev.ru 
132520Sigor@sysoev.ru         if (ret != NXT_OK) {
132620Sigor@sysoev.ru             return NXT_ERROR;
132720Sigor@sysoev.ru         }
132820Sigor@sysoev.ru 
132920Sigor@sysoev.ru     } nxt_list_loop;
133020Sigor@sysoev.ru 
133120Sigor@sysoev.ru     file = nxt_list_first(rt->log_files);
133220Sigor@sysoev.ru 
133320Sigor@sysoev.ru     return nxt_file_stderr(file);
133420Sigor@sysoev.ru }
133520Sigor@sysoev.ru 
133620Sigor@sysoev.ru 
133720Sigor@sysoev.ru nxt_int_t
133820Sigor@sysoev.ru nxt_runtime_listen_sockets_create(nxt_task_t *task, nxt_runtime_t *rt)
133920Sigor@sysoev.ru {
134020Sigor@sysoev.ru     nxt_int_t            ret;
134120Sigor@sysoev.ru     nxt_uint_t           c, p, ncurr, nprev;
134220Sigor@sysoev.ru     nxt_listen_socket_t  *curr, *prev;
134320Sigor@sysoev.ru 
134420Sigor@sysoev.ru     curr = rt->listen_sockets->elts;
134520Sigor@sysoev.ru     ncurr = rt->listen_sockets->nelts;
134620Sigor@sysoev.ru 
134720Sigor@sysoev.ru     if (rt->inherited_sockets != NULL) {
134820Sigor@sysoev.ru         prev = rt->inherited_sockets->elts;
134920Sigor@sysoev.ru         nprev = rt->inherited_sockets->nelts;
135020Sigor@sysoev.ru 
135120Sigor@sysoev.ru     } else {
135220Sigor@sysoev.ru         prev = NULL;
135320Sigor@sysoev.ru         nprev = 0;
135420Sigor@sysoev.ru     }
135520Sigor@sysoev.ru 
135620Sigor@sysoev.ru     for (c = 0; c < ncurr; c++) {
135720Sigor@sysoev.ru 
135820Sigor@sysoev.ru         for (p = 0; p < nprev; p++) {
135920Sigor@sysoev.ru 
136020Sigor@sysoev.ru             if (nxt_sockaddr_cmp(curr[c].sockaddr, prev[p].sockaddr)) {
136120Sigor@sysoev.ru 
136220Sigor@sysoev.ru                 ret = nxt_listen_socket_update(task, &curr[c], &prev[p]);
136320Sigor@sysoev.ru                 if (ret != NXT_OK) {
136420Sigor@sysoev.ru                     return NXT_ERROR;
136520Sigor@sysoev.ru                 }
136620Sigor@sysoev.ru 
136720Sigor@sysoev.ru                 goto next;
136820Sigor@sysoev.ru             }
136920Sigor@sysoev.ru         }
137020Sigor@sysoev.ru 
137120Sigor@sysoev.ru         if (nxt_listen_socket_create(task, &curr[c], 0) != NXT_OK) {
137220Sigor@sysoev.ru             return NXT_ERROR;
137320Sigor@sysoev.ru         }
137420Sigor@sysoev.ru 
137520Sigor@sysoev.ru     next:
137620Sigor@sysoev.ru 
137720Sigor@sysoev.ru         continue;
137820Sigor@sysoev.ru     }
137920Sigor@sysoev.ru 
138020Sigor@sysoev.ru     return NXT_OK;
138120Sigor@sysoev.ru }
138220Sigor@sysoev.ru 
138320Sigor@sysoev.ru 
138420Sigor@sysoev.ru nxt_int_t
138520Sigor@sysoev.ru nxt_runtime_listen_sockets_enable(nxt_task_t *task, nxt_runtime_t *rt)
138620Sigor@sysoev.ru {
138720Sigor@sysoev.ru     nxt_uint_t           i, n;
138820Sigor@sysoev.ru     nxt_listen_socket_t  *ls;
138920Sigor@sysoev.ru 
139020Sigor@sysoev.ru     ls = rt->listen_sockets->elts;
139120Sigor@sysoev.ru     n = rt->listen_sockets->nelts;
139220Sigor@sysoev.ru 
139320Sigor@sysoev.ru     for (i = 0; i < n; i++) {
139420Sigor@sysoev.ru         if (ls[i].flags == NXT_NONBLOCK) {
139520Sigor@sysoev.ru             if (nxt_event_conn_listen(task, &ls[i]) != NXT_OK) {
139620Sigor@sysoev.ru                 return NXT_ERROR;
139720Sigor@sysoev.ru             }
139820Sigor@sysoev.ru         }
139920Sigor@sysoev.ru     }
140020Sigor@sysoev.ru 
140120Sigor@sysoev.ru     return NXT_OK;
140220Sigor@sysoev.ru }
140320Sigor@sysoev.ru 
140420Sigor@sysoev.ru 
140520Sigor@sysoev.ru nxt_str_t *
140620Sigor@sysoev.ru nxt_current_directory(nxt_mem_pool_t *mp)
140720Sigor@sysoev.ru {
140820Sigor@sysoev.ru     size_t     length;
140920Sigor@sysoev.ru     u_char     *p;
141020Sigor@sysoev.ru     nxt_str_t  *name;
141120Sigor@sysoev.ru     char       buf[NXT_MAX_PATH_LEN];
141220Sigor@sysoev.ru 
141320Sigor@sysoev.ru     length = nxt_dir_current(buf, NXT_MAX_PATH_LEN);
141420Sigor@sysoev.ru 
141520Sigor@sysoev.ru     if (nxt_fast_path(length != 0)) {
141620Sigor@sysoev.ru         name = nxt_str_alloc(mp, length + 1);
141720Sigor@sysoev.ru 
141820Sigor@sysoev.ru         if (nxt_fast_path(name != NULL)) {
141920Sigor@sysoev.ru             p = nxt_cpymem(name->start, buf, length);
142020Sigor@sysoev.ru             *p = '/';
142120Sigor@sysoev.ru 
142220Sigor@sysoev.ru             return name;
142320Sigor@sysoev.ru         }
142420Sigor@sysoev.ru     }
142520Sigor@sysoev.ru 
142620Sigor@sysoev.ru     return NULL;
142720Sigor@sysoev.ru }
142820Sigor@sysoev.ru 
142920Sigor@sysoev.ru 
143020Sigor@sysoev.ru static nxt_int_t
143120Sigor@sysoev.ru nxt_runtime_pid_file_create(nxt_task_t *task, nxt_file_name_t *pid_file)
143220Sigor@sysoev.ru {
143320Sigor@sysoev.ru     ssize_t     length;
143420Sigor@sysoev.ru     nxt_int_t   n;
143520Sigor@sysoev.ru     nxt_file_t  file;
143620Sigor@sysoev.ru     u_char      pid[NXT_INT64_T_LEN + NXT_LINEFEED_SIZE];
143720Sigor@sysoev.ru 
143820Sigor@sysoev.ru     nxt_memzero(&file, sizeof(nxt_file_t));
143920Sigor@sysoev.ru 
144020Sigor@sysoev.ru     file.name = pid_file;
144120Sigor@sysoev.ru 
144220Sigor@sysoev.ru     n = nxt_file_open(task, &file, O_WRONLY, O_CREAT | O_TRUNC,
144320Sigor@sysoev.ru                       NXT_FILE_DEFAULT_ACCESS);
144420Sigor@sysoev.ru 
144520Sigor@sysoev.ru     if (n != NXT_OK) {
144620Sigor@sysoev.ru         return NXT_ERROR;
144720Sigor@sysoev.ru     }
144820Sigor@sysoev.ru 
144920Sigor@sysoev.ru     length = nxt_sprintf(pid, pid + sizeof(pid), "%PI%n", nxt_pid) - pid;
145020Sigor@sysoev.ru 
145120Sigor@sysoev.ru     if (nxt_file_write(&file, pid, length, 0) != length) {
145220Sigor@sysoev.ru         return NXT_ERROR;
145320Sigor@sysoev.ru     }
145420Sigor@sysoev.ru 
145520Sigor@sysoev.ru     nxt_file_close(task, &file);
145620Sigor@sysoev.ru 
145720Sigor@sysoev.ru     return NXT_OK;
145820Sigor@sysoev.ru }
145920Sigor@sysoev.ru 
146020Sigor@sysoev.ru 
146120Sigor@sysoev.ru nxt_process_t *
146242Smax.romanov@nginx.com nxt_runtime_process_new(nxt_runtime_t *rt)
146320Sigor@sysoev.ru {
146420Sigor@sysoev.ru     nxt_process_t  *process;
146520Sigor@sysoev.ru 
146620Sigor@sysoev.ru     /* TODO: memory failures. */
146720Sigor@sysoev.ru 
146842Smax.romanov@nginx.com     process = nxt_mem_cache_zalloc0(rt->mem_pool, sizeof(nxt_process_t));
146942Smax.romanov@nginx.com     if (nxt_slow_path(process == NULL)) {
147042Smax.romanov@nginx.com         return NULL;
147142Smax.romanov@nginx.com     }
147242Smax.romanov@nginx.com 
147342Smax.romanov@nginx.com     nxt_queue_init(&process->ports);
147442Smax.romanov@nginx.com 
147542Smax.romanov@nginx.com     /* TODO each process should have it's own mem_pool for ports allocation */
147642Smax.romanov@nginx.com     process->mem_pool = rt->mem_pool;
147742Smax.romanov@nginx.com 
147842Smax.romanov@nginx.com     return process;
147942Smax.romanov@nginx.com }
148042Smax.romanov@nginx.com 
148142Smax.romanov@nginx.com 
148242Smax.romanov@nginx.com static nxt_int_t
148342Smax.romanov@nginx.com nxt_runtime_lvlhsh_pid_test(nxt_lvlhsh_query_t *lhq, void *data)
148442Smax.romanov@nginx.com {
148542Smax.romanov@nginx.com     nxt_process_t  *process;
148642Smax.romanov@nginx.com 
148742Smax.romanov@nginx.com     process = data;
148842Smax.romanov@nginx.com 
148942Smax.romanov@nginx.com     if (lhq->key.length == sizeof(nxt_pid_t) &&
149042Smax.romanov@nginx.com         *(nxt_pid_t *) lhq->key.start == process->pid) {
149142Smax.romanov@nginx.com         return NXT_OK;
149242Smax.romanov@nginx.com     }
149342Smax.romanov@nginx.com 
149442Smax.romanov@nginx.com     return NXT_DECLINED;
149542Smax.romanov@nginx.com }
149642Smax.romanov@nginx.com 
149742Smax.romanov@nginx.com static const nxt_lvlhsh_proto_t  lvlhsh_processes_proto  nxt_aligned(64) = {
149842Smax.romanov@nginx.com     NXT_LVLHSH_DEFAULT,
149942Smax.romanov@nginx.com     0,
150042Smax.romanov@nginx.com     nxt_runtime_lvlhsh_pid_test,
150142Smax.romanov@nginx.com     nxt_lvlhsh_alloc,
150242Smax.romanov@nginx.com     nxt_lvlhsh_free,
150342Smax.romanov@nginx.com };
150442Smax.romanov@nginx.com 
150542Smax.romanov@nginx.com 
150642Smax.romanov@nginx.com typedef struct {
150742Smax.romanov@nginx.com     nxt_pid_t      pid;
150842Smax.romanov@nginx.com     nxt_port_id_t  port_id;
150942Smax.romanov@nginx.com } nxt_pid_port_id_t;
151042Smax.romanov@nginx.com 
151142Smax.romanov@nginx.com static nxt_int_t
151242Smax.romanov@nginx.com nxt_runtime_lvlhsh_port_test(nxt_lvlhsh_query_t *lhq, void *data)
151342Smax.romanov@nginx.com {
151442Smax.romanov@nginx.com     nxt_port_t         *port;
151542Smax.romanov@nginx.com     nxt_pid_port_id_t  *pid_port_id;
151642Smax.romanov@nginx.com 
151742Smax.romanov@nginx.com     port = data;
151842Smax.romanov@nginx.com     pid_port_id = (nxt_pid_port_id_t *) lhq->key.start;
151942Smax.romanov@nginx.com 
152042Smax.romanov@nginx.com     if (lhq->key.length == sizeof(nxt_pid_port_id_t) &&
152142Smax.romanov@nginx.com         pid_port_id->pid == port->pid &&
152242Smax.romanov@nginx.com         pid_port_id->port_id == port->id) {
152342Smax.romanov@nginx.com         return NXT_OK;
152442Smax.romanov@nginx.com     }
152542Smax.romanov@nginx.com 
152642Smax.romanov@nginx.com     return NXT_DECLINED;
152742Smax.romanov@nginx.com }
152842Smax.romanov@nginx.com 
152942Smax.romanov@nginx.com static const nxt_lvlhsh_proto_t  lvlhsh_ports_proto  nxt_aligned(64) = {
153042Smax.romanov@nginx.com     NXT_LVLHSH_DEFAULT,
153142Smax.romanov@nginx.com     0,
153242Smax.romanov@nginx.com     nxt_runtime_lvlhsh_port_test,
153342Smax.romanov@nginx.com     nxt_lvlhsh_alloc,
153442Smax.romanov@nginx.com     nxt_lvlhsh_free,
153542Smax.romanov@nginx.com };
153642Smax.romanov@nginx.com 
153742Smax.romanov@nginx.com 
153842Smax.romanov@nginx.com nxt_process_t *
153942Smax.romanov@nginx.com nxt_runtime_process_find(nxt_runtime_t *rt, nxt_pid_t pid)
154042Smax.romanov@nginx.com {
154142Smax.romanov@nginx.com     nxt_lvlhsh_query_t  lhq;
154242Smax.romanov@nginx.com 
154342Smax.romanov@nginx.com     lhq.key_hash = nxt_murmur_hash2(&pid, sizeof(pid));
154442Smax.romanov@nginx.com     lhq.key.length = sizeof(pid);
154542Smax.romanov@nginx.com     lhq.key.start = (u_char *) &pid;
154642Smax.romanov@nginx.com     lhq.proto = &lvlhsh_processes_proto;
154742Smax.romanov@nginx.com 
154842Smax.romanov@nginx.com     /* TODO lock processes */
154942Smax.romanov@nginx.com 
155042Smax.romanov@nginx.com     if (nxt_lvlhsh_find(&rt->processes, &lhq) == NXT_OK) {
155142Smax.romanov@nginx.com         nxt_thread_log_debug("process %PI found", pid);
155242Smax.romanov@nginx.com         return lhq.value;
155342Smax.romanov@nginx.com     }
155442Smax.romanov@nginx.com 
155542Smax.romanov@nginx.com     nxt_thread_log_debug("process %PI not found", pid);
155642Smax.romanov@nginx.com 
155742Smax.romanov@nginx.com     return NULL;
155842Smax.romanov@nginx.com }
155942Smax.romanov@nginx.com 
156042Smax.romanov@nginx.com 
156142Smax.romanov@nginx.com nxt_process_t *
156242Smax.romanov@nginx.com nxt_runtime_process_get(nxt_runtime_t *rt, nxt_pid_t pid)
156342Smax.romanov@nginx.com {
156442Smax.romanov@nginx.com     nxt_process_t       *process;
156542Smax.romanov@nginx.com     nxt_lvlhsh_query_t  lhq;
156642Smax.romanov@nginx.com 
156742Smax.romanov@nginx.com     lhq.key_hash = nxt_murmur_hash2(&pid, sizeof(pid));
156842Smax.romanov@nginx.com     lhq.key.length = sizeof(pid);
156942Smax.romanov@nginx.com     lhq.key.start = (u_char *) &pid;
157042Smax.romanov@nginx.com     lhq.proto = &lvlhsh_processes_proto;
157142Smax.romanov@nginx.com 
157242Smax.romanov@nginx.com     /* TODO lock processes */
157342Smax.romanov@nginx.com 
157442Smax.romanov@nginx.com     if (nxt_lvlhsh_find(&rt->processes, &lhq) == NXT_OK) {
157542Smax.romanov@nginx.com         nxt_thread_log_debug("process %PI found", pid);
157642Smax.romanov@nginx.com         return lhq.value;
157742Smax.romanov@nginx.com     }
157842Smax.romanov@nginx.com 
157942Smax.romanov@nginx.com     process = nxt_runtime_process_new(rt);
158020Sigor@sysoev.ru     if (nxt_slow_path(process == NULL)) {
158120Sigor@sysoev.ru         return NULL;
158220Sigor@sysoev.ru     }
158320Sigor@sysoev.ru 
158442Smax.romanov@nginx.com     process->pid = pid;
158542Smax.romanov@nginx.com 
158642Smax.romanov@nginx.com     lhq.replace = 0;
158742Smax.romanov@nginx.com     lhq.value = process;
158842Smax.romanov@nginx.com     lhq.pool = rt->mem_pool;
158942Smax.romanov@nginx.com 
159042Smax.romanov@nginx.com     switch (nxt_lvlhsh_insert(&rt->processes, &lhq)) {
159142Smax.romanov@nginx.com 
159242Smax.romanov@nginx.com     case NXT_OK:
159342Smax.romanov@nginx.com         if (rt->nprocesses == 0) {
159442Smax.romanov@nginx.com             rt->mprocess = process;
159542Smax.romanov@nginx.com         }
159642Smax.romanov@nginx.com 
159742Smax.romanov@nginx.com         rt->nprocesses++;
159842Smax.romanov@nginx.com 
159942Smax.romanov@nginx.com         nxt_thread_log_debug("process %PI insert", pid);
160042Smax.romanov@nginx.com         break;
160142Smax.romanov@nginx.com 
160242Smax.romanov@nginx.com     default:
160342Smax.romanov@nginx.com         nxt_thread_log_debug("process %PI insert failed", pid);
160442Smax.romanov@nginx.com         break;
160520Sigor@sysoev.ru     }
160620Sigor@sysoev.ru 
160720Sigor@sysoev.ru     return process;
160820Sigor@sysoev.ru }
160942Smax.romanov@nginx.com 
161042Smax.romanov@nginx.com 
161142Smax.romanov@nginx.com void
161242Smax.romanov@nginx.com nxt_runtime_process_add(nxt_runtime_t *rt, nxt_process_t *process)
161342Smax.romanov@nginx.com {
161442Smax.romanov@nginx.com     nxt_port_t          *port;
161542Smax.romanov@nginx.com     nxt_lvlhsh_query_t  lhq;
161642Smax.romanov@nginx.com 
161742Smax.romanov@nginx.com     lhq.key_hash = nxt_murmur_hash2(&process->pid, sizeof(process->pid));
161842Smax.romanov@nginx.com     lhq.key.length = sizeof(process->pid);
161942Smax.romanov@nginx.com     lhq.key.start = (u_char *) &process->pid;
162042Smax.romanov@nginx.com     lhq.proto = &lvlhsh_processes_proto;
162142Smax.romanov@nginx.com     lhq.replace = 0;
162242Smax.romanov@nginx.com     lhq.value = process;
162342Smax.romanov@nginx.com     lhq.pool = rt->mem_pool;
162442Smax.romanov@nginx.com 
162542Smax.romanov@nginx.com     /* TODO lock processes */
162642Smax.romanov@nginx.com 
162742Smax.romanov@nginx.com     switch (nxt_lvlhsh_insert(&rt->processes, &lhq)) {
162842Smax.romanov@nginx.com 
162942Smax.romanov@nginx.com     case NXT_OK:
163042Smax.romanov@nginx.com         if (rt->nprocesses == 0) {
163142Smax.romanov@nginx.com             rt->mprocess = process;
163242Smax.romanov@nginx.com         }
163342Smax.romanov@nginx.com 
163442Smax.romanov@nginx.com         rt->nprocesses++;
163542Smax.romanov@nginx.com 
163642Smax.romanov@nginx.com         nxt_process_port_each(process, port) {
163742Smax.romanov@nginx.com 
163842Smax.romanov@nginx.com             nxt_runtime_port_add(rt, port);
163942Smax.romanov@nginx.com 
164042Smax.romanov@nginx.com         } nxt_process_port_loop;
164142Smax.romanov@nginx.com 
164242Smax.romanov@nginx.com         break;
164342Smax.romanov@nginx.com 
164442Smax.romanov@nginx.com     default:
164542Smax.romanov@nginx.com         break;
164642Smax.romanov@nginx.com     }
164742Smax.romanov@nginx.com }
164842Smax.romanov@nginx.com 
164942Smax.romanov@nginx.com 
165042Smax.romanov@nginx.com void
165142Smax.romanov@nginx.com nxt_runtime_process_remove(nxt_runtime_t *rt, nxt_process_t *process)
165242Smax.romanov@nginx.com {
165342Smax.romanov@nginx.com     nxt_port_t          *port;
165442Smax.romanov@nginx.com     nxt_lvlhsh_query_t  lhq;
165542Smax.romanov@nginx.com 
165642Smax.romanov@nginx.com     lhq.key_hash = nxt_murmur_hash2(&process->pid, sizeof(process->pid));
165742Smax.romanov@nginx.com     lhq.key.length = sizeof(process->pid);
165842Smax.romanov@nginx.com     lhq.key.start = (u_char *) &process->pid;
165942Smax.romanov@nginx.com     lhq.proto = &lvlhsh_processes_proto;
166042Smax.romanov@nginx.com     lhq.replace = 0;
166142Smax.romanov@nginx.com     lhq.value = process;
166242Smax.romanov@nginx.com     lhq.pool = rt->mem_pool;
166342Smax.romanov@nginx.com 
166442Smax.romanov@nginx.com     /* TODO lock processes */
166542Smax.romanov@nginx.com 
166642Smax.romanov@nginx.com     switch (nxt_lvlhsh_delete(&rt->processes, &lhq)) {
166742Smax.romanov@nginx.com 
166842Smax.romanov@nginx.com     case NXT_OK:
166942Smax.romanov@nginx.com         rt->nprocesses--;
167042Smax.romanov@nginx.com 
167142Smax.romanov@nginx.com         nxt_process_port_each(process, port) {
167242Smax.romanov@nginx.com 
167342Smax.romanov@nginx.com             nxt_runtime_port_remove(rt, port);
167442Smax.romanov@nginx.com 
167542Smax.romanov@nginx.com         } nxt_process_port_loop;
167642Smax.romanov@nginx.com 
167742Smax.romanov@nginx.com         break;
167842Smax.romanov@nginx.com 
167942Smax.romanov@nginx.com     default:
168042Smax.romanov@nginx.com         break;
168142Smax.romanov@nginx.com     }
168242Smax.romanov@nginx.com }
168342Smax.romanov@nginx.com 
168442Smax.romanov@nginx.com 
168542Smax.romanov@nginx.com nxt_process_t *
168642Smax.romanov@nginx.com nxt_runtime_process_first(nxt_runtime_t *rt, nxt_lvlhsh_each_t *lhe)
168742Smax.romanov@nginx.com {
168842Smax.romanov@nginx.com     nxt_memzero(lhe, sizeof(nxt_lvlhsh_each_t));
168942Smax.romanov@nginx.com 
169042Smax.romanov@nginx.com     lhe->proto = &lvlhsh_processes_proto;
169142Smax.romanov@nginx.com 
169242Smax.romanov@nginx.com     return nxt_runtime_process_next(rt, lhe);
169342Smax.romanov@nginx.com }
169442Smax.romanov@nginx.com 
169542Smax.romanov@nginx.com 
169642Smax.romanov@nginx.com void
169742Smax.romanov@nginx.com nxt_runtime_port_add(nxt_runtime_t *rt, nxt_port_t *port)
169842Smax.romanov@nginx.com {
169942Smax.romanov@nginx.com     nxt_pid_port_id_t   pid_port;
170042Smax.romanov@nginx.com     nxt_lvlhsh_query_t  lhq;
170142Smax.romanov@nginx.com 
170242Smax.romanov@nginx.com     pid_port.pid = port->pid;
170342Smax.romanov@nginx.com     pid_port.port_id = port->id;
170442Smax.romanov@nginx.com 
170542Smax.romanov@nginx.com     lhq.key_hash = nxt_murmur_hash2(&pid_port, sizeof(pid_port));
170642Smax.romanov@nginx.com     lhq.key.length = sizeof(pid_port);
170742Smax.romanov@nginx.com     lhq.key.start = (u_char *) &pid_port;
170842Smax.romanov@nginx.com     lhq.proto = &lvlhsh_ports_proto;
170942Smax.romanov@nginx.com     lhq.replace = 0;
171042Smax.romanov@nginx.com     lhq.value = port;
171142Smax.romanov@nginx.com     lhq.pool = rt->mem_pool;
171242Smax.romanov@nginx.com 
171342Smax.romanov@nginx.com     /* TODO lock ports */
171442Smax.romanov@nginx.com 
171542Smax.romanov@nginx.com     switch (nxt_lvlhsh_insert(&rt->ports, &lhq)) {
171642Smax.romanov@nginx.com 
171742Smax.romanov@nginx.com     case NXT_OK:
171842Smax.romanov@nginx.com         break;
171942Smax.romanov@nginx.com 
172042Smax.romanov@nginx.com     default:
172142Smax.romanov@nginx.com         break;
172242Smax.romanov@nginx.com     }
172342Smax.romanov@nginx.com }
172442Smax.romanov@nginx.com 
172542Smax.romanov@nginx.com 
172642Smax.romanov@nginx.com void
172742Smax.romanov@nginx.com nxt_runtime_port_remove(nxt_runtime_t *rt, nxt_port_t *port)
172842Smax.romanov@nginx.com {
172942Smax.romanov@nginx.com     nxt_pid_port_id_t   pid_port;
173042Smax.romanov@nginx.com     nxt_lvlhsh_query_t  lhq;
173142Smax.romanov@nginx.com 
173242Smax.romanov@nginx.com     pid_port.pid = port->pid;
173342Smax.romanov@nginx.com     pid_port.port_id = port->id;
173442Smax.romanov@nginx.com 
173542Smax.romanov@nginx.com     lhq.key_hash = nxt_murmur_hash2(&pid_port, sizeof(pid_port));
173642Smax.romanov@nginx.com     lhq.key.length = sizeof(pid_port);
173742Smax.romanov@nginx.com     lhq.key.start = (u_char *) &pid_port;
173842Smax.romanov@nginx.com     lhq.proto = &lvlhsh_ports_proto;
173942Smax.romanov@nginx.com     lhq.replace = 0;
174042Smax.romanov@nginx.com     lhq.value = port;
174142Smax.romanov@nginx.com     lhq.pool = rt->mem_pool;
174242Smax.romanov@nginx.com 
174342Smax.romanov@nginx.com     /* TODO lock ports */
174442Smax.romanov@nginx.com 
174542Smax.romanov@nginx.com     switch (nxt_lvlhsh_delete(&rt->ports, &lhq)) {
174642Smax.romanov@nginx.com 
174742Smax.romanov@nginx.com     case NXT_OK:
174842Smax.romanov@nginx.com         break;
174942Smax.romanov@nginx.com 
175042Smax.romanov@nginx.com     default:
175142Smax.romanov@nginx.com         break;
175242Smax.romanov@nginx.com     }
175342Smax.romanov@nginx.com }
175442Smax.romanov@nginx.com 
175542Smax.romanov@nginx.com 
175642Smax.romanov@nginx.com nxt_port_t *
175742Smax.romanov@nginx.com nxt_runtime_port_find(nxt_runtime_t *rt, nxt_pid_t pid,
175842Smax.romanov@nginx.com     nxt_port_id_t port_id)
175942Smax.romanov@nginx.com {
176042Smax.romanov@nginx.com     nxt_pid_port_id_t   pid_port;
176142Smax.romanov@nginx.com     nxt_lvlhsh_query_t  lhq;
176242Smax.romanov@nginx.com 
176342Smax.romanov@nginx.com     pid_port.pid = pid;
176442Smax.romanov@nginx.com     pid_port.port_id = port_id;
176542Smax.romanov@nginx.com 
176642Smax.romanov@nginx.com     lhq.key_hash = nxt_murmur_hash2(&pid_port, sizeof(pid_port));
176742Smax.romanov@nginx.com     lhq.key.length = sizeof(pid_port);
176842Smax.romanov@nginx.com     lhq.key.start = (u_char *) &pid_port;
176942Smax.romanov@nginx.com     lhq.proto = &lvlhsh_ports_proto;
177042Smax.romanov@nginx.com 
177142Smax.romanov@nginx.com     /* TODO lock ports */
177242Smax.romanov@nginx.com 
177342Smax.romanov@nginx.com     if (nxt_lvlhsh_find(&rt->ports, &lhq) == NXT_OK) {
177442Smax.romanov@nginx.com         nxt_thread_log_debug("process port (%PI, %d) found", pid, port_id);
177542Smax.romanov@nginx.com         return lhq.value;
177642Smax.romanov@nginx.com     }
177742Smax.romanov@nginx.com 
177842Smax.romanov@nginx.com     nxt_thread_log_debug("process port (%PI, %d) not found", pid, port_id);
177942Smax.romanov@nginx.com 
178042Smax.romanov@nginx.com     return NULL;
178142Smax.romanov@nginx.com }
1782