xref: /unit/src/nxt_process.c (revision 1997:a8a3f1d243ee)
1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) NGINX, Inc.
5  */
6 
7 #include <nxt_main.h>
8 #include <nxt_main_process.h>
9 
10 #if (NXT_HAVE_CLONE)
11 #include <nxt_clone.h>
12 #endif
13 
14 #include <signal.h>
15 
16 #if (NXT_HAVE_PR_SET_NO_NEW_PRIVS)
17 #include <sys/prctl.h>
18 #endif
19 
20 static nxt_pid_t nxt_process_create(nxt_task_t *task, nxt_process_t *process);
21 static nxt_int_t nxt_process_setup(nxt_task_t *task, nxt_process_t *process);
22 static nxt_int_t nxt_process_child_fixup(nxt_task_t *task,
23     nxt_process_t *process);
24 static nxt_int_t nxt_process_send_created(nxt_task_t *task,
25     nxt_process_t *process);
26 static nxt_int_t nxt_process_send_ready(nxt_task_t *task,
27     nxt_process_t *process);
28 static void nxt_process_created_ok(nxt_task_t *task, nxt_port_recv_msg_t *msg,
29     void *data);
30 static void nxt_process_created_error(nxt_task_t *task,
31     nxt_port_recv_msg_t *msg, void *data);
32 
33 
34 /* A cached process pid. */
35 nxt_pid_t  nxt_pid;
36 
37 /* An original parent process pid. */
38 nxt_pid_t  nxt_ppid;
39 
40 /* A cached process effective uid */
41 nxt_uid_t  nxt_euid;
42 
43 /* A cached process effective gid */
44 nxt_gid_t  nxt_egid;
45 
46 nxt_bool_t  nxt_proc_conn_matrix[NXT_PROCESS_MAX][NXT_PROCESS_MAX] = {
47     { 1, 1, 1, 1, 1 },
48     { 1, 0, 0, 0, 0 },
49     { 1, 0, 0, 1, 0 },
50     { 1, 0, 1, 0, 1 },
51     { 1, 0, 0, 1, 0 },
52 };
53 
54 nxt_bool_t  nxt_proc_remove_notify_matrix[NXT_PROCESS_MAX][NXT_PROCESS_MAX] = {
55     { 0, 0, 0, 0, 0 },
56     { 0, 0, 0, 0, 0 },
57     { 0, 0, 0, 1, 0 },
58     { 0, 0, 1, 0, 1 },
59     { 0, 0, 0, 1, 0 },
60 };
61 
62 
63 nxt_process_t *
64 nxt_process_new(nxt_runtime_t *rt)
65 {
66     nxt_process_t  *process;
67 
68     process = nxt_mp_zalloc(rt->mem_pool, sizeof(nxt_process_t)
69                             + sizeof(nxt_process_init_t));
70 
71     if (nxt_slow_path(process == NULL)) {
72         return NULL;
73     }
74 
75     nxt_queue_init(&process->ports);
76 
77     nxt_thread_mutex_create(&process->incoming.mutex);
78 
79     process->use_count = 1;
80 
81     return process;
82 }
83 
84 
85 void
86 nxt_process_use(nxt_task_t *task, nxt_process_t *process, int i)
87 {
88     process->use_count += i;
89 
90     if (process->use_count == 0) {
91         nxt_runtime_process_release(task->thread->runtime, process);
92     }
93 }
94 
95 
96 nxt_int_t
97 nxt_process_init_start(nxt_task_t *task, nxt_process_init_t init)
98 {
99     nxt_int_t           ret;
100     nxt_runtime_t       *rt;
101     nxt_process_t       *process;
102     nxt_process_init_t  *pinit;
103 
104     rt = task->thread->runtime;
105 
106     process = nxt_process_new(rt);
107     if (nxt_slow_path(process == NULL)) {
108         return NXT_ERROR;
109     }
110 
111     process->name = init.name;
112     process->user_cred = &rt->user_cred;
113 
114     pinit = nxt_process_init(process);
115     *pinit = init;
116 
117     ret = nxt_process_start(task, process);
118     if (nxt_slow_path(ret == NXT_ERROR)) {
119         nxt_process_use(task, process, -1);
120     }
121 
122     return ret;
123 }
124 
125 
126 nxt_int_t
127 nxt_process_start(nxt_task_t *task, nxt_process_t *process)
128 {
129     nxt_mp_t            *tmp_mp;
130     nxt_int_t           ret;
131     nxt_pid_t           pid;
132     nxt_port_t          *port;
133     nxt_process_init_t  *init;
134 
135     init = nxt_process_init(process);
136 
137     port = nxt_port_new(task, 0, 0, init->type);
138     if (nxt_slow_path(port == NULL)) {
139         return NXT_ERROR;
140     }
141 
142     nxt_process_port_add(task, process, port);
143 
144     ret = nxt_port_socket_init(task, port, 0);
145     if (nxt_slow_path(ret != NXT_OK)) {
146         goto free_port;
147     }
148 
149     tmp_mp = nxt_mp_create(1024, 128, 256, 32);
150     if (nxt_slow_path(tmp_mp == NULL)) {
151         ret = NXT_ERROR;
152 
153         goto close_port;
154     }
155 
156     if (init->prefork) {
157         ret = init->prefork(task, process, tmp_mp);
158         if (nxt_slow_path(ret != NXT_OK)) {
159             goto free_mempool;
160         }
161     }
162 
163     pid = nxt_process_create(task, process);
164 
165     switch (pid) {
166 
167     case -1:
168         ret = NXT_ERROR;
169         break;
170 
171     case 0:
172         /* The child process: return to the event engine work queue loop. */
173 
174         nxt_process_use(task, process, -1);
175 
176         ret = NXT_AGAIN;
177         break;
178 
179     default:
180         /* The main process created a new process. */
181 
182         nxt_process_use(task, process, -1);
183 
184         nxt_port_read_close(port);
185         nxt_port_write_enable(task, port);
186 
187         ret = NXT_OK;
188         break;
189     }
190 
191 free_mempool:
192 
193     nxt_mp_destroy(tmp_mp);
194 
195 close_port:
196 
197     if (nxt_slow_path(ret == NXT_ERROR)) {
198         nxt_port_close(task, port);
199     }
200 
201 free_port:
202 
203     nxt_port_use(task, port, -1);
204 
205     return ret;
206 }
207 
208 
209 static nxt_int_t
210 nxt_process_child_fixup(nxt_task_t *task, nxt_process_t *process)
211 {
212     nxt_process_t       *p;
213     nxt_runtime_t       *rt;
214     nxt_process_init_t  *init;
215     nxt_process_type_t  ptype;
216 
217     init = nxt_process_init(process);
218 
219     nxt_pid = nxt_getpid();
220 
221     process->pid = nxt_pid;
222 
223     /* Clean inherited cached thread tid. */
224     task->thread->tid = 0;
225 
226 #if (NXT_HAVE_CLONE && NXT_HAVE_CLONE_NEWPID)
227     if (nxt_is_clone_flag_set(process->isolation.clone.flags, NEWPID)) {
228         ssize_t  pidsz;
229         char     procpid[10];
230 
231         nxt_debug(task, "%s isolated pid is %d", process->name, nxt_pid);
232 
233         pidsz = readlink("/proc/self", procpid, sizeof(procpid));
234 
235         if (nxt_slow_path(pidsz < 0 || pidsz >= (ssize_t) sizeof(procpid))) {
236             nxt_alert(task, "failed to read real pid from /proc/self");
237             return NXT_ERROR;
238         }
239 
240         procpid[pidsz] = '\0';
241 
242         nxt_pid = (nxt_pid_t) strtol(procpid, NULL, 10);
243 
244         nxt_assert(nxt_pid >  0 && nxt_errno != ERANGE);
245 
246         process->pid = nxt_pid;
247         task->thread->tid = nxt_pid;
248 
249         nxt_debug(task, "%s real pid is %d", process->name, nxt_pid);
250     }
251 
252 #endif
253 
254     ptype = init->type;
255 
256     nxt_port_reset_next_id();
257 
258     nxt_event_engine_thread_adopt(task->thread->engine);
259 
260     rt = task->thread->runtime;
261 
262     /* Remove not ready processes. */
263     nxt_runtime_process_each(rt, p) {
264 
265         if (nxt_proc_conn_matrix[ptype][nxt_process_type(p)] == 0) {
266             nxt_debug(task, "remove not required process %PI", p->pid);
267 
268             nxt_process_close_ports(task, p);
269 
270             continue;
271         }
272 
273         if (p->state != NXT_PROCESS_STATE_READY) {
274             nxt_debug(task, "remove not ready process %PI", p->pid);
275 
276             nxt_process_close_ports(task, p);
277 
278             continue;
279         }
280 
281         nxt_port_mmaps_destroy(&p->incoming, 0);
282 
283     } nxt_runtime_process_loop;
284 
285     return NXT_OK;
286 }
287 
288 
289 static nxt_pid_t
290 nxt_process_create(nxt_task_t *task, nxt_process_t *process)
291 {
292     nxt_int_t           ret;
293     nxt_pid_t           pid;
294 
295 #if (NXT_HAVE_CLONE)
296     pid = nxt_clone(SIGCHLD | process->isolation.clone.flags);
297     if (nxt_slow_path(pid < 0)) {
298         nxt_alert(task, "clone() failed for %s %E", process->name, nxt_errno);
299         return pid;
300     }
301 #else
302     pid = fork();
303     if (nxt_slow_path(pid < 0)) {
304         nxt_alert(task, "fork() failed for %s %E", process->name, nxt_errno);
305         return pid;
306     }
307 #endif
308 
309     if (pid == 0) {
310         /* Child. */
311 
312         ret = nxt_process_child_fixup(task, process);
313         if (nxt_slow_path(ret != NXT_OK)) {
314             nxt_process_quit(task, 1);
315             return -1;
316         }
317 
318         nxt_runtime_process_add(task, process);
319 
320         if (nxt_slow_path(nxt_process_setup(task, process) != NXT_OK)) {
321             nxt_process_quit(task, 1);
322         }
323 
324         /*
325          * Explicitly return 0 to notice the caller function this is the child.
326          * The caller must return to the event engine work queue loop.
327          */
328         return 0;
329     }
330 
331     /* Parent. */
332 
333 #if (NXT_HAVE_CLONE)
334     nxt_debug(task, "clone(%s): %PI", process->name, pid);
335 #else
336     nxt_debug(task, "fork(%s): %PI", process->name, pid);
337 #endif
338 
339     process->pid = pid;
340 
341     nxt_runtime_process_add(task, process);
342 
343     return pid;
344 }
345 
346 
347 static nxt_int_t
348 nxt_process_setup(nxt_task_t *task, nxt_process_t *process)
349 {
350     nxt_int_t                    ret;
351     nxt_port_t                   *port, *main_port;
352     nxt_thread_t                 *thread;
353     nxt_runtime_t                *rt;
354     nxt_process_init_t           *init;
355     nxt_event_engine_t           *engine;
356     const nxt_event_interface_t  *interface;
357 
358     init = nxt_process_init(process);
359 
360     nxt_debug(task, "%s setup", process->name);
361 
362     nxt_process_title(task, "unit: %s", process->name);
363 
364     thread = task->thread;
365     rt     = thread->runtime;
366 
367     nxt_random_init(&thread->random);
368 
369     rt->type = init->type;
370 
371     engine = thread->engine;
372 
373     /* Update inherited main process event engine and signals processing. */
374     engine->signals->sigev = init->signals;
375 
376     interface = nxt_service_get(rt->services, "engine", rt->engine);
377     if (nxt_slow_path(interface == NULL)) {
378         return NXT_ERROR;
379     }
380 
381     if (nxt_event_engine_change(engine, interface, rt->batch) != NXT_OK) {
382         return NXT_ERROR;
383     }
384 
385     ret = nxt_runtime_thread_pool_create(thread, rt, rt->auxiliary_threads,
386                                          60000 * 1000000LL);
387     if (nxt_slow_path(ret != NXT_OK)) {
388         return NXT_ERROR;
389     }
390 
391     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
392 
393     nxt_port_read_close(main_port);
394     nxt_port_write_enable(task, main_port);
395 
396     port = nxt_process_port_first(process);
397 
398     nxt_port_enable(task, port, init->port_handlers);
399 
400     ret = init->setup(task, process);
401 
402     if (nxt_slow_path(ret != NXT_OK)) {
403         return NXT_ERROR;
404     }
405 
406     switch (process->state) {
407 
408     case NXT_PROCESS_STATE_CREATED:
409         ret = nxt_process_send_created(task, process);
410         break;
411 
412     case NXT_PROCESS_STATE_READY:
413         ret = nxt_process_send_ready(task, process);
414 
415         if (nxt_slow_path(ret != NXT_OK)) {
416             break;
417         }
418 
419         ret = init->start(task, &process->data);
420 
421         nxt_port_write_close(port);
422 
423         break;
424 
425     default:
426         nxt_assert(0);
427     }
428 
429     if (nxt_slow_path(ret != NXT_OK)) {
430         nxt_alert(task, "%s failed to start", process->name);
431     }
432 
433     return ret;
434 }
435 
436 
437 static nxt_int_t
438 nxt_process_send_created(nxt_task_t *task, nxt_process_t *process)
439 {
440     uint32_t            stream;
441     nxt_int_t           ret;
442     nxt_port_t          *my_port, *main_port;
443     nxt_runtime_t       *rt;
444 
445     nxt_assert(process->state == NXT_PROCESS_STATE_CREATED);
446 
447     rt = task->thread->runtime;
448 
449     my_port = nxt_process_port_first(process);
450     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
451 
452     nxt_assert(my_port != NULL && main_port != NULL);
453 
454     stream = nxt_port_rpc_register_handler(task, my_port,
455                                            nxt_process_created_ok,
456                                            nxt_process_created_error,
457                                            main_port->pid, process);
458 
459     if (nxt_slow_path(stream == 0)) {
460         return NXT_ERROR;
461     }
462 
463     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_PROCESS_CREATED,
464                                 -1, stream, my_port->id, NULL);
465 
466     if (nxt_slow_path(ret != NXT_OK)) {
467         nxt_alert(task, "%s failed to send CREATED message", process->name);
468         nxt_port_rpc_cancel(task, my_port, stream);
469         return NXT_ERROR;
470     }
471 
472     nxt_debug(task, "%s created", process->name);
473 
474     return NXT_OK;
475 }
476 
477 
478 static void
479 nxt_process_created_ok(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data)
480 {
481     nxt_int_t           ret;
482     nxt_process_t       *process;
483     nxt_process_init_t  *init;
484 
485     process = data;
486     init = nxt_process_init(process);
487 
488     ret = nxt_process_apply_creds(task, process);
489     if (nxt_slow_path(ret != NXT_OK)) {
490         goto fail;
491     }
492 
493     nxt_log(task, NXT_LOG_INFO, "%s started", process->name);
494 
495     ret = init->start(task, &process->data);
496 
497 fail:
498 
499     nxt_process_quit(task, ret == NXT_OK ? 0 : 1);
500 }
501 
502 
503 static void
504 nxt_process_created_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
505     void *data)
506 {
507     nxt_process_t       *process;
508     nxt_process_init_t  *init;
509 
510     process = data;
511     init = nxt_process_init(process);
512 
513     nxt_alert(task, "%s failed to start", init->name);
514 
515     nxt_process_quit(task, 1);
516 }
517 
518 
519 nxt_int_t
520 nxt_process_core_setup(nxt_task_t *task, nxt_process_t *process)
521 {
522     nxt_int_t  ret;
523 
524     ret = nxt_process_apply_creds(task, process);
525     if (nxt_slow_path(ret != NXT_OK)) {
526         return NXT_ERROR;
527     }
528 
529     process->state = NXT_PROCESS_STATE_READY;
530 
531     return NXT_OK;
532 }
533 
534 
535 nxt_int_t
536 nxt_process_creds_set(nxt_task_t *task, nxt_process_t *process, nxt_str_t *user,
537     nxt_str_t *group)
538 {
539     char  *str;
540 
541     process->user_cred = nxt_mp_zalloc(process->mem_pool,
542                                        sizeof(nxt_credential_t));
543 
544     if (nxt_slow_path(process->user_cred == NULL)) {
545         return NXT_ERROR;
546     }
547 
548     str = nxt_mp_zalloc(process->mem_pool, user->length + 1);
549     if (nxt_slow_path(str == NULL)) {
550         return NXT_ERROR;
551     }
552 
553     nxt_memcpy(str, user->start, user->length);
554     str[user->length] = '\0';
555 
556     process->user_cred->user = str;
557 
558     if (group->start != NULL) {
559         str = nxt_mp_zalloc(process->mem_pool, group->length + 1);
560         if (nxt_slow_path(str == NULL)) {
561             return NXT_ERROR;
562         }
563 
564         nxt_memcpy(str, group->start, group->length);
565         str[group->length] = '\0';
566 
567     } else {
568         str = NULL;
569     }
570 
571     return nxt_credential_get(task, process->mem_pool, process->user_cred, str);
572 }
573 
574 
575 nxt_int_t
576 nxt_process_apply_creds(nxt_task_t *task, nxt_process_t *process)
577 {
578     nxt_int_t      ret, cap_setid;
579     nxt_runtime_t  *rt;
580 
581     rt = task->thread->runtime;
582 
583     cap_setid = rt->capabilities.setid;
584 
585 #if (NXT_HAVE_CLONE && NXT_HAVE_CLONE_NEWUSER)
586     if (!cap_setid
587         && nxt_is_clone_flag_set(process->isolation.clone.flags, NEWUSER)) {
588         cap_setid = 1;
589     }
590 #endif
591 
592     if (cap_setid) {
593         ret = nxt_credential_setgids(task, process->user_cred);
594         if (nxt_slow_path(ret != NXT_OK)) {
595             return NXT_ERROR;
596         }
597 
598         ret = nxt_credential_setuid(task, process->user_cred);
599         if (nxt_slow_path(ret != NXT_OK)) {
600             return NXT_ERROR;
601         }
602     }
603 
604 #if (NXT_HAVE_PR_SET_NO_NEW_PRIVS)
605     if (nxt_slow_path(process->isolation.new_privs == 0
606                       && prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0))
607     {
608         nxt_alert(task, "failed to set no_new_privs %E", nxt_errno);
609         return NXT_ERROR;
610     }
611 #endif
612 
613     return NXT_OK;
614 }
615 
616 
617 static nxt_int_t
618 nxt_process_send_ready(nxt_task_t *task, nxt_process_t *process)
619 {
620     nxt_int_t           ret;
621     nxt_port_t          *main_port;
622     nxt_runtime_t       *rt;
623 
624     rt = task->thread->runtime;
625 
626     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
627 
628     nxt_assert(main_port != NULL);
629 
630     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_PROCESS_READY,
631                                 -1, process->stream, 0, NULL);
632 
633     if (nxt_slow_path(ret != NXT_OK)) {
634         nxt_alert(task, "%s failed to send READY message", process->name);
635         return NXT_ERROR;
636     }
637 
638     nxt_debug(task, "%s sent ready", process->name);
639 
640     return NXT_OK;
641 }
642 
643 
644 #if (NXT_HAVE_POSIX_SPAWN)
645 
646 /*
647  * Linux glibc 2.2 posix_spawn() is implemented via fork()/execve().
648  * Linux glibc 2.4 posix_spawn() without file actions and spawn
649  * attributes uses vfork()/execve().
650  *
651  * On FreeBSD 8.0 posix_spawn() is implemented via vfork()/execve().
652  *
653  * Solaris 10:
654  *   In the Solaris 10 OS, posix_spawn() is currently implemented using
655  *   private-to-libc vfork(), execve(), and exit() functions.  They are
656  *   identical to regular vfork(), execve(), and exit() in functionality,
657  *   but they are not exported from libc and therefore don't cause the
658  *   deadlock-in-the-dynamic-linker problem that any multithreaded code
659  *   outside of libc that calls vfork() can cause.
660  *
661  * On MacOSX 10.5 (Leoprad) and NetBSD 6.0 posix_spawn() is implemented
662  * as syscall.
663  */
664 
665 nxt_pid_t
666 nxt_process_execute(nxt_task_t *task, char *name, char **argv, char **envp)
667 {
668     nxt_pid_t  pid;
669 
670     nxt_debug(task, "posix_spawn(\"%s\")", name);
671 
672     if (posix_spawn(&pid, name, NULL, NULL, argv, envp) != 0) {
673         nxt_alert(task, "posix_spawn(\"%s\") failed %E", name, nxt_errno);
674         return -1;
675     }
676 
677     return pid;
678 }
679 
680 #else
681 
682 nxt_pid_t
683 nxt_process_execute(nxt_task_t *task, char *name, char **argv, char **envp)
684 {
685     nxt_pid_t  pid;
686 
687     /*
688      * vfork() is better than fork() because:
689      *   it is faster several times;
690      *   its execution time does not depend on private memory mapping size;
691      *   it has lesser chances to fail due to the ENOMEM error.
692      */
693 
694     pid = vfork();
695 
696     switch (pid) {
697 
698     case -1:
699         nxt_alert(task, "vfork() failed while executing \"%s\" %E",
700                   name, nxt_errno);
701         break;
702 
703     case 0:
704         /* A child. */
705         nxt_debug(task, "execve(\"%s\")", name);
706 
707         (void) execve(name, argv, envp);
708 
709         nxt_alert(task, "execve(\"%s\") failed %E", name, nxt_errno);
710 
711         exit(1);
712         nxt_unreachable();
713         break;
714 
715     default:
716         /* A parent. */
717         nxt_debug(task, "vfork(): %PI", pid);
718         break;
719     }
720 
721     return pid;
722 }
723 
724 #endif
725 
726 
727 nxt_int_t
728 nxt_process_daemon(nxt_task_t *task)
729 {
730     nxt_fd_t      fd;
731     nxt_pid_t     pid;
732     const char    *msg;
733 
734     fd = -1;
735 
736     /*
737      * fork() followed by a parent process's exit() detaches a child process
738      * from an init script or terminal shell process which has started the
739      * parent process and allows the child process to run in background.
740      */
741 
742     pid = fork();
743 
744     switch (pid) {
745 
746     case -1:
747         msg = "fork() failed %E";
748         goto fail;
749 
750     case 0:
751         /* A child. */
752         break;
753 
754     default:
755         /* A parent. */
756         nxt_debug(task, "fork(): %PI", pid);
757         exit(0);
758         nxt_unreachable();
759     }
760 
761     nxt_pid = getpid();
762 
763     /* Clean inherited cached thread tid. */
764     task->thread->tid = 0;
765 
766     nxt_debug(task, "daemon");
767 
768     /* Detach from controlling terminal. */
769 
770     if (setsid() == -1) {
771         nxt_alert(task, "setsid() failed %E", nxt_errno);
772         return NXT_ERROR;
773     }
774 
775     /*
776      * Reset file mode creation mask: any access
777      * rights can be set on file creation.
778      */
779     umask(0);
780 
781     /* Redirect STDIN and STDOUT to the "/dev/null". */
782 
783     fd = open("/dev/null", O_RDWR);
784     if (fd == -1) {
785         msg = "open(\"/dev/null\") failed %E";
786         goto fail;
787     }
788 
789     if (dup2(fd, STDIN_FILENO) == -1) {
790         msg = "dup2(\"/dev/null\", STDIN) failed %E";
791         goto fail;
792     }
793 
794     if (dup2(fd, STDOUT_FILENO) == -1) {
795         msg = "dup2(\"/dev/null\", STDOUT) failed %E";
796         goto fail;
797     }
798 
799     if (fd > STDERR_FILENO) {
800         nxt_fd_close(fd);
801     }
802 
803     return NXT_OK;
804 
805 fail:
806 
807     nxt_alert(task, msg, nxt_errno);
808 
809     if (fd != -1) {
810         nxt_fd_close(fd);
811     }
812 
813     return NXT_ERROR;
814 }
815 
816 
817 void
818 nxt_nanosleep(nxt_nsec_t ns)
819 {
820     struct timespec  ts;
821 
822     ts.tv_sec = ns / 1000000000;
823     ts.tv_nsec = ns % 1000000000;
824 
825     (void) nanosleep(&ts, NULL);
826 }
827 
828 
829 void
830 nxt_process_port_add(nxt_task_t *task, nxt_process_t *process, nxt_port_t *port)
831 {
832     nxt_assert(port->process == NULL);
833 
834     port->process = process;
835     nxt_queue_insert_tail(&process->ports, &port->link);
836 
837     nxt_process_use(task, process, 1);
838 }
839 
840 
841 nxt_process_type_t
842 nxt_process_type(nxt_process_t *process)
843 {
844     return nxt_queue_is_empty(&process->ports) ? 0 :
845         (nxt_process_port_first(process))->type;
846 }
847 
848 
849 void
850 nxt_process_close_ports(nxt_task_t *task, nxt_process_t *process)
851 {
852     nxt_port_t  *port;
853 
854     nxt_process_port_each(process, port) {
855 
856         nxt_port_close(task, port);
857 
858         nxt_runtime_port_remove(task, port);
859 
860     } nxt_process_port_loop;
861 }
862 
863 
864 void
865 nxt_process_quit(nxt_task_t *task, nxt_uint_t exit_status)
866 {
867     nxt_uint_t           n;
868     nxt_queue_t          *listen;
869     nxt_runtime_t        *rt;
870     nxt_queue_link_t     *link, *next;
871     nxt_listen_event_t   *lev;
872     nxt_listen_socket_t  *ls;
873 
874     rt = task->thread->runtime;
875 
876     nxt_debug(task, "close listen connections");
877 
878     listen = &task->thread->engine->listen_connections;
879 
880     for (link = nxt_queue_first(listen);
881          link != nxt_queue_tail(listen);
882          link = next)
883     {
884         next = nxt_queue_next(link);
885         lev = nxt_queue_link_data(link, nxt_listen_event_t, link);
886         nxt_queue_remove(link);
887 
888         nxt_fd_event_close(task->thread->engine, &lev->socket);
889     }
890 
891     if (rt->listen_sockets != NULL) {
892 
893         ls = rt->listen_sockets->elts;
894         n = rt->listen_sockets->nelts;
895 
896         while (n != 0) {
897             nxt_socket_close(task, ls->socket);
898             ls->socket = -1;
899 
900             ls++;
901             n--;
902         }
903 
904         rt->listen_sockets->nelts = 0;
905     }
906 
907     nxt_runtime_quit(task, exit_status);
908 }
909