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 static void nxt_process_start(nxt_task_t *task, nxt_process_t *process); 17 static nxt_int_t nxt_process_worker_setup(nxt_task_t *task, 18 nxt_process_t *process, int parentfd); 19 20 /* A cached process pid. */ 21 nxt_pid_t nxt_pid; 22 23 /* An original parent process pid. */ 24 nxt_pid_t nxt_ppid; 25 26 nxt_bool_t nxt_proc_conn_matrix[NXT_PROCESS_MAX][NXT_PROCESS_MAX] = { 27 { 1, 1, 1, 1, 1 }, 28 { 1, 0, 0, 0, 0 }, 29 { 1, 0, 0, 1, 0 }, 30 { 1, 0, 1, 0, 1 }, 31 { 1, 0, 0, 0, 0 }, 32 }; 33 34 nxt_bool_t nxt_proc_remove_notify_matrix[NXT_PROCESS_MAX][NXT_PROCESS_MAX] = { 35 { 0, 0, 0, 0, 0 }, 36 { 0, 0, 0, 0, 0 }, 37 { 0, 0, 0, 1, 0 }, 38 { 0, 0, 1, 0, 1 }, 39 { 0, 0, 0, 1, 0 }, 40 }; 41 42 43 static nxt_int_t 44 nxt_process_worker_setup(nxt_task_t *task, nxt_process_t *process, int parentfd) 45 { 46 pid_t rpid, pid; 47 ssize_t n; 48 nxt_int_t parent_status; 49 nxt_process_t *p; 50 nxt_runtime_t *rt; 51 nxt_process_init_t *init; 52 nxt_process_type_t ptype; 53 54 pid = getpid(); 55 rpid = 0; 56 rt = task->thread->runtime; 57 init = process->init; 58 59 /* Setup the worker process. */ 60 61 n = read(parentfd, &rpid, sizeof(rpid)); 62 if (nxt_slow_path(n == -1 || n != sizeof(rpid))) { 63 nxt_alert(task, "failed to read real pid"); 64 return NXT_ERROR; 65 } 66 67 if (nxt_slow_path(rpid == 0)) { 68 nxt_alert(task, "failed to get real pid from parent"); 69 return NXT_ERROR; 70 } 71 72 nxt_pid = rpid; 73 74 /* Clean inherited cached thread tid. */ 75 task->thread->tid = 0; 76 77 process->pid = nxt_pid; 78 79 if (nxt_pid != pid) { 80 nxt_debug(task, "app \"%s\" real pid %d", init->name, nxt_pid); 81 nxt_debug(task, "app \"%s\" isolated pid: %d", init->name, pid); 82 } 83 84 n = read(parentfd, &parent_status, sizeof(parent_status)); 85 if (nxt_slow_path(n == -1 || n != sizeof(parent_status))) { 86 nxt_alert(task, "failed to read parent status"); 87 return NXT_ERROR; 88 } 89 90 if (nxt_slow_path(parent_status != NXT_OK)) { 91 return parent_status; 92 } 93 94 ptype = init->type; 95 96 nxt_port_reset_next_id(); 97 98 nxt_event_engine_thread_adopt(task->thread->engine); 99 100 /* Remove not ready processes. */ 101 nxt_runtime_process_each(rt, p) { 102 103 if (nxt_proc_conn_matrix[ptype][nxt_process_type(p)] == 0) { 104 nxt_debug(task, "remove not required process %PI", p->pid); 105 106 nxt_process_close_ports(task, p); 107 108 continue; 109 } 110 111 if (!p->ready) { 112 nxt_debug(task, "remove not ready process %PI", p->pid); 113 114 nxt_process_close_ports(task, p); 115 116 continue; 117 } 118 119 nxt_port_mmaps_destroy(&p->incoming, 0); 120 nxt_port_mmaps_destroy(&p->outgoing, 0); 121 122 } nxt_runtime_process_loop; 123 124 nxt_runtime_process_add(task, process); 125 126 nxt_process_start(task, process); 127 128 process->ready = 1; 129 130 return NXT_OK; 131 } 132 133 134 nxt_pid_t 135 nxt_process_create(nxt_task_t *task, nxt_process_t *process) 136 { 137 int pipefd[2]; 138 nxt_int_t ret; 139 nxt_pid_t pid; 140 nxt_process_init_t *init; 141 142 if (nxt_slow_path(pipe(pipefd) == -1)) { 143 nxt_alert(task, "failed to create process pipe for passing rpid"); 144 return -1; 145 } 146 147 init = process->init; 148 149 #if (NXT_HAVE_CLONE) 150 pid = nxt_clone(SIGCHLD | init->isolation.clone.flags); 151 if (nxt_slow_path(pid < 0)) { 152 nxt_alert(task, "clone() failed while creating \"%s\" %E", 153 init->name, nxt_errno); 154 goto cleanup; 155 } 156 #else 157 pid = fork(); 158 if (nxt_slow_path(pid < 0)) { 159 nxt_alert(task, "fork() failed while creating \"%s\" %E", 160 init->name, nxt_errno); 161 goto cleanup; 162 } 163 #endif 164 165 if (pid == 0) { 166 /* Child. */ 167 168 if (nxt_slow_path(close(pipefd[1]) == -1)) { 169 nxt_alert(task, "failed to close writer pipe fd"); 170 } 171 172 ret = nxt_process_worker_setup(task, process, pipefd[0]); 173 if (nxt_slow_path(ret != NXT_OK)) { 174 exit(1); 175 } 176 177 if (nxt_slow_path(close(pipefd[0]) == -1)) { 178 nxt_alert(task, "failed to close writer pipe fd"); 179 } 180 181 /* 182 * Explicitly return 0 to notice the caller function this is the child. 183 * The caller must return to the event engine work queue loop. 184 */ 185 return 0; 186 } 187 188 /* Parent. */ 189 190 /* 191 * At this point, the child process is blocked reading the 192 * pipe fd to get its real pid (rpid). 193 * 194 * If anything goes wrong now, we need to terminate the child 195 * process by sending a NXT_ERROR in the pipe. 196 */ 197 198 #if (NXT_HAVE_CLONE) 199 nxt_debug(task, "clone(\"%s\"): %PI", init->name, pid); 200 #else 201 nxt_debug(task, "fork(\"%s\"): %PI", init->name, pid); 202 #endif 203 204 if (nxt_slow_path(write(pipefd[1], &pid, sizeof(pid)) == -1)) { 205 nxt_alert(task, "failed to write real pid"); 206 goto fail; 207 } 208 209 #if (NXT_HAVE_CLONE && NXT_HAVE_CLONE_NEWUSER) 210 if ((init->isolation.clone.flags & CLONE_NEWUSER) == CLONE_NEWUSER) { 211 ret = nxt_clone_proc_map(task, pid, &init->isolation.clone); 212 if (nxt_slow_path(ret != NXT_OK)) { 213 goto fail; 214 } 215 } 216 #endif 217 218 ret = NXT_OK; 219 220 if (nxt_slow_path(write(pipefd[1], &ret, sizeof(ret)) == -1)) { 221 nxt_alert(task, "failed to write status"); 222 goto fail; 223 } 224 225 process->pid = pid; 226 227 nxt_runtime_process_add(task, process); 228 229 goto cleanup; 230 231 fail: 232 233 ret = NXT_ERROR; 234 235 if (nxt_slow_path(write(pipefd[1], &ret, sizeof(ret)) == -1)) { 236 nxt_alert(task, "failed to write status"); 237 } 238 239 waitpid(pid, NULL, 0); 240 241 pid = -1; 242 243 cleanup: 244 245 if (nxt_slow_path(close(pipefd[0]) != 0)) { 246 nxt_alert(task, "failed to close pipe: %E", nxt_errno); 247 } 248 249 if (nxt_slow_path(close(pipefd[1]) != 0)) { 250 nxt_alert(task, "failed to close pipe: %E", nxt_errno); 251 } 252 253 return pid; 254 } 255 256 257 static void 258 nxt_process_start(nxt_task_t *task, nxt_process_t *process) 259 { 260 nxt_int_t ret; 261 nxt_port_t *port, *main_port; 262 nxt_thread_t *thread; 263 nxt_runtime_t *rt; 264 nxt_process_init_t *init; 265 nxt_event_engine_t *engine; 266 const nxt_event_interface_t *interface; 267 268 init = process->init; 269 270 nxt_log(task, NXT_LOG_INFO, "%s started", init->name); 271 272 nxt_process_title(task, "unit: %s", init->name); 273 274 thread = task->thread; 275 rt = thread->runtime; 276 277 nxt_random_init(&thread->random); 278 279 if (rt->capabilities.setid && init->user_cred != NULL) { 280 ret = nxt_credential_set(task, init->user_cred); 281 if (ret != NXT_OK) { 282 goto fail; 283 } 284 } 285 286 rt->type = init->type; 287 288 engine = thread->engine; 289 290 /* Update inherited main process event engine and signals processing. */ 291 engine->signals->sigev = init->signals; 292 293 interface = nxt_service_get(rt->services, "engine", rt->engine); 294 if (nxt_slow_path(interface == NULL)) { 295 goto fail; 296 } 297 298 if (nxt_event_engine_change(engine, interface, rt->batch) != NXT_OK) { 299 goto fail; 300 } 301 302 ret = nxt_runtime_thread_pool_create(thread, rt, rt->auxiliary_threads, 303 60000 * 1000000LL); 304 if (nxt_slow_path(ret != NXT_OK)) { 305 goto fail; 306 } 307 308 main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 309 310 nxt_port_read_close(main_port); 311 nxt_port_write_enable(task, main_port); 312 313 port = nxt_process_port_first(process); 314 315 nxt_port_write_close(port); 316 317 ret = init->start(task, init->data); 318 319 if (nxt_slow_path(ret != NXT_OK)) { 320 goto fail; 321 } 322 323 nxt_port_enable(task, port, init->port_handlers); 324 325 ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_PROCESS_READY, 326 -1, init->stream, 0, NULL); 327 328 if (nxt_slow_path(ret != NXT_OK)) { 329 nxt_log(task, NXT_LOG_ERR, "failed to send READY message to main"); 330 331 goto fail; 332 } 333 334 return; 335 336 fail: 337 338 exit(1); 339 } 340 341 342 #if (NXT_HAVE_POSIX_SPAWN) 343 344 /* 345 * Linux glibc 2.2 posix_spawn() is implemented via fork()/execve(). 346 * Linux glibc 2.4 posix_spawn() without file actions and spawn 347 * attributes uses vfork()/execve(). 348 * 349 * On FreeBSD 8.0 posix_spawn() is implemented via vfork()/execve(). 350 * 351 * Solaris 10: 352 * In the Solaris 10 OS, posix_spawn() is currently implemented using 353 * private-to-libc vfork(), execve(), and exit() functions. They are 354 * identical to regular vfork(), execve(), and exit() in functionality, 355 * but they are not exported from libc and therefore don't cause the 356 * deadlock-in-the-dynamic-linker problem that any multithreaded code 357 * outside of libc that calls vfork() can cause. 358 * 359 * On MacOSX 10.5 (Leoprad) and NetBSD 6.0 posix_spawn() is implemented 360 * as syscall. 361 */ 362 363 nxt_pid_t 364 nxt_process_execute(nxt_task_t *task, char *name, char **argv, char **envp) 365 { 366 nxt_pid_t pid; 367 368 nxt_debug(task, "posix_spawn(\"%s\")", name); 369 370 if (posix_spawn(&pid, name, NULL, NULL, argv, envp) != 0) { 371 nxt_alert(task, "posix_spawn(\"%s\") failed %E", name, nxt_errno); 372 return -1; 373 } 374 375 return pid; 376 } 377 378 #else 379 380 nxt_pid_t 381 nxt_process_execute(nxt_task_t *task, char *name, char **argv, char **envp) 382 { 383 nxt_pid_t pid; 384 385 /* 386 * vfork() is better than fork() because: 387 * it is faster several times; 388 * its execution time does not depend on private memory mapping size; 389 * it has lesser chances to fail due to the ENOMEM error. 390 */ 391 392 pid = vfork(); 393 394 switch (pid) { 395 396 case -1: 397 nxt_alert(task, "vfork() failed while executing \"%s\" %E", 398 name, nxt_errno); 399 break; 400 401 case 0: 402 /* A child. */ 403 nxt_debug(task, "execve(\"%s\")", name); 404 405 (void) execve(name, argv, envp); 406 407 nxt_alert(task, "execve(\"%s\") failed %E", name, nxt_errno); 408 409 exit(1); 410 nxt_unreachable(); 411 break; 412 413 default: 414 /* A parent. */ 415 nxt_debug(task, "vfork(): %PI", pid); 416 break; 417 } 418 419 return pid; 420 } 421 422 #endif 423 424 425 nxt_int_t 426 nxt_process_daemon(nxt_task_t *task) 427 { 428 nxt_fd_t fd; 429 nxt_pid_t pid; 430 const char *msg; 431 432 fd = -1; 433 434 /* 435 * fork() followed by a parent process's exit() detaches a child process 436 * from an init script or terminal shell process which has started the 437 * parent process and allows the child process to run in background. 438 */ 439 440 pid = fork(); 441 442 switch (pid) { 443 444 case -1: 445 msg = "fork() failed %E"; 446 goto fail; 447 448 case 0: 449 /* A child. */ 450 break; 451 452 default: 453 /* A parent. */ 454 nxt_debug(task, "fork(): %PI", pid); 455 exit(0); 456 nxt_unreachable(); 457 } 458 459 nxt_pid = getpid(); 460 461 /* Clean inherited cached thread tid. */ 462 task->thread->tid = 0; 463 464 nxt_debug(task, "daemon"); 465 466 /* Detach from controlling terminal. */ 467 468 if (setsid() == -1) { 469 nxt_alert(task, "setsid() failed %E", nxt_errno); 470 return NXT_ERROR; 471 } 472 473 /* 474 * Reset file mode creation mask: any access 475 * rights can be set on file creation. 476 */ 477 umask(0); 478 479 /* Redirect STDIN and STDOUT to the "/dev/null". */ 480 481 fd = open("/dev/null", O_RDWR); 482 if (fd == -1) { 483 msg = "open(\"/dev/null\") failed %E"; 484 goto fail; 485 } 486 487 if (dup2(fd, STDIN_FILENO) == -1) { 488 msg = "dup2(\"/dev/null\", STDIN) failed %E"; 489 goto fail; 490 } 491 492 if (dup2(fd, STDOUT_FILENO) == -1) { 493 msg = "dup2(\"/dev/null\", STDOUT) failed %E"; 494 goto fail; 495 } 496 497 if (fd > STDERR_FILENO) { 498 nxt_fd_close(fd); 499 } 500 501 return NXT_OK; 502 503 fail: 504 505 nxt_alert(task, msg, nxt_errno); 506 507 if (fd != -1) { 508 nxt_fd_close(fd); 509 } 510 511 return NXT_ERROR; 512 } 513 514 515 void 516 nxt_nanosleep(nxt_nsec_t ns) 517 { 518 struct timespec ts; 519 520 ts.tv_sec = ns / 1000000000; 521 ts.tv_nsec = ns % 1000000000; 522 523 (void) nanosleep(&ts, NULL); 524 } 525 526 527 void 528 nxt_process_use(nxt_task_t *task, nxt_process_t *process, int i) 529 { 530 process->use_count += i; 531 532 if (process->use_count == 0) { 533 nxt_runtime_process_release(task->thread->runtime, process); 534 } 535 } 536 537 538 void 539 nxt_process_port_add(nxt_task_t *task, nxt_process_t *process, nxt_port_t *port) 540 { 541 nxt_assert(port->process == NULL); 542 543 port->process = process; 544 nxt_queue_insert_tail(&process->ports, &port->link); 545 546 nxt_process_use(task, process, 1); 547 } 548 549 550 nxt_process_type_t 551 nxt_process_type(nxt_process_t *process) 552 { 553 return nxt_queue_is_empty(&process->ports) ? 0 : 554 (nxt_process_port_first(process))->type; 555 } 556 557 558 void 559 nxt_process_close_ports(nxt_task_t *task, nxt_process_t *process) 560 { 561 nxt_port_t *port; 562 563 nxt_process_port_each(process, port) { 564 565 nxt_port_close(task, port); 566 567 nxt_runtime_port_remove(task, port); 568 569 } nxt_process_port_loop; 570 } 571 572 573 void 574 nxt_process_connected_port_add(nxt_process_t *process, nxt_port_t *port) 575 { 576 nxt_thread_mutex_lock(&process->cp_mutex); 577 578 nxt_port_hash_add(&process->connected_ports, port); 579 580 nxt_thread_mutex_unlock(&process->cp_mutex); 581 } 582 583 584 void 585 nxt_process_connected_port_remove(nxt_process_t *process, nxt_port_t *port) 586 { 587 nxt_thread_mutex_lock(&process->cp_mutex); 588 589 nxt_port_hash_remove(&process->connected_ports, port); 590 591 nxt_thread_mutex_unlock(&process->cp_mutex); 592 } 593 594 595 nxt_port_t * 596 nxt_process_connected_port_find(nxt_process_t *process, nxt_pid_t pid, 597 nxt_port_id_t port_id) 598 { 599 nxt_port_t *res; 600 601 nxt_thread_mutex_lock(&process->cp_mutex); 602 603 res = nxt_port_hash_find(&process->connected_ports, pid, port_id); 604 605 nxt_thread_mutex_unlock(&process->cp_mutex); 606 607 return res; 608 } 609