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); 22697Sigor@sysoev.ru static void nxt_runtime_initial_start(nxt_task_t *task, nxt_uint_t status); 2320Sigor@sysoev.ru static void nxt_runtime_close_idle_connections(nxt_event_engine_t *engine); 2420Sigor@sysoev.ru static void nxt_runtime_exit(nxt_task_t *task, void *obj, void *data); 2520Sigor@sysoev.ru static nxt_int_t nxt_runtime_event_engine_change(nxt_task_t *task, 2620Sigor@sysoev.ru nxt_runtime_t *rt); 2720Sigor@sysoev.ru static nxt_int_t nxt_runtime_conf_init(nxt_task_t *task, nxt_runtime_t *rt); 2820Sigor@sysoev.ru static nxt_int_t nxt_runtime_conf_read_cmd(nxt_task_t *task, nxt_runtime_t *rt); 2920Sigor@sysoev.ru static nxt_int_t nxt_runtime_hostname(nxt_task_t *task, nxt_runtime_t *rt); 3020Sigor@sysoev.ru static nxt_int_t nxt_runtime_log_files_init(nxt_runtime_t *rt); 3120Sigor@sysoev.ru static nxt_int_t nxt_runtime_log_files_create(nxt_task_t *task, 3220Sigor@sysoev.ru nxt_runtime_t *rt); 3320Sigor@sysoev.ru static nxt_int_t nxt_runtime_pid_file_create(nxt_task_t *task, 3420Sigor@sysoev.ru nxt_file_name_t *pid_file); 3520Sigor@sysoev.ru static void nxt_runtime_thread_pool_destroy(nxt_task_t *task, nxt_runtime_t *rt, 3620Sigor@sysoev.ru nxt_runtime_cont_t cont); 37223Sigor@sysoev.ru static void nxt_runtime_thread_pool_init(void); 38223Sigor@sysoev.ru static void nxt_runtime_thread_pool_exit(nxt_task_t *task, void *obj, 39223Sigor@sysoev.ru void *data); 40196Smax.romanov@nginx.com static void nxt_runtime_process_destroy(nxt_runtime_t *rt, 41196Smax.romanov@nginx.com nxt_process_t *process); 42196Smax.romanov@nginx.com static nxt_process_t *nxt_runtime_process_remove_pid(nxt_runtime_t *rt, 43196Smax.romanov@nginx.com nxt_pid_t pid); 44196Smax.romanov@nginx.com 4520Sigor@sysoev.ru 4620Sigor@sysoev.ru nxt_int_t 4720Sigor@sysoev.ru nxt_runtime_create(nxt_task_t *task) 4820Sigor@sysoev.ru { 49216Sigor@sysoev.ru nxt_mp_t *mp; 50216Sigor@sysoev.ru nxt_int_t ret; 51216Sigor@sysoev.ru nxt_array_t *listen_sockets; 52216Sigor@sysoev.ru nxt_runtime_t *rt; 53216Sigor@sysoev.ru nxt_app_lang_module_t *lang; 5420Sigor@sysoev.ru 5565Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 5620Sigor@sysoev.ru if (nxt_slow_path(mp == NULL)) { 5720Sigor@sysoev.ru return NXT_ERROR; 5820Sigor@sysoev.ru } 5920Sigor@sysoev.ru 6065Sigor@sysoev.ru rt = nxt_mp_zget(mp, sizeof(nxt_runtime_t)); 6165Sigor@sysoev.ru if (nxt_slow_path(rt == NULL)) { 621013Smax.romanov@nginx.com goto fail; 6365Sigor@sysoev.ru } 6420Sigor@sysoev.ru 6520Sigor@sysoev.ru task->thread->runtime = rt; 6620Sigor@sysoev.ru rt->mem_pool = mp; 6720Sigor@sysoev.ru 68196Smax.romanov@nginx.com nxt_thread_mutex_create(&rt->processes_mutex); 69196Smax.romanov@nginx.com 7020Sigor@sysoev.ru rt->services = nxt_services_init(mp); 7120Sigor@sysoev.ru if (nxt_slow_path(rt->services == NULL)) { 7220Sigor@sysoev.ru goto fail; 7320Sigor@sysoev.ru } 7420Sigor@sysoev.ru 75216Sigor@sysoev.ru rt->languages = nxt_array_create(mp, 1, sizeof(nxt_app_lang_module_t)); 76216Sigor@sysoev.ru if (nxt_slow_path(rt->languages == NULL)) { 77216Sigor@sysoev.ru goto fail; 78216Sigor@sysoev.ru } 79216Sigor@sysoev.ru 80216Sigor@sysoev.ru /* Should not fail. */ 81216Sigor@sysoev.ru lang = nxt_array_add(rt->languages); 82804Svbart@nginx.com lang->type = NXT_APP_EXTERNAL; 83354Svbart@nginx.com lang->version = (u_char *) ""; 84216Sigor@sysoev.ru lang->file = NULL; 85804Svbart@nginx.com lang->module = &nxt_external_module; 86216Sigor@sysoev.ru 8720Sigor@sysoev.ru listen_sockets = nxt_array_create(mp, 1, sizeof(nxt_listen_socket_t)); 8820Sigor@sysoev.ru if (nxt_slow_path(listen_sockets == NULL)) { 8920Sigor@sysoev.ru goto fail; 9020Sigor@sysoev.ru } 9120Sigor@sysoev.ru 9220Sigor@sysoev.ru rt->listen_sockets = listen_sockets; 9320Sigor@sysoev.ru 9420Sigor@sysoev.ru ret = nxt_runtime_inherited_listen_sockets(task, rt); 9520Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 9620Sigor@sysoev.ru goto fail; 9720Sigor@sysoev.ru } 9820Sigor@sysoev.ru 9920Sigor@sysoev.ru if (nxt_runtime_hostname(task, rt) != NXT_OK) { 10020Sigor@sysoev.ru goto fail; 10120Sigor@sysoev.ru } 10220Sigor@sysoev.ru 10320Sigor@sysoev.ru if (nxt_slow_path(nxt_runtime_log_files_init(rt) != NXT_OK)) { 10420Sigor@sysoev.ru goto fail; 10520Sigor@sysoev.ru } 10620Sigor@sysoev.ru 10720Sigor@sysoev.ru if (nxt_runtime_event_engines(task, rt) != NXT_OK) { 10820Sigor@sysoev.ru goto fail; 10920Sigor@sysoev.ru } 11020Sigor@sysoev.ru 11120Sigor@sysoev.ru if (nxt_slow_path(nxt_runtime_thread_pools(task->thread, rt) != NXT_OK)) { 11220Sigor@sysoev.ru goto fail; 11320Sigor@sysoev.ru } 11420Sigor@sysoev.ru 11520Sigor@sysoev.ru rt->start = nxt_runtime_initial_start; 11620Sigor@sysoev.ru 117221Sigor@sysoev.ru if (nxt_runtime_conf_init(task, rt) != NXT_OK) { 118221Sigor@sysoev.ru goto fail; 119221Sigor@sysoev.ru } 120221Sigor@sysoev.ru 12120Sigor@sysoev.ru nxt_work_queue_add(&task->thread->engine->fast_work_queue, 12220Sigor@sysoev.ru nxt_runtime_start, task, rt, NULL); 12320Sigor@sysoev.ru 12420Sigor@sysoev.ru return NXT_OK; 12520Sigor@sysoev.ru 12620Sigor@sysoev.ru fail: 12720Sigor@sysoev.ru 12865Sigor@sysoev.ru nxt_mp_destroy(mp); 12920Sigor@sysoev.ru 13020Sigor@sysoev.ru return NXT_ERROR; 13120Sigor@sysoev.ru } 13220Sigor@sysoev.ru 13320Sigor@sysoev.ru 13420Sigor@sysoev.ru static nxt_int_t 13520Sigor@sysoev.ru nxt_runtime_inherited_listen_sockets(nxt_task_t *task, nxt_runtime_t *rt) 13620Sigor@sysoev.ru { 13720Sigor@sysoev.ru u_char *v, *p; 13820Sigor@sysoev.ru nxt_int_t type; 13920Sigor@sysoev.ru nxt_array_t *inherited_sockets; 14020Sigor@sysoev.ru nxt_socket_t s; 14120Sigor@sysoev.ru nxt_listen_socket_t *ls; 14220Sigor@sysoev.ru 14320Sigor@sysoev.ru v = (u_char *) getenv("NGINX"); 14420Sigor@sysoev.ru 14520Sigor@sysoev.ru if (v == NULL) { 14620Sigor@sysoev.ru return nxt_runtime_systemd_listen_sockets(task, rt); 14720Sigor@sysoev.ru } 14820Sigor@sysoev.ru 149564Svbart@nginx.com nxt_alert(task, "using inherited listen sockets: %s", v); 15020Sigor@sysoev.ru 15120Sigor@sysoev.ru inherited_sockets = nxt_array_create(rt->mem_pool, 15220Sigor@sysoev.ru 1, sizeof(nxt_listen_socket_t)); 15320Sigor@sysoev.ru if (inherited_sockets == NULL) { 15420Sigor@sysoev.ru return NXT_ERROR; 15520Sigor@sysoev.ru } 15620Sigor@sysoev.ru 15720Sigor@sysoev.ru rt->inherited_sockets = inherited_sockets; 15820Sigor@sysoev.ru 15920Sigor@sysoev.ru for (p = v; *p != '\0'; p++) { 16020Sigor@sysoev.ru 16120Sigor@sysoev.ru if (*p == ';') { 16220Sigor@sysoev.ru s = nxt_int_parse(v, p - v); 16320Sigor@sysoev.ru 16420Sigor@sysoev.ru if (nxt_slow_path(s < 0)) { 165564Svbart@nginx.com nxt_alert(task, "invalid socket number \"%s\" " 166564Svbart@nginx.com "in NGINX environment variable, " 167564Svbart@nginx.com "ignoring the rest of the variable", v); 16820Sigor@sysoev.ru return NXT_ERROR; 16920Sigor@sysoev.ru } 17020Sigor@sysoev.ru 17120Sigor@sysoev.ru v = p + 1; 17220Sigor@sysoev.ru 17320Sigor@sysoev.ru ls = nxt_array_zero_add(inherited_sockets); 17420Sigor@sysoev.ru if (nxt_slow_path(ls == NULL)) { 17520Sigor@sysoev.ru return NXT_ERROR; 17620Sigor@sysoev.ru } 17720Sigor@sysoev.ru 17820Sigor@sysoev.ru ls->socket = s; 17920Sigor@sysoev.ru 18020Sigor@sysoev.ru ls->sockaddr = nxt_getsockname(task, rt->mem_pool, s); 18120Sigor@sysoev.ru if (nxt_slow_path(ls->sockaddr == NULL)) { 18220Sigor@sysoev.ru return NXT_ERROR; 18320Sigor@sysoev.ru } 18420Sigor@sysoev.ru 18520Sigor@sysoev.ru type = nxt_socket_getsockopt(task, s, SOL_SOCKET, SO_TYPE); 18620Sigor@sysoev.ru if (nxt_slow_path(type == -1)) { 18720Sigor@sysoev.ru return NXT_ERROR; 18820Sigor@sysoev.ru } 18920Sigor@sysoev.ru 19020Sigor@sysoev.ru ls->sockaddr->type = (uint16_t) type; 19120Sigor@sysoev.ru } 19220Sigor@sysoev.ru } 19320Sigor@sysoev.ru 19420Sigor@sysoev.ru return NXT_OK; 19520Sigor@sysoev.ru } 19620Sigor@sysoev.ru 19720Sigor@sysoev.ru 19820Sigor@sysoev.ru static nxt_int_t 19920Sigor@sysoev.ru nxt_runtime_systemd_listen_sockets(nxt_task_t *task, nxt_runtime_t *rt) 20020Sigor@sysoev.ru { 20120Sigor@sysoev.ru u_char *nfd, *pid; 20220Sigor@sysoev.ru nxt_int_t n; 20320Sigor@sysoev.ru nxt_array_t *inherited_sockets; 20420Sigor@sysoev.ru nxt_socket_t s; 20520Sigor@sysoev.ru nxt_listen_socket_t *ls; 20620Sigor@sysoev.ru 20720Sigor@sysoev.ru /* 20820Sigor@sysoev.ru * Number of listening sockets passed. The socket 20920Sigor@sysoev.ru * descriptors start from number 3 and are sequential. 21020Sigor@sysoev.ru */ 21120Sigor@sysoev.ru nfd = (u_char *) getenv("LISTEN_FDS"); 21220Sigor@sysoev.ru if (nfd == NULL) { 21320Sigor@sysoev.ru return NXT_OK; 21420Sigor@sysoev.ru } 21520Sigor@sysoev.ru 21620Sigor@sysoev.ru /* The pid of the service process. */ 21720Sigor@sysoev.ru pid = (u_char *) getenv("LISTEN_PID"); 21820Sigor@sysoev.ru if (pid == NULL) { 21920Sigor@sysoev.ru return NXT_OK; 22020Sigor@sysoev.ru } 22120Sigor@sysoev.ru 22220Sigor@sysoev.ru n = nxt_int_parse(nfd, nxt_strlen(nfd)); 22320Sigor@sysoev.ru if (n < 0) { 22420Sigor@sysoev.ru return NXT_OK; 22520Sigor@sysoev.ru } 22620Sigor@sysoev.ru 22720Sigor@sysoev.ru if (nxt_pid != nxt_int_parse(pid, nxt_strlen(pid))) { 22820Sigor@sysoev.ru return NXT_OK; 22920Sigor@sysoev.ru } 23020Sigor@sysoev.ru 231494Spluknet@nginx.com nxt_log(task, NXT_LOG_INFO, "using %i systemd listen sockets", n); 23220Sigor@sysoev.ru 23320Sigor@sysoev.ru inherited_sockets = nxt_array_create(rt->mem_pool, 23420Sigor@sysoev.ru n, sizeof(nxt_listen_socket_t)); 23520Sigor@sysoev.ru if (inherited_sockets == NULL) { 23620Sigor@sysoev.ru return NXT_ERROR; 23720Sigor@sysoev.ru } 23820Sigor@sysoev.ru 23920Sigor@sysoev.ru rt->inherited_sockets = inherited_sockets; 24020Sigor@sysoev.ru 24120Sigor@sysoev.ru for (s = 3; s < n; s++) { 24220Sigor@sysoev.ru ls = nxt_array_zero_add(inherited_sockets); 24320Sigor@sysoev.ru if (nxt_slow_path(ls == NULL)) { 24420Sigor@sysoev.ru return NXT_ERROR; 24520Sigor@sysoev.ru } 24620Sigor@sysoev.ru 24720Sigor@sysoev.ru ls->socket = s; 24820Sigor@sysoev.ru 24920Sigor@sysoev.ru ls->sockaddr = nxt_getsockname(task, rt->mem_pool, s); 25020Sigor@sysoev.ru if (nxt_slow_path(ls->sockaddr == NULL)) { 25120Sigor@sysoev.ru return NXT_ERROR; 25220Sigor@sysoev.ru } 25320Sigor@sysoev.ru 25420Sigor@sysoev.ru ls->sockaddr->type = SOCK_STREAM; 25520Sigor@sysoev.ru } 25620Sigor@sysoev.ru 25720Sigor@sysoev.ru return NXT_OK; 25820Sigor@sysoev.ru } 25920Sigor@sysoev.ru 26020Sigor@sysoev.ru 26120Sigor@sysoev.ru static nxt_int_t 26220Sigor@sysoev.ru nxt_runtime_event_engines(nxt_task_t *task, nxt_runtime_t *rt) 26320Sigor@sysoev.ru { 26453Sigor@sysoev.ru nxt_thread_t *thread; 26553Sigor@sysoev.ru nxt_event_engine_t *engine; 26620Sigor@sysoev.ru const nxt_event_interface_t *interface; 26720Sigor@sysoev.ru 26820Sigor@sysoev.ru interface = nxt_service_get(rt->services, "engine", NULL); 26920Sigor@sysoev.ru 27020Sigor@sysoev.ru if (nxt_slow_path(interface == NULL)) { 27120Sigor@sysoev.ru /* TODO: log */ 27220Sigor@sysoev.ru return NXT_ERROR; 27320Sigor@sysoev.ru } 27420Sigor@sysoev.ru 27520Sigor@sysoev.ru engine = nxt_event_engine_create(task, interface, 276240Sigor@sysoev.ru nxt_main_process_signals, 0, 0); 27720Sigor@sysoev.ru 27820Sigor@sysoev.ru if (nxt_slow_path(engine == NULL)) { 27920Sigor@sysoev.ru return NXT_ERROR; 28020Sigor@sysoev.ru } 28120Sigor@sysoev.ru 28253Sigor@sysoev.ru thread = task->thread; 28353Sigor@sysoev.ru thread->engine = engine; 284326Svbart@nginx.com #if 0 28553Sigor@sysoev.ru thread->fiber = &engine->fibers->fiber; 286326Svbart@nginx.com #endif 28753Sigor@sysoev.ru 28820Sigor@sysoev.ru engine->id = rt->last_engine_id++; 289342Smax.romanov@nginx.com engine->mem_pool = nxt_mp_create(1024, 128, 256, 32); 29053Sigor@sysoev.ru 29153Sigor@sysoev.ru nxt_queue_init(&rt->engines); 29253Sigor@sysoev.ru nxt_queue_insert_tail(&rt->engines, &engine->link); 29320Sigor@sysoev.ru 29420Sigor@sysoev.ru return NXT_OK; 29520Sigor@sysoev.ru } 29620Sigor@sysoev.ru 29720Sigor@sysoev.ru 29820Sigor@sysoev.ru static nxt_int_t 29920Sigor@sysoev.ru nxt_runtime_thread_pools(nxt_thread_t *thr, nxt_runtime_t *rt) 30020Sigor@sysoev.ru { 30120Sigor@sysoev.ru nxt_int_t ret; 30220Sigor@sysoev.ru nxt_array_t *thread_pools; 30320Sigor@sysoev.ru 30420Sigor@sysoev.ru thread_pools = nxt_array_create(rt->mem_pool, 1, 30520Sigor@sysoev.ru sizeof(nxt_thread_pool_t *)); 30620Sigor@sysoev.ru 30720Sigor@sysoev.ru if (nxt_slow_path(thread_pools == NULL)) { 30820Sigor@sysoev.ru return NXT_ERROR; 30920Sigor@sysoev.ru } 31020Sigor@sysoev.ru 31120Sigor@sysoev.ru rt->thread_pools = thread_pools; 31220Sigor@sysoev.ru ret = nxt_runtime_thread_pool_create(thr, rt, 2, 60000 * 1000000LL); 31320Sigor@sysoev.ru 31420Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 31520Sigor@sysoev.ru return NXT_ERROR; 31620Sigor@sysoev.ru } 31720Sigor@sysoev.ru 31820Sigor@sysoev.ru return NXT_OK; 31920Sigor@sysoev.ru } 32020Sigor@sysoev.ru 32120Sigor@sysoev.ru 32220Sigor@sysoev.ru static void 32320Sigor@sysoev.ru nxt_runtime_start(nxt_task_t *task, void *obj, void *data) 32420Sigor@sysoev.ru { 32520Sigor@sysoev.ru nxt_runtime_t *rt; 32620Sigor@sysoev.ru 32720Sigor@sysoev.ru rt = obj; 32820Sigor@sysoev.ru 32920Sigor@sysoev.ru nxt_debug(task, "rt conf done"); 33020Sigor@sysoev.ru 33120Sigor@sysoev.ru task->thread->log->ctx_handler = NULL; 33220Sigor@sysoev.ru task->thread->log->ctx = NULL; 33320Sigor@sysoev.ru 33420Sigor@sysoev.ru if (nxt_runtime_log_files_create(task, rt) != NXT_OK) { 33520Sigor@sysoev.ru goto fail; 33620Sigor@sysoev.ru } 33720Sigor@sysoev.ru 33820Sigor@sysoev.ru if (nxt_runtime_event_engine_change(task, rt) != NXT_OK) { 33920Sigor@sysoev.ru goto fail; 34020Sigor@sysoev.ru } 34120Sigor@sysoev.ru 34220Sigor@sysoev.ru /* 34320Sigor@sysoev.ru * Thread pools should be destroyed before starting worker 34420Sigor@sysoev.ru * processes, because thread pool semaphores will stick in 34520Sigor@sysoev.ru * locked state in new processes after fork(). 34620Sigor@sysoev.ru */ 34720Sigor@sysoev.ru nxt_runtime_thread_pool_destroy(task, rt, rt->start); 34820Sigor@sysoev.ru 34920Sigor@sysoev.ru return; 35020Sigor@sysoev.ru 35120Sigor@sysoev.ru fail: 35220Sigor@sysoev.ru 353697Sigor@sysoev.ru nxt_runtime_quit(task, 1); 35420Sigor@sysoev.ru } 35520Sigor@sysoev.ru 35620Sigor@sysoev.ru 35720Sigor@sysoev.ru static void 358697Sigor@sysoev.ru nxt_runtime_initial_start(nxt_task_t *task, nxt_uint_t status) 35920Sigor@sysoev.ru { 36020Sigor@sysoev.ru nxt_int_t ret; 36120Sigor@sysoev.ru nxt_thread_t *thr; 36220Sigor@sysoev.ru nxt_runtime_t *rt; 36320Sigor@sysoev.ru const nxt_event_interface_t *interface; 36420Sigor@sysoev.ru 36520Sigor@sysoev.ru thr = task->thread; 36620Sigor@sysoev.ru rt = thr->runtime; 36720Sigor@sysoev.ru 36820Sigor@sysoev.ru if (rt->inherited_sockets == NULL && rt->daemon) { 36920Sigor@sysoev.ru 37020Sigor@sysoev.ru if (nxt_process_daemon(task) != NXT_OK) { 37120Sigor@sysoev.ru goto fail; 37220Sigor@sysoev.ru } 37320Sigor@sysoev.ru 37420Sigor@sysoev.ru /* 37520Sigor@sysoev.ru * An event engine should be updated after fork() 37620Sigor@sysoev.ru * even if an event facility was not changed because: 37720Sigor@sysoev.ru * 1) inherited kqueue descriptor is invalid, 37820Sigor@sysoev.ru * 2) the signal thread is not inherited. 37920Sigor@sysoev.ru */ 38020Sigor@sysoev.ru interface = nxt_service_get(rt->services, "engine", rt->engine); 38120Sigor@sysoev.ru if (interface == NULL) { 38220Sigor@sysoev.ru goto fail; 38320Sigor@sysoev.ru } 38420Sigor@sysoev.ru 38520Sigor@sysoev.ru ret = nxt_event_engine_change(task->thread->engine, interface, 38620Sigor@sysoev.ru rt->batch); 38720Sigor@sysoev.ru if (ret != NXT_OK) { 38820Sigor@sysoev.ru goto fail; 38920Sigor@sysoev.ru } 39020Sigor@sysoev.ru } 39120Sigor@sysoev.ru 39220Sigor@sysoev.ru ret = nxt_runtime_pid_file_create(task, rt->pid_file); 39320Sigor@sysoev.ru if (ret != NXT_OK) { 39420Sigor@sysoev.ru goto fail; 39520Sigor@sysoev.ru } 39620Sigor@sysoev.ru 39720Sigor@sysoev.ru if (nxt_runtime_event_engine_change(task, rt) != NXT_OK) { 39820Sigor@sysoev.ru goto fail; 39920Sigor@sysoev.ru } 40020Sigor@sysoev.ru 40120Sigor@sysoev.ru thr->engine->max_connections = rt->engine_connections; 40220Sigor@sysoev.ru 403695Sigor@sysoev.ru if (nxt_main_process_start(thr, task, rt) != NXT_ERROR) { 40420Sigor@sysoev.ru return; 40520Sigor@sysoev.ru } 40620Sigor@sysoev.ru 40720Sigor@sysoev.ru fail: 40820Sigor@sysoev.ru 409697Sigor@sysoev.ru nxt_runtime_quit(task, 1); 41020Sigor@sysoev.ru } 41120Sigor@sysoev.ru 41220Sigor@sysoev.ru 41320Sigor@sysoev.ru void 414697Sigor@sysoev.ru nxt_runtime_quit(nxt_task_t *task, nxt_uint_t status) 41520Sigor@sysoev.ru { 41620Sigor@sysoev.ru nxt_bool_t done; 41720Sigor@sysoev.ru nxt_runtime_t *rt; 41820Sigor@sysoev.ru nxt_event_engine_t *engine; 41920Sigor@sysoev.ru 42020Sigor@sysoev.ru rt = task->thread->runtime; 421697Sigor@sysoev.ru rt->status |= status; 42220Sigor@sysoev.ru engine = task->thread->engine; 42320Sigor@sysoev.ru 42420Sigor@sysoev.ru nxt_debug(task, "exiting"); 42520Sigor@sysoev.ru 42620Sigor@sysoev.ru done = 1; 42720Sigor@sysoev.ru 42820Sigor@sysoev.ru if (!engine->shutdown) { 42920Sigor@sysoev.ru engine->shutdown = 1; 43020Sigor@sysoev.ru 43120Sigor@sysoev.ru if (!nxt_array_is_empty(rt->thread_pools)) { 43220Sigor@sysoev.ru nxt_runtime_thread_pool_destroy(task, rt, nxt_runtime_quit); 43320Sigor@sysoev.ru done = 0; 43420Sigor@sysoev.ru } 43520Sigor@sysoev.ru 436696Sigor@sysoev.ru if (rt->type == NXT_PROCESS_MAIN) { 437754Smax.romanov@nginx.com nxt_main_stop_all_processes(task, rt); 43820Sigor@sysoev.ru done = 0; 43920Sigor@sysoev.ru } 44020Sigor@sysoev.ru } 44120Sigor@sysoev.ru 44220Sigor@sysoev.ru nxt_runtime_close_idle_connections(engine); 44320Sigor@sysoev.ru 44420Sigor@sysoev.ru if (done) { 44520Sigor@sysoev.ru nxt_work_queue_add(&engine->fast_work_queue, nxt_runtime_exit, 44620Sigor@sysoev.ru task, rt, engine); 44720Sigor@sysoev.ru } 44820Sigor@sysoev.ru } 44920Sigor@sysoev.ru 45020Sigor@sysoev.ru 45120Sigor@sysoev.ru static void 45220Sigor@sysoev.ru nxt_runtime_close_idle_connections(nxt_event_engine_t *engine) 45320Sigor@sysoev.ru { 45462Sigor@sysoev.ru nxt_conn_t *c; 45520Sigor@sysoev.ru nxt_queue_t *idle; 45620Sigor@sysoev.ru nxt_queue_link_t *link, *next; 45720Sigor@sysoev.ru 45820Sigor@sysoev.ru nxt_debug(&engine->task, "close idle connections"); 45920Sigor@sysoev.ru 46020Sigor@sysoev.ru idle = &engine->idle_connections; 46120Sigor@sysoev.ru 46220Sigor@sysoev.ru for (link = nxt_queue_head(idle); 46320Sigor@sysoev.ru link != nxt_queue_tail(idle); 46420Sigor@sysoev.ru link = next) 46520Sigor@sysoev.ru { 46620Sigor@sysoev.ru next = nxt_queue_next(link); 46762Sigor@sysoev.ru c = nxt_queue_link_data(link, nxt_conn_t, link); 46820Sigor@sysoev.ru 46920Sigor@sysoev.ru if (!c->socket.read_ready) { 47020Sigor@sysoev.ru nxt_queue_remove(link); 47162Sigor@sysoev.ru nxt_conn_close(engine, c); 47220Sigor@sysoev.ru } 47320Sigor@sysoev.ru } 47420Sigor@sysoev.ru } 47520Sigor@sysoev.ru 47620Sigor@sysoev.ru 47720Sigor@sysoev.ru static void 47820Sigor@sysoev.ru nxt_runtime_exit(nxt_task_t *task, void *obj, void *data) 47920Sigor@sysoev.ru { 480697Sigor@sysoev.ru int status; 481125Smax.romanov@nginx.com nxt_runtime_t *rt; 482125Smax.romanov@nginx.com nxt_process_t *process; 48320Sigor@sysoev.ru nxt_event_engine_t *engine; 48420Sigor@sysoev.ru 48520Sigor@sysoev.ru rt = obj; 48620Sigor@sysoev.ru engine = data; 48720Sigor@sysoev.ru 48820Sigor@sysoev.ru nxt_debug(task, "thread pools: %d", rt->thread_pools->nelts); 48920Sigor@sysoev.ru 49020Sigor@sysoev.ru if (!nxt_array_is_empty(rt->thread_pools)) { 49120Sigor@sysoev.ru return; 49220Sigor@sysoev.ru } 49320Sigor@sysoev.ru 494696Sigor@sysoev.ru if (rt->type == NXT_PROCESS_MAIN) { 49520Sigor@sysoev.ru if (rt->pid_file != NULL) { 49620Sigor@sysoev.ru nxt_file_delete(rt->pid_file); 49720Sigor@sysoev.ru } 498234Sigor@sysoev.ru 499234Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 500234Sigor@sysoev.ru { 501234Sigor@sysoev.ru nxt_sockaddr_t *sa; 502234Sigor@sysoev.ru nxt_file_name_t *name; 503234Sigor@sysoev.ru 504234Sigor@sysoev.ru sa = rt->controller_listen; 505234Sigor@sysoev.ru 506234Sigor@sysoev.ru if (sa->u.sockaddr.sa_family == AF_UNIX) { 507234Sigor@sysoev.ru name = (nxt_file_name_t *) sa->u.sockaddr_un.sun_path; 508234Sigor@sysoev.ru (void) nxt_file_delete(name); 509234Sigor@sysoev.ru } 510234Sigor@sysoev.ru } 511234Sigor@sysoev.ru #endif 51220Sigor@sysoev.ru } 51320Sigor@sysoev.ru 51420Sigor@sysoev.ru if (!engine->event.signal_support) { 51520Sigor@sysoev.ru nxt_event_engine_signals_stop(engine); 51620Sigor@sysoev.ru } 51720Sigor@sysoev.ru 518125Smax.romanov@nginx.com nxt_runtime_process_each(rt, process) { 519125Smax.romanov@nginx.com 520349Smax.romanov@nginx.com nxt_process_close_ports(task, process); 521125Smax.romanov@nginx.com 522125Smax.romanov@nginx.com } nxt_runtime_process_loop; 523125Smax.romanov@nginx.com 524196Smax.romanov@nginx.com nxt_thread_mutex_destroy(&rt->processes_mutex); 525196Smax.romanov@nginx.com 526697Sigor@sysoev.ru status = rt->status; 527125Smax.romanov@nginx.com nxt_mp_destroy(rt->mem_pool); 528125Smax.romanov@nginx.com 529697Sigor@sysoev.ru nxt_debug(task, "exit: %d", status); 53020Sigor@sysoev.ru 531697Sigor@sysoev.ru exit(status); 53220Sigor@sysoev.ru nxt_unreachable(); 53320Sigor@sysoev.ru } 53420Sigor@sysoev.ru 53520Sigor@sysoev.ru 53620Sigor@sysoev.ru static nxt_int_t 53720Sigor@sysoev.ru nxt_runtime_event_engine_change(nxt_task_t *task, nxt_runtime_t *rt) 53820Sigor@sysoev.ru { 53920Sigor@sysoev.ru nxt_event_engine_t *engine; 54020Sigor@sysoev.ru const nxt_event_interface_t *interface; 54120Sigor@sysoev.ru 54220Sigor@sysoev.ru engine = task->thread->engine; 54320Sigor@sysoev.ru 54420Sigor@sysoev.ru if (engine->batch == rt->batch 54520Sigor@sysoev.ru && nxt_strcmp(engine->event.name, rt->engine) == 0) 54620Sigor@sysoev.ru { 54720Sigor@sysoev.ru return NXT_OK; 54820Sigor@sysoev.ru } 54920Sigor@sysoev.ru 55020Sigor@sysoev.ru interface = nxt_service_get(rt->services, "engine", rt->engine); 55120Sigor@sysoev.ru 55220Sigor@sysoev.ru if (interface != NULL) { 55320Sigor@sysoev.ru return nxt_event_engine_change(engine, interface, rt->batch); 55420Sigor@sysoev.ru } 55520Sigor@sysoev.ru 55620Sigor@sysoev.ru return NXT_ERROR; 55720Sigor@sysoev.ru } 55820Sigor@sysoev.ru 55920Sigor@sysoev.ru 56020Sigor@sysoev.ru void 56120Sigor@sysoev.ru nxt_runtime_event_engine_free(nxt_runtime_t *rt) 56220Sigor@sysoev.ru { 56353Sigor@sysoev.ru nxt_queue_link_t *link; 56453Sigor@sysoev.ru nxt_event_engine_t *engine; 56520Sigor@sysoev.ru 56653Sigor@sysoev.ru link = nxt_queue_first(&rt->engines); 56753Sigor@sysoev.ru nxt_queue_remove(link); 56820Sigor@sysoev.ru 56953Sigor@sysoev.ru engine = nxt_queue_link_data(link, nxt_event_engine_t, link); 57020Sigor@sysoev.ru nxt_event_engine_free(engine); 57120Sigor@sysoev.ru } 57220Sigor@sysoev.ru 57320Sigor@sysoev.ru 57420Sigor@sysoev.ru nxt_int_t 57520Sigor@sysoev.ru nxt_runtime_thread_pool_create(nxt_thread_t *thr, nxt_runtime_t *rt, 57620Sigor@sysoev.ru nxt_uint_t max_threads, nxt_nsec_t timeout) 57720Sigor@sysoev.ru { 57820Sigor@sysoev.ru nxt_thread_pool_t *thread_pool, **tp; 57920Sigor@sysoev.ru 58020Sigor@sysoev.ru tp = nxt_array_add(rt->thread_pools); 58120Sigor@sysoev.ru if (tp == NULL) { 58220Sigor@sysoev.ru return NXT_ERROR; 58320Sigor@sysoev.ru } 58420Sigor@sysoev.ru 58520Sigor@sysoev.ru thread_pool = nxt_thread_pool_create(max_threads, timeout, 58620Sigor@sysoev.ru nxt_runtime_thread_pool_init, 58720Sigor@sysoev.ru thr->engine, 58820Sigor@sysoev.ru nxt_runtime_thread_pool_exit); 58920Sigor@sysoev.ru 59020Sigor@sysoev.ru if (nxt_fast_path(thread_pool != NULL)) { 59120Sigor@sysoev.ru *tp = thread_pool; 59220Sigor@sysoev.ru } 59320Sigor@sysoev.ru 59420Sigor@sysoev.ru return NXT_OK; 59520Sigor@sysoev.ru } 59620Sigor@sysoev.ru 59720Sigor@sysoev.ru 59820Sigor@sysoev.ru static void 59920Sigor@sysoev.ru nxt_runtime_thread_pool_destroy(nxt_task_t *task, nxt_runtime_t *rt, 60020Sigor@sysoev.ru nxt_runtime_cont_t cont) 60120Sigor@sysoev.ru { 60220Sigor@sysoev.ru nxt_uint_t n; 60320Sigor@sysoev.ru nxt_thread_pool_t **tp; 60420Sigor@sysoev.ru 60520Sigor@sysoev.ru rt->continuation = cont; 60620Sigor@sysoev.ru 60720Sigor@sysoev.ru n = rt->thread_pools->nelts; 60820Sigor@sysoev.ru 60920Sigor@sysoev.ru if (n == 0) { 610697Sigor@sysoev.ru cont(task, 0); 61120Sigor@sysoev.ru return; 61220Sigor@sysoev.ru } 61320Sigor@sysoev.ru 61420Sigor@sysoev.ru tp = rt->thread_pools->elts; 61520Sigor@sysoev.ru 61620Sigor@sysoev.ru do { 61720Sigor@sysoev.ru nxt_thread_pool_destroy(*tp); 61820Sigor@sysoev.ru 61920Sigor@sysoev.ru tp++; 62020Sigor@sysoev.ru n--; 62120Sigor@sysoev.ru } while (n != 0); 62220Sigor@sysoev.ru } 62320Sigor@sysoev.ru 62420Sigor@sysoev.ru 62520Sigor@sysoev.ru static void 62620Sigor@sysoev.ru nxt_runtime_thread_pool_init(void) 62720Sigor@sysoev.ru { 62820Sigor@sysoev.ru #if (NXT_REGEX) 62920Sigor@sysoev.ru nxt_regex_init(0); 63020Sigor@sysoev.ru #endif 63120Sigor@sysoev.ru } 63220Sigor@sysoev.ru 63320Sigor@sysoev.ru 63420Sigor@sysoev.ru static void 63520Sigor@sysoev.ru nxt_runtime_thread_pool_exit(nxt_task_t *task, void *obj, void *data) 63620Sigor@sysoev.ru { 63720Sigor@sysoev.ru nxt_uint_t i, n; 63820Sigor@sysoev.ru nxt_runtime_t *rt; 63920Sigor@sysoev.ru nxt_thread_pool_t *tp, **thread_pools; 64020Sigor@sysoev.ru nxt_thread_handle_t handle; 64120Sigor@sysoev.ru 64220Sigor@sysoev.ru tp = obj; 64320Sigor@sysoev.ru 64420Sigor@sysoev.ru if (data != NULL) { 64520Sigor@sysoev.ru handle = (nxt_thread_handle_t) (uintptr_t) data; 64620Sigor@sysoev.ru nxt_thread_wait(handle); 64720Sigor@sysoev.ru } 64820Sigor@sysoev.ru 64920Sigor@sysoev.ru rt = task->thread->runtime; 65020Sigor@sysoev.ru 65120Sigor@sysoev.ru thread_pools = rt->thread_pools->elts; 65220Sigor@sysoev.ru n = rt->thread_pools->nelts; 65320Sigor@sysoev.ru 65420Sigor@sysoev.ru nxt_debug(task, "thread pools: %ui", n); 65520Sigor@sysoev.ru 65620Sigor@sysoev.ru for (i = 0; i < n; i++) { 65720Sigor@sysoev.ru 65820Sigor@sysoev.ru if (tp == thread_pools[i]) { 65920Sigor@sysoev.ru nxt_array_remove(rt->thread_pools, &thread_pools[i]); 66020Sigor@sysoev.ru 66120Sigor@sysoev.ru if (n == 1) { 66220Sigor@sysoev.ru /* The last thread pool. */ 663697Sigor@sysoev.ru rt->continuation(task, 0); 66420Sigor@sysoev.ru } 66520Sigor@sysoev.ru 66620Sigor@sysoev.ru return; 66720Sigor@sysoev.ru } 66820Sigor@sysoev.ru } 66920Sigor@sysoev.ru } 67020Sigor@sysoev.ru 67120Sigor@sysoev.ru 67220Sigor@sysoev.ru static nxt_int_t 67320Sigor@sysoev.ru nxt_runtime_conf_init(nxt_task_t *task, nxt_runtime_t *rt) 67420Sigor@sysoev.ru { 67520Sigor@sysoev.ru nxt_int_t ret; 676251Sigor@sysoev.ru nxt_str_t control; 677251Sigor@sysoev.ru nxt_uint_t n; 67820Sigor@sysoev.ru nxt_file_t *file; 679251Sigor@sysoev.ru const char *slash; 680234Sigor@sysoev.ru nxt_sockaddr_t *sa; 68120Sigor@sysoev.ru nxt_file_name_str_t file_name; 68220Sigor@sysoev.ru const nxt_event_interface_t *interface; 68320Sigor@sysoev.ru 68420Sigor@sysoev.ru rt->daemon = 1; 68520Sigor@sysoev.ru rt->engine_connections = 256; 68620Sigor@sysoev.ru rt->auxiliary_threads = 2; 687232Sigor@sysoev.ru rt->user_cred.user = NXT_USER; 688232Sigor@sysoev.ru rt->group = NXT_GROUP; 689231Sigor@sysoev.ru rt->pid = NXT_PID; 690230Sigor@sysoev.ru rt->log = NXT_LOG; 691233Sigor@sysoev.ru rt->modules = NXT_MODULES; 692314Svbart@nginx.com rt->state = NXT_STATE; 693234Sigor@sysoev.ru rt->control = NXT_CONTROL_SOCK; 69420Sigor@sysoev.ru 695*1182St.nateldemoura@f5.com nxt_memzero(&rt->capabilities, sizeof(nxt_capabilities_t)); 696*1182St.nateldemoura@f5.com 69720Sigor@sysoev.ru if (nxt_runtime_conf_read_cmd(task, rt) != NXT_OK) { 69820Sigor@sysoev.ru return NXT_ERROR; 69920Sigor@sysoev.ru } 70020Sigor@sysoev.ru 701*1182St.nateldemoura@f5.com if (nxt_capability_set(task, &rt->capabilities) != NXT_OK) { 70220Sigor@sysoev.ru return NXT_ERROR; 70320Sigor@sysoev.ru } 70420Sigor@sysoev.ru 705*1182St.nateldemoura@f5.com if (rt->capabilities.setid) { 706*1182St.nateldemoura@f5.com if (nxt_user_cred_get(task, &rt->user_cred, rt->group) != NXT_OK) { 707*1182St.nateldemoura@f5.com return NXT_ERROR; 708*1182St.nateldemoura@f5.com } 709*1182St.nateldemoura@f5.com 710*1182St.nateldemoura@f5.com } else { 711*1182St.nateldemoura@f5.com nxt_log(task, NXT_LOG_WARN, "Unit is running unprivileged, then it " 712*1182St.nateldemoura@f5.com "cannot use arbitrary user and group."); 713*1182St.nateldemoura@f5.com } 714*1182St.nateldemoura@f5.com 71520Sigor@sysoev.ru /* An engine's parameters. */ 71620Sigor@sysoev.ru 71720Sigor@sysoev.ru interface = nxt_service_get(rt->services, "engine", rt->engine); 71820Sigor@sysoev.ru if (interface == NULL) { 71920Sigor@sysoev.ru return NXT_ERROR; 72020Sigor@sysoev.ru } 72120Sigor@sysoev.ru 72220Sigor@sysoev.ru rt->engine = interface->name; 72320Sigor@sysoev.ru 724252Smax.romanov@nginx.com ret = nxt_file_name_create(rt->mem_pool, &file_name, "%s%Z", rt->pid); 72520Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 72620Sigor@sysoev.ru return NXT_ERROR; 72720Sigor@sysoev.ru } 72820Sigor@sysoev.ru 72920Sigor@sysoev.ru rt->pid_file = file_name.start; 73020Sigor@sysoev.ru 731230Sigor@sysoev.ru ret = nxt_file_name_create(rt->mem_pool, &file_name, "%s%Z", rt->log); 73220Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 73320Sigor@sysoev.ru return NXT_ERROR; 73420Sigor@sysoev.ru } 73520Sigor@sysoev.ru 73620Sigor@sysoev.ru file = nxt_list_first(rt->log_files); 73720Sigor@sysoev.ru file->name = file_name.start; 73820Sigor@sysoev.ru 739251Sigor@sysoev.ru slash = ""; 740251Sigor@sysoev.ru n = nxt_strlen(rt->modules); 741251Sigor@sysoev.ru 742251Sigor@sysoev.ru if (n > 1 && rt->modules[n - 1] != '/') { 743251Sigor@sysoev.ru slash = "/"; 744251Sigor@sysoev.ru } 745251Sigor@sysoev.ru 746260Sigor@sysoev.ru ret = nxt_file_name_create(rt->mem_pool, &file_name, "%s%s*.unit.so%Z", 747251Sigor@sysoev.ru rt->modules, slash); 748233Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 749233Sigor@sysoev.ru return NXT_ERROR; 750233Sigor@sysoev.ru } 751233Sigor@sysoev.ru 752233Sigor@sysoev.ru rt->modules = (char *) file_name.start; 753233Sigor@sysoev.ru 754314Svbart@nginx.com slash = ""; 755314Svbart@nginx.com n = nxt_strlen(rt->state); 756314Svbart@nginx.com 757314Svbart@nginx.com if (n > 1 && rt->state[n - 1] != '/') { 758314Svbart@nginx.com slash = "/"; 759314Svbart@nginx.com } 760314Svbart@nginx.com 761314Svbart@nginx.com ret = nxt_file_name_create(rt->mem_pool, &file_name, "%s%sconf.json%Z", 762314Svbart@nginx.com rt->state, slash); 763314Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 764314Svbart@nginx.com return NXT_ERROR; 765314Svbart@nginx.com } 766314Svbart@nginx.com 767314Svbart@nginx.com rt->conf = (char *) file_name.start; 768314Svbart@nginx.com 769314Svbart@nginx.com ret = nxt_file_name_create(rt->mem_pool, &file_name, "%s.tmp%Z", rt->conf); 770314Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 771314Svbart@nginx.com return NXT_ERROR; 772314Svbart@nginx.com } 773314Svbart@nginx.com 774314Svbart@nginx.com rt->conf_tmp = (char *) file_name.start; 775314Svbart@nginx.com 776774Svbart@nginx.com ret = nxt_file_name_create(rt->mem_pool, &file_name, "%s%scerts/%Z", 777774Svbart@nginx.com rt->state, slash); 778774Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 779774Svbart@nginx.com return NXT_ERROR; 780774Svbart@nginx.com } 781774Svbart@nginx.com 782774Svbart@nginx.com ret = mkdir((char *) file_name.start, S_IRWXU); 783774Svbart@nginx.com 784774Svbart@nginx.com if (nxt_fast_path(ret == 0 || nxt_errno == EEXIST)) { 785774Svbart@nginx.com rt->certs.length = file_name.len; 786774Svbart@nginx.com rt->certs.start = file_name.start; 787774Svbart@nginx.com 788774Svbart@nginx.com } else { 789774Svbart@nginx.com nxt_alert(task, "Unable to create certificates storage directory: " 790774Svbart@nginx.com "mkdir(%s) failed %E", file_name.start, nxt_errno); 791774Svbart@nginx.com } 792774Svbart@nginx.com 793234Sigor@sysoev.ru control.length = nxt_strlen(rt->control); 794234Sigor@sysoev.ru control.start = (u_char *) rt->control; 795234Sigor@sysoev.ru 796649Svbart@nginx.com sa = nxt_sockaddr_parse(rt->mem_pool, &control); 797234Sigor@sysoev.ru if (nxt_slow_path(sa == NULL)) { 798234Sigor@sysoev.ru return NXT_ERROR; 799234Sigor@sysoev.ru } 800234Sigor@sysoev.ru 801649Svbart@nginx.com sa->type = SOCK_STREAM; 802649Svbart@nginx.com 803234Sigor@sysoev.ru rt->controller_listen = sa; 804234Sigor@sysoev.ru 805234Sigor@sysoev.ru if (nxt_runtime_controller_socket(task, rt) != NXT_OK) { 806234Sigor@sysoev.ru return NXT_ERROR; 807234Sigor@sysoev.ru } 808234Sigor@sysoev.ru 80920Sigor@sysoev.ru return NXT_OK; 81020Sigor@sysoev.ru } 81120Sigor@sysoev.ru 81220Sigor@sysoev.ru 81320Sigor@sysoev.ru static nxt_int_t 81420Sigor@sysoev.ru nxt_runtime_conf_read_cmd(nxt_task_t *task, nxt_runtime_t *rt) 81520Sigor@sysoev.ru { 816234Sigor@sysoev.ru char *p, **argv; 817234Sigor@sysoev.ru u_char *end; 818234Sigor@sysoev.ru u_char buf[1024]; 81920Sigor@sysoev.ru 820226Svbart@nginx.com static const char version[] = 821259Sigor@sysoev.ru "unit version: " NXT_VERSION "\n" 822221Sigor@sysoev.ru "configured as ./configure" NXT_CONFIGURE_OPTIONS "\n"; 823221Sigor@sysoev.ru 824234Sigor@sysoev.ru static const char no_control[] = 825234Sigor@sysoev.ru "option \"--control\" requires socket address\n"; 826232Sigor@sysoev.ru static const char no_user[] = "option \"--user\" requires username\n"; 827232Sigor@sysoev.ru static const char no_group[] = "option \"--group\" requires group name\n"; 828231Sigor@sysoev.ru static const char no_pid[] = "option \"--pid\" requires filename\n"; 829230Sigor@sysoev.ru static const char no_log[] = "option \"--log\" requires filename\n"; 830233Sigor@sysoev.ru static const char no_modules[] = 831233Sigor@sysoev.ru "option \"--modules\" requires directory\n"; 832314Svbart@nginx.com static const char no_state[] = "option \"--state\" requires directory\n"; 833230Sigor@sysoev.ru 834235Sigor@sysoev.ru static const char help[] = 835235Sigor@sysoev.ru "\n" 836259Sigor@sysoev.ru "unit options:\n" 837235Sigor@sysoev.ru "\n" 838259Sigor@sysoev.ru " --version print unit version and configure options\n" 839235Sigor@sysoev.ru "\n" 840259Sigor@sysoev.ru " --no-daemon run unit in non-daemon mode\n" 841235Sigor@sysoev.ru "\n" 842235Sigor@sysoev.ru " --control ADDRESS set address of control API socket\n" 843235Sigor@sysoev.ru " default: \"" NXT_CONTROL_SOCK "\"\n" 844235Sigor@sysoev.ru "\n" 845239Sigor@sysoev.ru " --pid FILE set pid filename\n" 846235Sigor@sysoev.ru " default: \"" NXT_PID "\"\n" 847235Sigor@sysoev.ru "\n" 848239Sigor@sysoev.ru " --log FILE set log filename\n" 849235Sigor@sysoev.ru " default: \"" NXT_LOG "\"\n" 850235Sigor@sysoev.ru "\n" 851239Sigor@sysoev.ru " --modules DIRECTORY set modules directory name\n" 852235Sigor@sysoev.ru " default: \"" NXT_MODULES "\"\n" 853235Sigor@sysoev.ru "\n" 854314Svbart@nginx.com " --state DIRECTORY set state directory name\n" 855314Svbart@nginx.com " default: \"" NXT_STATE "\"\n" 856314Svbart@nginx.com "\n" 857235Sigor@sysoev.ru " --user USER set non-privileged processes to run" 858235Sigor@sysoev.ru " as specified user\n" 859235Sigor@sysoev.ru " default: \"" NXT_USER "\"\n" 860235Sigor@sysoev.ru "\n" 861235Sigor@sysoev.ru " --group GROUP set non-privileged processes to run" 862235Sigor@sysoev.ru " as specified group\n" 863235Sigor@sysoev.ru " default: "; 864235Sigor@sysoev.ru 865235Sigor@sysoev.ru static const char group[] = "\"" NXT_GROUP "\"\n\n"; 866235Sigor@sysoev.ru static const char primary[] = "user's primary group\n\n"; 867235Sigor@sysoev.ru 868222Sigor@sysoev.ru argv = &nxt_process_argv[1]; 86920Sigor@sysoev.ru 87020Sigor@sysoev.ru while (*argv != NULL) { 87120Sigor@sysoev.ru p = *argv++; 87220Sigor@sysoev.ru 873234Sigor@sysoev.ru if (nxt_strcmp(p, "--control") == 0) { 87420Sigor@sysoev.ru if (*argv == NULL) { 875703Svbart@nginx.com write(STDERR_FILENO, no_control, nxt_length(no_control)); 87620Sigor@sysoev.ru return NXT_ERROR; 87720Sigor@sysoev.ru } 87820Sigor@sysoev.ru 87920Sigor@sysoev.ru p = *argv++; 88020Sigor@sysoev.ru 881234Sigor@sysoev.ru rt->control = p; 88220Sigor@sysoev.ru 88320Sigor@sysoev.ru continue; 88420Sigor@sysoev.ru } 88520Sigor@sysoev.ru 88620Sigor@sysoev.ru if (nxt_strcmp(p, "--user") == 0) { 88720Sigor@sysoev.ru if (*argv == NULL) { 888703Svbart@nginx.com write(STDERR_FILENO, no_user, nxt_length(no_user)); 88920Sigor@sysoev.ru return NXT_ERROR; 89020Sigor@sysoev.ru } 89120Sigor@sysoev.ru 89220Sigor@sysoev.ru p = *argv++; 89320Sigor@sysoev.ru 89420Sigor@sysoev.ru rt->user_cred.user = p; 89520Sigor@sysoev.ru 89620Sigor@sysoev.ru continue; 89720Sigor@sysoev.ru } 89820Sigor@sysoev.ru 89920Sigor@sysoev.ru if (nxt_strcmp(p, "--group") == 0) { 90020Sigor@sysoev.ru if (*argv == NULL) { 901703Svbart@nginx.com write(STDERR_FILENO, no_group, nxt_length(no_group)); 90220Sigor@sysoev.ru return NXT_ERROR; 90320Sigor@sysoev.ru } 90420Sigor@sysoev.ru 90520Sigor@sysoev.ru p = *argv++; 90620Sigor@sysoev.ru 90720Sigor@sysoev.ru rt->group = p; 90820Sigor@sysoev.ru 90920Sigor@sysoev.ru continue; 91020Sigor@sysoev.ru } 91120Sigor@sysoev.ru 91220Sigor@sysoev.ru if (nxt_strcmp(p, "--pid") == 0) { 91320Sigor@sysoev.ru if (*argv == NULL) { 914703Svbart@nginx.com write(STDERR_FILENO, no_pid, nxt_length(no_pid)); 91520Sigor@sysoev.ru return NXT_ERROR; 91620Sigor@sysoev.ru } 91720Sigor@sysoev.ru 91820Sigor@sysoev.ru p = *argv++; 91920Sigor@sysoev.ru 92020Sigor@sysoev.ru rt->pid = p; 92120Sigor@sysoev.ru 92220Sigor@sysoev.ru continue; 92320Sigor@sysoev.ru } 92420Sigor@sysoev.ru 92520Sigor@sysoev.ru if (nxt_strcmp(p, "--log") == 0) { 92620Sigor@sysoev.ru if (*argv == NULL) { 927703Svbart@nginx.com write(STDERR_FILENO, no_log, nxt_length(no_log)); 92820Sigor@sysoev.ru return NXT_ERROR; 92920Sigor@sysoev.ru } 93020Sigor@sysoev.ru 93120Sigor@sysoev.ru p = *argv++; 93220Sigor@sysoev.ru 933230Sigor@sysoev.ru rt->log = p; 93420Sigor@sysoev.ru 93520Sigor@sysoev.ru continue; 93620Sigor@sysoev.ru } 93720Sigor@sysoev.ru 938233Sigor@sysoev.ru if (nxt_strcmp(p, "--modules") == 0) { 939233Sigor@sysoev.ru if (*argv == NULL) { 940703Svbart@nginx.com write(STDERR_FILENO, no_modules, nxt_length(no_modules)); 941233Sigor@sysoev.ru return NXT_ERROR; 942233Sigor@sysoev.ru } 943233Sigor@sysoev.ru 944233Sigor@sysoev.ru p = *argv++; 945233Sigor@sysoev.ru 946233Sigor@sysoev.ru rt->modules = p; 947233Sigor@sysoev.ru 948233Sigor@sysoev.ru continue; 949233Sigor@sysoev.ru } 950233Sigor@sysoev.ru 951314Svbart@nginx.com if (nxt_strcmp(p, "--state") == 0) { 952314Svbart@nginx.com if (*argv == NULL) { 953703Svbart@nginx.com write(STDERR_FILENO, no_state, nxt_length(no_state)); 954314Svbart@nginx.com return NXT_ERROR; 955314Svbart@nginx.com } 956314Svbart@nginx.com 957314Svbart@nginx.com p = *argv++; 958314Svbart@nginx.com 959314Svbart@nginx.com rt->state = p; 960314Svbart@nginx.com 961314Svbart@nginx.com continue; 962314Svbart@nginx.com } 963314Svbart@nginx.com 964219Sigor@sysoev.ru if (nxt_strcmp(p, "--no-daemon") == 0) { 96520Sigor@sysoev.ru rt->daemon = 0; 96620Sigor@sysoev.ru continue; 96720Sigor@sysoev.ru } 968221Sigor@sysoev.ru 969221Sigor@sysoev.ru if (nxt_strcmp(p, "--version") == 0) { 970703Svbart@nginx.com write(STDERR_FILENO, version, nxt_length(version)); 971221Sigor@sysoev.ru exit(0); 972221Sigor@sysoev.ru } 973222Sigor@sysoev.ru 974643Svbart@nginx.com if (nxt_strcmp(p, "--help") == 0 || nxt_strcmp(p, "-h") == 0) { 975703Svbart@nginx.com write(STDOUT_FILENO, help, nxt_length(help)); 976235Sigor@sysoev.ru 977235Sigor@sysoev.ru if (sizeof(NXT_GROUP) == 1) { 978703Svbart@nginx.com write(STDOUT_FILENO, primary, nxt_length(primary)); 979235Sigor@sysoev.ru 980235Sigor@sysoev.ru } else { 981703Svbart@nginx.com write(STDOUT_FILENO, group, nxt_length(group)); 982235Sigor@sysoev.ru } 983235Sigor@sysoev.ru 984235Sigor@sysoev.ru exit(0); 985235Sigor@sysoev.ru } 986235Sigor@sysoev.ru 987643Svbart@nginx.com end = nxt_sprintf(buf, buf + sizeof(buf), "unknown option \"%s\", " 988643Svbart@nginx.com "try \"%s -h\" for available options\n", 989643Svbart@nginx.com p, nxt_process_argv[0]); 990643Svbart@nginx.com 991222Sigor@sysoev.ru write(STDERR_FILENO, buf, end - buf); 992222Sigor@sysoev.ru 993222Sigor@sysoev.ru return NXT_ERROR; 99420Sigor@sysoev.ru } 99520Sigor@sysoev.ru 99620Sigor@sysoev.ru return NXT_OK; 99720Sigor@sysoev.ru } 99820Sigor@sysoev.ru 99920Sigor@sysoev.ru 100020Sigor@sysoev.ru nxt_listen_socket_t * 100120Sigor@sysoev.ru nxt_runtime_listen_socket_add(nxt_runtime_t *rt, nxt_sockaddr_t *sa) 100220Sigor@sysoev.ru { 100365Sigor@sysoev.ru nxt_mp_t *mp; 100420Sigor@sysoev.ru nxt_listen_socket_t *ls; 100520Sigor@sysoev.ru 100620Sigor@sysoev.ru ls = nxt_array_zero_add(rt->listen_sockets); 100720Sigor@sysoev.ru if (ls == NULL) { 100820Sigor@sysoev.ru return NULL; 100920Sigor@sysoev.ru } 101020Sigor@sysoev.ru 101120Sigor@sysoev.ru mp = rt->mem_pool; 101220Sigor@sysoev.ru 101320Sigor@sysoev.ru ls->sockaddr = nxt_sockaddr_create(mp, &sa->u.sockaddr, sa->socklen, 101420Sigor@sysoev.ru sa->length); 101520Sigor@sysoev.ru if (ls->sockaddr == NULL) { 101620Sigor@sysoev.ru return NULL; 101720Sigor@sysoev.ru } 101820Sigor@sysoev.ru 101920Sigor@sysoev.ru ls->sockaddr->type = sa->type; 102020Sigor@sysoev.ru 102120Sigor@sysoev.ru nxt_sockaddr_text(ls->sockaddr); 102220Sigor@sysoev.ru 102320Sigor@sysoev.ru ls->socket = -1; 102420Sigor@sysoev.ru ls->backlog = NXT_LISTEN_BACKLOG; 102520Sigor@sysoev.ru 102620Sigor@sysoev.ru return ls; 102720Sigor@sysoev.ru } 102820Sigor@sysoev.ru 102920Sigor@sysoev.ru 103020Sigor@sysoev.ru static nxt_int_t 103120Sigor@sysoev.ru nxt_runtime_hostname(nxt_task_t *task, nxt_runtime_t *rt) 103220Sigor@sysoev.ru { 103320Sigor@sysoev.ru size_t length; 103420Sigor@sysoev.ru char hostname[NXT_MAXHOSTNAMELEN + 1]; 103520Sigor@sysoev.ru 103620Sigor@sysoev.ru if (gethostname(hostname, NXT_MAXHOSTNAMELEN) != 0) { 1037564Svbart@nginx.com nxt_alert(task, "gethostname() failed %E", nxt_errno); 103820Sigor@sysoev.ru return NXT_ERROR; 103920Sigor@sysoev.ru } 104020Sigor@sysoev.ru 104120Sigor@sysoev.ru /* 104220Sigor@sysoev.ru * Linux gethostname(2): 104320Sigor@sysoev.ru * 104420Sigor@sysoev.ru * If the null-terminated hostname is too large to fit, 104520Sigor@sysoev.ru * then the name is truncated, and no error is returned. 104620Sigor@sysoev.ru * 104720Sigor@sysoev.ru * For this reason an additional byte is reserved in the buffer. 104820Sigor@sysoev.ru */ 104920Sigor@sysoev.ru hostname[NXT_MAXHOSTNAMELEN] = '\0'; 105020Sigor@sysoev.ru 105120Sigor@sysoev.ru length = nxt_strlen(hostname); 105220Sigor@sysoev.ru rt->hostname.length = length; 105320Sigor@sysoev.ru 105465Sigor@sysoev.ru rt->hostname.start = nxt_mp_nget(rt->mem_pool, length); 105520Sigor@sysoev.ru 105620Sigor@sysoev.ru if (rt->hostname.start != NULL) { 105720Sigor@sysoev.ru nxt_memcpy_lowcase(rt->hostname.start, (u_char *) hostname, length); 105820Sigor@sysoev.ru return NXT_OK; 105920Sigor@sysoev.ru } 106020Sigor@sysoev.ru 106120Sigor@sysoev.ru return NXT_ERROR; 106220Sigor@sysoev.ru } 106320Sigor@sysoev.ru 106420Sigor@sysoev.ru 106520Sigor@sysoev.ru static nxt_int_t 106620Sigor@sysoev.ru nxt_runtime_log_files_init(nxt_runtime_t *rt) 106720Sigor@sysoev.ru { 106820Sigor@sysoev.ru nxt_file_t *file; 106920Sigor@sysoev.ru nxt_list_t *log_files; 107020Sigor@sysoev.ru 107120Sigor@sysoev.ru log_files = nxt_list_create(rt->mem_pool, 1, sizeof(nxt_file_t)); 107220Sigor@sysoev.ru 107320Sigor@sysoev.ru if (nxt_fast_path(log_files != NULL)) { 107420Sigor@sysoev.ru rt->log_files = log_files; 107520Sigor@sysoev.ru 1076230Sigor@sysoev.ru /* Preallocate the main log. This allocation cannot fail. */ 107720Sigor@sysoev.ru file = nxt_list_zero_add(log_files); 107820Sigor@sysoev.ru 107920Sigor@sysoev.ru file->fd = NXT_FILE_INVALID; 1080564Svbart@nginx.com file->log_level = NXT_LOG_ALERT; 108120Sigor@sysoev.ru 108220Sigor@sysoev.ru return NXT_OK; 108320Sigor@sysoev.ru } 108420Sigor@sysoev.ru 108520Sigor@sysoev.ru return NXT_ERROR; 108620Sigor@sysoev.ru } 108720Sigor@sysoev.ru 108820Sigor@sysoev.ru 108920Sigor@sysoev.ru nxt_file_t * 109020Sigor@sysoev.ru nxt_runtime_log_file_add(nxt_runtime_t *rt, nxt_str_t *name) 109120Sigor@sysoev.ru { 109220Sigor@sysoev.ru nxt_int_t ret; 109320Sigor@sysoev.ru nxt_file_t *file; 109420Sigor@sysoev.ru nxt_file_name_str_t file_name; 109520Sigor@sysoev.ru 1096230Sigor@sysoev.ru ret = nxt_file_name_create(rt->mem_pool, &file_name, "V%Z", name); 109720Sigor@sysoev.ru 109820Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 109920Sigor@sysoev.ru return NULL; 110020Sigor@sysoev.ru } 110120Sigor@sysoev.ru 110220Sigor@sysoev.ru nxt_list_each(file, rt->log_files) { 110320Sigor@sysoev.ru 110420Sigor@sysoev.ru /* STUB: hardecoded case sensitive/insensitive. */ 110520Sigor@sysoev.ru 110620Sigor@sysoev.ru if (file->name != NULL 110720Sigor@sysoev.ru && nxt_file_name_eq(file->name, file_name.start)) 110820Sigor@sysoev.ru { 110920Sigor@sysoev.ru return file; 111020Sigor@sysoev.ru } 111120Sigor@sysoev.ru 111220Sigor@sysoev.ru } nxt_list_loop; 111320Sigor@sysoev.ru 111420Sigor@sysoev.ru file = nxt_list_zero_add(rt->log_files); 111520Sigor@sysoev.ru 111620Sigor@sysoev.ru if (nxt_slow_path(file == NULL)) { 111720Sigor@sysoev.ru return NULL; 111820Sigor@sysoev.ru } 111920Sigor@sysoev.ru 112020Sigor@sysoev.ru file->fd = NXT_FILE_INVALID; 1121564Svbart@nginx.com file->log_level = NXT_LOG_ALERT; 112220Sigor@sysoev.ru file->name = file_name.start; 112320Sigor@sysoev.ru 112420Sigor@sysoev.ru return file; 112520Sigor@sysoev.ru } 112620Sigor@sysoev.ru 112720Sigor@sysoev.ru 112820Sigor@sysoev.ru static nxt_int_t 112920Sigor@sysoev.ru nxt_runtime_log_files_create(nxt_task_t *task, nxt_runtime_t *rt) 113020Sigor@sysoev.ru { 113120Sigor@sysoev.ru nxt_int_t ret; 113220Sigor@sysoev.ru nxt_file_t *file; 113320Sigor@sysoev.ru 113420Sigor@sysoev.ru nxt_list_each(file, rt->log_files) { 113520Sigor@sysoev.ru 113620Sigor@sysoev.ru ret = nxt_file_open(task, file, O_WRONLY | O_APPEND, O_CREAT, 113720Sigor@sysoev.ru NXT_FILE_OWNER_ACCESS); 113820Sigor@sysoev.ru 113920Sigor@sysoev.ru if (ret != NXT_OK) { 114020Sigor@sysoev.ru return NXT_ERROR; 114120Sigor@sysoev.ru } 114220Sigor@sysoev.ru 114320Sigor@sysoev.ru } nxt_list_loop; 114420Sigor@sysoev.ru 114520Sigor@sysoev.ru file = nxt_list_first(rt->log_files); 114620Sigor@sysoev.ru 114720Sigor@sysoev.ru return nxt_file_stderr(file); 114820Sigor@sysoev.ru } 114920Sigor@sysoev.ru 115020Sigor@sysoev.ru 115120Sigor@sysoev.ru nxt_int_t 115220Sigor@sysoev.ru nxt_runtime_listen_sockets_create(nxt_task_t *task, nxt_runtime_t *rt) 115320Sigor@sysoev.ru { 115420Sigor@sysoev.ru nxt_int_t ret; 115520Sigor@sysoev.ru nxt_uint_t c, p, ncurr, nprev; 115620Sigor@sysoev.ru nxt_listen_socket_t *curr, *prev; 115720Sigor@sysoev.ru 115820Sigor@sysoev.ru curr = rt->listen_sockets->elts; 115920Sigor@sysoev.ru ncurr = rt->listen_sockets->nelts; 116020Sigor@sysoev.ru 116120Sigor@sysoev.ru if (rt->inherited_sockets != NULL) { 116220Sigor@sysoev.ru prev = rt->inherited_sockets->elts; 116320Sigor@sysoev.ru nprev = rt->inherited_sockets->nelts; 116420Sigor@sysoev.ru 116520Sigor@sysoev.ru } else { 116620Sigor@sysoev.ru prev = NULL; 116720Sigor@sysoev.ru nprev = 0; 116820Sigor@sysoev.ru } 116920Sigor@sysoev.ru 117020Sigor@sysoev.ru for (c = 0; c < ncurr; c++) { 117120Sigor@sysoev.ru 117220Sigor@sysoev.ru for (p = 0; p < nprev; p++) { 117320Sigor@sysoev.ru 117420Sigor@sysoev.ru if (nxt_sockaddr_cmp(curr[c].sockaddr, prev[p].sockaddr)) { 117520Sigor@sysoev.ru 117620Sigor@sysoev.ru ret = nxt_listen_socket_update(task, &curr[c], &prev[p]); 117720Sigor@sysoev.ru if (ret != NXT_OK) { 117820Sigor@sysoev.ru return NXT_ERROR; 117920Sigor@sysoev.ru } 118020Sigor@sysoev.ru 118120Sigor@sysoev.ru goto next; 118220Sigor@sysoev.ru } 118320Sigor@sysoev.ru } 118420Sigor@sysoev.ru 118520Sigor@sysoev.ru if (nxt_listen_socket_create(task, &curr[c], 0) != NXT_OK) { 118620Sigor@sysoev.ru return NXT_ERROR; 118720Sigor@sysoev.ru } 118820Sigor@sysoev.ru 118920Sigor@sysoev.ru next: 119020Sigor@sysoev.ru 119120Sigor@sysoev.ru continue; 119220Sigor@sysoev.ru } 119320Sigor@sysoev.ru 119420Sigor@sysoev.ru return NXT_OK; 119520Sigor@sysoev.ru } 119620Sigor@sysoev.ru 119720Sigor@sysoev.ru 119820Sigor@sysoev.ru nxt_int_t 119920Sigor@sysoev.ru nxt_runtime_listen_sockets_enable(nxt_task_t *task, nxt_runtime_t *rt) 120020Sigor@sysoev.ru { 120120Sigor@sysoev.ru nxt_uint_t i, n; 120220Sigor@sysoev.ru nxt_listen_socket_t *ls; 120320Sigor@sysoev.ru 120420Sigor@sysoev.ru ls = rt->listen_sockets->elts; 120520Sigor@sysoev.ru n = rt->listen_sockets->nelts; 120620Sigor@sysoev.ru 120720Sigor@sysoev.ru for (i = 0; i < n; i++) { 120820Sigor@sysoev.ru if (ls[i].flags == NXT_NONBLOCK) { 120954Sigor@sysoev.ru if (nxt_listen_event(task, &ls[i]) == NULL) { 121020Sigor@sysoev.ru return NXT_ERROR; 121120Sigor@sysoev.ru } 121220Sigor@sysoev.ru } 121320Sigor@sysoev.ru } 121420Sigor@sysoev.ru 121520Sigor@sysoev.ru return NXT_OK; 121620Sigor@sysoev.ru } 121720Sigor@sysoev.ru 121820Sigor@sysoev.ru 121920Sigor@sysoev.ru nxt_str_t * 122065Sigor@sysoev.ru nxt_current_directory(nxt_mp_t *mp) 122120Sigor@sysoev.ru { 122220Sigor@sysoev.ru size_t length; 122320Sigor@sysoev.ru u_char *p; 122420Sigor@sysoev.ru nxt_str_t *name; 122520Sigor@sysoev.ru char buf[NXT_MAX_PATH_LEN]; 122620Sigor@sysoev.ru 122720Sigor@sysoev.ru length = nxt_dir_current(buf, NXT_MAX_PATH_LEN); 122820Sigor@sysoev.ru 122920Sigor@sysoev.ru if (nxt_fast_path(length != 0)) { 123020Sigor@sysoev.ru name = nxt_str_alloc(mp, length + 1); 123120Sigor@sysoev.ru 123220Sigor@sysoev.ru if (nxt_fast_path(name != NULL)) { 123320Sigor@sysoev.ru p = nxt_cpymem(name->start, buf, length); 123420Sigor@sysoev.ru *p = '/'; 123520Sigor@sysoev.ru 123620Sigor@sysoev.ru return name; 123720Sigor@sysoev.ru } 123820Sigor@sysoev.ru } 123920Sigor@sysoev.ru 124020Sigor@sysoev.ru return NULL; 124120Sigor@sysoev.ru } 124220Sigor@sysoev.ru 124320Sigor@sysoev.ru 124420Sigor@sysoev.ru static nxt_int_t 124520Sigor@sysoev.ru nxt_runtime_pid_file_create(nxt_task_t *task, nxt_file_name_t *pid_file) 124620Sigor@sysoev.ru { 124720Sigor@sysoev.ru ssize_t length; 124820Sigor@sysoev.ru nxt_int_t n; 124920Sigor@sysoev.ru nxt_file_t file; 1250704Sigor@sysoev.ru u_char pid[NXT_INT64_T_LEN + nxt_length("\n")]; 125120Sigor@sysoev.ru 125220Sigor@sysoev.ru nxt_memzero(&file, sizeof(nxt_file_t)); 125320Sigor@sysoev.ru 125420Sigor@sysoev.ru file.name = pid_file; 125520Sigor@sysoev.ru 125620Sigor@sysoev.ru n = nxt_file_open(task, &file, O_WRONLY, O_CREAT | O_TRUNC, 125720Sigor@sysoev.ru NXT_FILE_DEFAULT_ACCESS); 125820Sigor@sysoev.ru 125920Sigor@sysoev.ru if (n != NXT_OK) { 126020Sigor@sysoev.ru return NXT_ERROR; 126120Sigor@sysoev.ru } 126220Sigor@sysoev.ru 126320Sigor@sysoev.ru length = nxt_sprintf(pid, pid + sizeof(pid), "%PI%n", nxt_pid) - pid; 126420Sigor@sysoev.ru 126520Sigor@sysoev.ru if (nxt_file_write(&file, pid, length, 0) != length) { 126620Sigor@sysoev.ru return NXT_ERROR; 126720Sigor@sysoev.ru } 126820Sigor@sysoev.ru 126920Sigor@sysoev.ru nxt_file_close(task, &file); 127020Sigor@sysoev.ru 127120Sigor@sysoev.ru return NXT_OK; 127220Sigor@sysoev.ru } 127320Sigor@sysoev.ru 127420Sigor@sysoev.ru 127520Sigor@sysoev.ru nxt_process_t * 127642Smax.romanov@nginx.com nxt_runtime_process_new(nxt_runtime_t *rt) 127720Sigor@sysoev.ru { 127820Sigor@sysoev.ru nxt_process_t *process; 127920Sigor@sysoev.ru 128020Sigor@sysoev.ru /* TODO: memory failures. */ 128120Sigor@sysoev.ru 128265Sigor@sysoev.ru process = nxt_mp_zalloc(rt->mem_pool, sizeof(nxt_process_t)); 128342Smax.romanov@nginx.com if (nxt_slow_path(process == NULL)) { 128442Smax.romanov@nginx.com return NULL; 128542Smax.romanov@nginx.com } 128642Smax.romanov@nginx.com 128742Smax.romanov@nginx.com nxt_queue_init(&process->ports); 128842Smax.romanov@nginx.com 1289364Smax.romanov@nginx.com nxt_thread_mutex_create(&process->incoming.mutex); 1290364Smax.romanov@nginx.com nxt_thread_mutex_create(&process->outgoing.mutex); 1291141Smax.romanov@nginx.com nxt_thread_mutex_create(&process->cp_mutex); 129290Smax.romanov@nginx.com 1293349Smax.romanov@nginx.com process->use_count = 1; 1294349Smax.romanov@nginx.com 129542Smax.romanov@nginx.com return process; 129642Smax.romanov@nginx.com } 129742Smax.romanov@nginx.com 129842Smax.romanov@nginx.com 1299196Smax.romanov@nginx.com static void 1300141Smax.romanov@nginx.com nxt_runtime_process_destroy(nxt_runtime_t *rt, nxt_process_t *process) 1301141Smax.romanov@nginx.com { 1302597Sigor@sysoev.ru nxt_port_t *port; 1303341Smax.romanov@nginx.com 1304349Smax.romanov@nginx.com nxt_assert(process->use_count == 0); 1305196Smax.romanov@nginx.com nxt_assert(process->registered == 0); 1306164Smax.romanov@nginx.com 1307364Smax.romanov@nginx.com nxt_port_mmaps_destroy(&process->incoming, 1); 1308364Smax.romanov@nginx.com nxt_port_mmaps_destroy(&process->outgoing, 1); 1309141Smax.romanov@nginx.com 1310597Sigor@sysoev.ru do { 1311597Sigor@sysoev.ru port = nxt_port_hash_retrieve(&process->connected_ports); 1312597Sigor@sysoev.ru 1313597Sigor@sysoev.ru } while (port != NULL); 1314141Smax.romanov@nginx.com 1315364Smax.romanov@nginx.com nxt_thread_mutex_destroy(&process->incoming.mutex); 1316364Smax.romanov@nginx.com nxt_thread_mutex_destroy(&process->outgoing.mutex); 1317141Smax.romanov@nginx.com nxt_thread_mutex_destroy(&process->cp_mutex); 1318141Smax.romanov@nginx.com 1319141Smax.romanov@nginx.com nxt_mp_free(rt->mem_pool, process); 1320141Smax.romanov@nginx.com } 1321141Smax.romanov@nginx.com 1322141Smax.romanov@nginx.com 132342Smax.romanov@nginx.com static nxt_int_t 132442Smax.romanov@nginx.com nxt_runtime_lvlhsh_pid_test(nxt_lvlhsh_query_t *lhq, void *data) 132542Smax.romanov@nginx.com { 132642Smax.romanov@nginx.com nxt_process_t *process; 132742Smax.romanov@nginx.com 132842Smax.romanov@nginx.com process = data; 132942Smax.romanov@nginx.com 1330277Sigor@sysoev.ru if (lhq->key.length == sizeof(nxt_pid_t) 1331277Sigor@sysoev.ru && *(nxt_pid_t *) lhq->key.start == process->pid) 1332277Sigor@sysoev.ru { 133342Smax.romanov@nginx.com return NXT_OK; 133442Smax.romanov@nginx.com } 133542Smax.romanov@nginx.com 133642Smax.romanov@nginx.com return NXT_DECLINED; 133742Smax.romanov@nginx.com } 133842Smax.romanov@nginx.com 133942Smax.romanov@nginx.com static const nxt_lvlhsh_proto_t lvlhsh_processes_proto nxt_aligned(64) = { 134042Smax.romanov@nginx.com NXT_LVLHSH_DEFAULT, 134142Smax.romanov@nginx.com nxt_runtime_lvlhsh_pid_test, 134242Smax.romanov@nginx.com nxt_lvlhsh_alloc, 134342Smax.romanov@nginx.com nxt_lvlhsh_free, 134442Smax.romanov@nginx.com }; 134542Smax.romanov@nginx.com 134642Smax.romanov@nginx.com 1347196Smax.romanov@nginx.com nxt_inline void 1348196Smax.romanov@nginx.com nxt_runtime_process_lhq_pid(nxt_lvlhsh_query_t *lhq, nxt_pid_t *pid) 1349196Smax.romanov@nginx.com { 1350196Smax.romanov@nginx.com lhq->key_hash = nxt_murmur_hash2(pid, sizeof(*pid)); 1351196Smax.romanov@nginx.com lhq->key.length = sizeof(*pid); 1352196Smax.romanov@nginx.com lhq->key.start = (u_char *) pid; 1353196Smax.romanov@nginx.com lhq->proto = &lvlhsh_processes_proto; 1354196Smax.romanov@nginx.com } 1355196Smax.romanov@nginx.com 1356196Smax.romanov@nginx.com 135742Smax.romanov@nginx.com nxt_process_t * 135842Smax.romanov@nginx.com nxt_runtime_process_find(nxt_runtime_t *rt, nxt_pid_t pid) 135942Smax.romanov@nginx.com { 1360196Smax.romanov@nginx.com nxt_process_t *process; 136142Smax.romanov@nginx.com nxt_lvlhsh_query_t lhq; 136242Smax.romanov@nginx.com 1363196Smax.romanov@nginx.com process = NULL; 1364196Smax.romanov@nginx.com 1365196Smax.romanov@nginx.com nxt_runtime_process_lhq_pid(&lhq, &pid); 1366196Smax.romanov@nginx.com 1367196Smax.romanov@nginx.com nxt_thread_mutex_lock(&rt->processes_mutex); 136842Smax.romanov@nginx.com 136942Smax.romanov@nginx.com if (nxt_lvlhsh_find(&rt->processes, &lhq) == NXT_OK) { 1370196Smax.romanov@nginx.com process = lhq.value; 1371196Smax.romanov@nginx.com 1372196Smax.romanov@nginx.com } else { 1373196Smax.romanov@nginx.com nxt_thread_log_debug("process %PI not found", pid); 137442Smax.romanov@nginx.com } 137542Smax.romanov@nginx.com 1376196Smax.romanov@nginx.com nxt_thread_mutex_unlock(&rt->processes_mutex); 137742Smax.romanov@nginx.com 1378196Smax.romanov@nginx.com return process; 137942Smax.romanov@nginx.com } 138042Smax.romanov@nginx.com 138142Smax.romanov@nginx.com 138242Smax.romanov@nginx.com nxt_process_t * 138342Smax.romanov@nginx.com nxt_runtime_process_get(nxt_runtime_t *rt, nxt_pid_t pid) 138442Smax.romanov@nginx.com { 138542Smax.romanov@nginx.com nxt_process_t *process; 138642Smax.romanov@nginx.com nxt_lvlhsh_query_t lhq; 138742Smax.romanov@nginx.com 1388196Smax.romanov@nginx.com nxt_runtime_process_lhq_pid(&lhq, &pid); 1389196Smax.romanov@nginx.com 1390196Smax.romanov@nginx.com nxt_thread_mutex_lock(&rt->processes_mutex); 139142Smax.romanov@nginx.com 139242Smax.romanov@nginx.com if (nxt_lvlhsh_find(&rt->processes, &lhq) == NXT_OK) { 139342Smax.romanov@nginx.com nxt_thread_log_debug("process %PI found", pid); 1394196Smax.romanov@nginx.com 1395196Smax.romanov@nginx.com nxt_thread_mutex_unlock(&rt->processes_mutex); 1396349Smax.romanov@nginx.com 1397349Smax.romanov@nginx.com process = lhq.value; 1398349Smax.romanov@nginx.com process->use_count++; 1399349Smax.romanov@nginx.com 1400349Smax.romanov@nginx.com return process; 140142Smax.romanov@nginx.com } 140242Smax.romanov@nginx.com 140342Smax.romanov@nginx.com process = nxt_runtime_process_new(rt); 140420Sigor@sysoev.ru if (nxt_slow_path(process == NULL)) { 1405382Smax.romanov@nginx.com 1406382Smax.romanov@nginx.com nxt_thread_mutex_unlock(&rt->processes_mutex); 1407382Smax.romanov@nginx.com 140820Sigor@sysoev.ru return NULL; 140920Sigor@sysoev.ru } 141020Sigor@sysoev.ru 141142Smax.romanov@nginx.com process->pid = pid; 141242Smax.romanov@nginx.com 141342Smax.romanov@nginx.com lhq.replace = 0; 141442Smax.romanov@nginx.com lhq.value = process; 141542Smax.romanov@nginx.com lhq.pool = rt->mem_pool; 141642Smax.romanov@nginx.com 141742Smax.romanov@nginx.com switch (nxt_lvlhsh_insert(&rt->processes, &lhq)) { 141842Smax.romanov@nginx.com 141942Smax.romanov@nginx.com case NXT_OK: 142042Smax.romanov@nginx.com if (rt->nprocesses == 0) { 142142Smax.romanov@nginx.com rt->mprocess = process; 142242Smax.romanov@nginx.com } 142342Smax.romanov@nginx.com 142442Smax.romanov@nginx.com rt->nprocesses++; 142542Smax.romanov@nginx.com 1426196Smax.romanov@nginx.com process->registered = 1; 1427196Smax.romanov@nginx.com 142842Smax.romanov@nginx.com nxt_thread_log_debug("process %PI insert", pid); 142942Smax.romanov@nginx.com break; 143042Smax.romanov@nginx.com 143142Smax.romanov@nginx.com default: 143242Smax.romanov@nginx.com nxt_thread_log_debug("process %PI insert failed", pid); 143342Smax.romanov@nginx.com break; 143420Sigor@sysoev.ru } 143520Sigor@sysoev.ru 1436196Smax.romanov@nginx.com nxt_thread_mutex_unlock(&rt->processes_mutex); 1437196Smax.romanov@nginx.com 143820Sigor@sysoev.ru return process; 143920Sigor@sysoev.ru } 144042Smax.romanov@nginx.com 144142Smax.romanov@nginx.com 144242Smax.romanov@nginx.com void 1443343Smax.romanov@nginx.com nxt_runtime_process_add(nxt_task_t *task, nxt_process_t *process) 144442Smax.romanov@nginx.com { 144542Smax.romanov@nginx.com nxt_port_t *port; 1446343Smax.romanov@nginx.com nxt_runtime_t *rt; 144742Smax.romanov@nginx.com nxt_lvlhsh_query_t lhq; 144842Smax.romanov@nginx.com 1449196Smax.romanov@nginx.com nxt_assert(process->registered == 0); 1450196Smax.romanov@nginx.com 1451343Smax.romanov@nginx.com rt = task->thread->runtime; 1452343Smax.romanov@nginx.com 1453196Smax.romanov@nginx.com nxt_runtime_process_lhq_pid(&lhq, &process->pid); 1454196Smax.romanov@nginx.com 145542Smax.romanov@nginx.com lhq.replace = 0; 145642Smax.romanov@nginx.com lhq.value = process; 145742Smax.romanov@nginx.com lhq.pool = rt->mem_pool; 145842Smax.romanov@nginx.com 1459196Smax.romanov@nginx.com nxt_thread_mutex_lock(&rt->processes_mutex); 1460196Smax.romanov@nginx.com 146142Smax.romanov@nginx.com switch (nxt_lvlhsh_insert(&rt->processes, &lhq)) { 146242Smax.romanov@nginx.com 146342Smax.romanov@nginx.com case NXT_OK: 146442Smax.romanov@nginx.com if (rt->nprocesses == 0) { 146542Smax.romanov@nginx.com rt->mprocess = process; 146642Smax.romanov@nginx.com } 146742Smax.romanov@nginx.com 146842Smax.romanov@nginx.com rt->nprocesses++; 146942Smax.romanov@nginx.com 147042Smax.romanov@nginx.com nxt_process_port_each(process, port) { 147142Smax.romanov@nginx.com 1472141Smax.romanov@nginx.com port->pid = process->pid; 1473141Smax.romanov@nginx.com 1474343Smax.romanov@nginx.com nxt_runtime_port_add(task, port); 147542Smax.romanov@nginx.com 147642Smax.romanov@nginx.com } nxt_process_port_loop; 147742Smax.romanov@nginx.com 1478196Smax.romanov@nginx.com process->registered = 1; 1479196Smax.romanov@nginx.com 1480196Smax.romanov@nginx.com nxt_thread_log_debug("process %PI added", process->pid); 148142Smax.romanov@nginx.com break; 148242Smax.romanov@nginx.com 148342Smax.romanov@nginx.com default: 1484196Smax.romanov@nginx.com nxt_thread_log_debug("process %PI failed to add", process->pid); 148542Smax.romanov@nginx.com break; 148642Smax.romanov@nginx.com } 1487196Smax.romanov@nginx.com 1488196Smax.romanov@nginx.com nxt_thread_mutex_unlock(&rt->processes_mutex); 1489196Smax.romanov@nginx.com } 1490196Smax.romanov@nginx.com 1491196Smax.romanov@nginx.com 1492196Smax.romanov@nginx.com static nxt_process_t * 1493196Smax.romanov@nginx.com nxt_runtime_process_remove_pid(nxt_runtime_t *rt, nxt_pid_t pid) 1494196Smax.romanov@nginx.com { 1495196Smax.romanov@nginx.com nxt_process_t *process; 1496196Smax.romanov@nginx.com nxt_lvlhsh_query_t lhq; 1497196Smax.romanov@nginx.com 1498196Smax.romanov@nginx.com process = NULL; 1499196Smax.romanov@nginx.com 1500196Smax.romanov@nginx.com nxt_runtime_process_lhq_pid(&lhq, &pid); 1501196Smax.romanov@nginx.com 1502196Smax.romanov@nginx.com lhq.pool = rt->mem_pool; 1503196Smax.romanov@nginx.com 1504196Smax.romanov@nginx.com nxt_thread_mutex_lock(&rt->processes_mutex); 1505196Smax.romanov@nginx.com 1506196Smax.romanov@nginx.com switch (nxt_lvlhsh_delete(&rt->processes, &lhq)) { 1507196Smax.romanov@nginx.com 1508196Smax.romanov@nginx.com case NXT_OK: 1509196Smax.romanov@nginx.com rt->nprocesses--; 1510196Smax.romanov@nginx.com 1511196Smax.romanov@nginx.com process = lhq.value; 1512196Smax.romanov@nginx.com 1513196Smax.romanov@nginx.com process->registered = 0; 1514196Smax.romanov@nginx.com 1515196Smax.romanov@nginx.com nxt_thread_log_debug("process %PI removed", pid); 1516196Smax.romanov@nginx.com break; 1517196Smax.romanov@nginx.com 1518196Smax.romanov@nginx.com default: 1519196Smax.romanov@nginx.com nxt_thread_log_debug("process %PI remove failed", pid); 1520196Smax.romanov@nginx.com break; 1521196Smax.romanov@nginx.com } 1522196Smax.romanov@nginx.com 1523196Smax.romanov@nginx.com nxt_thread_mutex_unlock(&rt->processes_mutex); 1524196Smax.romanov@nginx.com 1525196Smax.romanov@nginx.com return process; 152642Smax.romanov@nginx.com } 152742Smax.romanov@nginx.com 152842Smax.romanov@nginx.com 152942Smax.romanov@nginx.com void 1530349Smax.romanov@nginx.com nxt_process_use(nxt_task_t *task, nxt_process_t *process, int i) 153142Smax.romanov@nginx.com { 1532343Smax.romanov@nginx.com nxt_runtime_t *rt; 1533343Smax.romanov@nginx.com 1534349Smax.romanov@nginx.com process->use_count += i; 1535349Smax.romanov@nginx.com 1536349Smax.romanov@nginx.com if (process->use_count == 0) { 1537349Smax.romanov@nginx.com rt = task->thread->runtime; 1538349Smax.romanov@nginx.com 1539196Smax.romanov@nginx.com if (process->registered == 1) { 1540196Smax.romanov@nginx.com nxt_runtime_process_remove_pid(rt, process->pid); 1541164Smax.romanov@nginx.com } 1542164Smax.romanov@nginx.com 1543196Smax.romanov@nginx.com nxt_runtime_process_destroy(rt, process); 154442Smax.romanov@nginx.com } 154542Smax.romanov@nginx.com } 154642Smax.romanov@nginx.com 154742Smax.romanov@nginx.com 154842Smax.romanov@nginx.com nxt_process_t * 154942Smax.romanov@nginx.com nxt_runtime_process_first(nxt_runtime_t *rt, nxt_lvlhsh_each_t *lhe) 155042Smax.romanov@nginx.com { 1551598Sigor@sysoev.ru nxt_lvlhsh_each_init(lhe, &lvlhsh_processes_proto); 155242Smax.romanov@nginx.com 155342Smax.romanov@nginx.com return nxt_runtime_process_next(rt, lhe); 155442Smax.romanov@nginx.com } 155542Smax.romanov@nginx.com 155642Smax.romanov@nginx.com 155742Smax.romanov@nginx.com void 1558343Smax.romanov@nginx.com nxt_runtime_port_add(nxt_task_t *task, nxt_port_t *port) 155942Smax.romanov@nginx.com { 1560348Smax.romanov@nginx.com nxt_int_t res; 1561343Smax.romanov@nginx.com nxt_runtime_t *rt; 1562343Smax.romanov@nginx.com 1563343Smax.romanov@nginx.com rt = task->thread->runtime; 1564343Smax.romanov@nginx.com 1565348Smax.romanov@nginx.com res = nxt_port_hash_add(&rt->ports, port); 1566348Smax.romanov@nginx.com 1567348Smax.romanov@nginx.com if (res != NXT_OK) { 1568348Smax.romanov@nginx.com return; 1569348Smax.romanov@nginx.com } 1570141Smax.romanov@nginx.com 1571141Smax.romanov@nginx.com rt->port_by_type[port->type] = port; 1572343Smax.romanov@nginx.com 1573343Smax.romanov@nginx.com nxt_port_use(task, port, 1); 157442Smax.romanov@nginx.com } 157542Smax.romanov@nginx.com 157642Smax.romanov@nginx.com 157742Smax.romanov@nginx.com void 1578343Smax.romanov@nginx.com nxt_runtime_port_remove(nxt_task_t *task, nxt_port_t *port) 157942Smax.romanov@nginx.com { 1580348Smax.romanov@nginx.com nxt_int_t res; 1581343Smax.romanov@nginx.com nxt_runtime_t *rt; 1582343Smax.romanov@nginx.com 1583343Smax.romanov@nginx.com rt = task->thread->runtime; 1584343Smax.romanov@nginx.com 1585348Smax.romanov@nginx.com res = nxt_port_hash_remove(&rt->ports, port); 1586348Smax.romanov@nginx.com 1587348Smax.romanov@nginx.com if (res != NXT_OK) { 1588348Smax.romanov@nginx.com return; 1589348Smax.romanov@nginx.com } 1590125Smax.romanov@nginx.com 1591141Smax.romanov@nginx.com if (rt->port_by_type[port->type] == port) { 1592141Smax.romanov@nginx.com rt->port_by_type[port->type] = NULL; 1593141Smax.romanov@nginx.com } 1594343Smax.romanov@nginx.com 1595343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 159642Smax.romanov@nginx.com } 159742Smax.romanov@nginx.com 159842Smax.romanov@nginx.com 159942Smax.romanov@nginx.com nxt_port_t * 160042Smax.romanov@nginx.com nxt_runtime_port_find(nxt_runtime_t *rt, nxt_pid_t pid, 160142Smax.romanov@nginx.com nxt_port_id_t port_id) 160242Smax.romanov@nginx.com { 160375Smax.romanov@nginx.com return nxt_port_hash_find(&rt->ports, pid, port_id); 160442Smax.romanov@nginx.com } 1605