xref: /unit/src/nxt_runtime.c (revision 354)
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>
11240Sigor@sysoev.ru #include <nxt_main_process.h>
12141Smax.romanov@nginx.com #include <nxt_router.h>
1320Sigor@sysoev.ru 
1420Sigor@sysoev.ru 
1520Sigor@sysoev.ru static nxt_int_t nxt_runtime_inherited_listen_sockets(nxt_task_t *task,
1620Sigor@sysoev.ru     nxt_runtime_t *rt);
1720Sigor@sysoev.ru static nxt_int_t nxt_runtime_systemd_listen_sockets(nxt_task_t *task,
1820Sigor@sysoev.ru     nxt_runtime_t *rt);
1920Sigor@sysoev.ru static nxt_int_t nxt_runtime_event_engines(nxt_task_t *task, nxt_runtime_t *rt);
2020Sigor@sysoev.ru static nxt_int_t nxt_runtime_thread_pools(nxt_thread_t *thr, nxt_runtime_t *rt);
2120Sigor@sysoev.ru static void nxt_runtime_start(nxt_task_t *task, void *obj, void *data);
2220Sigor@sysoev.ru static void nxt_runtime_initial_start(nxt_task_t *task);
2320Sigor@sysoev.ru static void nxt_single_process_start(nxt_thread_t *thr, nxt_task_t *task,
2420Sigor@sysoev.ru     nxt_runtime_t *rt);
2520Sigor@sysoev.ru static void nxt_runtime_close_idle_connections(nxt_event_engine_t *engine);
2620Sigor@sysoev.ru static void nxt_runtime_exit(nxt_task_t *task, void *obj, void *data);
2720Sigor@sysoev.ru static nxt_int_t nxt_runtime_event_engine_change(nxt_task_t *task,
2820Sigor@sysoev.ru     nxt_runtime_t *rt);
2920Sigor@sysoev.ru static nxt_int_t nxt_runtime_conf_init(nxt_task_t *task, nxt_runtime_t *rt);
3020Sigor@sysoev.ru static nxt_int_t nxt_runtime_conf_read_cmd(nxt_task_t *task, nxt_runtime_t *rt);
3120Sigor@sysoev.ru static nxt_sockaddr_t *nxt_runtime_sockaddr_parse(nxt_task_t *task,
3265Sigor@sysoev.ru     nxt_mp_t *mp, nxt_str_t *addr);
3320Sigor@sysoev.ru static nxt_sockaddr_t *nxt_runtime_sockaddr_unix_parse(nxt_task_t *task,
3465Sigor@sysoev.ru     nxt_mp_t *mp, nxt_str_t *addr);
3520Sigor@sysoev.ru static nxt_sockaddr_t *nxt_runtime_sockaddr_inet6_parse(nxt_task_t *task,
3665Sigor@sysoev.ru     nxt_mp_t *mp, nxt_str_t *addr);
3720Sigor@sysoev.ru static nxt_sockaddr_t *nxt_runtime_sockaddr_inet_parse(nxt_task_t *task,
3865Sigor@sysoev.ru     nxt_mp_t *mp, nxt_str_t *addr);
3920Sigor@sysoev.ru static nxt_int_t nxt_runtime_hostname(nxt_task_t *task, nxt_runtime_t *rt);
4020Sigor@sysoev.ru static nxt_int_t nxt_runtime_log_files_init(nxt_runtime_t *rt);
4120Sigor@sysoev.ru static nxt_int_t nxt_runtime_log_files_create(nxt_task_t *task,
4220Sigor@sysoev.ru     nxt_runtime_t *rt);
4320Sigor@sysoev.ru static nxt_int_t nxt_runtime_pid_file_create(nxt_task_t *task,
4420Sigor@sysoev.ru     nxt_file_name_t *pid_file);
4520Sigor@sysoev.ru static void nxt_runtime_thread_pool_destroy(nxt_task_t *task, nxt_runtime_t *rt,
4620Sigor@sysoev.ru     nxt_runtime_cont_t cont);
47223Sigor@sysoev.ru static void nxt_runtime_thread_pool_init(void);
48223Sigor@sysoev.ru static void nxt_runtime_thread_pool_exit(nxt_task_t *task, void *obj,
49223Sigor@sysoev.ru     void *data);
50196Smax.romanov@nginx.com static void nxt_runtime_process_destroy(nxt_runtime_t *rt,
51196Smax.romanov@nginx.com     nxt_process_t *process);
52196Smax.romanov@nginx.com static nxt_process_t *nxt_runtime_process_remove_pid(nxt_runtime_t *rt,
53196Smax.romanov@nginx.com     nxt_pid_t pid);
54196Smax.romanov@nginx.com 
5520Sigor@sysoev.ru 
5620Sigor@sysoev.ru nxt_int_t
5720Sigor@sysoev.ru nxt_runtime_create(nxt_task_t *task)
5820Sigor@sysoev.ru {
59216Sigor@sysoev.ru     nxt_mp_t               *mp;
60216Sigor@sysoev.ru     nxt_int_t              ret;
61216Sigor@sysoev.ru     nxt_array_t            *listen_sockets;
62216Sigor@sysoev.ru     nxt_runtime_t          *rt;
63216Sigor@sysoev.ru     nxt_app_lang_module_t  *lang;
6420Sigor@sysoev.ru 
6565Sigor@sysoev.ru     mp = nxt_mp_create(1024, 128, 256, 32);
6620Sigor@sysoev.ru 
6720Sigor@sysoev.ru     if (nxt_slow_path(mp == NULL)) {
6820Sigor@sysoev.ru         return NXT_ERROR;
6920Sigor@sysoev.ru     }
7020Sigor@sysoev.ru 
7165Sigor@sysoev.ru     rt = nxt_mp_zget(mp, sizeof(nxt_runtime_t));
7265Sigor@sysoev.ru     if (nxt_slow_path(rt == NULL)) {
7365Sigor@sysoev.ru         return NXT_ERROR;
7465Sigor@sysoev.ru     }
7520Sigor@sysoev.ru 
7620Sigor@sysoev.ru     task->thread->runtime = rt;
7720Sigor@sysoev.ru     rt->mem_pool = mp;
7820Sigor@sysoev.ru 
79196Smax.romanov@nginx.com     nxt_thread_mutex_create(&rt->processes_mutex);
80196Smax.romanov@nginx.com 
8120Sigor@sysoev.ru     rt->services = nxt_services_init(mp);
8220Sigor@sysoev.ru     if (nxt_slow_path(rt->services == NULL)) {
8320Sigor@sysoev.ru         goto fail;
8420Sigor@sysoev.ru     }
8520Sigor@sysoev.ru 
86216Sigor@sysoev.ru     rt->languages = nxt_array_create(mp, 1, sizeof(nxt_app_lang_module_t));
87216Sigor@sysoev.ru     if (nxt_slow_path(rt->languages == NULL)) {
88216Sigor@sysoev.ru         goto fail;
89216Sigor@sysoev.ru     }
90216Sigor@sysoev.ru 
91216Sigor@sysoev.ru     /* Should not fail. */
92216Sigor@sysoev.ru     lang = nxt_array_add(rt->languages);
93216Sigor@sysoev.ru     lang->type = (nxt_str_t) nxt_string("go");
94*354Svbart@nginx.com     lang->version = (u_char *) "";
95216Sigor@sysoev.ru     lang->file = NULL;
96216Sigor@sysoev.ru     lang->module = &nxt_go_module;
97216Sigor@sysoev.ru 
9820Sigor@sysoev.ru     listen_sockets = nxt_array_create(mp, 1, sizeof(nxt_listen_socket_t));
9920Sigor@sysoev.ru     if (nxt_slow_path(listen_sockets == NULL)) {
10020Sigor@sysoev.ru         goto fail;
10120Sigor@sysoev.ru     }
10220Sigor@sysoev.ru 
10320Sigor@sysoev.ru     rt->listen_sockets = listen_sockets;
10420Sigor@sysoev.ru 
10520Sigor@sysoev.ru     ret = nxt_runtime_inherited_listen_sockets(task, rt);
10620Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
10720Sigor@sysoev.ru         goto fail;
10820Sigor@sysoev.ru     }
10920Sigor@sysoev.ru 
11020Sigor@sysoev.ru     if (nxt_runtime_hostname(task, rt) != NXT_OK) {
11120Sigor@sysoev.ru         goto fail;
11220Sigor@sysoev.ru     }
11320Sigor@sysoev.ru 
11420Sigor@sysoev.ru     if (nxt_slow_path(nxt_runtime_log_files_init(rt) != NXT_OK)) {
11520Sigor@sysoev.ru         goto fail;
11620Sigor@sysoev.ru     }
11720Sigor@sysoev.ru 
11820Sigor@sysoev.ru     if (nxt_runtime_event_engines(task, rt) != NXT_OK) {
11920Sigor@sysoev.ru         goto fail;
12020Sigor@sysoev.ru     }
12120Sigor@sysoev.ru 
12220Sigor@sysoev.ru     if (nxt_slow_path(nxt_runtime_thread_pools(task->thread, rt) != NXT_OK)) {
12320Sigor@sysoev.ru         goto fail;
12420Sigor@sysoev.ru     }
12520Sigor@sysoev.ru 
12620Sigor@sysoev.ru     rt->start = nxt_runtime_initial_start;
12720Sigor@sysoev.ru 
128221Sigor@sysoev.ru     if (nxt_runtime_conf_init(task, rt) != NXT_OK) {
129221Sigor@sysoev.ru         goto fail;
130221Sigor@sysoev.ru     }
131221Sigor@sysoev.ru 
13220Sigor@sysoev.ru     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
13320Sigor@sysoev.ru                        nxt_runtime_start, task, rt, NULL);
13420Sigor@sysoev.ru 
13520Sigor@sysoev.ru     return NXT_OK;
13620Sigor@sysoev.ru 
13720Sigor@sysoev.ru fail:
13820Sigor@sysoev.ru 
13965Sigor@sysoev.ru     nxt_mp_destroy(mp);
14020Sigor@sysoev.ru 
14120Sigor@sysoev.ru     return NXT_ERROR;
14220Sigor@sysoev.ru }
14320Sigor@sysoev.ru 
14420Sigor@sysoev.ru 
14520Sigor@sysoev.ru static nxt_int_t
14620Sigor@sysoev.ru nxt_runtime_inherited_listen_sockets(nxt_task_t *task, nxt_runtime_t *rt)
14720Sigor@sysoev.ru {
14820Sigor@sysoev.ru     u_char               *v, *p;
14920Sigor@sysoev.ru     nxt_int_t            type;
15020Sigor@sysoev.ru     nxt_array_t          *inherited_sockets;
15120Sigor@sysoev.ru     nxt_socket_t         s;
15220Sigor@sysoev.ru     nxt_listen_socket_t  *ls;
15320Sigor@sysoev.ru 
15420Sigor@sysoev.ru     v = (u_char *) getenv("NGINX");
15520Sigor@sysoev.ru 
15620Sigor@sysoev.ru     if (v == NULL) {
15720Sigor@sysoev.ru         return nxt_runtime_systemd_listen_sockets(task, rt);
15820Sigor@sysoev.ru     }
15920Sigor@sysoev.ru 
16020Sigor@sysoev.ru     nxt_log(task, NXT_LOG_CRIT, "using inherited listen sockets: %s", v);
16120Sigor@sysoev.ru 
16220Sigor@sysoev.ru     inherited_sockets = nxt_array_create(rt->mem_pool,
16320Sigor@sysoev.ru                                          1, sizeof(nxt_listen_socket_t));
16420Sigor@sysoev.ru     if (inherited_sockets == NULL) {
16520Sigor@sysoev.ru         return NXT_ERROR;
16620Sigor@sysoev.ru     }
16720Sigor@sysoev.ru 
16820Sigor@sysoev.ru     rt->inherited_sockets = inherited_sockets;
16920Sigor@sysoev.ru 
17020Sigor@sysoev.ru     for (p = v; *p != '\0'; p++) {
17120Sigor@sysoev.ru 
17220Sigor@sysoev.ru         if (*p == ';') {
17320Sigor@sysoev.ru             s = nxt_int_parse(v, p - v);
17420Sigor@sysoev.ru 
17520Sigor@sysoev.ru             if (nxt_slow_path(s < 0)) {
17620Sigor@sysoev.ru                 nxt_log(task, NXT_LOG_CRIT, "invalid socket number "
17720Sigor@sysoev.ru                         "\"%s\" in NGINX environment variable, "
17820Sigor@sysoev.ru                         "ignoring the rest of the variable", v);
17920Sigor@sysoev.ru                 return NXT_ERROR;
18020Sigor@sysoev.ru             }
18120Sigor@sysoev.ru 
18220Sigor@sysoev.ru             v = p + 1;
18320Sigor@sysoev.ru 
18420Sigor@sysoev.ru             ls = nxt_array_zero_add(inherited_sockets);
18520Sigor@sysoev.ru             if (nxt_slow_path(ls == NULL)) {
18620Sigor@sysoev.ru                 return NXT_ERROR;
18720Sigor@sysoev.ru             }
18820Sigor@sysoev.ru 
18920Sigor@sysoev.ru             ls->socket = s;
19020Sigor@sysoev.ru 
19120Sigor@sysoev.ru             ls->sockaddr = nxt_getsockname(task, rt->mem_pool, s);
19220Sigor@sysoev.ru             if (nxt_slow_path(ls->sockaddr == NULL)) {
19320Sigor@sysoev.ru                 return NXT_ERROR;
19420Sigor@sysoev.ru             }
19520Sigor@sysoev.ru 
19620Sigor@sysoev.ru             type = nxt_socket_getsockopt(task, s, SOL_SOCKET, SO_TYPE);
19720Sigor@sysoev.ru             if (nxt_slow_path(type == -1)) {
19820Sigor@sysoev.ru                 return NXT_ERROR;
19920Sigor@sysoev.ru             }
20020Sigor@sysoev.ru 
20120Sigor@sysoev.ru             ls->sockaddr->type = (uint16_t) type;
20220Sigor@sysoev.ru         }
20320Sigor@sysoev.ru     }
20420Sigor@sysoev.ru 
20520Sigor@sysoev.ru     return NXT_OK;
20620Sigor@sysoev.ru }
20720Sigor@sysoev.ru 
20820Sigor@sysoev.ru 
20920Sigor@sysoev.ru static nxt_int_t
21020Sigor@sysoev.ru nxt_runtime_systemd_listen_sockets(nxt_task_t *task, nxt_runtime_t *rt)
21120Sigor@sysoev.ru {
21220Sigor@sysoev.ru     u_char               *nfd, *pid;
21320Sigor@sysoev.ru     nxt_int_t            n;
21420Sigor@sysoev.ru     nxt_array_t          *inherited_sockets;
21520Sigor@sysoev.ru     nxt_socket_t         s;
21620Sigor@sysoev.ru     nxt_listen_socket_t  *ls;
21720Sigor@sysoev.ru 
21820Sigor@sysoev.ru     /*
21920Sigor@sysoev.ru      * Number of listening sockets passed.  The socket
22020Sigor@sysoev.ru      * descriptors start from number 3 and are sequential.
22120Sigor@sysoev.ru      */
22220Sigor@sysoev.ru     nfd = (u_char *) getenv("LISTEN_FDS");
22320Sigor@sysoev.ru     if (nfd == NULL) {
22420Sigor@sysoev.ru         return NXT_OK;
22520Sigor@sysoev.ru     }
22620Sigor@sysoev.ru 
22720Sigor@sysoev.ru     /* The pid of the service process. */
22820Sigor@sysoev.ru     pid = (u_char *) getenv("LISTEN_PID");
22920Sigor@sysoev.ru     if (pid == NULL) {
23020Sigor@sysoev.ru         return NXT_OK;
23120Sigor@sysoev.ru     }
23220Sigor@sysoev.ru 
23320Sigor@sysoev.ru     n = nxt_int_parse(nfd, nxt_strlen(nfd));
23420Sigor@sysoev.ru     if (n < 0) {
23520Sigor@sysoev.ru         return NXT_OK;
23620Sigor@sysoev.ru     }
23720Sigor@sysoev.ru 
23820Sigor@sysoev.ru     if (nxt_pid != nxt_int_parse(pid, nxt_strlen(pid))) {
23920Sigor@sysoev.ru         return NXT_OK;
24020Sigor@sysoev.ru     }
24120Sigor@sysoev.ru 
24220Sigor@sysoev.ru     nxt_log(task, NXT_LOG_INFO, "using %s systemd listen sockets", n);
24320Sigor@sysoev.ru 
24420Sigor@sysoev.ru     inherited_sockets = nxt_array_create(rt->mem_pool,
24520Sigor@sysoev.ru                                          n, sizeof(nxt_listen_socket_t));
24620Sigor@sysoev.ru     if (inherited_sockets == NULL) {
24720Sigor@sysoev.ru         return NXT_ERROR;
24820Sigor@sysoev.ru     }
24920Sigor@sysoev.ru 
25020Sigor@sysoev.ru     rt->inherited_sockets = inherited_sockets;
25120Sigor@sysoev.ru 
25220Sigor@sysoev.ru     for (s = 3; s < n; s++) {
25320Sigor@sysoev.ru         ls = nxt_array_zero_add(inherited_sockets);
25420Sigor@sysoev.ru         if (nxt_slow_path(ls == NULL)) {
25520Sigor@sysoev.ru             return NXT_ERROR;
25620Sigor@sysoev.ru         }
25720Sigor@sysoev.ru 
25820Sigor@sysoev.ru         ls->socket = s;
25920Sigor@sysoev.ru 
26020Sigor@sysoev.ru         ls->sockaddr = nxt_getsockname(task, rt->mem_pool, s);
26120Sigor@sysoev.ru         if (nxt_slow_path(ls->sockaddr == NULL)) {
26220Sigor@sysoev.ru             return NXT_ERROR;
26320Sigor@sysoev.ru         }
26420Sigor@sysoev.ru 
26520Sigor@sysoev.ru         ls->sockaddr->type = SOCK_STREAM;
26620Sigor@sysoev.ru     }
26720Sigor@sysoev.ru 
26820Sigor@sysoev.ru     return NXT_OK;
26920Sigor@sysoev.ru }
27020Sigor@sysoev.ru 
27120Sigor@sysoev.ru 
27220Sigor@sysoev.ru static nxt_int_t
27320Sigor@sysoev.ru nxt_runtime_event_engines(nxt_task_t *task, nxt_runtime_t *rt)
27420Sigor@sysoev.ru {
27553Sigor@sysoev.ru     nxt_thread_t                 *thread;
27653Sigor@sysoev.ru     nxt_event_engine_t           *engine;
27720Sigor@sysoev.ru     const nxt_event_interface_t  *interface;
27820Sigor@sysoev.ru 
27920Sigor@sysoev.ru     interface = nxt_service_get(rt->services, "engine", NULL);
28020Sigor@sysoev.ru 
28120Sigor@sysoev.ru     if (nxt_slow_path(interface == NULL)) {
28220Sigor@sysoev.ru         /* TODO: log */
28320Sigor@sysoev.ru         return NXT_ERROR;
28420Sigor@sysoev.ru     }
28520Sigor@sysoev.ru 
28620Sigor@sysoev.ru     engine = nxt_event_engine_create(task, interface,
287240Sigor@sysoev.ru                                      nxt_main_process_signals, 0, 0);
28820Sigor@sysoev.ru 
28920Sigor@sysoev.ru     if (nxt_slow_path(engine == NULL)) {
29020Sigor@sysoev.ru         return NXT_ERROR;
29120Sigor@sysoev.ru     }
29220Sigor@sysoev.ru 
29353Sigor@sysoev.ru     thread = task->thread;
29453Sigor@sysoev.ru     thread->engine = engine;
295326Svbart@nginx.com #if 0
29653Sigor@sysoev.ru     thread->fiber = &engine->fibers->fiber;
297326Svbart@nginx.com #endif
29853Sigor@sysoev.ru 
29920Sigor@sysoev.ru     engine->id = rt->last_engine_id++;
300342Smax.romanov@nginx.com     engine->mem_pool = nxt_mp_create(1024, 128, 256, 32);
30153Sigor@sysoev.ru 
30253Sigor@sysoev.ru     nxt_queue_init(&rt->engines);
30353Sigor@sysoev.ru     nxt_queue_insert_tail(&rt->engines, &engine->link);
30420Sigor@sysoev.ru 
30520Sigor@sysoev.ru     return NXT_OK;
30620Sigor@sysoev.ru }
30720Sigor@sysoev.ru 
30820Sigor@sysoev.ru 
30920Sigor@sysoev.ru static nxt_int_t
31020Sigor@sysoev.ru nxt_runtime_thread_pools(nxt_thread_t *thr, nxt_runtime_t *rt)
31120Sigor@sysoev.ru {
31220Sigor@sysoev.ru     nxt_int_t    ret;
31320Sigor@sysoev.ru     nxt_array_t  *thread_pools;
31420Sigor@sysoev.ru 
31520Sigor@sysoev.ru     thread_pools = nxt_array_create(rt->mem_pool, 1,
31620Sigor@sysoev.ru                                     sizeof(nxt_thread_pool_t *));
31720Sigor@sysoev.ru 
31820Sigor@sysoev.ru     if (nxt_slow_path(thread_pools == NULL)) {
31920Sigor@sysoev.ru         return NXT_ERROR;
32020Sigor@sysoev.ru     }
32120Sigor@sysoev.ru 
32220Sigor@sysoev.ru     rt->thread_pools = thread_pools;
32320Sigor@sysoev.ru     ret = nxt_runtime_thread_pool_create(thr, rt, 2, 60000 * 1000000LL);
32420Sigor@sysoev.ru 
32520Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
32620Sigor@sysoev.ru         return NXT_ERROR;
32720Sigor@sysoev.ru     }
32820Sigor@sysoev.ru 
32920Sigor@sysoev.ru     return NXT_OK;
33020Sigor@sysoev.ru }
33120Sigor@sysoev.ru 
33220Sigor@sysoev.ru 
33320Sigor@sysoev.ru static void
33420Sigor@sysoev.ru nxt_runtime_start(nxt_task_t *task, void *obj, void *data)
33520Sigor@sysoev.ru {
33620Sigor@sysoev.ru     nxt_runtime_t  *rt;
33720Sigor@sysoev.ru 
33820Sigor@sysoev.ru     rt = obj;
33920Sigor@sysoev.ru 
34020Sigor@sysoev.ru     nxt_debug(task, "rt conf done");
34120Sigor@sysoev.ru 
34220Sigor@sysoev.ru     task->thread->log->ctx_handler = NULL;
34320Sigor@sysoev.ru     task->thread->log->ctx = NULL;
34420Sigor@sysoev.ru 
34520Sigor@sysoev.ru     if (nxt_runtime_log_files_create(task, rt) != NXT_OK) {
34620Sigor@sysoev.ru         goto fail;
34720Sigor@sysoev.ru     }
34820Sigor@sysoev.ru 
34920Sigor@sysoev.ru     if (nxt_runtime_event_engine_change(task, rt) != NXT_OK) {
35020Sigor@sysoev.ru         goto fail;
35120Sigor@sysoev.ru     }
35220Sigor@sysoev.ru 
35320Sigor@sysoev.ru     /*
35420Sigor@sysoev.ru      * Thread pools should be destroyed before starting worker
35520Sigor@sysoev.ru      * processes, because thread pool semaphores will stick in
35620Sigor@sysoev.ru      * locked state in new processes after fork().
35720Sigor@sysoev.ru      */
35820Sigor@sysoev.ru     nxt_runtime_thread_pool_destroy(task, rt, rt->start);
35920Sigor@sysoev.ru 
36020Sigor@sysoev.ru     return;
36120Sigor@sysoev.ru 
36220Sigor@sysoev.ru fail:
36320Sigor@sysoev.ru 
36420Sigor@sysoev.ru     nxt_runtime_quit(task);
36520Sigor@sysoev.ru }
36620Sigor@sysoev.ru 
36720Sigor@sysoev.ru 
36820Sigor@sysoev.ru static void
36920Sigor@sysoev.ru nxt_runtime_initial_start(nxt_task_t *task)
37020Sigor@sysoev.ru {
37120Sigor@sysoev.ru     nxt_int_t                    ret;
37220Sigor@sysoev.ru     nxt_thread_t                 *thr;
37320Sigor@sysoev.ru     nxt_runtime_t                *rt;
37420Sigor@sysoev.ru     const nxt_event_interface_t  *interface;
37520Sigor@sysoev.ru 
37620Sigor@sysoev.ru     thr = task->thread;
37720Sigor@sysoev.ru     rt = thr->runtime;
37820Sigor@sysoev.ru 
37920Sigor@sysoev.ru     if (rt->inherited_sockets == NULL && rt->daemon) {
38020Sigor@sysoev.ru 
38120Sigor@sysoev.ru         if (nxt_process_daemon(task) != NXT_OK) {
38220Sigor@sysoev.ru             goto fail;
38320Sigor@sysoev.ru         }
38420Sigor@sysoev.ru 
38520Sigor@sysoev.ru         /*
38620Sigor@sysoev.ru          * An event engine should be updated after fork()
38720Sigor@sysoev.ru          * even if an event facility was not changed because:
38820Sigor@sysoev.ru          * 1) inherited kqueue descriptor is invalid,
38920Sigor@sysoev.ru          * 2) the signal thread is not inherited.
39020Sigor@sysoev.ru          */
39120Sigor@sysoev.ru         interface = nxt_service_get(rt->services, "engine", rt->engine);
39220Sigor@sysoev.ru         if (interface == NULL) {
39320Sigor@sysoev.ru             goto fail;
39420Sigor@sysoev.ru         }
39520Sigor@sysoev.ru 
39620Sigor@sysoev.ru         ret = nxt_event_engine_change(task->thread->engine, interface,
39720Sigor@sysoev.ru                                       rt->batch);
39820Sigor@sysoev.ru         if (ret != NXT_OK) {
39920Sigor@sysoev.ru             goto fail;
40020Sigor@sysoev.ru         }
40120Sigor@sysoev.ru     }
40220Sigor@sysoev.ru 
40320Sigor@sysoev.ru     ret = nxt_runtime_pid_file_create(task, rt->pid_file);
40420Sigor@sysoev.ru     if (ret != NXT_OK) {
40520Sigor@sysoev.ru         goto fail;
40620Sigor@sysoev.ru     }
40720Sigor@sysoev.ru 
40820Sigor@sysoev.ru     if (nxt_runtime_event_engine_change(task, rt) != NXT_OK) {
40920Sigor@sysoev.ru         goto fail;
41020Sigor@sysoev.ru     }
41120Sigor@sysoev.ru 
41220Sigor@sysoev.ru     thr->engine->max_connections = rt->engine_connections;
41320Sigor@sysoev.ru 
414240Sigor@sysoev.ru     if (rt->main_process) {
415240Sigor@sysoev.ru         if (nxt_main_process_start(thr, task, rt) != NXT_ERROR) {
41620Sigor@sysoev.ru             return;
41720Sigor@sysoev.ru         }
41820Sigor@sysoev.ru 
41920Sigor@sysoev.ru     } else {
42020Sigor@sysoev.ru         nxt_single_process_start(thr, task, rt);
42120Sigor@sysoev.ru         return;
42220Sigor@sysoev.ru     }
42320Sigor@sysoev.ru 
42420Sigor@sysoev.ru fail:
42520Sigor@sysoev.ru 
42620Sigor@sysoev.ru     nxt_runtime_quit(task);
42720Sigor@sysoev.ru }
42820Sigor@sysoev.ru 
42920Sigor@sysoev.ru 
43020Sigor@sysoev.ru static void
43120Sigor@sysoev.ru nxt_single_process_start(nxt_thread_t *thr, nxt_task_t *task, nxt_runtime_t *rt)
43220Sigor@sysoev.ru {
43320Sigor@sysoev.ru     nxt_int_t  ret;
43420Sigor@sysoev.ru 
43520Sigor@sysoev.ru     ret = nxt_runtime_thread_pool_create(thr, rt, rt->auxiliary_threads,
43620Sigor@sysoev.ru                                        60000 * 1000000LL);
43720Sigor@sysoev.ru 
43820Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
43920Sigor@sysoev.ru         nxt_runtime_quit(task);
44020Sigor@sysoev.ru         return;
44120Sigor@sysoev.ru     }
44220Sigor@sysoev.ru 
443125Smax.romanov@nginx.com     rt->types |= (1U << NXT_PROCESS_SINGLE);
44420Sigor@sysoev.ru 
44520Sigor@sysoev.ru     nxt_runtime_listen_sockets_enable(task, rt);
44620Sigor@sysoev.ru 
44720Sigor@sysoev.ru     return;
44820Sigor@sysoev.ru }
44920Sigor@sysoev.ru 
45020Sigor@sysoev.ru 
45120Sigor@sysoev.ru void
45220Sigor@sysoev.ru nxt_runtime_quit(nxt_task_t *task)
45320Sigor@sysoev.ru {
45420Sigor@sysoev.ru     nxt_bool_t          done;
45520Sigor@sysoev.ru     nxt_runtime_t       *rt;
45620Sigor@sysoev.ru     nxt_event_engine_t  *engine;
45720Sigor@sysoev.ru 
45820Sigor@sysoev.ru     rt = task->thread->runtime;
45920Sigor@sysoev.ru     engine = task->thread->engine;
46020Sigor@sysoev.ru 
46120Sigor@sysoev.ru     nxt_debug(task, "exiting");
46220Sigor@sysoev.ru 
46320Sigor@sysoev.ru     done = 1;
46420Sigor@sysoev.ru 
46520Sigor@sysoev.ru     if (!engine->shutdown) {
46620Sigor@sysoev.ru         engine->shutdown = 1;
46720Sigor@sysoev.ru 
46820Sigor@sysoev.ru         if (!nxt_array_is_empty(rt->thread_pools)) {
46920Sigor@sysoev.ru             nxt_runtime_thread_pool_destroy(task, rt, nxt_runtime_quit);
47020Sigor@sysoev.ru             done = 0;
47120Sigor@sysoev.ru         }
47220Sigor@sysoev.ru 
473240Sigor@sysoev.ru         if (nxt_runtime_is_main(rt)) {
474240Sigor@sysoev.ru             nxt_main_stop_worker_processes(task, rt);
47520Sigor@sysoev.ru             done = 0;
47620Sigor@sysoev.ru         }
47720Sigor@sysoev.ru     }
47820Sigor@sysoev.ru 
47920Sigor@sysoev.ru     nxt_runtime_close_idle_connections(engine);
48020Sigor@sysoev.ru 
48120Sigor@sysoev.ru     if (done) {
48220Sigor@sysoev.ru         nxt_work_queue_add(&engine->fast_work_queue, nxt_runtime_exit,
48320Sigor@sysoev.ru                            task, rt, engine);
48420Sigor@sysoev.ru     }
48520Sigor@sysoev.ru }
48620Sigor@sysoev.ru 
48720Sigor@sysoev.ru 
48820Sigor@sysoev.ru static void
48920Sigor@sysoev.ru nxt_runtime_close_idle_connections(nxt_event_engine_t *engine)
49020Sigor@sysoev.ru {
49162Sigor@sysoev.ru     nxt_conn_t        *c;
49220Sigor@sysoev.ru     nxt_queue_t       *idle;
49320Sigor@sysoev.ru     nxt_queue_link_t  *link, *next;
49420Sigor@sysoev.ru 
49520Sigor@sysoev.ru     nxt_debug(&engine->task, "close idle connections");
49620Sigor@sysoev.ru 
49720Sigor@sysoev.ru     idle = &engine->idle_connections;
49820Sigor@sysoev.ru 
49920Sigor@sysoev.ru     for (link = nxt_queue_head(idle);
50020Sigor@sysoev.ru          link != nxt_queue_tail(idle);
50120Sigor@sysoev.ru          link = next)
50220Sigor@sysoev.ru     {
50320Sigor@sysoev.ru         next = nxt_queue_next(link);
50462Sigor@sysoev.ru         c = nxt_queue_link_data(link, nxt_conn_t, link);
50520Sigor@sysoev.ru 
50620Sigor@sysoev.ru         if (!c->socket.read_ready) {
50720Sigor@sysoev.ru             nxt_queue_remove(link);
50862Sigor@sysoev.ru             nxt_conn_close(engine, c);
50920Sigor@sysoev.ru         }
51020Sigor@sysoev.ru     }
51120Sigor@sysoev.ru }
51220Sigor@sysoev.ru 
51320Sigor@sysoev.ru 
51420Sigor@sysoev.ru static void
51520Sigor@sysoev.ru nxt_runtime_exit(nxt_task_t *task, void *obj, void *data)
51620Sigor@sysoev.ru {
517125Smax.romanov@nginx.com     nxt_runtime_t       *rt;
518125Smax.romanov@nginx.com     nxt_process_t       *process;
51920Sigor@sysoev.ru     nxt_event_engine_t  *engine;
52020Sigor@sysoev.ru 
52120Sigor@sysoev.ru     rt = obj;
52220Sigor@sysoev.ru     engine = data;
52320Sigor@sysoev.ru 
52420Sigor@sysoev.ru     nxt_debug(task, "thread pools: %d", rt->thread_pools->nelts);
52520Sigor@sysoev.ru 
52620Sigor@sysoev.ru     if (!nxt_array_is_empty(rt->thread_pools)) {
52720Sigor@sysoev.ru         return;
52820Sigor@sysoev.ru     }
52920Sigor@sysoev.ru 
530240Sigor@sysoev.ru     if (nxt_runtime_is_main(rt)) {
53120Sigor@sysoev.ru         if (rt->pid_file != NULL) {
53220Sigor@sysoev.ru             nxt_file_delete(rt->pid_file);
53320Sigor@sysoev.ru         }
534234Sigor@sysoev.ru 
535234Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
536234Sigor@sysoev.ru         {
537234Sigor@sysoev.ru             nxt_sockaddr_t   *sa;
538234Sigor@sysoev.ru             nxt_file_name_t  *name;
539234Sigor@sysoev.ru 
540234Sigor@sysoev.ru             sa = rt->controller_listen;
541234Sigor@sysoev.ru 
542234Sigor@sysoev.ru             if (sa->u.sockaddr.sa_family == AF_UNIX) {
543234Sigor@sysoev.ru                 name = (nxt_file_name_t *) sa->u.sockaddr_un.sun_path;
544234Sigor@sysoev.ru                 (void) nxt_file_delete(name);
545234Sigor@sysoev.ru             }
546234Sigor@sysoev.ru         }
547234Sigor@sysoev.ru #endif
54820Sigor@sysoev.ru     }
54920Sigor@sysoev.ru 
55020Sigor@sysoev.ru     if (!engine->event.signal_support) {
55120Sigor@sysoev.ru         nxt_event_engine_signals_stop(engine);
55220Sigor@sysoev.ru     }
55320Sigor@sysoev.ru 
554125Smax.romanov@nginx.com     nxt_runtime_process_each(rt, process) {
555125Smax.romanov@nginx.com 
556349Smax.romanov@nginx.com         nxt_process_close_ports(task, process);
557125Smax.romanov@nginx.com 
558125Smax.romanov@nginx.com     } nxt_runtime_process_loop;
559125Smax.romanov@nginx.com 
560196Smax.romanov@nginx.com     nxt_thread_mutex_destroy(&rt->processes_mutex);
561196Smax.romanov@nginx.com 
562125Smax.romanov@nginx.com     nxt_mp_destroy(rt->mem_pool);
563125Smax.romanov@nginx.com 
56420Sigor@sysoev.ru     nxt_debug(task, "exit");
56520Sigor@sysoev.ru 
56620Sigor@sysoev.ru     exit(0);
56720Sigor@sysoev.ru     nxt_unreachable();
56820Sigor@sysoev.ru }
56920Sigor@sysoev.ru 
57020Sigor@sysoev.ru 
57120Sigor@sysoev.ru static nxt_int_t
57220Sigor@sysoev.ru nxt_runtime_event_engine_change(nxt_task_t *task, nxt_runtime_t *rt)
57320Sigor@sysoev.ru {
57420Sigor@sysoev.ru     nxt_event_engine_t           *engine;
57520Sigor@sysoev.ru     const nxt_event_interface_t  *interface;
57620Sigor@sysoev.ru 
57720Sigor@sysoev.ru     engine = task->thread->engine;
57820Sigor@sysoev.ru 
57920Sigor@sysoev.ru     if (engine->batch == rt->batch
58020Sigor@sysoev.ru         && nxt_strcmp(engine->event.name, rt->engine) == 0)
58120Sigor@sysoev.ru     {
58220Sigor@sysoev.ru         return NXT_OK;
58320Sigor@sysoev.ru     }
58420Sigor@sysoev.ru 
58520Sigor@sysoev.ru     interface = nxt_service_get(rt->services, "engine", rt->engine);
58620Sigor@sysoev.ru 
58720Sigor@sysoev.ru     if (interface != NULL) {
58820Sigor@sysoev.ru         return nxt_event_engine_change(engine, interface, rt->batch);
58920Sigor@sysoev.ru     }
59020Sigor@sysoev.ru 
59120Sigor@sysoev.ru     return NXT_ERROR;
59220Sigor@sysoev.ru }
59320Sigor@sysoev.ru 
59420Sigor@sysoev.ru 
59520Sigor@sysoev.ru void
59620Sigor@sysoev.ru nxt_runtime_event_engine_free(nxt_runtime_t *rt)
59720Sigor@sysoev.ru {
59853Sigor@sysoev.ru     nxt_queue_link_t    *link;
59953Sigor@sysoev.ru     nxt_event_engine_t  *engine;
60020Sigor@sysoev.ru 
60153Sigor@sysoev.ru     link = nxt_queue_first(&rt->engines);
60253Sigor@sysoev.ru     nxt_queue_remove(link);
60320Sigor@sysoev.ru 
60453Sigor@sysoev.ru     engine = nxt_queue_link_data(link, nxt_event_engine_t, link);
60520Sigor@sysoev.ru     nxt_event_engine_free(engine);
60620Sigor@sysoev.ru }
60720Sigor@sysoev.ru 
60820Sigor@sysoev.ru 
60920Sigor@sysoev.ru nxt_int_t
61020Sigor@sysoev.ru nxt_runtime_thread_pool_create(nxt_thread_t *thr, nxt_runtime_t *rt,
61120Sigor@sysoev.ru     nxt_uint_t max_threads, nxt_nsec_t timeout)
61220Sigor@sysoev.ru {
61320Sigor@sysoev.ru     nxt_thread_pool_t   *thread_pool, **tp;
61420Sigor@sysoev.ru 
61520Sigor@sysoev.ru     tp = nxt_array_add(rt->thread_pools);
61620Sigor@sysoev.ru     if (tp == NULL) {
61720Sigor@sysoev.ru         return NXT_ERROR;
61820Sigor@sysoev.ru     }
61920Sigor@sysoev.ru 
62020Sigor@sysoev.ru     thread_pool = nxt_thread_pool_create(max_threads, timeout,
62120Sigor@sysoev.ru                                          nxt_runtime_thread_pool_init,
62220Sigor@sysoev.ru                                          thr->engine,
62320Sigor@sysoev.ru                                          nxt_runtime_thread_pool_exit);
62420Sigor@sysoev.ru 
62520Sigor@sysoev.ru     if (nxt_fast_path(thread_pool != NULL)) {
62620Sigor@sysoev.ru         *tp = thread_pool;
62720Sigor@sysoev.ru     }
62820Sigor@sysoev.ru 
62920Sigor@sysoev.ru     return NXT_OK;
63020Sigor@sysoev.ru }
63120Sigor@sysoev.ru 
63220Sigor@sysoev.ru 
63320Sigor@sysoev.ru static void
63420Sigor@sysoev.ru nxt_runtime_thread_pool_destroy(nxt_task_t *task, nxt_runtime_t *rt,
63520Sigor@sysoev.ru     nxt_runtime_cont_t cont)
63620Sigor@sysoev.ru {
63720Sigor@sysoev.ru     nxt_uint_t         n;
63820Sigor@sysoev.ru     nxt_thread_pool_t  **tp;
63920Sigor@sysoev.ru 
64020Sigor@sysoev.ru     rt->continuation = cont;
64120Sigor@sysoev.ru 
64220Sigor@sysoev.ru     n = rt->thread_pools->nelts;
64320Sigor@sysoev.ru 
64420Sigor@sysoev.ru     if (n == 0) {
64520Sigor@sysoev.ru         cont(task);
64620Sigor@sysoev.ru         return;
64720Sigor@sysoev.ru     }
64820Sigor@sysoev.ru 
64920Sigor@sysoev.ru     tp = rt->thread_pools->elts;
65020Sigor@sysoev.ru 
65120Sigor@sysoev.ru     do {
65220Sigor@sysoev.ru         nxt_thread_pool_destroy(*tp);
65320Sigor@sysoev.ru 
65420Sigor@sysoev.ru         tp++;
65520Sigor@sysoev.ru         n--;
65620Sigor@sysoev.ru     } while (n != 0);
65720Sigor@sysoev.ru }
65820Sigor@sysoev.ru 
65920Sigor@sysoev.ru 
66020Sigor@sysoev.ru static void
66120Sigor@sysoev.ru nxt_runtime_thread_pool_init(void)
66220Sigor@sysoev.ru {
66320Sigor@sysoev.ru #if (NXT_REGEX)
66420Sigor@sysoev.ru     nxt_regex_init(0);
66520Sigor@sysoev.ru #endif
66620Sigor@sysoev.ru }
66720Sigor@sysoev.ru 
66820Sigor@sysoev.ru 
66920Sigor@sysoev.ru static void
67020Sigor@sysoev.ru nxt_runtime_thread_pool_exit(nxt_task_t *task, void *obj, void *data)
67120Sigor@sysoev.ru {
67220Sigor@sysoev.ru     nxt_uint_t           i, n;
67320Sigor@sysoev.ru     nxt_runtime_t        *rt;
67420Sigor@sysoev.ru     nxt_thread_pool_t    *tp, **thread_pools;
67520Sigor@sysoev.ru     nxt_thread_handle_t  handle;
67620Sigor@sysoev.ru 
67720Sigor@sysoev.ru     tp = obj;
67820Sigor@sysoev.ru 
67920Sigor@sysoev.ru     if (data != NULL) {
68020Sigor@sysoev.ru         handle = (nxt_thread_handle_t) (uintptr_t) data;
68120Sigor@sysoev.ru         nxt_thread_wait(handle);
68220Sigor@sysoev.ru     }
68320Sigor@sysoev.ru 
68420Sigor@sysoev.ru     rt = task->thread->runtime;
68520Sigor@sysoev.ru 
68620Sigor@sysoev.ru     thread_pools = rt->thread_pools->elts;
68720Sigor@sysoev.ru     n = rt->thread_pools->nelts;
68820Sigor@sysoev.ru 
68920Sigor@sysoev.ru     nxt_debug(task, "thread pools: %ui", n);
69020Sigor@sysoev.ru 
69120Sigor@sysoev.ru     for (i = 0; i < n; i++) {
69220Sigor@sysoev.ru 
69320Sigor@sysoev.ru         if (tp == thread_pools[i]) {
69420Sigor@sysoev.ru             nxt_array_remove(rt->thread_pools, &thread_pools[i]);
69520Sigor@sysoev.ru 
69620Sigor@sysoev.ru             if (n == 1) {
69720Sigor@sysoev.ru                 /* The last thread pool. */
69820Sigor@sysoev.ru                 rt->continuation(task);
69920Sigor@sysoev.ru             }
70020Sigor@sysoev.ru 
70120Sigor@sysoev.ru             return;
70220Sigor@sysoev.ru         }
70320Sigor@sysoev.ru     }
70420Sigor@sysoev.ru }
70520Sigor@sysoev.ru 
70620Sigor@sysoev.ru 
70720Sigor@sysoev.ru static nxt_int_t
70820Sigor@sysoev.ru nxt_runtime_conf_init(nxt_task_t *task, nxt_runtime_t *rt)
70920Sigor@sysoev.ru {
71020Sigor@sysoev.ru     nxt_int_t                    ret;
711251Sigor@sysoev.ru     nxt_str_t                    control;
712251Sigor@sysoev.ru     nxt_uint_t                   n;
71320Sigor@sysoev.ru     nxt_file_t                   *file;
714251Sigor@sysoev.ru     const char                   *slash;
715234Sigor@sysoev.ru     nxt_sockaddr_t               *sa;
71620Sigor@sysoev.ru     nxt_file_name_str_t          file_name;
71720Sigor@sysoev.ru     const nxt_event_interface_t  *interface;
71820Sigor@sysoev.ru 
71920Sigor@sysoev.ru     rt->daemon = 1;
720240Sigor@sysoev.ru     rt->main_process = 1;
72120Sigor@sysoev.ru     rt->engine_connections = 256;
72220Sigor@sysoev.ru     rt->auxiliary_threads = 2;
723232Sigor@sysoev.ru     rt->user_cred.user = NXT_USER;
724232Sigor@sysoev.ru     rt->group = NXT_GROUP;
725231Sigor@sysoev.ru     rt->pid = NXT_PID;
726230Sigor@sysoev.ru     rt->log = NXT_LOG;
727233Sigor@sysoev.ru     rt->modules = NXT_MODULES;
728314Svbart@nginx.com     rt->state = NXT_STATE;
729234Sigor@sysoev.ru     rt->control = NXT_CONTROL_SOCK;
73020Sigor@sysoev.ru 
73120Sigor@sysoev.ru     if (nxt_runtime_conf_read_cmd(task, rt) != NXT_OK) {
73220Sigor@sysoev.ru         return NXT_ERROR;
73320Sigor@sysoev.ru     }
73420Sigor@sysoev.ru 
73520Sigor@sysoev.ru     if (nxt_user_cred_get(task, &rt->user_cred, rt->group) != NXT_OK) {
73620Sigor@sysoev.ru         return NXT_ERROR;
73720Sigor@sysoev.ru     }
73820Sigor@sysoev.ru 
73920Sigor@sysoev.ru     /* An engine's parameters. */
74020Sigor@sysoev.ru 
74120Sigor@sysoev.ru     interface = nxt_service_get(rt->services, "engine", rt->engine);
74220Sigor@sysoev.ru     if (interface == NULL) {
74320Sigor@sysoev.ru         return NXT_ERROR;
74420Sigor@sysoev.ru     }
74520Sigor@sysoev.ru 
74620Sigor@sysoev.ru     rt->engine = interface->name;
74720Sigor@sysoev.ru 
748252Smax.romanov@nginx.com     ret = nxt_file_name_create(rt->mem_pool, &file_name, "%s%Z", rt->pid);
74920Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
75020Sigor@sysoev.ru         return NXT_ERROR;
75120Sigor@sysoev.ru     }
75220Sigor@sysoev.ru 
75320Sigor@sysoev.ru     rt->pid_file = file_name.start;
75420Sigor@sysoev.ru 
755230Sigor@sysoev.ru     ret = nxt_file_name_create(rt->mem_pool, &file_name, "%s%Z", rt->log);
75620Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
75720Sigor@sysoev.ru         return NXT_ERROR;
75820Sigor@sysoev.ru     }
75920Sigor@sysoev.ru 
76020Sigor@sysoev.ru     file = nxt_list_first(rt->log_files);
76120Sigor@sysoev.ru     file->name = file_name.start;
76220Sigor@sysoev.ru 
763251Sigor@sysoev.ru     slash = "";
764251Sigor@sysoev.ru     n = nxt_strlen(rt->modules);
765251Sigor@sysoev.ru 
766251Sigor@sysoev.ru     if (n > 1 && rt->modules[n - 1] != '/') {
767251Sigor@sysoev.ru         slash = "/";
768251Sigor@sysoev.ru     }
769251Sigor@sysoev.ru 
770260Sigor@sysoev.ru     ret = nxt_file_name_create(rt->mem_pool, &file_name, "%s%s*.unit.so%Z",
771251Sigor@sysoev.ru                                rt->modules, slash);
772233Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
773233Sigor@sysoev.ru         return NXT_ERROR;
774233Sigor@sysoev.ru     }
775233Sigor@sysoev.ru 
776233Sigor@sysoev.ru     rt->modules = (char *) file_name.start;
777233Sigor@sysoev.ru 
778314Svbart@nginx.com     slash = "";
779314Svbart@nginx.com     n = nxt_strlen(rt->state);
780314Svbart@nginx.com 
781314Svbart@nginx.com     if (n > 1 && rt->state[n - 1] != '/') {
782314Svbart@nginx.com         slash = "/";
783314Svbart@nginx.com     }
784314Svbart@nginx.com 
785314Svbart@nginx.com     ret = nxt_file_name_create(rt->mem_pool, &file_name, "%s%sconf.json%Z",
786314Svbart@nginx.com                                rt->state, slash);
787314Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
788314Svbart@nginx.com         return NXT_ERROR;
789314Svbart@nginx.com     }
790314Svbart@nginx.com 
791314Svbart@nginx.com     rt->conf = (char *) file_name.start;
792314Svbart@nginx.com 
793314Svbart@nginx.com     ret = nxt_file_name_create(rt->mem_pool, &file_name, "%s.tmp%Z", rt->conf);
794314Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
795314Svbart@nginx.com         return NXT_ERROR;
796314Svbart@nginx.com     }
797314Svbart@nginx.com 
798314Svbart@nginx.com     rt->conf_tmp = (char *) file_name.start;
799314Svbart@nginx.com 
800234Sigor@sysoev.ru     control.length = nxt_strlen(rt->control);
801234Sigor@sysoev.ru     control.start = (u_char *) rt->control;
802234Sigor@sysoev.ru 
803234Sigor@sysoev.ru     sa = nxt_runtime_sockaddr_parse(task, rt->mem_pool, &control);
804234Sigor@sysoev.ru     if (nxt_slow_path(sa == NULL)) {
805234Sigor@sysoev.ru         return NXT_ERROR;
806234Sigor@sysoev.ru     }
807234Sigor@sysoev.ru 
808234Sigor@sysoev.ru     rt->controller_listen = sa;
809234Sigor@sysoev.ru 
810234Sigor@sysoev.ru     if (nxt_runtime_controller_socket(task, rt) != NXT_OK) {
811234Sigor@sysoev.ru         return NXT_ERROR;
812234Sigor@sysoev.ru     }
813234Sigor@sysoev.ru 
81420Sigor@sysoev.ru     return NXT_OK;
81520Sigor@sysoev.ru }
81620Sigor@sysoev.ru 
81720Sigor@sysoev.ru 
81820Sigor@sysoev.ru static nxt_int_t
81920Sigor@sysoev.ru nxt_runtime_conf_read_cmd(nxt_task_t *task, nxt_runtime_t *rt)
82020Sigor@sysoev.ru {
821234Sigor@sysoev.ru     char    *p, **argv;
822234Sigor@sysoev.ru     u_char  *end;
823234Sigor@sysoev.ru     u_char  buf[1024];
82420Sigor@sysoev.ru 
825226Svbart@nginx.com     static const char  version[] =
826259Sigor@sysoev.ru         "unit version: " NXT_VERSION "\n"
827221Sigor@sysoev.ru         "configured as ./configure" NXT_CONFIGURE_OPTIONS "\n";
828221Sigor@sysoev.ru 
829234Sigor@sysoev.ru     static const char  no_control[] =
830234Sigor@sysoev.ru                        "option \"--control\" requires socket address\n";
831232Sigor@sysoev.ru     static const char  no_user[] = "option \"--user\" requires username\n";
832232Sigor@sysoev.ru     static const char  no_group[] = "option \"--group\" requires group name\n";
833231Sigor@sysoev.ru     static const char  no_pid[] = "option \"--pid\" requires filename\n";
834230Sigor@sysoev.ru     static const char  no_log[] = "option \"--log\" requires filename\n";
835233Sigor@sysoev.ru     static const char  no_modules[] =
836233Sigor@sysoev.ru                        "option \"--modules\" requires directory\n";
837314Svbart@nginx.com     static const char  no_state[] = "option \"--state\" requires directory\n";
838230Sigor@sysoev.ru 
839235Sigor@sysoev.ru     static const char  help[] =
840235Sigor@sysoev.ru         "\n"
841259Sigor@sysoev.ru         "unit options:\n"
842235Sigor@sysoev.ru         "\n"
843259Sigor@sysoev.ru         "  --version            print unit version and configure options\n"
844235Sigor@sysoev.ru         "\n"
845259Sigor@sysoev.ru         "  --no-daemon          run unit in non-daemon mode\n"
846235Sigor@sysoev.ru         "\n"
847235Sigor@sysoev.ru         "  --control ADDRESS    set address of control API socket\n"
848235Sigor@sysoev.ru         "                       default: \"" NXT_CONTROL_SOCK "\"\n"
849235Sigor@sysoev.ru         "\n"
850239Sigor@sysoev.ru         "  --pid FILE           set pid filename\n"
851235Sigor@sysoev.ru         "                       default: \"" NXT_PID "\"\n"
852235Sigor@sysoev.ru         "\n"
853239Sigor@sysoev.ru         "  --log FILE           set log filename\n"
854235Sigor@sysoev.ru         "                       default: \"" NXT_LOG "\"\n"
855235Sigor@sysoev.ru         "\n"
856239Sigor@sysoev.ru         "  --modules DIRECTORY  set modules directory name\n"
857235Sigor@sysoev.ru         "                       default: \"" NXT_MODULES "\"\n"
858235Sigor@sysoev.ru         "\n"
859314Svbart@nginx.com         "  --state DIRECTORY    set state directory name\n"
860314Svbart@nginx.com         "                       default: \"" NXT_STATE "\"\n"
861314Svbart@nginx.com         "\n"
862235Sigor@sysoev.ru         "  --user USER          set non-privileged processes to run"
863235Sigor@sysoev.ru                                 " as specified user\n"
864235Sigor@sysoev.ru         "                       default: \"" NXT_USER "\"\n"
865235Sigor@sysoev.ru         "\n"
866235Sigor@sysoev.ru         "  --group GROUP        set non-privileged processes to run"
867235Sigor@sysoev.ru                                 " as specified group\n"
868235Sigor@sysoev.ru         "                       default: ";
869235Sigor@sysoev.ru 
870235Sigor@sysoev.ru     static const char  group[] = "\"" NXT_GROUP "\"\n\n";
871235Sigor@sysoev.ru     static const char  primary[] = "user's primary group\n\n";
872235Sigor@sysoev.ru 
873222Sigor@sysoev.ru     argv = &nxt_process_argv[1];
87420Sigor@sysoev.ru 
87520Sigor@sysoev.ru     while (*argv != NULL) {
87620Sigor@sysoev.ru         p = *argv++;
87720Sigor@sysoev.ru 
878234Sigor@sysoev.ru         if (nxt_strcmp(p, "--control") == 0) {
87920Sigor@sysoev.ru             if (*argv == NULL) {
880234Sigor@sysoev.ru                 write(STDERR_FILENO, no_control, sizeof(no_control) - 1);
88120Sigor@sysoev.ru                 return NXT_ERROR;
88220Sigor@sysoev.ru             }
88320Sigor@sysoev.ru 
88420Sigor@sysoev.ru             p = *argv++;
88520Sigor@sysoev.ru 
886234Sigor@sysoev.ru             rt->control = p;
88720Sigor@sysoev.ru 
88820Sigor@sysoev.ru             continue;
88920Sigor@sysoev.ru         }
89020Sigor@sysoev.ru 
89120Sigor@sysoev.ru         if (nxt_strcmp(p, "--upstream") == 0) {
89220Sigor@sysoev.ru             if (*argv == NULL) {
89320Sigor@sysoev.ru                 nxt_log(task, NXT_LOG_CRIT,
89420Sigor@sysoev.ru                               "no argument for option \"--upstream\"");
89520Sigor@sysoev.ru                 return NXT_ERROR;
89620Sigor@sysoev.ru             }
89720Sigor@sysoev.ru 
89820Sigor@sysoev.ru             p = *argv++;
89920Sigor@sysoev.ru 
90020Sigor@sysoev.ru             rt->upstream.length = nxt_strlen(p);
90120Sigor@sysoev.ru             rt->upstream.start = (u_char *) p;
90220Sigor@sysoev.ru 
90320Sigor@sysoev.ru             continue;
90420Sigor@sysoev.ru         }
90520Sigor@sysoev.ru 
90620Sigor@sysoev.ru         if (nxt_strcmp(p, "--user") == 0) {
90720Sigor@sysoev.ru             if (*argv == NULL) {
908232Sigor@sysoev.ru                 write(STDERR_FILENO, no_user, sizeof(no_user) - 1);
90920Sigor@sysoev.ru                 return NXT_ERROR;
91020Sigor@sysoev.ru             }
91120Sigor@sysoev.ru 
91220Sigor@sysoev.ru             p = *argv++;
91320Sigor@sysoev.ru 
91420Sigor@sysoev.ru             rt->user_cred.user = p;
91520Sigor@sysoev.ru 
91620Sigor@sysoev.ru             continue;
91720Sigor@sysoev.ru         }
91820Sigor@sysoev.ru 
91920Sigor@sysoev.ru         if (nxt_strcmp(p, "--group") == 0) {
92020Sigor@sysoev.ru             if (*argv == NULL) {
921232Sigor@sysoev.ru                 write(STDERR_FILENO, no_group, sizeof(no_group) - 1);
92220Sigor@sysoev.ru                 return NXT_ERROR;
92320Sigor@sysoev.ru             }
92420Sigor@sysoev.ru 
92520Sigor@sysoev.ru             p = *argv++;
92620Sigor@sysoev.ru 
92720Sigor@sysoev.ru             rt->group = p;
92820Sigor@sysoev.ru 
92920Sigor@sysoev.ru             continue;
93020Sigor@sysoev.ru         }
93120Sigor@sysoev.ru 
93220Sigor@sysoev.ru         if (nxt_strcmp(p, "--pid") == 0) {
93320Sigor@sysoev.ru             if (*argv == NULL) {
934231Sigor@sysoev.ru                 write(STDERR_FILENO, no_pid, sizeof(no_pid) - 1);
93520Sigor@sysoev.ru                 return NXT_ERROR;
93620Sigor@sysoev.ru             }
93720Sigor@sysoev.ru 
93820Sigor@sysoev.ru             p = *argv++;
93920Sigor@sysoev.ru 
94020Sigor@sysoev.ru             rt->pid = p;
94120Sigor@sysoev.ru 
94220Sigor@sysoev.ru             continue;
94320Sigor@sysoev.ru         }
94420Sigor@sysoev.ru 
94520Sigor@sysoev.ru         if (nxt_strcmp(p, "--log") == 0) {
94620Sigor@sysoev.ru             if (*argv == NULL) {
947230Sigor@sysoev.ru                 write(STDERR_FILENO, no_log, sizeof(no_log) - 1);
94820Sigor@sysoev.ru                 return NXT_ERROR;
94920Sigor@sysoev.ru             }
95020Sigor@sysoev.ru 
95120Sigor@sysoev.ru             p = *argv++;
95220Sigor@sysoev.ru 
953230Sigor@sysoev.ru             rt->log = p;
95420Sigor@sysoev.ru 
95520Sigor@sysoev.ru             continue;
95620Sigor@sysoev.ru         }
95720Sigor@sysoev.ru 
958233Sigor@sysoev.ru         if (nxt_strcmp(p, "--modules") == 0) {
959233Sigor@sysoev.ru             if (*argv == NULL) {
960233Sigor@sysoev.ru                 write(STDERR_FILENO, no_modules, sizeof(no_modules) - 1);
961233Sigor@sysoev.ru                 return NXT_ERROR;
962233Sigor@sysoev.ru             }
963233Sigor@sysoev.ru 
964233Sigor@sysoev.ru             p = *argv++;
965233Sigor@sysoev.ru 
966233Sigor@sysoev.ru             rt->modules = p;
967233Sigor@sysoev.ru 
968233Sigor@sysoev.ru             continue;
969233Sigor@sysoev.ru         }
970233Sigor@sysoev.ru 
971314Svbart@nginx.com         if (nxt_strcmp(p, "--state") == 0) {
972314Svbart@nginx.com             if (*argv == NULL) {
973314Svbart@nginx.com                 write(STDERR_FILENO, no_state, sizeof(no_state) - 1);
974314Svbart@nginx.com                 return NXT_ERROR;
975314Svbart@nginx.com             }
976314Svbart@nginx.com 
977314Svbart@nginx.com             p = *argv++;
978314Svbart@nginx.com 
979314Svbart@nginx.com             rt->state = p;
980314Svbart@nginx.com 
981314Svbart@nginx.com             continue;
982314Svbart@nginx.com         }
983314Svbart@nginx.com 
984219Sigor@sysoev.ru         if (nxt_strcmp(p, "--no-daemon") == 0) {
98520Sigor@sysoev.ru             rt->daemon = 0;
98620Sigor@sysoev.ru             continue;
98720Sigor@sysoev.ru         }
988221Sigor@sysoev.ru 
989221Sigor@sysoev.ru         if (nxt_strcmp(p, "--version") == 0) {
990221Sigor@sysoev.ru             write(STDERR_FILENO, version, sizeof(version) - 1);
991221Sigor@sysoev.ru             exit(0);
992221Sigor@sysoev.ru         }
993222Sigor@sysoev.ru 
994235Sigor@sysoev.ru         if (nxt_strcmp(p, "--help") == 0) {
995235Sigor@sysoev.ru             write(STDOUT_FILENO, help, sizeof(help) - 1);
996235Sigor@sysoev.ru 
997235Sigor@sysoev.ru             if (sizeof(NXT_GROUP) == 1) {
998235Sigor@sysoev.ru                 write(STDOUT_FILENO, primary, sizeof(primary) - 1);
999235Sigor@sysoev.ru 
1000235Sigor@sysoev.ru             } else {
1001235Sigor@sysoev.ru                 write(STDOUT_FILENO, group, sizeof(group) - 1);
1002235Sigor@sysoev.ru             }
1003235Sigor@sysoev.ru 
1004235Sigor@sysoev.ru             exit(0);
1005235Sigor@sysoev.ru         }
1006235Sigor@sysoev.ru 
1007222Sigor@sysoev.ru         end = nxt_sprintf(buf, buf + sizeof(buf), "unknown option \"%s\"\n", p);
1008222Sigor@sysoev.ru         write(STDERR_FILENO, buf, end - buf);
1009222Sigor@sysoev.ru 
1010222Sigor@sysoev.ru         return NXT_ERROR;
101120Sigor@sysoev.ru     }
101220Sigor@sysoev.ru 
101320Sigor@sysoev.ru     return NXT_OK;
101420Sigor@sysoev.ru }
101520Sigor@sysoev.ru 
101620Sigor@sysoev.ru 
101720Sigor@sysoev.ru static nxt_sockaddr_t *
101865Sigor@sysoev.ru nxt_runtime_sockaddr_parse(nxt_task_t *task, nxt_mp_t *mp, nxt_str_t *addr)
101920Sigor@sysoev.ru {
102020Sigor@sysoev.ru     u_char  *p;
102120Sigor@sysoev.ru     size_t  length;
102220Sigor@sysoev.ru 
102320Sigor@sysoev.ru     length = addr->length;
102420Sigor@sysoev.ru     p = addr->start;
102520Sigor@sysoev.ru 
102671Svbart@nginx.com     if (length >= 5 && nxt_memcmp(p, "unix:", 5) == 0) {
102720Sigor@sysoev.ru         return nxt_runtime_sockaddr_unix_parse(task, mp, addr);
102820Sigor@sysoev.ru     }
102920Sigor@sysoev.ru 
103020Sigor@sysoev.ru     if (length != 0 && *p == '[') {
103120Sigor@sysoev.ru         return nxt_runtime_sockaddr_inet6_parse(task, mp, addr);
103220Sigor@sysoev.ru     }
103320Sigor@sysoev.ru 
103420Sigor@sysoev.ru     return nxt_runtime_sockaddr_inet_parse(task, mp, addr);
103520Sigor@sysoev.ru }
103620Sigor@sysoev.ru 
103720Sigor@sysoev.ru 
103820Sigor@sysoev.ru static nxt_sockaddr_t *
103965Sigor@sysoev.ru nxt_runtime_sockaddr_unix_parse(nxt_task_t *task, nxt_mp_t *mp, nxt_str_t *addr)
104020Sigor@sysoev.ru {
104120Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
104220Sigor@sysoev.ru     u_char          *p;
104320Sigor@sysoev.ru     size_t          length, socklen;
104420Sigor@sysoev.ru     nxt_sockaddr_t  *sa;
104520Sigor@sysoev.ru 
104620Sigor@sysoev.ru     /*
104720Sigor@sysoev.ru      * Actual sockaddr_un length can be lesser or even larger than defined
1048211Sru@nginx.com      * struct sockaddr_un length (see comment in nxt_socket.h).  So
104920Sigor@sysoev.ru      * limit maximum Unix domain socket address length by defined sun_path[]
105020Sigor@sysoev.ru      * length because some OSes accept addresses twice larger than defined
105120Sigor@sysoev.ru      * struct sockaddr_un.  Also reserve space for a trailing zero to avoid
105220Sigor@sysoev.ru      * ambiguity, since many OSes accept Unix domain socket addresses
105320Sigor@sysoev.ru      * without a trailing zero.
105420Sigor@sysoev.ru      */
105520Sigor@sysoev.ru     const size_t max_len = sizeof(struct sockaddr_un)
105620Sigor@sysoev.ru                            - offsetof(struct sockaddr_un, sun_path) - 1;
105720Sigor@sysoev.ru 
105820Sigor@sysoev.ru     /* cutting "unix:" */
105920Sigor@sysoev.ru     length = addr->length - 5;
106020Sigor@sysoev.ru     p = addr->start + 5;
106120Sigor@sysoev.ru 
106220Sigor@sysoev.ru     if (length == 0) {
106320Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT,
106420Sigor@sysoev.ru                 "unix domain socket \"%V\" name is invalid", addr);
106520Sigor@sysoev.ru         return NULL;
106620Sigor@sysoev.ru     }
106720Sigor@sysoev.ru 
106820Sigor@sysoev.ru     if (length > max_len) {
106920Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT,
107020Sigor@sysoev.ru                 "unix domain socket \"%V\" name is too long", addr);
107120Sigor@sysoev.ru         return NULL;
107220Sigor@sysoev.ru     }
107320Sigor@sysoev.ru 
107420Sigor@sysoev.ru     socklen = offsetof(struct sockaddr_un, sun_path) + length + 1;
107520Sigor@sysoev.ru 
107620Sigor@sysoev.ru #if (NXT_LINUX)
107720Sigor@sysoev.ru 
107820Sigor@sysoev.ru     /*
107920Sigor@sysoev.ru      * Linux unix(7):
108020Sigor@sysoev.ru      *
108120Sigor@sysoev.ru      *   abstract: an abstract socket address is distinguished by the fact
108220Sigor@sysoev.ru      *   that sun_path[0] is a null byte ('\0').  The socket's address in
108320Sigor@sysoev.ru      *   this namespace is given by the additional bytes in sun_path that
108420Sigor@sysoev.ru      *   are covered by the specified length of the address structure.
108520Sigor@sysoev.ru      *   (Null bytes in the name have no special significance.)
108620Sigor@sysoev.ru      */
108720Sigor@sysoev.ru     if (p[0] == '@') {
108820Sigor@sysoev.ru         p[0] = '\0';
108920Sigor@sysoev.ru         socklen--;
109020Sigor@sysoev.ru     }
109120Sigor@sysoev.ru 
109220Sigor@sysoev.ru #endif
109320Sigor@sysoev.ru 
109420Sigor@sysoev.ru     sa = nxt_sockaddr_alloc(mp, socklen, addr->length);
109520Sigor@sysoev.ru 
109620Sigor@sysoev.ru     if (nxt_slow_path(sa == NULL)) {
109720Sigor@sysoev.ru         return NULL;
109820Sigor@sysoev.ru     }
109920Sigor@sysoev.ru 
110020Sigor@sysoev.ru     sa->type = SOCK_STREAM;
110120Sigor@sysoev.ru 
110220Sigor@sysoev.ru     sa->u.sockaddr_un.sun_family = AF_UNIX;
110320Sigor@sysoev.ru     nxt_memcpy(sa->u.sockaddr_un.sun_path, p, length);
110420Sigor@sysoev.ru 
110520Sigor@sysoev.ru     return sa;
110620Sigor@sysoev.ru 
110720Sigor@sysoev.ru #else  /* !(NXT_HAVE_UNIX_DOMAIN) */
110820Sigor@sysoev.ru 
110920Sigor@sysoev.ru     nxt_log(task, NXT_LOG_CRIT, "unix domain socket \"%V\" is not supported",
111020Sigor@sysoev.ru             addr);
111120Sigor@sysoev.ru 
111220Sigor@sysoev.ru     return NULL;
111320Sigor@sysoev.ru 
111420Sigor@sysoev.ru #endif
111520Sigor@sysoev.ru }
111620Sigor@sysoev.ru 
111720Sigor@sysoev.ru 
111820Sigor@sysoev.ru static nxt_sockaddr_t *
111965Sigor@sysoev.ru nxt_runtime_sockaddr_inet6_parse(nxt_task_t *task, nxt_mp_t *mp,
112020Sigor@sysoev.ru     nxt_str_t *addr)
112120Sigor@sysoev.ru {
112220Sigor@sysoev.ru #if (NXT_INET6)
1123105Sigor@sysoev.ru     u_char           *p, *addr_end;
112420Sigor@sysoev.ru     size_t           length;
112520Sigor@sysoev.ru     nxt_int_t        port;
112620Sigor@sysoev.ru     nxt_sockaddr_t   *sa;
112720Sigor@sysoev.ru     struct in6_addr  *in6_addr;
112820Sigor@sysoev.ru 
112920Sigor@sysoev.ru     length = addr->length - 1;
113020Sigor@sysoev.ru     p = addr->start + 1;
113120Sigor@sysoev.ru 
113220Sigor@sysoev.ru     addr_end = nxt_memchr(p, ']', length);
113320Sigor@sysoev.ru 
113420Sigor@sysoev.ru     if (addr_end == NULL) {
113520Sigor@sysoev.ru         goto invalid_address;
113620Sigor@sysoev.ru     }
113720Sigor@sysoev.ru 
1138105Sigor@sysoev.ru     sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in6),
1139105Sigor@sysoev.ru                             NXT_INET6_ADDR_STR_LEN);
114020Sigor@sysoev.ru     if (nxt_slow_path(sa == NULL)) {
114120Sigor@sysoev.ru         return NULL;
114220Sigor@sysoev.ru     }
114320Sigor@sysoev.ru 
114420Sigor@sysoev.ru     in6_addr = &sa->u.sockaddr_in6.sin6_addr;
114520Sigor@sysoev.ru 
114620Sigor@sysoev.ru     if (nxt_inet6_addr(in6_addr, p, addr_end - p) != NXT_OK) {
114720Sigor@sysoev.ru         goto invalid_address;
114820Sigor@sysoev.ru     }
114920Sigor@sysoev.ru 
1150105Sigor@sysoev.ru     port = 0;
115120Sigor@sysoev.ru     p = addr_end + 1;
115220Sigor@sysoev.ru     length = (p + length) - p;
115320Sigor@sysoev.ru 
115420Sigor@sysoev.ru     if (length == 0) {
115520Sigor@sysoev.ru         goto found;
115620Sigor@sysoev.ru     }
115720Sigor@sysoev.ru 
115820Sigor@sysoev.ru     if (*p == ':') {
115920Sigor@sysoev.ru         port = nxt_int_parse(p + 1, length - 1);
116020Sigor@sysoev.ru 
116120Sigor@sysoev.ru         if (port >= 1 && port <= 65535) {
116220Sigor@sysoev.ru             goto found;
116320Sigor@sysoev.ru         }
116420Sigor@sysoev.ru     }
116520Sigor@sysoev.ru 
116620Sigor@sysoev.ru     nxt_log(task, NXT_LOG_CRIT, "invalid port in \"%V\"", addr);
116720Sigor@sysoev.ru 
116820Sigor@sysoev.ru     return NULL;
116920Sigor@sysoev.ru 
117020Sigor@sysoev.ru found:
117120Sigor@sysoev.ru 
117220Sigor@sysoev.ru     sa->type = SOCK_STREAM;
117320Sigor@sysoev.ru 
117420Sigor@sysoev.ru     sa->u.sockaddr_in6.sin6_family = AF_INET6;
117520Sigor@sysoev.ru     sa->u.sockaddr_in6.sin6_port = htons((in_port_t) port);
117620Sigor@sysoev.ru 
117720Sigor@sysoev.ru     return sa;
117820Sigor@sysoev.ru 
117920Sigor@sysoev.ru invalid_address:
118020Sigor@sysoev.ru 
118120Sigor@sysoev.ru     nxt_log(task, NXT_LOG_CRIT, "invalid IPv6 address in \"%V\"", addr);
118220Sigor@sysoev.ru 
118320Sigor@sysoev.ru     return NULL;
118420Sigor@sysoev.ru 
118520Sigor@sysoev.ru #else
118620Sigor@sysoev.ru 
118720Sigor@sysoev.ru     nxt_log(task, NXT_LOG_CRIT, "IPv6 socket \"%V\" is not supported", addr);
118820Sigor@sysoev.ru 
118920Sigor@sysoev.ru     return NULL;
119020Sigor@sysoev.ru 
119120Sigor@sysoev.ru #endif
119220Sigor@sysoev.ru }
119320Sigor@sysoev.ru 
119420Sigor@sysoev.ru 
119520Sigor@sysoev.ru static nxt_sockaddr_t *
119665Sigor@sysoev.ru nxt_runtime_sockaddr_inet_parse(nxt_task_t *task, nxt_mp_t *mp,
119726Sigor@sysoev.ru     nxt_str_t *string)
119820Sigor@sysoev.ru {
119920Sigor@sysoev.ru     u_char          *p, *ip;
120020Sigor@sysoev.ru     size_t          length;
120126Sigor@sysoev.ru     in_addr_t       addr;
120220Sigor@sysoev.ru     nxt_int_t       port;
120320Sigor@sysoev.ru     nxt_sockaddr_t  *sa;
120420Sigor@sysoev.ru 
120526Sigor@sysoev.ru     addr = INADDR_ANY;
120620Sigor@sysoev.ru 
120726Sigor@sysoev.ru     length = string->length;
120826Sigor@sysoev.ru     ip = string->start;
120920Sigor@sysoev.ru 
121020Sigor@sysoev.ru     p = nxt_memchr(ip, ':', length);
121120Sigor@sysoev.ru 
121220Sigor@sysoev.ru     if (p == NULL) {
121320Sigor@sysoev.ru 
121420Sigor@sysoev.ru         /* single value port, or address */
121520Sigor@sysoev.ru 
121620Sigor@sysoev.ru         port = nxt_int_parse(ip, length);
121720Sigor@sysoev.ru 
121820Sigor@sysoev.ru         if (port > 0) {
121920Sigor@sysoev.ru             /* "*:XX" */
122020Sigor@sysoev.ru 
122120Sigor@sysoev.ru             if (port < 1 || port > 65535) {
122220Sigor@sysoev.ru                 goto invalid_port;
122320Sigor@sysoev.ru             }
122420Sigor@sysoev.ru 
122520Sigor@sysoev.ru         } else {
122620Sigor@sysoev.ru             /* "x.x.x.x" */
122720Sigor@sysoev.ru 
122826Sigor@sysoev.ru             addr = nxt_inet_addr(ip, length);
122920Sigor@sysoev.ru 
123026Sigor@sysoev.ru             if (addr == INADDR_NONE) {
123120Sigor@sysoev.ru                 goto invalid_port;
123220Sigor@sysoev.ru             }
123320Sigor@sysoev.ru 
123420Sigor@sysoev.ru             port = 8080;
123520Sigor@sysoev.ru         }
123620Sigor@sysoev.ru 
123720Sigor@sysoev.ru     } else {
123820Sigor@sysoev.ru 
123920Sigor@sysoev.ru         /* x.x.x.x:XX */
124020Sigor@sysoev.ru 
124120Sigor@sysoev.ru         p++;
124220Sigor@sysoev.ru         length = (ip + length) - p;
124320Sigor@sysoev.ru         port = nxt_int_parse(p, length);
124420Sigor@sysoev.ru 
124520Sigor@sysoev.ru         if (port < 1 || port > 65535) {
124620Sigor@sysoev.ru             goto invalid_port;
124720Sigor@sysoev.ru         }
124820Sigor@sysoev.ru 
124920Sigor@sysoev.ru         length = (p - 1) - ip;
125020Sigor@sysoev.ru 
125120Sigor@sysoev.ru         if (length != 1 || ip[0] != '*') {
125226Sigor@sysoev.ru             addr = nxt_inet_addr(ip, length);
125320Sigor@sysoev.ru 
125426Sigor@sysoev.ru             if (addr == INADDR_NONE) {
125520Sigor@sysoev.ru                 goto invalid_addr;
125620Sigor@sysoev.ru             }
125720Sigor@sysoev.ru 
125820Sigor@sysoev.ru             /* "x.x.x.x:XX" */
125920Sigor@sysoev.ru         }
126020Sigor@sysoev.ru     }
126120Sigor@sysoev.ru 
126220Sigor@sysoev.ru     sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in),
126320Sigor@sysoev.ru                             NXT_INET_ADDR_STR_LEN);
126420Sigor@sysoev.ru     if (nxt_slow_path(sa == NULL)) {
126520Sigor@sysoev.ru         return NULL;
126620Sigor@sysoev.ru     }
126720Sigor@sysoev.ru 
126820Sigor@sysoev.ru     sa->type = SOCK_STREAM;
126920Sigor@sysoev.ru 
127020Sigor@sysoev.ru     sa->u.sockaddr_in.sin_family = AF_INET;
127120Sigor@sysoev.ru     sa->u.sockaddr_in.sin_port = htons((in_port_t) port);
127226Sigor@sysoev.ru     sa->u.sockaddr_in.sin_addr.s_addr = addr;
127320Sigor@sysoev.ru 
127420Sigor@sysoev.ru     return sa;
127520Sigor@sysoev.ru 
127620Sigor@sysoev.ru invalid_port:
127720Sigor@sysoev.ru 
127826Sigor@sysoev.ru     nxt_log(task, NXT_LOG_CRIT, "invalid port in \"%V\"", string);
127920Sigor@sysoev.ru 
128020Sigor@sysoev.ru     return NULL;
128120Sigor@sysoev.ru 
128220Sigor@sysoev.ru invalid_addr:
128320Sigor@sysoev.ru 
128426Sigor@sysoev.ru     nxt_log(task, NXT_LOG_CRIT, "invalid address in \"%V\"", string);
128520Sigor@sysoev.ru 
128620Sigor@sysoev.ru     return NULL;
128720Sigor@sysoev.ru }
128820Sigor@sysoev.ru 
128920Sigor@sysoev.ru 
129020Sigor@sysoev.ru nxt_listen_socket_t *
129120Sigor@sysoev.ru nxt_runtime_listen_socket_add(nxt_runtime_t *rt, nxt_sockaddr_t *sa)
129220Sigor@sysoev.ru {
129365Sigor@sysoev.ru     nxt_mp_t             *mp;
129420Sigor@sysoev.ru     nxt_listen_socket_t  *ls;
129520Sigor@sysoev.ru 
129620Sigor@sysoev.ru     ls = nxt_array_zero_add(rt->listen_sockets);
129720Sigor@sysoev.ru     if (ls == NULL) {
129820Sigor@sysoev.ru         return NULL;
129920Sigor@sysoev.ru     }
130020Sigor@sysoev.ru 
130120Sigor@sysoev.ru     mp = rt->mem_pool;
130220Sigor@sysoev.ru 
130320Sigor@sysoev.ru     ls->sockaddr = nxt_sockaddr_create(mp, &sa->u.sockaddr, sa->socklen,
130420Sigor@sysoev.ru                                        sa->length);
130520Sigor@sysoev.ru     if (ls->sockaddr == NULL) {
130620Sigor@sysoev.ru         return NULL;
130720Sigor@sysoev.ru     }
130820Sigor@sysoev.ru 
130920Sigor@sysoev.ru     ls->sockaddr->type = sa->type;
131020Sigor@sysoev.ru 
131120Sigor@sysoev.ru     nxt_sockaddr_text(ls->sockaddr);
131220Sigor@sysoev.ru 
131320Sigor@sysoev.ru     ls->socket = -1;
131420Sigor@sysoev.ru     ls->backlog = NXT_LISTEN_BACKLOG;
131520Sigor@sysoev.ru 
131620Sigor@sysoev.ru     return ls;
131720Sigor@sysoev.ru }
131820Sigor@sysoev.ru 
131920Sigor@sysoev.ru 
132020Sigor@sysoev.ru static nxt_int_t
132120Sigor@sysoev.ru nxt_runtime_hostname(nxt_task_t *task, nxt_runtime_t *rt)
132220Sigor@sysoev.ru {
132320Sigor@sysoev.ru     size_t  length;
132420Sigor@sysoev.ru     char    hostname[NXT_MAXHOSTNAMELEN + 1];
132520Sigor@sysoev.ru 
132620Sigor@sysoev.ru     if (gethostname(hostname, NXT_MAXHOSTNAMELEN) != 0) {
132720Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "gethostname() failed %E", nxt_errno);
132820Sigor@sysoev.ru         return NXT_ERROR;
132920Sigor@sysoev.ru     }
133020Sigor@sysoev.ru 
133120Sigor@sysoev.ru     /*
133220Sigor@sysoev.ru      * Linux gethostname(2):
133320Sigor@sysoev.ru      *
133420Sigor@sysoev.ru      *    If the null-terminated hostname is too large to fit,
133520Sigor@sysoev.ru      *    then the name is truncated, and no error is returned.
133620Sigor@sysoev.ru      *
133720Sigor@sysoev.ru      * For this reason an additional byte is reserved in the buffer.
133820Sigor@sysoev.ru      */
133920Sigor@sysoev.ru     hostname[NXT_MAXHOSTNAMELEN] = '\0';
134020Sigor@sysoev.ru 
134120Sigor@sysoev.ru     length = nxt_strlen(hostname);
134220Sigor@sysoev.ru     rt->hostname.length = length;
134320Sigor@sysoev.ru 
134465Sigor@sysoev.ru     rt->hostname.start = nxt_mp_nget(rt->mem_pool, length);
134520Sigor@sysoev.ru 
134620Sigor@sysoev.ru     if (rt->hostname.start != NULL) {
134720Sigor@sysoev.ru         nxt_memcpy_lowcase(rt->hostname.start, (u_char *) hostname, length);
134820Sigor@sysoev.ru         return NXT_OK;
134920Sigor@sysoev.ru     }
135020Sigor@sysoev.ru 
135120Sigor@sysoev.ru     return NXT_ERROR;
135220Sigor@sysoev.ru }
135320Sigor@sysoev.ru 
135420Sigor@sysoev.ru 
135520Sigor@sysoev.ru static nxt_int_t
135620Sigor@sysoev.ru nxt_runtime_log_files_init(nxt_runtime_t *rt)
135720Sigor@sysoev.ru {
135820Sigor@sysoev.ru     nxt_file_t  *file;
135920Sigor@sysoev.ru     nxt_list_t  *log_files;
136020Sigor@sysoev.ru 
136120Sigor@sysoev.ru     log_files = nxt_list_create(rt->mem_pool, 1, sizeof(nxt_file_t));
136220Sigor@sysoev.ru 
136320Sigor@sysoev.ru     if (nxt_fast_path(log_files != NULL)) {
136420Sigor@sysoev.ru         rt->log_files = log_files;
136520Sigor@sysoev.ru 
1366230Sigor@sysoev.ru         /* Preallocate the main log.  This allocation cannot fail. */
136720Sigor@sysoev.ru         file = nxt_list_zero_add(log_files);
136820Sigor@sysoev.ru 
136920Sigor@sysoev.ru         file->fd = NXT_FILE_INVALID;
137020Sigor@sysoev.ru         file->log_level = NXT_LOG_CRIT;
137120Sigor@sysoev.ru 
137220Sigor@sysoev.ru         return NXT_OK;
137320Sigor@sysoev.ru     }
137420Sigor@sysoev.ru 
137520Sigor@sysoev.ru     return NXT_ERROR;
137620Sigor@sysoev.ru }
137720Sigor@sysoev.ru 
137820Sigor@sysoev.ru 
137920Sigor@sysoev.ru nxt_file_t *
138020Sigor@sysoev.ru nxt_runtime_log_file_add(nxt_runtime_t *rt, nxt_str_t *name)
138120Sigor@sysoev.ru {
138220Sigor@sysoev.ru     nxt_int_t            ret;
138320Sigor@sysoev.ru     nxt_file_t           *file;
138420Sigor@sysoev.ru     nxt_file_name_str_t  file_name;
138520Sigor@sysoev.ru 
1386230Sigor@sysoev.ru     ret = nxt_file_name_create(rt->mem_pool, &file_name, "V%Z", name);
138720Sigor@sysoev.ru 
138820Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
138920Sigor@sysoev.ru         return NULL;
139020Sigor@sysoev.ru     }
139120Sigor@sysoev.ru 
139220Sigor@sysoev.ru     nxt_list_each(file, rt->log_files) {
139320Sigor@sysoev.ru 
139420Sigor@sysoev.ru         /* STUB: hardecoded case sensitive/insensitive. */
139520Sigor@sysoev.ru 
139620Sigor@sysoev.ru         if (file->name != NULL
139720Sigor@sysoev.ru             && nxt_file_name_eq(file->name, file_name.start))
139820Sigor@sysoev.ru         {
139920Sigor@sysoev.ru             return file;
140020Sigor@sysoev.ru         }
140120Sigor@sysoev.ru 
140220Sigor@sysoev.ru     } nxt_list_loop;
140320Sigor@sysoev.ru 
140420Sigor@sysoev.ru     file = nxt_list_zero_add(rt->log_files);
140520Sigor@sysoev.ru 
140620Sigor@sysoev.ru     if (nxt_slow_path(file == NULL)) {
140720Sigor@sysoev.ru         return NULL;
140820Sigor@sysoev.ru     }
140920Sigor@sysoev.ru 
141020Sigor@sysoev.ru     file->fd = NXT_FILE_INVALID;
141120Sigor@sysoev.ru     file->log_level = NXT_LOG_CRIT;
141220Sigor@sysoev.ru     file->name = file_name.start;
141320Sigor@sysoev.ru 
141420Sigor@sysoev.ru     return file;
141520Sigor@sysoev.ru }
141620Sigor@sysoev.ru 
141720Sigor@sysoev.ru 
141820Sigor@sysoev.ru static nxt_int_t
141920Sigor@sysoev.ru nxt_runtime_log_files_create(nxt_task_t *task, nxt_runtime_t *rt)
142020Sigor@sysoev.ru {
142120Sigor@sysoev.ru     nxt_int_t   ret;
142220Sigor@sysoev.ru     nxt_file_t  *file;
142320Sigor@sysoev.ru 
142420Sigor@sysoev.ru     nxt_list_each(file, rt->log_files) {
142520Sigor@sysoev.ru 
142620Sigor@sysoev.ru         ret = nxt_file_open(task, file, O_WRONLY | O_APPEND, O_CREAT,
142720Sigor@sysoev.ru                             NXT_FILE_OWNER_ACCESS);
142820Sigor@sysoev.ru 
142920Sigor@sysoev.ru         if (ret != NXT_OK) {
143020Sigor@sysoev.ru             return NXT_ERROR;
143120Sigor@sysoev.ru         }
143220Sigor@sysoev.ru 
143320Sigor@sysoev.ru     } nxt_list_loop;
143420Sigor@sysoev.ru 
143520Sigor@sysoev.ru     file = nxt_list_first(rt->log_files);
143620Sigor@sysoev.ru 
143720Sigor@sysoev.ru     return nxt_file_stderr(file);
143820Sigor@sysoev.ru }
143920Sigor@sysoev.ru 
144020Sigor@sysoev.ru 
144120Sigor@sysoev.ru nxt_int_t
144220Sigor@sysoev.ru nxt_runtime_listen_sockets_create(nxt_task_t *task, nxt_runtime_t *rt)
144320Sigor@sysoev.ru {
144420Sigor@sysoev.ru     nxt_int_t            ret;
144520Sigor@sysoev.ru     nxt_uint_t           c, p, ncurr, nprev;
144620Sigor@sysoev.ru     nxt_listen_socket_t  *curr, *prev;
144720Sigor@sysoev.ru 
144820Sigor@sysoev.ru     curr = rt->listen_sockets->elts;
144920Sigor@sysoev.ru     ncurr = rt->listen_sockets->nelts;
145020Sigor@sysoev.ru 
145120Sigor@sysoev.ru     if (rt->inherited_sockets != NULL) {
145220Sigor@sysoev.ru         prev = rt->inherited_sockets->elts;
145320Sigor@sysoev.ru         nprev = rt->inherited_sockets->nelts;
145420Sigor@sysoev.ru 
145520Sigor@sysoev.ru     } else {
145620Sigor@sysoev.ru         prev = NULL;
145720Sigor@sysoev.ru         nprev = 0;
145820Sigor@sysoev.ru     }
145920Sigor@sysoev.ru 
146020Sigor@sysoev.ru     for (c = 0; c < ncurr; c++) {
146120Sigor@sysoev.ru 
146220Sigor@sysoev.ru         for (p = 0; p < nprev; p++) {
146320Sigor@sysoev.ru 
146420Sigor@sysoev.ru             if (nxt_sockaddr_cmp(curr[c].sockaddr, prev[p].sockaddr)) {
146520Sigor@sysoev.ru 
146620Sigor@sysoev.ru                 ret = nxt_listen_socket_update(task, &curr[c], &prev[p]);
146720Sigor@sysoev.ru                 if (ret != NXT_OK) {
146820Sigor@sysoev.ru                     return NXT_ERROR;
146920Sigor@sysoev.ru                 }
147020Sigor@sysoev.ru 
147120Sigor@sysoev.ru                 goto next;
147220Sigor@sysoev.ru             }
147320Sigor@sysoev.ru         }
147420Sigor@sysoev.ru 
147520Sigor@sysoev.ru         if (nxt_listen_socket_create(task, &curr[c], 0) != NXT_OK) {
147620Sigor@sysoev.ru             return NXT_ERROR;
147720Sigor@sysoev.ru         }
147820Sigor@sysoev.ru 
147920Sigor@sysoev.ru     next:
148020Sigor@sysoev.ru 
148120Sigor@sysoev.ru         continue;
148220Sigor@sysoev.ru     }
148320Sigor@sysoev.ru 
148420Sigor@sysoev.ru     return NXT_OK;
148520Sigor@sysoev.ru }
148620Sigor@sysoev.ru 
148720Sigor@sysoev.ru 
148820Sigor@sysoev.ru nxt_int_t
148920Sigor@sysoev.ru nxt_runtime_listen_sockets_enable(nxt_task_t *task, nxt_runtime_t *rt)
149020Sigor@sysoev.ru {
149120Sigor@sysoev.ru     nxt_uint_t           i, n;
149220Sigor@sysoev.ru     nxt_listen_socket_t  *ls;
149320Sigor@sysoev.ru 
149420Sigor@sysoev.ru     ls = rt->listen_sockets->elts;
149520Sigor@sysoev.ru     n = rt->listen_sockets->nelts;
149620Sigor@sysoev.ru 
149720Sigor@sysoev.ru     for (i = 0; i < n; i++) {
149820Sigor@sysoev.ru         if (ls[i].flags == NXT_NONBLOCK) {
149954Sigor@sysoev.ru             if (nxt_listen_event(task, &ls[i]) == NULL) {
150020Sigor@sysoev.ru                 return NXT_ERROR;
150120Sigor@sysoev.ru             }
150220Sigor@sysoev.ru         }
150320Sigor@sysoev.ru     }
150420Sigor@sysoev.ru 
150520Sigor@sysoev.ru     return NXT_OK;
150620Sigor@sysoev.ru }
150720Sigor@sysoev.ru 
150820Sigor@sysoev.ru 
150920Sigor@sysoev.ru nxt_str_t *
151065Sigor@sysoev.ru nxt_current_directory(nxt_mp_t *mp)
151120Sigor@sysoev.ru {
151220Sigor@sysoev.ru     size_t     length;
151320Sigor@sysoev.ru     u_char     *p;
151420Sigor@sysoev.ru     nxt_str_t  *name;
151520Sigor@sysoev.ru     char       buf[NXT_MAX_PATH_LEN];
151620Sigor@sysoev.ru 
151720Sigor@sysoev.ru     length = nxt_dir_current(buf, NXT_MAX_PATH_LEN);
151820Sigor@sysoev.ru 
151920Sigor@sysoev.ru     if (nxt_fast_path(length != 0)) {
152020Sigor@sysoev.ru         name = nxt_str_alloc(mp, length + 1);
152120Sigor@sysoev.ru 
152220Sigor@sysoev.ru         if (nxt_fast_path(name != NULL)) {
152320Sigor@sysoev.ru             p = nxt_cpymem(name->start, buf, length);
152420Sigor@sysoev.ru             *p = '/';
152520Sigor@sysoev.ru 
152620Sigor@sysoev.ru             return name;
152720Sigor@sysoev.ru         }
152820Sigor@sysoev.ru     }
152920Sigor@sysoev.ru 
153020Sigor@sysoev.ru     return NULL;
153120Sigor@sysoev.ru }
153220Sigor@sysoev.ru 
153320Sigor@sysoev.ru 
153420Sigor@sysoev.ru static nxt_int_t
153520Sigor@sysoev.ru nxt_runtime_pid_file_create(nxt_task_t *task, nxt_file_name_t *pid_file)
153620Sigor@sysoev.ru {
153720Sigor@sysoev.ru     ssize_t     length;
153820Sigor@sysoev.ru     nxt_int_t   n;
153920Sigor@sysoev.ru     nxt_file_t  file;
154020Sigor@sysoev.ru     u_char      pid[NXT_INT64_T_LEN + NXT_LINEFEED_SIZE];
154120Sigor@sysoev.ru 
154220Sigor@sysoev.ru     nxt_memzero(&file, sizeof(nxt_file_t));
154320Sigor@sysoev.ru 
154420Sigor@sysoev.ru     file.name = pid_file;
154520Sigor@sysoev.ru 
154620Sigor@sysoev.ru     n = nxt_file_open(task, &file, O_WRONLY, O_CREAT | O_TRUNC,
154720Sigor@sysoev.ru                       NXT_FILE_DEFAULT_ACCESS);
154820Sigor@sysoev.ru 
154920Sigor@sysoev.ru     if (n != NXT_OK) {
155020Sigor@sysoev.ru         return NXT_ERROR;
155120Sigor@sysoev.ru     }
155220Sigor@sysoev.ru 
155320Sigor@sysoev.ru     length = nxt_sprintf(pid, pid + sizeof(pid), "%PI%n", nxt_pid) - pid;
155420Sigor@sysoev.ru 
155520Sigor@sysoev.ru     if (nxt_file_write(&file, pid, length, 0) != length) {
155620Sigor@sysoev.ru         return NXT_ERROR;
155720Sigor@sysoev.ru     }
155820Sigor@sysoev.ru 
155920Sigor@sysoev.ru     nxt_file_close(task, &file);
156020Sigor@sysoev.ru 
156120Sigor@sysoev.ru     return NXT_OK;
156220Sigor@sysoev.ru }
156320Sigor@sysoev.ru 
156420Sigor@sysoev.ru 
156520Sigor@sysoev.ru nxt_process_t *
156642Smax.romanov@nginx.com nxt_runtime_process_new(nxt_runtime_t *rt)
156720Sigor@sysoev.ru {
156820Sigor@sysoev.ru     nxt_process_t  *process;
156920Sigor@sysoev.ru 
157020Sigor@sysoev.ru     /* TODO: memory failures. */
157120Sigor@sysoev.ru 
157265Sigor@sysoev.ru     process = nxt_mp_zalloc(rt->mem_pool, sizeof(nxt_process_t));
157342Smax.romanov@nginx.com     if (nxt_slow_path(process == NULL)) {
157442Smax.romanov@nginx.com         return NULL;
157542Smax.romanov@nginx.com     }
157642Smax.romanov@nginx.com 
157742Smax.romanov@nginx.com     nxt_queue_init(&process->ports);
157842Smax.romanov@nginx.com 
157990Smax.romanov@nginx.com     nxt_thread_mutex_create(&process->incoming_mutex);
158090Smax.romanov@nginx.com     nxt_thread_mutex_create(&process->outgoing_mutex);
1581141Smax.romanov@nginx.com     nxt_thread_mutex_create(&process->cp_mutex);
158290Smax.romanov@nginx.com 
1583349Smax.romanov@nginx.com     process->use_count = 1;
1584349Smax.romanov@nginx.com 
158542Smax.romanov@nginx.com     return process;
158642Smax.romanov@nginx.com }
158742Smax.romanov@nginx.com 
158842Smax.romanov@nginx.com 
1589196Smax.romanov@nginx.com static void
1590141Smax.romanov@nginx.com nxt_runtime_process_destroy(nxt_runtime_t *rt, nxt_process_t *process)
1591141Smax.romanov@nginx.com {
1592341Smax.romanov@nginx.com     nxt_port_t         *port;
1593341Smax.romanov@nginx.com     nxt_lvlhsh_each_t  lhe;
1594341Smax.romanov@nginx.com 
1595349Smax.romanov@nginx.com     nxt_assert(process->use_count == 0);
1596196Smax.romanov@nginx.com     nxt_assert(process->registered == 0);
1597164Smax.romanov@nginx.com 
1598141Smax.romanov@nginx.com     nxt_port_mmaps_destroy(process->incoming, 1);
1599141Smax.romanov@nginx.com     nxt_port_mmaps_destroy(process->outgoing, 1);
1600141Smax.romanov@nginx.com 
1601341Smax.romanov@nginx.com     port = nxt_port_hash_first(&process->connected_ports, &lhe);
1602141Smax.romanov@nginx.com 
1603341Smax.romanov@nginx.com     while(port != NULL) {
1604341Smax.romanov@nginx.com         nxt_port_hash_remove(&process->connected_ports, port);
1605341Smax.romanov@nginx.com 
1606341Smax.romanov@nginx.com         port = nxt_port_hash_first(&process->connected_ports, &lhe);
1607141Smax.romanov@nginx.com     }
1608141Smax.romanov@nginx.com 
1609141Smax.romanov@nginx.com     nxt_thread_mutex_destroy(&process->incoming_mutex);
1610141Smax.romanov@nginx.com     nxt_thread_mutex_destroy(&process->outgoing_mutex);
1611141Smax.romanov@nginx.com     nxt_thread_mutex_destroy(&process->cp_mutex);
1612141Smax.romanov@nginx.com 
1613141Smax.romanov@nginx.com     nxt_mp_free(rt->mem_pool, process);
1614141Smax.romanov@nginx.com }
1615141Smax.romanov@nginx.com 
1616141Smax.romanov@nginx.com 
161742Smax.romanov@nginx.com static nxt_int_t
161842Smax.romanov@nginx.com nxt_runtime_lvlhsh_pid_test(nxt_lvlhsh_query_t *lhq, void *data)
161942Smax.romanov@nginx.com {
162042Smax.romanov@nginx.com     nxt_process_t  *process;
162142Smax.romanov@nginx.com 
162242Smax.romanov@nginx.com     process = data;
162342Smax.romanov@nginx.com 
1624277Sigor@sysoev.ru     if (lhq->key.length == sizeof(nxt_pid_t)
1625277Sigor@sysoev.ru         && *(nxt_pid_t *) lhq->key.start == process->pid)
1626277Sigor@sysoev.ru     {
162742Smax.romanov@nginx.com         return NXT_OK;
162842Smax.romanov@nginx.com     }
162942Smax.romanov@nginx.com 
163042Smax.romanov@nginx.com     return NXT_DECLINED;
163142Smax.romanov@nginx.com }
163242Smax.romanov@nginx.com 
163342Smax.romanov@nginx.com static const nxt_lvlhsh_proto_t  lvlhsh_processes_proto  nxt_aligned(64) = {
163442Smax.romanov@nginx.com     NXT_LVLHSH_DEFAULT,
163542Smax.romanov@nginx.com     nxt_runtime_lvlhsh_pid_test,
163642Smax.romanov@nginx.com     nxt_lvlhsh_alloc,
163742Smax.romanov@nginx.com     nxt_lvlhsh_free,
163842Smax.romanov@nginx.com };
163942Smax.romanov@nginx.com 
164042Smax.romanov@nginx.com 
1641196Smax.romanov@nginx.com nxt_inline void
1642196Smax.romanov@nginx.com nxt_runtime_process_lhq_pid(nxt_lvlhsh_query_t *lhq, nxt_pid_t *pid)
1643196Smax.romanov@nginx.com {
1644196Smax.romanov@nginx.com     lhq->key_hash = nxt_murmur_hash2(pid, sizeof(*pid));
1645196Smax.romanov@nginx.com     lhq->key.length = sizeof(*pid);
1646196Smax.romanov@nginx.com     lhq->key.start = (u_char *) pid;
1647196Smax.romanov@nginx.com     lhq->proto = &lvlhsh_processes_proto;
1648196Smax.romanov@nginx.com }
1649196Smax.romanov@nginx.com 
1650196Smax.romanov@nginx.com 
165142Smax.romanov@nginx.com nxt_process_t *
165242Smax.romanov@nginx.com nxt_runtime_process_find(nxt_runtime_t *rt, nxt_pid_t pid)
165342Smax.romanov@nginx.com {
1654196Smax.romanov@nginx.com     nxt_process_t       *process;
165542Smax.romanov@nginx.com     nxt_lvlhsh_query_t  lhq;
165642Smax.romanov@nginx.com 
1657196Smax.romanov@nginx.com     process = NULL;
1658196Smax.romanov@nginx.com 
1659196Smax.romanov@nginx.com     nxt_runtime_process_lhq_pid(&lhq, &pid);
1660196Smax.romanov@nginx.com 
1661196Smax.romanov@nginx.com     nxt_thread_mutex_lock(&rt->processes_mutex);
166242Smax.romanov@nginx.com 
166342Smax.romanov@nginx.com     if (nxt_lvlhsh_find(&rt->processes, &lhq) == NXT_OK) {
1664196Smax.romanov@nginx.com         process = lhq.value;
1665196Smax.romanov@nginx.com 
1666196Smax.romanov@nginx.com     } else {
1667196Smax.romanov@nginx.com         nxt_thread_log_debug("process %PI not found", pid);
166842Smax.romanov@nginx.com     }
166942Smax.romanov@nginx.com 
1670196Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&rt->processes_mutex);
167142Smax.romanov@nginx.com 
1672196Smax.romanov@nginx.com     return process;
167342Smax.romanov@nginx.com }
167442Smax.romanov@nginx.com 
167542Smax.romanov@nginx.com 
167642Smax.romanov@nginx.com nxt_process_t *
167742Smax.romanov@nginx.com nxt_runtime_process_get(nxt_runtime_t *rt, nxt_pid_t pid)
167842Smax.romanov@nginx.com {
167942Smax.romanov@nginx.com     nxt_process_t       *process;
168042Smax.romanov@nginx.com     nxt_lvlhsh_query_t  lhq;
168142Smax.romanov@nginx.com 
1682196Smax.romanov@nginx.com     nxt_runtime_process_lhq_pid(&lhq, &pid);
1683196Smax.romanov@nginx.com 
1684196Smax.romanov@nginx.com     nxt_thread_mutex_lock(&rt->processes_mutex);
168542Smax.romanov@nginx.com 
168642Smax.romanov@nginx.com     if (nxt_lvlhsh_find(&rt->processes, &lhq) == NXT_OK) {
168742Smax.romanov@nginx.com         nxt_thread_log_debug("process %PI found", pid);
1688196Smax.romanov@nginx.com 
1689196Smax.romanov@nginx.com         nxt_thread_mutex_unlock(&rt->processes_mutex);
1690349Smax.romanov@nginx.com 
1691349Smax.romanov@nginx.com         process = lhq.value;
1692349Smax.romanov@nginx.com         process->use_count++;
1693349Smax.romanov@nginx.com 
1694349Smax.romanov@nginx.com         return process;
169542Smax.romanov@nginx.com     }
169642Smax.romanov@nginx.com 
169742Smax.romanov@nginx.com     process = nxt_runtime_process_new(rt);
169820Sigor@sysoev.ru     if (nxt_slow_path(process == NULL)) {
169920Sigor@sysoev.ru         return NULL;
170020Sigor@sysoev.ru     }
170120Sigor@sysoev.ru 
170242Smax.romanov@nginx.com     process->pid = pid;
170342Smax.romanov@nginx.com 
170442Smax.romanov@nginx.com     lhq.replace = 0;
170542Smax.romanov@nginx.com     lhq.value = process;
170642Smax.romanov@nginx.com     lhq.pool = rt->mem_pool;
170742Smax.romanov@nginx.com 
170842Smax.romanov@nginx.com     switch (nxt_lvlhsh_insert(&rt->processes, &lhq)) {
170942Smax.romanov@nginx.com 
171042Smax.romanov@nginx.com     case NXT_OK:
171142Smax.romanov@nginx.com         if (rt->nprocesses == 0) {
171242Smax.romanov@nginx.com             rt->mprocess = process;
171342Smax.romanov@nginx.com         }
171442Smax.romanov@nginx.com 
171542Smax.romanov@nginx.com         rt->nprocesses++;
171642Smax.romanov@nginx.com 
1717196Smax.romanov@nginx.com         process->registered = 1;
1718196Smax.romanov@nginx.com 
171942Smax.romanov@nginx.com         nxt_thread_log_debug("process %PI insert", pid);
172042Smax.romanov@nginx.com         break;
172142Smax.romanov@nginx.com 
172242Smax.romanov@nginx.com     default:
172342Smax.romanov@nginx.com         nxt_thread_log_debug("process %PI insert failed", pid);
172442Smax.romanov@nginx.com         break;
172520Sigor@sysoev.ru     }
172620Sigor@sysoev.ru 
1727196Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&rt->processes_mutex);
1728196Smax.romanov@nginx.com 
172920Sigor@sysoev.ru     return process;
173020Sigor@sysoev.ru }
173142Smax.romanov@nginx.com 
173242Smax.romanov@nginx.com 
173342Smax.romanov@nginx.com void
1734343Smax.romanov@nginx.com nxt_runtime_process_add(nxt_task_t *task, nxt_process_t *process)
173542Smax.romanov@nginx.com {
173642Smax.romanov@nginx.com     nxt_port_t          *port;
1737343Smax.romanov@nginx.com     nxt_runtime_t       *rt;
173842Smax.romanov@nginx.com     nxt_lvlhsh_query_t  lhq;
173942Smax.romanov@nginx.com 
1740196Smax.romanov@nginx.com     nxt_assert(process->registered == 0);
1741196Smax.romanov@nginx.com 
1742343Smax.romanov@nginx.com     rt = task->thread->runtime;
1743343Smax.romanov@nginx.com 
1744196Smax.romanov@nginx.com     nxt_runtime_process_lhq_pid(&lhq, &process->pid);
1745196Smax.romanov@nginx.com 
174642Smax.romanov@nginx.com     lhq.replace = 0;
174742Smax.romanov@nginx.com     lhq.value = process;
174842Smax.romanov@nginx.com     lhq.pool = rt->mem_pool;
174942Smax.romanov@nginx.com 
1750196Smax.romanov@nginx.com     nxt_thread_mutex_lock(&rt->processes_mutex);
1751196Smax.romanov@nginx.com 
175242Smax.romanov@nginx.com     switch (nxt_lvlhsh_insert(&rt->processes, &lhq)) {
175342Smax.romanov@nginx.com 
175442Smax.romanov@nginx.com     case NXT_OK:
175542Smax.romanov@nginx.com         if (rt->nprocesses == 0) {
175642Smax.romanov@nginx.com             rt->mprocess = process;
175742Smax.romanov@nginx.com         }
175842Smax.romanov@nginx.com 
175942Smax.romanov@nginx.com         rt->nprocesses++;
176042Smax.romanov@nginx.com 
176142Smax.romanov@nginx.com         nxt_process_port_each(process, port) {
176242Smax.romanov@nginx.com 
1763141Smax.romanov@nginx.com             port->pid = process->pid;
1764141Smax.romanov@nginx.com 
1765343Smax.romanov@nginx.com             nxt_runtime_port_add(task, port);
176642Smax.romanov@nginx.com 
176742Smax.romanov@nginx.com         } nxt_process_port_loop;
176842Smax.romanov@nginx.com 
1769196Smax.romanov@nginx.com         process->registered = 1;
1770196Smax.romanov@nginx.com 
1771196Smax.romanov@nginx.com         nxt_thread_log_debug("process %PI added", process->pid);
177242Smax.romanov@nginx.com         break;
177342Smax.romanov@nginx.com 
177442Smax.romanov@nginx.com     default:
1775196Smax.romanov@nginx.com         nxt_thread_log_debug("process %PI failed to add", process->pid);
177642Smax.romanov@nginx.com         break;
177742Smax.romanov@nginx.com     }
1778196Smax.romanov@nginx.com 
1779196Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&rt->processes_mutex);
1780196Smax.romanov@nginx.com }
1781196Smax.romanov@nginx.com 
1782196Smax.romanov@nginx.com 
1783196Smax.romanov@nginx.com static nxt_process_t *
1784196Smax.romanov@nginx.com nxt_runtime_process_remove_pid(nxt_runtime_t *rt, nxt_pid_t pid)
1785196Smax.romanov@nginx.com {
1786196Smax.romanov@nginx.com     nxt_process_t       *process;
1787196Smax.romanov@nginx.com     nxt_lvlhsh_query_t  lhq;
1788196Smax.romanov@nginx.com 
1789196Smax.romanov@nginx.com     process = NULL;
1790196Smax.romanov@nginx.com 
1791196Smax.romanov@nginx.com     nxt_runtime_process_lhq_pid(&lhq, &pid);
1792196Smax.romanov@nginx.com 
1793196Smax.romanov@nginx.com     lhq.pool = rt->mem_pool;
1794196Smax.romanov@nginx.com 
1795196Smax.romanov@nginx.com     nxt_thread_mutex_lock(&rt->processes_mutex);
1796196Smax.romanov@nginx.com 
1797196Smax.romanov@nginx.com     switch (nxt_lvlhsh_delete(&rt->processes, &lhq)) {
1798196Smax.romanov@nginx.com 
1799196Smax.romanov@nginx.com     case NXT_OK:
1800196Smax.romanov@nginx.com         rt->nprocesses--;
1801196Smax.romanov@nginx.com 
1802196Smax.romanov@nginx.com         process = lhq.value;
1803196Smax.romanov@nginx.com 
1804196Smax.romanov@nginx.com         process->registered = 0;
1805196Smax.romanov@nginx.com 
1806196Smax.romanov@nginx.com         nxt_thread_log_debug("process %PI removed", pid);
1807196Smax.romanov@nginx.com         break;
1808196Smax.romanov@nginx.com 
1809196Smax.romanov@nginx.com     default:
1810196Smax.romanov@nginx.com         nxt_thread_log_debug("process %PI remove failed", pid);
1811196Smax.romanov@nginx.com         break;
1812196Smax.romanov@nginx.com     }
1813196Smax.romanov@nginx.com 
1814196Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&rt->processes_mutex);
1815196Smax.romanov@nginx.com 
1816196Smax.romanov@nginx.com     return process;
181742Smax.romanov@nginx.com }
181842Smax.romanov@nginx.com 
181942Smax.romanov@nginx.com 
182042Smax.romanov@nginx.com void
1821349Smax.romanov@nginx.com nxt_process_use(nxt_task_t *task, nxt_process_t *process, int i)
182242Smax.romanov@nginx.com {
1823343Smax.romanov@nginx.com     nxt_runtime_t  *rt;
1824343Smax.romanov@nginx.com 
1825349Smax.romanov@nginx.com     process->use_count += i;
1826349Smax.romanov@nginx.com 
1827349Smax.romanov@nginx.com     if (process->use_count == 0) {
1828349Smax.romanov@nginx.com         rt = task->thread->runtime;
1829349Smax.romanov@nginx.com 
1830196Smax.romanov@nginx.com         if (process->registered == 1) {
1831196Smax.romanov@nginx.com             nxt_runtime_process_remove_pid(rt, process->pid);
1832164Smax.romanov@nginx.com         }
1833164Smax.romanov@nginx.com 
1834196Smax.romanov@nginx.com         nxt_runtime_process_destroy(rt, process);
183542Smax.romanov@nginx.com     }
183642Smax.romanov@nginx.com }
183742Smax.romanov@nginx.com 
183842Smax.romanov@nginx.com 
183942Smax.romanov@nginx.com nxt_process_t *
184042Smax.romanov@nginx.com nxt_runtime_process_first(nxt_runtime_t *rt, nxt_lvlhsh_each_t *lhe)
184142Smax.romanov@nginx.com {
184242Smax.romanov@nginx.com     nxt_memzero(lhe, sizeof(nxt_lvlhsh_each_t));
184342Smax.romanov@nginx.com 
184442Smax.romanov@nginx.com     lhe->proto = &lvlhsh_processes_proto;
184542Smax.romanov@nginx.com 
184642Smax.romanov@nginx.com     return nxt_runtime_process_next(rt, lhe);
184742Smax.romanov@nginx.com }
184842Smax.romanov@nginx.com 
184942Smax.romanov@nginx.com 
185074Smax.romanov@nginx.com nxt_port_t *
185174Smax.romanov@nginx.com nxt_runtime_port_first(nxt_runtime_t *rt, nxt_lvlhsh_each_t *lhe)
185274Smax.romanov@nginx.com {
185375Smax.romanov@nginx.com     return nxt_port_hash_first(&rt->ports, lhe);
185474Smax.romanov@nginx.com }
185574Smax.romanov@nginx.com 
185674Smax.romanov@nginx.com 
185742Smax.romanov@nginx.com void
1858343Smax.romanov@nginx.com nxt_runtime_port_add(nxt_task_t *task, nxt_port_t *port)
185942Smax.romanov@nginx.com {
1860348Smax.romanov@nginx.com     nxt_int_t      res;
1861343Smax.romanov@nginx.com     nxt_runtime_t  *rt;
1862343Smax.romanov@nginx.com 
1863343Smax.romanov@nginx.com     rt = task->thread->runtime;
1864343Smax.romanov@nginx.com 
1865348Smax.romanov@nginx.com     res = nxt_port_hash_add(&rt->ports, port);
1866348Smax.romanov@nginx.com 
1867348Smax.romanov@nginx.com     if (res != NXT_OK) {
1868348Smax.romanov@nginx.com         return;
1869348Smax.romanov@nginx.com     }
1870141Smax.romanov@nginx.com 
1871141Smax.romanov@nginx.com     rt->port_by_type[port->type] = port;
1872343Smax.romanov@nginx.com 
1873343Smax.romanov@nginx.com     nxt_port_use(task, port, 1);
187442Smax.romanov@nginx.com }
187542Smax.romanov@nginx.com 
187642Smax.romanov@nginx.com 
187742Smax.romanov@nginx.com void
1878343Smax.romanov@nginx.com nxt_runtime_port_remove(nxt_task_t *task, nxt_port_t *port)
187942Smax.romanov@nginx.com {
1880348Smax.romanov@nginx.com     nxt_int_t      res;
1881343Smax.romanov@nginx.com     nxt_runtime_t  *rt;
1882343Smax.romanov@nginx.com 
1883343Smax.romanov@nginx.com     rt = task->thread->runtime;
1884343Smax.romanov@nginx.com 
1885348Smax.romanov@nginx.com     res = nxt_port_hash_remove(&rt->ports, port);
1886348Smax.romanov@nginx.com 
1887348Smax.romanov@nginx.com     if (res != NXT_OK) {
1888348Smax.romanov@nginx.com         return;
1889348Smax.romanov@nginx.com     }
1890125Smax.romanov@nginx.com 
1891141Smax.romanov@nginx.com     if (rt->port_by_type[port->type] == port) {
1892141Smax.romanov@nginx.com         rt->port_by_type[port->type] = NULL;
1893141Smax.romanov@nginx.com     }
1894343Smax.romanov@nginx.com 
1895343Smax.romanov@nginx.com     nxt_port_use(task, port, -1);
189642Smax.romanov@nginx.com }
189742Smax.romanov@nginx.com 
189842Smax.romanov@nginx.com 
189942Smax.romanov@nginx.com nxt_port_t *
190042Smax.romanov@nginx.com nxt_runtime_port_find(nxt_runtime_t *rt, nxt_pid_t pid,
190142Smax.romanov@nginx.com     nxt_port_id_t port_id)
190242Smax.romanov@nginx.com {
190375Smax.romanov@nginx.com     return nxt_port_hash_find(&rt->ports, pid, port_id);
190442Smax.romanov@nginx.com }
1905