xref: /unit/src/nxt_process.c (revision 2174:a7fb5d8a9590)
10Sigor@sysoev.ru 
20Sigor@sysoev.ru /*
30Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
40Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
50Sigor@sysoev.ru  */
60Sigor@sysoev.ru 
70Sigor@sysoev.ru #include <nxt_main.h>
80Sigor@sysoev.ru 
91182St.nateldemoura@f5.com #if (NXT_HAVE_CLONE)
101182St.nateldemoura@f5.com #include <nxt_clone.h>
111182St.nateldemoura@f5.com #endif
121182St.nateldemoura@f5.com 
131182St.nateldemoura@f5.com #include <signal.h>
140Sigor@sysoev.ru 
151489St.nateldemoura@f5.com #if (NXT_HAVE_PR_SET_NO_NEW_PRIVS)
161489St.nateldemoura@f5.com #include <sys/prctl.h>
171489St.nateldemoura@f5.com #endif
181489St.nateldemoura@f5.com 
191998St.nateldemoura@f5.com 
201998St.nateldemoura@f5.com #if (NXT_HAVE_CLONE) && (NXT_HAVE_CLONE_NEWPID)
211998St.nateldemoura@f5.com #define nxt_is_pid_isolated(process)                                          \
221998St.nateldemoura@f5.com     nxt_is_clone_flag_set(process->isolation.clone.flags, NEWPID)
231998St.nateldemoura@f5.com #else
241998St.nateldemoura@f5.com #define nxt_is_pid_isolated(process)                                          \
251998St.nateldemoura@f5.com     (0)
261998St.nateldemoura@f5.com #endif
271998St.nateldemoura@f5.com 
281998St.nateldemoura@f5.com 
291997St.nateldemoura@f5.com static nxt_pid_t nxt_process_create(nxt_task_t *task, nxt_process_t *process);
301998St.nateldemoura@f5.com static nxt_int_t nxt_process_do_start(nxt_task_t *task, nxt_process_t *process);
311998St.nateldemoura@f5.com static nxt_int_t nxt_process_whoami(nxt_task_t *task, nxt_process_t *process);
321488St.nateldemoura@f5.com static nxt_int_t nxt_process_setup(nxt_task_t *task, nxt_process_t *process);
331488St.nateldemoura@f5.com static nxt_int_t nxt_process_child_fixup(nxt_task_t *task,
341488St.nateldemoura@f5.com     nxt_process_t *process);
351998St.nateldemoura@f5.com static void nxt_process_whoami_ok(nxt_task_t *task, nxt_port_recv_msg_t *msg,
361998St.nateldemoura@f5.com     void *data);
371998St.nateldemoura@f5.com static void nxt_process_whoami_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
381998St.nateldemoura@f5.com     void *data);
391488St.nateldemoura@f5.com static nxt_int_t nxt_process_send_created(nxt_task_t *task,
401488St.nateldemoura@f5.com     nxt_process_t *process);
411488St.nateldemoura@f5.com static nxt_int_t nxt_process_send_ready(nxt_task_t *task,
421488St.nateldemoura@f5.com     nxt_process_t *process);
431488St.nateldemoura@f5.com static void nxt_process_created_ok(nxt_task_t *task, nxt_port_recv_msg_t *msg,
441488St.nateldemoura@f5.com     void *data);
451488St.nateldemoura@f5.com static void nxt_process_created_error(nxt_task_t *task,
461488St.nateldemoura@f5.com     nxt_port_recv_msg_t *msg, void *data);
471488St.nateldemoura@f5.com 
480Sigor@sysoev.ru 
490Sigor@sysoev.ru /* A cached process pid. */
500Sigor@sysoev.ru nxt_pid_t  nxt_pid;
510Sigor@sysoev.ru 
520Sigor@sysoev.ru /* An original parent process pid. */
530Sigor@sysoev.ru nxt_pid_t  nxt_ppid;
540Sigor@sysoev.ru 
551306St.nateldemoura@f5.com /* A cached process effective uid */
561306St.nateldemoura@f5.com nxt_uid_t  nxt_euid;
571306St.nateldemoura@f5.com 
581306St.nateldemoura@f5.com /* A cached process effective gid */
591306St.nateldemoura@f5.com nxt_gid_t  nxt_egid;
601306St.nateldemoura@f5.com 
612015Smax.romanov@nginx.com uint8_t  nxt_proc_keep_matrix[NXT_PROCESS_MAX][NXT_PROCESS_MAX] = {
621998St.nateldemoura@f5.com     { 1, 1, 1, 1, 1, 1 },
631998St.nateldemoura@f5.com     { 1, 0, 0, 0, 0, 0 },
641998St.nateldemoura@f5.com     { 1, 0, 0, 1, 0, 0 },
651998St.nateldemoura@f5.com     { 1, 0, 1, 1, 1, 1 },
661998St.nateldemoura@f5.com     { 1, 0, 0, 1, 0, 0 },
671998St.nateldemoura@f5.com     { 1, 0, 0, 1, 0, 0 },
68366Smax.romanov@nginx.com };
69366Smax.romanov@nginx.com 
702015Smax.romanov@nginx.com uint8_t  nxt_proc_send_matrix[NXT_PROCESS_MAX][NXT_PROCESS_MAX] = {
712015Smax.romanov@nginx.com     { 1, 1, 1, 1, 1, 1 },
722015Smax.romanov@nginx.com     { 1, 0, 0, 0, 0, 0 },
732015Smax.romanov@nginx.com     { 1, 0, 0, 1, 0, 0 },
742015Smax.romanov@nginx.com     { 1, 0, 1, 1, 1, 1 },
752015Smax.romanov@nginx.com     { 1, 0, 0, 0, 0, 0 },
762015Smax.romanov@nginx.com     { 1, 0, 0, 0, 0, 0 },
772015Smax.romanov@nginx.com };
782015Smax.romanov@nginx.com 
792015Smax.romanov@nginx.com uint8_t  nxt_proc_remove_notify_matrix[NXT_PROCESS_MAX][NXT_PROCESS_MAX] = {
801998St.nateldemoura@f5.com     { 0, 0, 0, 0, 0, 0 },
811998St.nateldemoura@f5.com     { 0, 0, 0, 0, 0, 0 },
821998St.nateldemoura@f5.com     { 0, 0, 0, 1, 0, 0 },
831998St.nateldemoura@f5.com     { 0, 0, 1, 0, 1, 1 },
841998St.nateldemoura@f5.com     { 0, 0, 0, 1, 0, 0 },
851998St.nateldemoura@f5.com     { 1, 0, 0, 1, 0, 0 },
861998St.nateldemoura@f5.com };
871998St.nateldemoura@f5.com 
881998St.nateldemoura@f5.com 
891998St.nateldemoura@f5.com static const nxt_port_handlers_t  nxt_process_whoami_port_handlers = {
901998St.nateldemoura@f5.com     .quit         = nxt_signal_quit_handler,
911998St.nateldemoura@f5.com     .rpc_ready    = nxt_port_rpc_handler,
921998St.nateldemoura@f5.com     .rpc_error    = nxt_port_rpc_handler,
93366Smax.romanov@nginx.com };
940Sigor@sysoev.ru 
951182St.nateldemoura@f5.com 
961997St.nateldemoura@f5.com nxt_process_t *
nxt_process_new(nxt_runtime_t * rt)971997St.nateldemoura@f5.com nxt_process_new(nxt_runtime_t *rt)
981997St.nateldemoura@f5.com {
991997St.nateldemoura@f5.com     nxt_process_t  *process;
1001997St.nateldemoura@f5.com 
1011997St.nateldemoura@f5.com     process = nxt_mp_zalloc(rt->mem_pool, sizeof(nxt_process_t)
1021997St.nateldemoura@f5.com                             + sizeof(nxt_process_init_t));
1031997St.nateldemoura@f5.com 
1041997St.nateldemoura@f5.com     if (nxt_slow_path(process == NULL)) {
1051997St.nateldemoura@f5.com         return NULL;
1061997St.nateldemoura@f5.com     }
1071997St.nateldemoura@f5.com 
1081997St.nateldemoura@f5.com     nxt_queue_init(&process->ports);
1091997St.nateldemoura@f5.com 
1101997St.nateldemoura@f5.com     nxt_thread_mutex_create(&process->incoming.mutex);
1111997St.nateldemoura@f5.com 
1121997St.nateldemoura@f5.com     process->use_count = 1;
1131997St.nateldemoura@f5.com 
1141998St.nateldemoura@f5.com     nxt_queue_init(&process->children);
1151998St.nateldemoura@f5.com 
1161997St.nateldemoura@f5.com     return process;
1171997St.nateldemoura@f5.com }
1181997St.nateldemoura@f5.com 
1191997St.nateldemoura@f5.com 
1201997St.nateldemoura@f5.com void
nxt_process_use(nxt_task_t * task,nxt_process_t * process,int i)1211997St.nateldemoura@f5.com nxt_process_use(nxt_task_t *task, nxt_process_t *process, int i)
1221997St.nateldemoura@f5.com {
1231997St.nateldemoura@f5.com     process->use_count += i;
1241997St.nateldemoura@f5.com 
1251997St.nateldemoura@f5.com     if (process->use_count == 0) {
1261997St.nateldemoura@f5.com         nxt_runtime_process_release(task->thread->runtime, process);
1271997St.nateldemoura@f5.com     }
1281997St.nateldemoura@f5.com }
1291997St.nateldemoura@f5.com 
1301997St.nateldemoura@f5.com 
1311997St.nateldemoura@f5.com nxt_int_t
nxt_process_init_start(nxt_task_t * task,nxt_process_init_t init)1321997St.nateldemoura@f5.com nxt_process_init_start(nxt_task_t *task, nxt_process_init_t init)
1331997St.nateldemoura@f5.com {
1341997St.nateldemoura@f5.com     nxt_int_t           ret;
1351997St.nateldemoura@f5.com     nxt_runtime_t       *rt;
1361997St.nateldemoura@f5.com     nxt_process_t       *process;
1371997St.nateldemoura@f5.com     nxt_process_init_t  *pinit;
1381997St.nateldemoura@f5.com 
1391997St.nateldemoura@f5.com     rt = task->thread->runtime;
1401997St.nateldemoura@f5.com 
1411997St.nateldemoura@f5.com     process = nxt_process_new(rt);
1421997St.nateldemoura@f5.com     if (nxt_slow_path(process == NULL)) {
1431997St.nateldemoura@f5.com         return NXT_ERROR;
1441997St.nateldemoura@f5.com     }
1451997St.nateldemoura@f5.com 
1461998St.nateldemoura@f5.com     process->parent_port = rt->port_by_type[rt->type];
1471998St.nateldemoura@f5.com 
1481997St.nateldemoura@f5.com     process->name = init.name;
1491997St.nateldemoura@f5.com     process->user_cred = &rt->user_cred;
1501997St.nateldemoura@f5.com 
1511997St.nateldemoura@f5.com     pinit = nxt_process_init(process);
1521997St.nateldemoura@f5.com     *pinit = init;
1531997St.nateldemoura@f5.com 
1541997St.nateldemoura@f5.com     ret = nxt_process_start(task, process);
1551997St.nateldemoura@f5.com     if (nxt_slow_path(ret == NXT_ERROR)) {
1561997St.nateldemoura@f5.com         nxt_process_use(task, process, -1);
1571997St.nateldemoura@f5.com     }
1581997St.nateldemoura@f5.com 
1591997St.nateldemoura@f5.com     return ret;
1601997St.nateldemoura@f5.com }
1611997St.nateldemoura@f5.com 
1621997St.nateldemoura@f5.com 
1631997St.nateldemoura@f5.com nxt_int_t
nxt_process_start(nxt_task_t * task,nxt_process_t * process)1641997St.nateldemoura@f5.com nxt_process_start(nxt_task_t *task, nxt_process_t *process)
1651997St.nateldemoura@f5.com {
1661997St.nateldemoura@f5.com     nxt_mp_t            *tmp_mp;
1671997St.nateldemoura@f5.com     nxt_int_t           ret;
1681997St.nateldemoura@f5.com     nxt_pid_t           pid;
1691997St.nateldemoura@f5.com     nxt_port_t          *port;
1701997St.nateldemoura@f5.com     nxt_process_init_t  *init;
1711997St.nateldemoura@f5.com 
1721997St.nateldemoura@f5.com     init = nxt_process_init(process);
1731997St.nateldemoura@f5.com 
1741997St.nateldemoura@f5.com     port = nxt_port_new(task, 0, 0, init->type);
1751997St.nateldemoura@f5.com     if (nxt_slow_path(port == NULL)) {
1761997St.nateldemoura@f5.com         return NXT_ERROR;
1771997St.nateldemoura@f5.com     }
1781997St.nateldemoura@f5.com 
1791997St.nateldemoura@f5.com     nxt_process_port_add(task, process, port);
1801997St.nateldemoura@f5.com 
1811997St.nateldemoura@f5.com     ret = nxt_port_socket_init(task, port, 0);
1821997St.nateldemoura@f5.com     if (nxt_slow_path(ret != NXT_OK)) {
1831997St.nateldemoura@f5.com         goto free_port;
1841997St.nateldemoura@f5.com     }
1851997St.nateldemoura@f5.com 
1861997St.nateldemoura@f5.com     tmp_mp = nxt_mp_create(1024, 128, 256, 32);
1871997St.nateldemoura@f5.com     if (nxt_slow_path(tmp_mp == NULL)) {
1881997St.nateldemoura@f5.com         ret = NXT_ERROR;
1891997St.nateldemoura@f5.com 
1901997St.nateldemoura@f5.com         goto close_port;
1911997St.nateldemoura@f5.com     }
1921997St.nateldemoura@f5.com 
1931997St.nateldemoura@f5.com     if (init->prefork) {
1941997St.nateldemoura@f5.com         ret = init->prefork(task, process, tmp_mp);
1951997St.nateldemoura@f5.com         if (nxt_slow_path(ret != NXT_OK)) {
1961997St.nateldemoura@f5.com             goto free_mempool;
1971997St.nateldemoura@f5.com         }
1981997St.nateldemoura@f5.com     }
1991997St.nateldemoura@f5.com 
2001997St.nateldemoura@f5.com     pid = nxt_process_create(task, process);
2011997St.nateldemoura@f5.com 
2021997St.nateldemoura@f5.com     switch (pid) {
2031997St.nateldemoura@f5.com 
2041997St.nateldemoura@f5.com     case -1:
2051997St.nateldemoura@f5.com         ret = NXT_ERROR;
2061997St.nateldemoura@f5.com         break;
2071997St.nateldemoura@f5.com 
2081997St.nateldemoura@f5.com     case 0:
2091997St.nateldemoura@f5.com         /* The child process: return to the event engine work queue loop. */
2101997St.nateldemoura@f5.com 
2111997St.nateldemoura@f5.com         nxt_process_use(task, process, -1);
2121997St.nateldemoura@f5.com 
2131997St.nateldemoura@f5.com         ret = NXT_AGAIN;
2141997St.nateldemoura@f5.com         break;
2151997St.nateldemoura@f5.com 
2161997St.nateldemoura@f5.com     default:
2171998St.nateldemoura@f5.com         /* The parent process created a new process. */
2181997St.nateldemoura@f5.com 
2191997St.nateldemoura@f5.com         nxt_process_use(task, process, -1);
2201997St.nateldemoura@f5.com 
2211997St.nateldemoura@f5.com         nxt_port_read_close(port);
2221997St.nateldemoura@f5.com         nxt_port_write_enable(task, port);
2231997St.nateldemoura@f5.com 
2241997St.nateldemoura@f5.com         ret = NXT_OK;
2251997St.nateldemoura@f5.com         break;
2261997St.nateldemoura@f5.com     }
2271997St.nateldemoura@f5.com 
2281997St.nateldemoura@f5.com free_mempool:
2291997St.nateldemoura@f5.com 
2301997St.nateldemoura@f5.com     nxt_mp_destroy(tmp_mp);
2311997St.nateldemoura@f5.com 
2321997St.nateldemoura@f5.com close_port:
2331997St.nateldemoura@f5.com 
2341997St.nateldemoura@f5.com     if (nxt_slow_path(ret == NXT_ERROR)) {
2351997St.nateldemoura@f5.com         nxt_port_close(task, port);
2361997St.nateldemoura@f5.com     }
2371997St.nateldemoura@f5.com 
2381997St.nateldemoura@f5.com free_port:
2391997St.nateldemoura@f5.com 
2401997St.nateldemoura@f5.com     nxt_port_use(task, port, -1);
2411997St.nateldemoura@f5.com 
2421997St.nateldemoura@f5.com     return ret;
2431997St.nateldemoura@f5.com }
2441997St.nateldemoura@f5.com 
2451997St.nateldemoura@f5.com 
2461182St.nateldemoura@f5.com static nxt_int_t
nxt_process_child_fixup(nxt_task_t * task,nxt_process_t * process)2471488St.nateldemoura@f5.com nxt_process_child_fixup(nxt_task_t *task, nxt_process_t *process)
2481210Svbart@nginx.com {
2491182St.nateldemoura@f5.com     nxt_process_t       *p;
2501182St.nateldemoura@f5.com     nxt_runtime_t       *rt;
2511182St.nateldemoura@f5.com     nxt_process_init_t  *init;
2521182St.nateldemoura@f5.com     nxt_process_type_t  ptype;
2531182St.nateldemoura@f5.com 
2541488St.nateldemoura@f5.com     init = nxt_process_init(process);
2551182St.nateldemoura@f5.com 
2561998St.nateldemoura@f5.com     nxt_ppid = nxt_pid;
2571998St.nateldemoura@f5.com 
2581488St.nateldemoura@f5.com     nxt_pid = nxt_getpid();
2591182St.nateldemoura@f5.com 
2601488St.nateldemoura@f5.com     process->pid = nxt_pid;
2611998St.nateldemoura@f5.com     process->isolated_pid = nxt_pid;
2621182St.nateldemoura@f5.com 
2631182St.nateldemoura@f5.com     /* Clean inherited cached thread tid. */
2641182St.nateldemoura@f5.com     task->thread->tid = 0;
2651182St.nateldemoura@f5.com 
2661182St.nateldemoura@f5.com     ptype = init->type;
2671182St.nateldemoura@f5.com 
2681182St.nateldemoura@f5.com     nxt_port_reset_next_id();
2691182St.nateldemoura@f5.com 
2701182St.nateldemoura@f5.com     nxt_event_engine_thread_adopt(task->thread->engine);
2711182St.nateldemoura@f5.com 
2721488St.nateldemoura@f5.com     rt = task->thread->runtime;
2731488St.nateldemoura@f5.com 
2741182St.nateldemoura@f5.com     /* Remove not ready processes. */
2751182St.nateldemoura@f5.com     nxt_runtime_process_each(rt, p) {
2761182St.nateldemoura@f5.com 
2772015Smax.romanov@nginx.com         if (nxt_proc_keep_matrix[ptype][nxt_process_type(p)] == 0
2781998St.nateldemoura@f5.com             && p->pid != nxt_ppid) /* Always keep parent's port. */
2791998St.nateldemoura@f5.com         {
2801182St.nateldemoura@f5.com             nxt_debug(task, "remove not required process %PI", p->pid);
2811182St.nateldemoura@f5.com 
2821182St.nateldemoura@f5.com             nxt_process_close_ports(task, p);
2831182St.nateldemoura@f5.com 
2841182St.nateldemoura@f5.com             continue;
2851182St.nateldemoura@f5.com         }
2861182St.nateldemoura@f5.com 
2871488St.nateldemoura@f5.com         if (p->state != NXT_PROCESS_STATE_READY) {
2881182St.nateldemoura@f5.com             nxt_debug(task, "remove not ready process %PI", p->pid);
2891182St.nateldemoura@f5.com 
2901182St.nateldemoura@f5.com             nxt_process_close_ports(task, p);
2911182St.nateldemoura@f5.com 
2921182St.nateldemoura@f5.com             continue;
2931182St.nateldemoura@f5.com         }
2941182St.nateldemoura@f5.com 
2951182St.nateldemoura@f5.com         nxt_port_mmaps_destroy(&p->incoming, 0);
2961182St.nateldemoura@f5.com 
2971182St.nateldemoura@f5.com     } nxt_runtime_process_loop;
2981182St.nateldemoura@f5.com 
299*2174Smax.romanov@gmail.com     if (init->siblings != NULL) {
300*2174Smax.romanov@gmail.com         nxt_queue_each(p, init->siblings, nxt_process_t, link) {
301*2174Smax.romanov@gmail.com 
302*2174Smax.romanov@gmail.com             nxt_debug(task, "remove sibling process %PI", p->pid);
303*2174Smax.romanov@gmail.com 
304*2174Smax.romanov@gmail.com             nxt_process_close_ports(task, p);
305*2174Smax.romanov@gmail.com 
306*2174Smax.romanov@gmail.com         } nxt_queue_loop;
307*2174Smax.romanov@gmail.com     }
308*2174Smax.romanov@gmail.com 
3091182St.nateldemoura@f5.com     return NXT_OK;
3101182St.nateldemoura@f5.com }
3111182St.nateldemoura@f5.com 
3121182St.nateldemoura@f5.com 
3131997St.nateldemoura@f5.com static nxt_pid_t
nxt_process_create(nxt_task_t * task,nxt_process_t * process)31478Smax.romanov@nginx.com nxt_process_create(nxt_task_t *task, nxt_process_t *process)
3150Sigor@sysoev.ru {
316*2174Smax.romanov@gmail.com     nxt_int_t      ret;
317*2174Smax.romanov@gmail.com     nxt_pid_t      pid;
318*2174Smax.romanov@gmail.com     nxt_runtime_t  *rt;
3190Sigor@sysoev.ru 
3201182St.nateldemoura@f5.com #if (NXT_HAVE_CLONE)
3211488St.nateldemoura@f5.com     pid = nxt_clone(SIGCHLD | process->isolation.clone.flags);
3221210Svbart@nginx.com     if (nxt_slow_path(pid < 0)) {
3231488St.nateldemoura@f5.com         nxt_alert(task, "clone() failed for %s %E", process->name, nxt_errno);
3241488St.nateldemoura@f5.com         return pid;
3251210Svbart@nginx.com     }
3261182St.nateldemoura@f5.com #else
3271182St.nateldemoura@f5.com     pid = fork();
3281182St.nateldemoura@f5.com     if (nxt_slow_path(pid < 0)) {
3291488St.nateldemoura@f5.com         nxt_alert(task, "fork() failed for %s %E", process->name, nxt_errno);
3301488St.nateldemoura@f5.com         return pid;
3311210Svbart@nginx.com     }
3321182St.nateldemoura@f5.com #endif
333141Smax.romanov@nginx.com 
3341182St.nateldemoura@f5.com     if (pid == 0) {
3351182St.nateldemoura@f5.com         /* Child. */
336277Sigor@sysoev.ru 
3371488St.nateldemoura@f5.com         ret = nxt_process_child_fixup(task, process);
3381488St.nateldemoura@f5.com         if (nxt_slow_path(ret != NXT_OK)) {
3391488St.nateldemoura@f5.com             nxt_process_quit(task, 1);
3401488St.nateldemoura@f5.com             return -1;
3411182St.nateldemoura@f5.com         }
342366Smax.romanov@nginx.com 
3431998St.nateldemoura@f5.com         ret = nxt_process_setup(task, process);
3441998St.nateldemoura@f5.com         if (nxt_slow_path(ret != NXT_OK)) {
3451488St.nateldemoura@f5.com             nxt_process_quit(task, 1);
3461210Svbart@nginx.com         }
3471210Svbart@nginx.com 
3481182St.nateldemoura@f5.com         /*
3491182St.nateldemoura@f5.com          * Explicitly return 0 to notice the caller function this is the child.
3501182St.nateldemoura@f5.com          * The caller must return to the event engine work queue loop.
3511182St.nateldemoura@f5.com          */
3521182St.nateldemoura@f5.com         return 0;
3531182St.nateldemoura@f5.com     }
35478Smax.romanov@nginx.com 
3551182St.nateldemoura@f5.com     /* Parent. */
35678Smax.romanov@nginx.com 
3571182St.nateldemoura@f5.com #if (NXT_HAVE_CLONE)
3581488St.nateldemoura@f5.com     nxt_debug(task, "clone(%s): %PI", process->name, pid);
3591182St.nateldemoura@f5.com #else
3601488St.nateldemoura@f5.com     nxt_debug(task, "fork(%s): %PI", process->name, pid);
3611182St.nateldemoura@f5.com #endif
3621182St.nateldemoura@f5.com 
3631182St.nateldemoura@f5.com     process->pid = pid;
3641998St.nateldemoura@f5.com     process->isolated_pid = pid;
3651182St.nateldemoura@f5.com 
366*2174Smax.romanov@gmail.com     rt = task->thread->runtime;
367*2174Smax.romanov@gmail.com 
368*2174Smax.romanov@gmail.com     if (rt->is_pid_isolated) {
369*2174Smax.romanov@gmail.com         /*
370*2174Smax.romanov@gmail.com          * Do not register process in runtime with isolated pid.
371*2174Smax.romanov@gmail.com          * Only global pid can be the key to avoid clash.
372*2174Smax.romanov@gmail.com          */
373*2174Smax.romanov@gmail.com         nxt_assert(!nxt_queue_is_empty(&process->ports));
374*2174Smax.romanov@gmail.com 
375*2174Smax.romanov@gmail.com         nxt_port_use(task, nxt_process_port_first(process), 1);
376*2174Smax.romanov@gmail.com 
377*2174Smax.romanov@gmail.com     } else {
378*2174Smax.romanov@gmail.com         nxt_runtime_process_add(task, process);
379*2174Smax.romanov@gmail.com     }
3801182St.nateldemoura@f5.com 
3811210Svbart@nginx.com     return pid;
3820Sigor@sysoev.ru }
3830Sigor@sysoev.ru 
3840Sigor@sysoev.ru 
3851488St.nateldemoura@f5.com static nxt_int_t
nxt_process_setup(nxt_task_t * task,nxt_process_t * process)3861488St.nateldemoura@f5.com nxt_process_setup(nxt_task_t *task, nxt_process_t *process)
38720Sigor@sysoev.ru {
3881488St.nateldemoura@f5.com     nxt_int_t                    ret;
38920Sigor@sysoev.ru     nxt_thread_t                 *thread;
39020Sigor@sysoev.ru     nxt_runtime_t                *rt;
391141Smax.romanov@nginx.com     nxt_process_init_t           *init;
39220Sigor@sysoev.ru     nxt_event_engine_t           *engine;
39320Sigor@sysoev.ru     const nxt_event_interface_t  *interface;
39420Sigor@sysoev.ru 
3951488St.nateldemoura@f5.com     init = nxt_process_init(process);
39620Sigor@sysoev.ru 
3971488St.nateldemoura@f5.com     nxt_debug(task, "%s setup", process->name);
398141Smax.romanov@nginx.com 
3991488St.nateldemoura@f5.com     nxt_process_title(task, "unit: %s", process->name);
40020Sigor@sysoev.ru 
401138Sigor@sysoev.ru     thread = task->thread;
4021182St.nateldemoura@f5.com     rt     = thread->runtime;
403138Sigor@sysoev.ru 
404138Sigor@sysoev.ru     nxt_random_init(&thread->random);
40520Sigor@sysoev.ru 
406696Sigor@sysoev.ru     rt->type = init->type;
40720Sigor@sysoev.ru 
40820Sigor@sysoev.ru     engine = thread->engine;
40920Sigor@sysoev.ru 
410240Sigor@sysoev.ru     /* Update inherited main process event engine and signals processing. */
411141Smax.romanov@nginx.com     engine->signals->sigev = init->signals;
41220Sigor@sysoev.ru 
41320Sigor@sysoev.ru     interface = nxt_service_get(rt->services, "engine", rt->engine);
414141Smax.romanov@nginx.com     if (nxt_slow_path(interface == NULL)) {
4151488St.nateldemoura@f5.com         return NXT_ERROR;
41620Sigor@sysoev.ru     }
41720Sigor@sysoev.ru 
41820Sigor@sysoev.ru     if (nxt_event_engine_change(engine, interface, rt->batch) != NXT_OK) {
4191488St.nateldemoura@f5.com         return NXT_ERROR;
42020Sigor@sysoev.ru     }
42120Sigor@sysoev.ru 
42220Sigor@sysoev.ru     ret = nxt_runtime_thread_pool_create(thread, rt, rt->auxiliary_threads,
42320Sigor@sysoev.ru                                          60000 * 1000000LL);
424141Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
4251488St.nateldemoura@f5.com         return NXT_ERROR;
42620Sigor@sysoev.ru     }
42720Sigor@sysoev.ru 
4281998St.nateldemoura@f5.com     nxt_port_read_close(process->parent_port);
4291998St.nateldemoura@f5.com     nxt_port_write_enable(task, process->parent_port);
4301998St.nateldemoura@f5.com 
4311998St.nateldemoura@f5.com     /*
4321998St.nateldemoura@f5.com      * If the parent process is already isolated, rt->pid_isolation is already
4331998St.nateldemoura@f5.com      * set to 1 at this point.
4341998St.nateldemoura@f5.com      */
4351998St.nateldemoura@f5.com     if (nxt_is_pid_isolated(process)) {
4361998St.nateldemoura@f5.com         rt->is_pid_isolated = 1;
4371998St.nateldemoura@f5.com     }
4381998St.nateldemoura@f5.com 
4391998St.nateldemoura@f5.com     if (rt->is_pid_isolated
4401998St.nateldemoura@f5.com         || process->parent_port != rt->port_by_type[NXT_PROCESS_MAIN])
4411998St.nateldemoura@f5.com     {
4421998St.nateldemoura@f5.com         ret = nxt_process_whoami(task, process);
443141Smax.romanov@nginx.com 
4441998St.nateldemoura@f5.com     } else {
4451998St.nateldemoura@f5.com         ret = nxt_process_do_start(task, process);
4461998St.nateldemoura@f5.com     }
4471998St.nateldemoura@f5.com 
4481998St.nateldemoura@f5.com     return ret;
4491998St.nateldemoura@f5.com }
4501998St.nateldemoura@f5.com 
451141Smax.romanov@nginx.com 
4521998St.nateldemoura@f5.com static nxt_int_t
nxt_process_do_start(nxt_task_t * task,nxt_process_t * process)4531998St.nateldemoura@f5.com nxt_process_do_start(nxt_task_t *task, nxt_process_t *process)
4541998St.nateldemoura@f5.com {
4551998St.nateldemoura@f5.com     nxt_int_t           ret;
4561998St.nateldemoura@f5.com     nxt_port_t          *port;
4571998St.nateldemoura@f5.com     nxt_process_init_t  *init;
4581998St.nateldemoura@f5.com 
4591998St.nateldemoura@f5.com     nxt_runtime_process_add(task, process);
4601998St.nateldemoura@f5.com 
4611998St.nateldemoura@f5.com     init = nxt_process_init(process);
462141Smax.romanov@nginx.com     port = nxt_process_port_first(process);
463141Smax.romanov@nginx.com 
4641488St.nateldemoura@f5.com     nxt_port_enable(task, port, init->port_handlers);
4651488St.nateldemoura@f5.com 
4661488St.nateldemoura@f5.com     ret = init->setup(task, process);
4671488St.nateldemoura@f5.com     if (nxt_slow_path(ret != NXT_OK)) {
4681488St.nateldemoura@f5.com         return NXT_ERROR;
4691488St.nateldemoura@f5.com     }
4701488St.nateldemoura@f5.com 
4711488St.nateldemoura@f5.com     switch (process->state) {
4721488St.nateldemoura@f5.com 
4731488St.nateldemoura@f5.com     case NXT_PROCESS_STATE_CREATED:
4741488St.nateldemoura@f5.com         ret = nxt_process_send_created(task, process);
4751488St.nateldemoura@f5.com         break;
4761488St.nateldemoura@f5.com 
4771488St.nateldemoura@f5.com     case NXT_PROCESS_STATE_READY:
4781488St.nateldemoura@f5.com         ret = nxt_process_send_ready(task, process);
4791488St.nateldemoura@f5.com 
4801488St.nateldemoura@f5.com         if (nxt_slow_path(ret != NXT_OK)) {
4811488St.nateldemoura@f5.com             break;
4821488St.nateldemoura@f5.com         }
4831488St.nateldemoura@f5.com 
4841488St.nateldemoura@f5.com         ret = init->start(task, &process->data);
4851668Smax.romanov@nginx.com 
4861668Smax.romanov@nginx.com         nxt_port_write_close(port);
4871668Smax.romanov@nginx.com 
4881488St.nateldemoura@f5.com         break;
4891488St.nateldemoura@f5.com 
4901488St.nateldemoura@f5.com     default:
4911488St.nateldemoura@f5.com         nxt_assert(0);
4921488St.nateldemoura@f5.com     }
4931488St.nateldemoura@f5.com 
4941488St.nateldemoura@f5.com     if (nxt_slow_path(ret != NXT_OK)) {
4951488St.nateldemoura@f5.com         nxt_alert(task, "%s failed to start", process->name);
4961488St.nateldemoura@f5.com     }
4971488St.nateldemoura@f5.com 
4981488St.nateldemoura@f5.com     return ret;
4991488St.nateldemoura@f5.com }
5001488St.nateldemoura@f5.com 
5011488St.nateldemoura@f5.com 
5021488St.nateldemoura@f5.com static nxt_int_t
nxt_process_whoami(nxt_task_t * task,nxt_process_t * process)5031998St.nateldemoura@f5.com nxt_process_whoami(nxt_task_t *task, nxt_process_t *process)
5041998St.nateldemoura@f5.com {
5051998St.nateldemoura@f5.com     uint32_t       stream;
5061998St.nateldemoura@f5.com     nxt_fd_t       fd;
5071998St.nateldemoura@f5.com     nxt_buf_t      *buf;
5081998St.nateldemoura@f5.com     nxt_int_t      ret;
5091998St.nateldemoura@f5.com     nxt_port_t     *my_port, *main_port;
5101998St.nateldemoura@f5.com     nxt_runtime_t  *rt;
5111998St.nateldemoura@f5.com 
5121998St.nateldemoura@f5.com     rt = task->thread->runtime;
5131998St.nateldemoura@f5.com 
5141998St.nateldemoura@f5.com     my_port = nxt_process_port_first(process);
5151998St.nateldemoura@f5.com     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
5161998St.nateldemoura@f5.com 
5171998St.nateldemoura@f5.com     nxt_assert(my_port != NULL && main_port != NULL);
5181998St.nateldemoura@f5.com 
5191998St.nateldemoura@f5.com     nxt_port_enable(task, my_port, &nxt_process_whoami_port_handlers);
5201998St.nateldemoura@f5.com 
5211998St.nateldemoura@f5.com     buf = nxt_buf_mem_alloc(main_port->mem_pool, sizeof(nxt_pid_t), 0);
5221998St.nateldemoura@f5.com     if (nxt_slow_path(buf == NULL)) {
5231998St.nateldemoura@f5.com         return NXT_ERROR;
5241998St.nateldemoura@f5.com     }
5251998St.nateldemoura@f5.com 
5261998St.nateldemoura@f5.com     buf->mem.free = nxt_cpymem(buf->mem.free, &nxt_ppid, sizeof(nxt_pid_t));
5271998St.nateldemoura@f5.com 
5281998St.nateldemoura@f5.com     stream = nxt_port_rpc_register_handler(task, my_port,
5291998St.nateldemoura@f5.com                                            nxt_process_whoami_ok,
5301998St.nateldemoura@f5.com                                            nxt_process_whoami_error,
5311998St.nateldemoura@f5.com                                            main_port->pid, process);
5321998St.nateldemoura@f5.com     if (nxt_slow_path(stream == 0)) {
5331998St.nateldemoura@f5.com         nxt_mp_free(main_port->mem_pool, buf);
5341998St.nateldemoura@f5.com 
5351998St.nateldemoura@f5.com         return NXT_ERROR;
5361998St.nateldemoura@f5.com     }
5371998St.nateldemoura@f5.com 
5381998St.nateldemoura@f5.com     fd = (process->parent_port != main_port) ? my_port->pair[1] : -1;
5391998St.nateldemoura@f5.com 
5401998St.nateldemoura@f5.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_WHOAMI,
5411998St.nateldemoura@f5.com                                 fd, stream, my_port->id, buf);
5421998St.nateldemoura@f5.com 
5431998St.nateldemoura@f5.com     if (nxt_slow_path(ret != NXT_OK)) {
5441998St.nateldemoura@f5.com         nxt_alert(task, "%s failed to send WHOAMI message", process->name);
5451998St.nateldemoura@f5.com         nxt_port_rpc_cancel(task, my_port, stream);
5461998St.nateldemoura@f5.com         nxt_mp_free(main_port->mem_pool, buf);
5471998St.nateldemoura@f5.com 
5481998St.nateldemoura@f5.com         return NXT_ERROR;
5491998St.nateldemoura@f5.com     }
5501998St.nateldemoura@f5.com 
5511998St.nateldemoura@f5.com     return NXT_OK;
5521998St.nateldemoura@f5.com }
5531998St.nateldemoura@f5.com 
5541998St.nateldemoura@f5.com 
5551998St.nateldemoura@f5.com static void
nxt_process_whoami_ok(nxt_task_t * task,nxt_port_recv_msg_t * msg,void * data)5561998St.nateldemoura@f5.com nxt_process_whoami_ok(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data)
5571998St.nateldemoura@f5.com {
5581998St.nateldemoura@f5.com     nxt_pid_t      pid, isolated_pid;
5591998St.nateldemoura@f5.com     nxt_buf_t      *buf;
5601998St.nateldemoura@f5.com     nxt_port_t     *port;
5611998St.nateldemoura@f5.com     nxt_process_t  *process;
5621998St.nateldemoura@f5.com     nxt_runtime_t  *rt;
5631998St.nateldemoura@f5.com 
5641998St.nateldemoura@f5.com     process = data;
5651998St.nateldemoura@f5.com 
5661998St.nateldemoura@f5.com     buf = msg->buf;
5671998St.nateldemoura@f5.com 
5681998St.nateldemoura@f5.com     nxt_assert(nxt_buf_used_size(buf) == sizeof(nxt_pid_t));
5691998St.nateldemoura@f5.com 
5701998St.nateldemoura@f5.com     nxt_memcpy(&pid, buf->mem.pos, sizeof(nxt_pid_t));
5711998St.nateldemoura@f5.com 
5721998St.nateldemoura@f5.com     isolated_pid = nxt_pid;
5731998St.nateldemoura@f5.com 
5741998St.nateldemoura@f5.com     if (isolated_pid != pid) {
5751998St.nateldemoura@f5.com         nxt_pid = pid;
5761998St.nateldemoura@f5.com         process->pid = pid;
5771998St.nateldemoura@f5.com 
5781998St.nateldemoura@f5.com         nxt_process_port_each(process, port) {
5791998St.nateldemoura@f5.com             port->pid = pid;
5801998St.nateldemoura@f5.com         } nxt_process_port_loop;
5811998St.nateldemoura@f5.com     }
5821998St.nateldemoura@f5.com 
5831998St.nateldemoura@f5.com     rt = task->thread->runtime;
5841998St.nateldemoura@f5.com 
5851998St.nateldemoura@f5.com     if (process->parent_port != rt->port_by_type[NXT_PROCESS_MAIN]) {
5861998St.nateldemoura@f5.com         port = process->parent_port;
5871998St.nateldemoura@f5.com 
5881998St.nateldemoura@f5.com         (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_PROCESS_CREATED,
5891998St.nateldemoura@f5.com                                      -1, 0, 0, NULL);
5901998St.nateldemoura@f5.com 
5911998St.nateldemoura@f5.com         nxt_log(task, NXT_LOG_INFO, "%s started", process->name);
5921998St.nateldemoura@f5.com     }
5931998St.nateldemoura@f5.com 
5941998St.nateldemoura@f5.com     if (nxt_slow_path(nxt_process_do_start(task, process) != NXT_OK)) {
5951998St.nateldemoura@f5.com         nxt_process_quit(task, 1);
5961998St.nateldemoura@f5.com     }
5971998St.nateldemoura@f5.com }
5981998St.nateldemoura@f5.com 
5991998St.nateldemoura@f5.com 
6001998St.nateldemoura@f5.com static void
nxt_process_whoami_error(nxt_task_t * task,nxt_port_recv_msg_t * msg,void * data)6011998St.nateldemoura@f5.com nxt_process_whoami_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data)
6021998St.nateldemoura@f5.com {
6031998St.nateldemoura@f5.com     nxt_alert(task, "WHOAMI error");
6041998St.nateldemoura@f5.com 
6051998St.nateldemoura@f5.com     nxt_process_quit(task, 1);
6061998St.nateldemoura@f5.com }
6071998St.nateldemoura@f5.com 
6081998St.nateldemoura@f5.com 
6091998St.nateldemoura@f5.com static nxt_int_t
nxt_process_send_created(nxt_task_t * task,nxt_process_t * process)6101488St.nateldemoura@f5.com nxt_process_send_created(nxt_task_t *task, nxt_process_t *process)
6111488St.nateldemoura@f5.com {
6121488St.nateldemoura@f5.com     uint32_t            stream;
6131488St.nateldemoura@f5.com     nxt_int_t           ret;
6141488St.nateldemoura@f5.com     nxt_port_t          *my_port, *main_port;
6151488St.nateldemoura@f5.com     nxt_runtime_t       *rt;
61620Sigor@sysoev.ru 
6171488St.nateldemoura@f5.com     nxt_assert(process->state == NXT_PROCESS_STATE_CREATED);
6181488St.nateldemoura@f5.com 
6191488St.nateldemoura@f5.com     rt = task->thread->runtime;
6201488St.nateldemoura@f5.com 
6211488St.nateldemoura@f5.com     my_port = nxt_process_port_first(process);
6221488St.nateldemoura@f5.com     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
6231488St.nateldemoura@f5.com 
6241488St.nateldemoura@f5.com     nxt_assert(my_port != NULL && main_port != NULL);
6251488St.nateldemoura@f5.com 
6261488St.nateldemoura@f5.com     stream = nxt_port_rpc_register_handler(task, my_port,
6271488St.nateldemoura@f5.com                                            nxt_process_created_ok,
6281488St.nateldemoura@f5.com                                            nxt_process_created_error,
6291488St.nateldemoura@f5.com                                            main_port->pid, process);
6301488St.nateldemoura@f5.com 
6311488St.nateldemoura@f5.com     if (nxt_slow_path(stream == 0)) {
6321488St.nateldemoura@f5.com         return NXT_ERROR;
6331488St.nateldemoura@f5.com     }
6341488St.nateldemoura@f5.com 
6351488St.nateldemoura@f5.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_PROCESS_CREATED,
6361488St.nateldemoura@f5.com                                 -1, stream, my_port->id, NULL);
6371488St.nateldemoura@f5.com 
6381488St.nateldemoura@f5.com     if (nxt_slow_path(ret != NXT_OK)) {
6391488St.nateldemoura@f5.com         nxt_alert(task, "%s failed to send CREATED message", process->name);
6401488St.nateldemoura@f5.com         nxt_port_rpc_cancel(task, my_port, stream);
6411488St.nateldemoura@f5.com         return NXT_ERROR;
6421488St.nateldemoura@f5.com     }
6431488St.nateldemoura@f5.com 
6441488St.nateldemoura@f5.com     nxt_debug(task, "%s created", process->name);
6451488St.nateldemoura@f5.com 
6461488St.nateldemoura@f5.com     return NXT_OK;
6471488St.nateldemoura@f5.com }
6481488St.nateldemoura@f5.com 
6491488St.nateldemoura@f5.com 
6501488St.nateldemoura@f5.com static void
nxt_process_created_ok(nxt_task_t * task,nxt_port_recv_msg_t * msg,void * data)6511488St.nateldemoura@f5.com nxt_process_created_ok(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data)
6521488St.nateldemoura@f5.com {
6531488St.nateldemoura@f5.com     nxt_int_t           ret;
6541488St.nateldemoura@f5.com     nxt_process_t       *process;
6551488St.nateldemoura@f5.com     nxt_process_init_t  *init;
6561488St.nateldemoura@f5.com 
6571488St.nateldemoura@f5.com     process = data;
6581998St.nateldemoura@f5.com 
6591998St.nateldemoura@f5.com     process->state = NXT_PROCESS_STATE_READY;
6601998St.nateldemoura@f5.com 
6611488St.nateldemoura@f5.com     init = nxt_process_init(process);
6621488St.nateldemoura@f5.com 
6631488St.nateldemoura@f5.com     ret = nxt_process_apply_creds(task, process);
664141Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
665141Smax.romanov@nginx.com         goto fail;
66620Sigor@sysoev.ru     }
66720Sigor@sysoev.ru 
6681488St.nateldemoura@f5.com     nxt_log(task, NXT_LOG_INFO, "%s started", process->name);
669141Smax.romanov@nginx.com 
6701998St.nateldemoura@f5.com     ret = nxt_process_send_ready(task, process);
6711998St.nateldemoura@f5.com     if (nxt_slow_path(ret != NXT_OK)) {
6721998St.nateldemoura@f5.com         goto fail;
6731998St.nateldemoura@f5.com     }
6741998St.nateldemoura@f5.com 
6751488St.nateldemoura@f5.com     ret = init->start(task, &process->data);
676141Smax.romanov@nginx.com 
6771998St.nateldemoura@f5.com     if (nxt_process_type(process) != NXT_PROCESS_PROTOTYPE) {
6781998St.nateldemoura@f5.com         nxt_port_write_close(nxt_process_port_first(process));
6791998St.nateldemoura@f5.com     }
6801998St.nateldemoura@f5.com 
6811998St.nateldemoura@f5.com     if (nxt_fast_path(ret == NXT_OK)) {
6821998St.nateldemoura@f5.com         return;
6831998St.nateldemoura@f5.com     }
6841998St.nateldemoura@f5.com 
68520Sigor@sysoev.ru fail:
6861998St.nateldemoura@f5.com     nxt_process_quit(task, 1);
6871488St.nateldemoura@f5.com }
6881488St.nateldemoura@f5.com 
6891488St.nateldemoura@f5.com 
6901488St.nateldemoura@f5.com static void
nxt_process_created_error(nxt_task_t * task,nxt_port_recv_msg_t * msg,void * data)6911488St.nateldemoura@f5.com nxt_process_created_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
6921488St.nateldemoura@f5.com     void *data)
6931488St.nateldemoura@f5.com {
694