1 2 /* 3 * Copyright (C) Igor Sysoev 4 * Copyright (C) Valentin V. Bartenev 5 * Copyright (C) NGINX, Inc. 6 */ 7 8 #include <nxt_main.h> 9 #include <nxt_runtime.h> 10 #include <nxt_port.h> 11 #include <nxt_master_process.h> 12 #include <nxt_router.h> 13 14 15 static nxt_int_t nxt_runtime_inherited_listen_sockets(nxt_task_t *task, 16 nxt_runtime_t *rt); 17 static nxt_int_t nxt_runtime_systemd_listen_sockets(nxt_task_t *task, 18 nxt_runtime_t *rt); 19 static nxt_int_t nxt_runtime_event_engines(nxt_task_t *task, nxt_runtime_t *rt); 20 static nxt_int_t nxt_runtime_thread_pools(nxt_thread_t *thr, nxt_runtime_t *rt); 21 static void nxt_runtime_start(nxt_task_t *task, void *obj, void *data); 22 static void nxt_runtime_initial_start(nxt_task_t *task); 23 static void nxt_single_process_start(nxt_thread_t *thr, nxt_task_t *task, 24 nxt_runtime_t *rt); 25 static void nxt_runtime_close_idle_connections(nxt_event_engine_t *engine); 26 static void nxt_runtime_exit(nxt_task_t *task, void *obj, void *data); 27 static nxt_int_t nxt_runtime_event_engine_change(nxt_task_t *task, 28 nxt_runtime_t *rt); 29 static nxt_int_t nxt_runtime_conf_init(nxt_task_t *task, nxt_runtime_t *rt); 30 static nxt_int_t nxt_runtime_conf_read_cmd(nxt_task_t *task, nxt_runtime_t *rt); 31 static nxt_sockaddr_t *nxt_runtime_sockaddr_parse(nxt_task_t *task, 32 nxt_mp_t *mp, nxt_str_t *addr); 33 static nxt_sockaddr_t *nxt_runtime_sockaddr_unix_parse(nxt_task_t *task, 34 nxt_mp_t *mp, nxt_str_t *addr); 35 static nxt_sockaddr_t *nxt_runtime_sockaddr_inet6_parse(nxt_task_t *task, 36 nxt_mp_t *mp, nxt_str_t *addr); 37 static nxt_sockaddr_t *nxt_runtime_sockaddr_inet_parse(nxt_task_t *task, 38 nxt_mp_t *mp, nxt_str_t *addr); 39 static nxt_int_t nxt_runtime_hostname(nxt_task_t *task, nxt_runtime_t *rt); 40 static nxt_int_t nxt_runtime_log_files_init(nxt_runtime_t *rt); 41 static nxt_int_t nxt_runtime_log_files_create(nxt_task_t *task, 42 nxt_runtime_t *rt); 43 static nxt_int_t nxt_runtime_pid_file_create(nxt_task_t *task, 44 nxt_file_name_t *pid_file); 45 static void nxt_runtime_thread_pool_destroy(nxt_task_t *task, nxt_runtime_t *rt, 46 nxt_runtime_cont_t cont); 47 static void nxt_runtime_thread_pool_init(void); 48 static void nxt_runtime_thread_pool_exit(nxt_task_t *task, void *obj, 49 void *data); 50 static void nxt_runtime_process_destroy(nxt_runtime_t *rt, 51 nxt_process_t *process); 52 static nxt_process_t *nxt_runtime_process_remove_pid(nxt_runtime_t *rt, 53 nxt_pid_t pid); 54 55 56 nxt_int_t 57 nxt_runtime_create(nxt_task_t *task) 58 { 59 nxt_mp_t *mp; 60 nxt_int_t ret; 61 nxt_array_t *listen_sockets; 62 nxt_runtime_t *rt; 63 nxt_app_lang_module_t *lang; 64 65 mp = nxt_mp_create(1024, 128, 256, 32); 66 67 if (nxt_slow_path(mp == NULL)) { 68 return NXT_ERROR; 69 } 70 71 rt = nxt_mp_zget(mp, sizeof(nxt_runtime_t)); 72 if (nxt_slow_path(rt == NULL)) { 73 return NXT_ERROR; 74 } 75 76 task->thread->runtime = rt; 77 rt->mem_pool = mp; 78 79 nxt_thread_mutex_create(&rt->processes_mutex); 80 81 rt->services = nxt_services_init(mp); 82 if (nxt_slow_path(rt->services == NULL)) { 83 goto fail; 84 } 85 86 rt->languages = nxt_array_create(mp, 1, sizeof(nxt_app_lang_module_t)); 87 if (nxt_slow_path(rt->languages == NULL)) { 88 goto fail; 89 } 90 91 /* Should not fail. */ 92 lang = nxt_array_add(rt->languages); 93 lang->type = (nxt_str_t) nxt_string("go"); 94 lang->version = (nxt_str_t) nxt_null_string; 95 lang->file = NULL; 96 lang->module = &nxt_go_module; 97 98 listen_sockets = nxt_array_create(mp, 1, sizeof(nxt_listen_socket_t)); 99 if (nxt_slow_path(listen_sockets == NULL)) { 100 goto fail; 101 } 102 103 rt->listen_sockets = listen_sockets; 104 105 ret = nxt_runtime_inherited_listen_sockets(task, rt); 106 if (nxt_slow_path(ret != NXT_OK)) { 107 goto fail; 108 } 109 110 if (nxt_runtime_hostname(task, rt) != NXT_OK) { 111 goto fail; 112 } 113 114 if (nxt_slow_path(nxt_runtime_log_files_init(rt) != NXT_OK)) { 115 goto fail; 116 } 117 118 if (nxt_runtime_event_engines(task, rt) != NXT_OK) { 119 goto fail; 120 } 121 122 if (nxt_slow_path(nxt_runtime_thread_pools(task->thread, rt) != NXT_OK)) { 123 goto fail; 124 } 125 126 rt->start = nxt_runtime_initial_start; 127 128 if (nxt_runtime_conf_init(task, rt) != NXT_OK) { 129 goto fail; 130 } 131 132 nxt_work_queue_add(&task->thread->engine->fast_work_queue, 133 nxt_runtime_start, task, rt, NULL); 134 135 return NXT_OK; 136 137 fail: 138 139 nxt_mp_destroy(mp); 140 141 return NXT_ERROR; 142 } 143 144 145 static nxt_int_t 146 nxt_runtime_inherited_listen_sockets(nxt_task_t *task, nxt_runtime_t *rt) 147 { 148 u_char *v, *p; 149 nxt_int_t type; 150 nxt_array_t *inherited_sockets; 151 nxt_socket_t s; 152 nxt_listen_socket_t *ls; 153 154 v = (u_char *) getenv("NGINX"); 155 156 if (v == NULL) { 157 return nxt_runtime_systemd_listen_sockets(task, rt); 158 } 159 160 nxt_log(task, NXT_LOG_CRIT, "using inherited listen sockets: %s", v); 161 162 inherited_sockets = nxt_array_create(rt->mem_pool, 163 1, sizeof(nxt_listen_socket_t)); 164 if (inherited_sockets == NULL) { 165 return NXT_ERROR; 166 } 167 168 rt->inherited_sockets = inherited_sockets; 169 170 for (p = v; *p != '\0'; p++) { 171 172 if (*p == ';') { 173 s = nxt_int_parse(v, p - v); 174 175 if (nxt_slow_path(s < 0)) { 176 nxt_log(task, NXT_LOG_CRIT, "invalid socket number " 177 "\"%s\" in NGINX environment variable, " 178 "ignoring the rest of the variable", v); 179 return NXT_ERROR; 180 } 181 182 v = p + 1; 183 184 ls = nxt_array_zero_add(inherited_sockets); 185 if (nxt_slow_path(ls == NULL)) { 186 return NXT_ERROR; 187 } 188 189 ls->socket = s; 190 191 ls->sockaddr = nxt_getsockname(task, rt->mem_pool, s); 192 if (nxt_slow_path(ls->sockaddr == NULL)) { 193 return NXT_ERROR; 194 } 195 196 type = nxt_socket_getsockopt(task, s, SOL_SOCKET, SO_TYPE); 197 if (nxt_slow_path(type == -1)) { 198 return NXT_ERROR; 199 } 200 201 ls->sockaddr->type = (uint16_t) type; 202 } 203 } 204 205 return NXT_OK; 206 } 207 208 209 static nxt_int_t 210 nxt_runtime_systemd_listen_sockets(nxt_task_t *task, nxt_runtime_t *rt) 211 { 212 u_char *nfd, *pid; 213 nxt_int_t n; 214 nxt_array_t *inherited_sockets; 215 nxt_socket_t s; 216 nxt_listen_socket_t *ls; 217 218 /* 219 * Number of listening sockets passed. The socket 220 * descriptors start from number 3 and are sequential. 221 */ 222 nfd = (u_char *) getenv("LISTEN_FDS"); 223 if (nfd == NULL) { 224 return NXT_OK; 225 } 226 227 /* The pid of the service process. */ 228 pid = (u_char *) getenv("LISTEN_PID"); 229 if (pid == NULL) { 230 return NXT_OK; 231 } 232 233 n = nxt_int_parse(nfd, nxt_strlen(nfd)); 234 if (n < 0) { 235 return NXT_OK; 236 } 237 238 if (nxt_pid != nxt_int_parse(pid, nxt_strlen(pid))) { 239 return NXT_OK; 240 } 241 242 nxt_log(task, NXT_LOG_INFO, "using %s systemd listen sockets", n); 243 244 inherited_sockets = nxt_array_create(rt->mem_pool, 245 n, sizeof(nxt_listen_socket_t)); 246 if (inherited_sockets == NULL) { 247 return NXT_ERROR; 248 } 249 250 rt->inherited_sockets = inherited_sockets; 251 252 for (s = 3; s < n; s++) { 253 ls = nxt_array_zero_add(inherited_sockets); 254 if (nxt_slow_path(ls == NULL)) { 255 return NXT_ERROR; 256 } 257 258 ls->socket = s; 259 260 ls->sockaddr = nxt_getsockname(task, rt->mem_pool, s); 261 if (nxt_slow_path(ls->sockaddr == NULL)) { 262 return NXT_ERROR; 263 } 264 265 ls->sockaddr->type = SOCK_STREAM; 266 } 267 268 return NXT_OK; 269 } 270 271 272 static nxt_int_t 273 nxt_runtime_event_engines(nxt_task_t *task, nxt_runtime_t *rt) 274 { 275 nxt_thread_t *thread; 276 nxt_event_engine_t *engine; 277 const nxt_event_interface_t *interface; 278 279 interface = nxt_service_get(rt->services, "engine", NULL); 280 281 if (nxt_slow_path(interface == NULL)) { 282 /* TODO: log */ 283 return NXT_ERROR; 284 } 285 286 engine = nxt_event_engine_create(task, interface, 287 nxt_master_process_signals, 0, 0); 288 289 if (nxt_slow_path(engine == NULL)) { 290 return NXT_ERROR; 291 } 292 293 thread = task->thread; 294 thread->engine = engine; 295 thread->fiber = &engine->fibers->fiber; 296 297 engine->id = rt->last_engine_id++; 298 299 nxt_queue_init(&rt->engines); 300 nxt_queue_insert_tail(&rt->engines, &engine->link); 301 302 return NXT_OK; 303 } 304 305 306 static nxt_int_t 307 nxt_runtime_thread_pools(nxt_thread_t *thr, nxt_runtime_t *rt) 308 { 309 nxt_int_t ret; 310 nxt_array_t *thread_pools; 311 312 thread_pools = nxt_array_create(rt->mem_pool, 1, 313 sizeof(nxt_thread_pool_t *)); 314 315 if (nxt_slow_path(thread_pools == NULL)) { 316 return NXT_ERROR; 317 } 318 319 rt->thread_pools = thread_pools; 320 ret = nxt_runtime_thread_pool_create(thr, rt, 2, 60000 * 1000000LL); 321 322 if (nxt_slow_path(ret != NXT_OK)) { 323 return NXT_ERROR; 324 } 325 326 return NXT_OK; 327 } 328 329 330 static void 331 nxt_runtime_start(nxt_task_t *task, void *obj, void *data) 332 { 333 nxt_runtime_t *rt; 334 335 rt = obj; 336 337 nxt_debug(task, "rt conf done"); 338 339 task->thread->log->ctx_handler = NULL; 340 task->thread->log->ctx = NULL; 341 342 if (nxt_runtime_log_files_create(task, rt) != NXT_OK) { 343 goto fail; 344 } 345 346 if (nxt_runtime_event_engine_change(task, rt) != NXT_OK) { 347 goto fail; 348 } 349 350 /* 351 * Thread pools should be destroyed before starting worker 352 * processes, because thread pool semaphores will stick in 353 * locked state in new processes after fork(). 354 */ 355 nxt_runtime_thread_pool_destroy(task, rt, rt->start); 356 357 return; 358 359 fail: 360 361 nxt_runtime_quit(task); 362 } 363 364 365 static void 366 nxt_runtime_initial_start(nxt_task_t *task) 367 { 368 nxt_int_t ret; 369 nxt_thread_t *thr; 370 nxt_runtime_t *rt; 371 const nxt_event_interface_t *interface; 372 373 thr = task->thread; 374 rt = thr->runtime; 375 376 if (rt->inherited_sockets == NULL && rt->daemon) { 377 378 if (nxt_process_daemon(task) != NXT_OK) { 379 goto fail; 380 } 381 382 /* 383 * An event engine should be updated after fork() 384 * even if an event facility was not changed because: 385 * 1) inherited kqueue descriptor is invalid, 386 * 2) the signal thread is not inherited. 387 */ 388 interface = nxt_service_get(rt->services, "engine", rt->engine); 389 if (interface == NULL) { 390 goto fail; 391 } 392 393 ret = nxt_event_engine_change(task->thread->engine, interface, 394 rt->batch); 395 if (ret != NXT_OK) { 396 goto fail; 397 } 398 } 399 400 ret = nxt_runtime_pid_file_create(task, rt->pid_file); 401 if (ret != NXT_OK) { 402 goto fail; 403 } 404 405 if (nxt_runtime_event_engine_change(task, rt) != NXT_OK) { 406 goto fail; 407 } 408 409 thr->engine->max_connections = rt->engine_connections; 410 411 if (rt->master_process) { 412 if (nxt_master_process_start(thr, task, rt) != NXT_ERROR) { 413 return; 414 } 415 416 } else { 417 nxt_single_process_start(thr, task, rt); 418 return; 419 } 420 421 fail: 422 423 nxt_runtime_quit(task); 424 } 425 426 427 static void 428 nxt_single_process_start(nxt_thread_t *thr, nxt_task_t *task, nxt_runtime_t *rt) 429 { 430 nxt_int_t ret; 431 432 ret = nxt_runtime_thread_pool_create(thr, rt, rt->auxiliary_threads, 433 60000 * 1000000LL); 434 435 if (nxt_slow_path(ret != NXT_OK)) { 436 nxt_runtime_quit(task); 437 return; 438 } 439 440 rt->types |= (1U << NXT_PROCESS_SINGLE); 441 442 nxt_runtime_listen_sockets_enable(task, rt); 443 444 return; 445 } 446 447 448 void 449 nxt_runtime_quit(nxt_task_t *task) 450 { 451 nxt_bool_t done; 452 nxt_runtime_t *rt; 453 nxt_event_engine_t *engine; 454 455 rt = task->thread->runtime; 456 engine = task->thread->engine; 457 458 nxt_debug(task, "exiting"); 459 460 done = 1; 461 462 if (!engine->shutdown) { 463 engine->shutdown = 1; 464 465 if (!nxt_array_is_empty(rt->thread_pools)) { 466 nxt_runtime_thread_pool_destroy(task, rt, nxt_runtime_quit); 467 done = 0; 468 } 469 470 if (nxt_runtime_is_master(rt)) { 471 nxt_master_stop_worker_processes(task, rt); 472 done = 0; 473 } 474 } 475 476 nxt_runtime_close_idle_connections(engine); 477 478 if (done) { 479 nxt_work_queue_add(&engine->fast_work_queue, nxt_runtime_exit, 480 task, rt, engine); 481 } 482 } 483 484 485 static void 486 nxt_runtime_close_idle_connections(nxt_event_engine_t *engine) 487 { 488 nxt_conn_t *c; 489 nxt_queue_t *idle; 490 nxt_queue_link_t *link, *next; 491 492 nxt_debug(&engine->task, "close idle connections"); 493 494 idle = &engine->idle_connections; 495 496 for (link = nxt_queue_head(idle); 497 link != nxt_queue_tail(idle); 498 link = next) 499 { 500 next = nxt_queue_next(link); 501 c = nxt_queue_link_data(link, nxt_conn_t, link); 502 503 if (!c->socket.read_ready) { 504 nxt_queue_remove(link); 505 nxt_conn_close(engine, c); 506 } 507 } 508 } 509 510 511 static void 512 nxt_runtime_exit(nxt_task_t *task, void *obj, void *data) 513 { 514 nxt_runtime_t *rt; 515 nxt_process_t *process; 516 nxt_event_engine_t *engine; 517 518 rt = obj; 519 engine = data; 520 521 nxt_debug(task, "thread pools: %d", rt->thread_pools->nelts); 522 523 if (!nxt_array_is_empty(rt->thread_pools)) { 524 return; 525 } 526 527 if (nxt_runtime_is_master(rt)) { 528 if (rt->pid_file != NULL) { 529 nxt_file_delete(rt->pid_file); 530 } 531 532 #if (NXT_HAVE_UNIX_DOMAIN) 533 { 534 nxt_sockaddr_t *sa; 535 nxt_file_name_t *name; 536 537 sa = rt->controller_listen; 538 539 if (sa->u.sockaddr.sa_family == AF_UNIX) { 540 name = (nxt_file_name_t *) sa->u.sockaddr_un.sun_path; 541 (void) nxt_file_delete(name); 542 } 543 } 544 #endif 545 } 546 547 if (!engine->event.signal_support) { 548 nxt_event_engine_signals_stop(engine); 549 } 550 551 nxt_runtime_process_each(rt, process) { 552 553 nxt_runtime_process_remove(rt, process); 554 555 } nxt_runtime_process_loop; 556 557 nxt_thread_mutex_destroy(&rt->processes_mutex); 558 559 nxt_mp_destroy(rt->mem_pool); 560 561 nxt_debug(task, "exit"); 562 563 exit(0); 564 nxt_unreachable(); 565 } 566 567 568 static nxt_int_t 569 nxt_runtime_event_engine_change(nxt_task_t *task, nxt_runtime_t *rt) 570 { 571 nxt_event_engine_t *engine; 572 const nxt_event_interface_t *interface; 573 574 engine = task->thread->engine; 575 576 if (engine->batch == rt->batch 577 && nxt_strcmp(engine->event.name, rt->engine) == 0) 578 { 579 return NXT_OK; 580 } 581 582 interface = nxt_service_get(rt->services, "engine", rt->engine); 583 584 if (interface != NULL) { 585 return nxt_event_engine_change(engine, interface, rt->batch); 586 } 587 588 return NXT_ERROR; 589 } 590 591 592 void 593 nxt_runtime_event_engine_free(nxt_runtime_t *rt) 594 { 595 nxt_queue_link_t *link; 596 nxt_event_engine_t *engine; 597 598 link = nxt_queue_first(&rt->engines); 599 nxt_queue_remove(link); 600 601 engine = nxt_queue_link_data(link, nxt_event_engine_t, link); 602 nxt_event_engine_free(engine); 603 } 604 605 606 nxt_int_t 607 nxt_runtime_thread_pool_create(nxt_thread_t *thr, nxt_runtime_t *rt, 608 nxt_uint_t max_threads, nxt_nsec_t timeout) 609 { 610 nxt_thread_pool_t *thread_pool, **tp; 611 612 tp = nxt_array_add(rt->thread_pools); 613 if (tp == NULL) { 614 return NXT_ERROR; 615 } 616 617 thread_pool = nxt_thread_pool_create(max_threads, timeout, 618 nxt_runtime_thread_pool_init, 619 thr->engine, 620 nxt_runtime_thread_pool_exit); 621 622 if (nxt_fast_path(thread_pool != NULL)) { 623 *tp = thread_pool; 624 } 625 626 return NXT_OK; 627 } 628 629 630 static void 631 nxt_runtime_thread_pool_destroy(nxt_task_t *task, nxt_runtime_t *rt, 632 nxt_runtime_cont_t cont) 633 { 634 nxt_uint_t n; 635 nxt_thread_pool_t **tp; 636 637 rt->continuation = cont; 638 639 n = rt->thread_pools->nelts; 640 641 if (n == 0) { 642 cont(task); 643 return; 644 } 645 646 tp = rt->thread_pools->elts; 647 648 do { 649 nxt_thread_pool_destroy(*tp); 650 651 tp++; 652 n--; 653 } while (n != 0); 654 } 655 656 657 static void 658 nxt_runtime_thread_pool_init(void) 659 { 660 #if (NXT_REGEX) 661 nxt_regex_init(0); 662 #endif 663 } 664 665 666 static void 667 nxt_runtime_thread_pool_exit(nxt_task_t *task, void *obj, void *data) 668 { 669 nxt_uint_t i, n; 670 nxt_runtime_t *rt; 671 nxt_thread_pool_t *tp, **thread_pools; 672 nxt_thread_handle_t handle; 673 674 tp = obj; 675 676 if (data != NULL) { 677 handle = (nxt_thread_handle_t) (uintptr_t) data; 678 nxt_thread_wait(handle); 679 } 680 681 rt = task->thread->runtime; 682 683 thread_pools = rt->thread_pools->elts; 684 n = rt->thread_pools->nelts; 685 686 nxt_debug(task, "thread pools: %ui", n); 687 688 for (i = 0; i < n; i++) { 689 690 if (tp == thread_pools[i]) { 691 nxt_array_remove(rt->thread_pools, &thread_pools[i]); 692 693 if (n == 1) { 694 /* The last thread pool. */ 695 rt->continuation(task); 696 } 697 698 return; 699 } 700 } 701 } 702 703 704 static nxt_int_t 705 nxt_runtime_conf_init(nxt_task_t *task, nxt_runtime_t *rt) 706 { 707 nxt_int_t ret; 708 nxt_file_t *file; 709 nxt_str_t control; 710 nxt_sockaddr_t *sa; 711 nxt_file_name_str_t file_name; 712 const nxt_event_interface_t *interface; 713 714 rt->daemon = 1; 715 rt->master_process = 1; 716 rt->engine_connections = 256; 717 rt->auxiliary_threads = 2; 718 rt->user_cred.user = NXT_USER; 719 rt->group = NXT_GROUP; 720 rt->pid = NXT_PID; 721 rt->log = NXT_LOG; 722 rt->modules = NXT_MODULES; 723 rt->control = NXT_CONTROL_SOCK; 724 725 if (nxt_runtime_conf_read_cmd(task, rt) != NXT_OK) { 726 return NXT_ERROR; 727 } 728 729 if (nxt_user_cred_get(task, &rt->user_cred, rt->group) != NXT_OK) { 730 return NXT_ERROR; 731 } 732 733 /* An engine's parameters. */ 734 735 interface = nxt_service_get(rt->services, "engine", rt->engine); 736 if (interface == NULL) { 737 return NXT_ERROR; 738 } 739 740 rt->engine = interface->name; 741 742 ret = nxt_file_name_create(rt->mem_pool, &file_name, "s%Z", rt->pid); 743 if (nxt_slow_path(ret != NXT_OK)) { 744 return NXT_ERROR; 745 } 746 747 rt->pid_file = file_name.start; 748 749 ret = nxt_file_name_create(rt->mem_pool, &file_name, "%s%Z", rt->log); 750 if (nxt_slow_path(ret != NXT_OK)) { 751 return NXT_ERROR; 752 } 753 754 file = nxt_list_first(rt->log_files); 755 file->name = file_name.start; 756 757 ret = nxt_file_name_create(rt->mem_pool, &file_name, "%snginext.*%Z", 758 rt->modules); 759 if (nxt_slow_path(ret != NXT_OK)) { 760 return NXT_ERROR; 761 } 762 763 rt->modules = (char *) file_name.start; 764 765 control.length = nxt_strlen(rt->control); 766 control.start = (u_char *) rt->control; 767 768 sa = nxt_runtime_sockaddr_parse(task, rt->mem_pool, &control); 769 if (nxt_slow_path(sa == NULL)) { 770 return NXT_ERROR; 771 } 772 773 rt->controller_listen = sa; 774 775 if (nxt_runtime_controller_socket(task, rt) != NXT_OK) { 776 return NXT_ERROR; 777 } 778 779 return NXT_OK; 780 } 781 782 783 static nxt_int_t 784 nxt_runtime_conf_read_cmd(nxt_task_t *task, nxt_runtime_t *rt) 785 { 786 char *p, **argv; 787 u_char *end; 788 u_char buf[1024]; 789 790 static const char version[] = 791 "nginext version: " NXT_VERSION "\n" 792 "configured as ./configure" NXT_CONFIGURE_OPTIONS "\n"; 793 794 static const char no_control[] = 795 "option \"--control\" requires socket address\n"; 796 static const char no_user[] = "option \"--user\" requires username\n"; 797 static const char no_group[] = "option \"--group\" requires group name\n"; 798 static const char no_pid[] = "option \"--pid\" requires filename\n"; 799 static const char no_log[] = "option \"--log\" requires filename\n"; 800 static const char no_modules[] = 801 "option \"--modules\" requires directory\n"; 802 803 static const char help[] = 804 "\n" 805 "nginext options:\n" 806 "\n" 807 " --version print nginext version and configure options\n" 808 "\n" 809 " --no-daemon run nginext in non-daemon mode\n" 810 "\n" 811 " --control ADDRESS set address of control API socket\n" 812 " default: \"" NXT_CONTROL_SOCK "\"\n" 813 "\n" 814 " --pid FILE set pid file name\n" 815 " default: \"" NXT_PID "\"\n" 816 "\n" 817 " --log FILE set log file name\n" 818 " default: \"" NXT_LOG "\"\n" 819 "\n" 820 " --modules DIRECTORY set modules directory\n" 821 " default: \"" NXT_MODULES "\"\n" 822 "\n" 823 " --user USER set non-privileged processes to run" 824 " as specified user\n" 825 " default: \"" NXT_USER "\"\n" 826 "\n" 827 " --group GROUP set non-privileged processes to run" 828 " as specified group\n" 829 " default: "; 830 831 static const char group[] = "\"" NXT_GROUP "\"\n\n"; 832 static const char primary[] = "user's primary group\n\n"; 833 834 argv = &nxt_process_argv[1]; 835 836 while (*argv != NULL) { 837 p = *argv++; 838 839 if (nxt_strcmp(p, "--control") == 0) { 840 if (*argv == NULL) { 841 write(STDERR_FILENO, no_control, sizeof(no_control) - 1); 842 return NXT_ERROR; 843 } 844 845 p = *argv++; 846 847 rt->control = p; 848 849 continue; 850 } 851 852 if (nxt_strcmp(p, "--upstream") == 0) { 853 if (*argv == NULL) { 854 nxt_log(task, NXT_LOG_CRIT, 855 "no argument for option \"--upstream\""); 856 return NXT_ERROR; 857 } 858 859 p = *argv++; 860 861 rt->upstream.length = nxt_strlen(p); 862 rt->upstream.start = (u_char *) p; 863 864 continue; 865 } 866 867 if (nxt_strcmp(p, "--user") == 0) { 868 if (*argv == NULL) { 869 write(STDERR_FILENO, no_user, sizeof(no_user) - 1); 870 return NXT_ERROR; 871 } 872 873 p = *argv++; 874 875 rt->user_cred.user = p; 876 877 continue; 878 } 879 880 if (nxt_strcmp(p, "--group") == 0) { 881 if (*argv == NULL) { 882 write(STDERR_FILENO, no_group, sizeof(no_group) - 1); 883 return NXT_ERROR; 884 } 885 886 p = *argv++; 887 888 rt->group = p; 889 890 continue; 891 } 892 893 if (nxt_strcmp(p, "--pid") == 0) { 894 if (*argv == NULL) { 895 write(STDERR_FILENO, no_pid, sizeof(no_pid) - 1); 896 return NXT_ERROR; 897 } 898 899 p = *argv++; 900 901 rt->pid = p; 902 903 continue; 904 } 905 906 if (nxt_strcmp(p, "--log") == 0) { 907 if (*argv == NULL) { 908 write(STDERR_FILENO, no_log, sizeof(no_log) - 1); 909 return NXT_ERROR; 910 } 911 912 p = *argv++; 913 914 rt->log = p; 915 916 continue; 917 } 918 919 if (nxt_strcmp(p, "--modules") == 0) { 920 if (*argv == NULL) { 921 write(STDERR_FILENO, no_modules, sizeof(no_modules) - 1); 922 return NXT_ERROR; 923 } 924 925 p = *argv++; 926 927 rt->modules = p; 928 929 continue; 930 } 931 932 if (nxt_strcmp(p, "--no-daemon") == 0) { 933 rt->daemon = 0; 934 continue; 935 } 936 937 if (nxt_strcmp(p, "--version") == 0) { 938 write(STDERR_FILENO, version, sizeof(version) - 1); 939 exit(0); 940 } 941 942 if (nxt_strcmp(p, "--help") == 0) { 943 write(STDOUT_FILENO, help, sizeof(help) - 1); 944 945 if (sizeof(NXT_GROUP) == 1) { 946 write(STDOUT_FILENO, primary, sizeof(primary) - 1); 947 948 } else { 949 write(STDOUT_FILENO, group, sizeof(group) - 1); 950 } 951 952 exit(0); 953 } 954 955 end = nxt_sprintf(buf, buf + sizeof(buf), "unknown option \"%s\"\n", p); 956 write(STDERR_FILENO, buf, end - buf); 957 958 return NXT_ERROR; 959 } 960 961 return NXT_OK; 962 } 963 964 965 static nxt_sockaddr_t * 966 nxt_runtime_sockaddr_parse(nxt_task_t *task, nxt_mp_t *mp, nxt_str_t *addr) 967 { 968 u_char *p; 969 size_t length; 970 971 length = addr->length; 972 p = addr->start; 973 974 if (length >= 5 && nxt_memcmp(p, "unix:", 5) == 0) { 975 return nxt_runtime_sockaddr_unix_parse(task, mp, addr); 976 } 977 978 if (length != 0 && *p == '[') { 979 return nxt_runtime_sockaddr_inet6_parse(task, mp, addr); 980 } 981 982 return nxt_runtime_sockaddr_inet_parse(task, mp, addr); 983 } 984 985 986 static nxt_sockaddr_t * 987 nxt_runtime_sockaddr_unix_parse(nxt_task_t *task, nxt_mp_t *mp, nxt_str_t *addr) 988 { 989 #if (NXT_HAVE_UNIX_DOMAIN) 990 u_char *p; 991 size_t length, socklen; 992 nxt_sockaddr_t *sa; 993 994 /* 995 * Actual sockaddr_un length can be lesser or even larger than defined 996 * struct sockaddr_un length (see comment in nxt_socket.h). So 997 * limit maximum Unix domain socket address length by defined sun_path[] 998 * length because some OSes accept addresses twice larger than defined 999 * struct sockaddr_un. Also reserve space for a trailing zero to avoid 1000 * ambiguity, since many OSes accept Unix domain socket addresses 1001 * without a trailing zero. 1002 */ 1003 const size_t max_len = sizeof(struct sockaddr_un) 1004 - offsetof(struct sockaddr_un, sun_path) - 1; 1005 1006 /* cutting "unix:" */ 1007 length = addr->length - 5; 1008 p = addr->start + 5; 1009 1010 if (length == 0) { 1011 nxt_log(task, NXT_LOG_CRIT, 1012 "unix domain socket \"%V\" name is invalid", addr); 1013 return NULL; 1014 } 1015 1016 if (length > max_len) { 1017 nxt_log(task, NXT_LOG_CRIT, 1018 "unix domain socket \"%V\" name is too long", addr); 1019 return NULL; 1020 } 1021 1022 socklen = offsetof(struct sockaddr_un, sun_path) + length + 1; 1023 1024 #if (NXT_LINUX) 1025 1026 /* 1027 * Linux unix(7): 1028 * 1029 * abstract: an abstract socket address is distinguished by the fact 1030 * that sun_path[0] is a null byte ('\0'). The socket's address in 1031 * this namespace is given by the additional bytes in sun_path that 1032 * are covered by the specified length of the address structure. 1033 * (Null bytes in the name have no special significance.) 1034 */ 1035 if (p[0] == '@') { 1036 p[0] = '\0'; 1037 socklen--; 1038 } 1039 1040 #endif 1041 1042 sa = nxt_sockaddr_alloc(mp, socklen, addr->length); 1043 1044 if (nxt_slow_path(sa == NULL)) { 1045 return NULL; 1046 } 1047 1048 sa->type = SOCK_STREAM; 1049 1050 sa->u.sockaddr_un.sun_family = AF_UNIX; 1051 nxt_memcpy(sa->u.sockaddr_un.sun_path, p, length); 1052 1053 return sa; 1054 1055 #else /* !(NXT_HAVE_UNIX_DOMAIN) */ 1056 1057 nxt_log(task, NXT_LOG_CRIT, "unix domain socket \"%V\" is not supported", 1058 addr); 1059 1060 return NULL; 1061 1062 #endif 1063 } 1064 1065 1066 static nxt_sockaddr_t * 1067 nxt_runtime_sockaddr_inet6_parse(nxt_task_t *task, nxt_mp_t *mp, 1068 nxt_str_t *addr) 1069 { 1070 #if (NXT_INET6) 1071 u_char *p, *addr_end; 1072 size_t length; 1073 nxt_int_t port; 1074 nxt_sockaddr_t *sa; 1075 struct in6_addr *in6_addr; 1076 1077 length = addr->length - 1; 1078 p = addr->start + 1; 1079 1080 addr_end = nxt_memchr(p, ']', length); 1081 1082 if (addr_end == NULL) { 1083 goto invalid_address; 1084 } 1085 1086 sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in6), 1087 NXT_INET6_ADDR_STR_LEN); 1088 if (nxt_slow_path(sa == NULL)) { 1089 return NULL; 1090 } 1091 1092 in6_addr = &sa->u.sockaddr_in6.sin6_addr; 1093 1094 if (nxt_inet6_addr(in6_addr, p, addr_end - p) != NXT_OK) { 1095 goto invalid_address; 1096 } 1097 1098 port = 0; 1099 p = addr_end + 1; 1100 length = (p + length) - p; 1101 1102 if (length == 0) { 1103 goto found; 1104 } 1105 1106 if (*p == ':') { 1107 port = nxt_int_parse(p + 1, length - 1); 1108 1109 if (port >= 1 && port <= 65535) { 1110 goto found; 1111 } 1112 } 1113 1114 nxt_log(task, NXT_LOG_CRIT, "invalid port in \"%V\"", addr); 1115 1116 return NULL; 1117 1118 found: 1119 1120 sa->type = SOCK_STREAM; 1121 1122 sa->u.sockaddr_in6.sin6_family = AF_INET6; 1123 sa->u.sockaddr_in6.sin6_port = htons((in_port_t) port); 1124 1125 return sa; 1126 1127 invalid_address: 1128 1129 nxt_log(task, NXT_LOG_CRIT, "invalid IPv6 address in \"%V\"", addr); 1130 1131 return NULL; 1132 1133 #else 1134 1135 nxt_log(task, NXT_LOG_CRIT, "IPv6 socket \"%V\" is not supported", addr); 1136 1137 return NULL; 1138 1139 #endif 1140 } 1141 1142 1143 static nxt_sockaddr_t * 1144 nxt_runtime_sockaddr_inet_parse(nxt_task_t *task, nxt_mp_t *mp, 1145 nxt_str_t *string) 1146 { 1147 u_char *p, *ip; 1148 size_t length; 1149 in_addr_t addr; 1150 nxt_int_t port; 1151 nxt_sockaddr_t *sa; 1152 1153 addr = INADDR_ANY; 1154 1155 length = string->length; 1156 ip = string->start; 1157 1158 p = nxt_memchr(ip, ':', length); 1159 1160 if (p == NULL) { 1161 1162 /* single value port, or address */ 1163 1164 port = nxt_int_parse(ip, length); 1165 1166 if (port > 0) { 1167 /* "*:XX" */ 1168 1169 if (port < 1 || port > 65535) { 1170 goto invalid_port; 1171 } 1172 1173 } else { 1174 /* "x.x.x.x" */ 1175 1176 addr = nxt_inet_addr(ip, length); 1177 1178 if (addr == INADDR_NONE) { 1179 goto invalid_port; 1180 } 1181 1182 port = 8080; 1183 } 1184 1185 } else { 1186 1187 /* x.x.x.x:XX */ 1188 1189 p++; 1190 length = (ip + length) - p; 1191 port = nxt_int_parse(p, length); 1192 1193 if (port < 1 || port > 65535) { 1194 goto invalid_port; 1195 } 1196 1197 length = (p - 1) - ip; 1198 1199 if (length != 1 || ip[0] != '*') { 1200 addr = nxt_inet_addr(ip, length); 1201 1202 if (addr == INADDR_NONE) { 1203 goto invalid_addr; 1204 } 1205 1206 /* "x.x.x.x:XX" */ 1207 } 1208 } 1209 1210 sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in), 1211 NXT_INET_ADDR_STR_LEN); 1212 if (nxt_slow_path(sa == NULL)) { 1213 return NULL; 1214 } 1215 1216 sa->type = SOCK_STREAM; 1217 1218 sa->u.sockaddr_in.sin_family = AF_INET; 1219 sa->u.sockaddr_in.sin_port = htons((in_port_t) port); 1220 sa->u.sockaddr_in.sin_addr.s_addr = addr; 1221 1222 return sa; 1223 1224 invalid_port: 1225 1226 nxt_log(task, NXT_LOG_CRIT, "invalid port in \"%V\"", string); 1227 1228 return NULL; 1229 1230 invalid_addr: 1231 1232 nxt_log(task, NXT_LOG_CRIT, "invalid address in \"%V\"", string); 1233 1234 return NULL; 1235 } 1236 1237 1238 nxt_listen_socket_t * 1239 nxt_runtime_listen_socket_add(nxt_runtime_t *rt, nxt_sockaddr_t *sa) 1240 { 1241 nxt_mp_t *mp; 1242 nxt_listen_socket_t *ls; 1243 1244 ls = nxt_array_zero_add(rt->listen_sockets); 1245 if (ls == NULL) { 1246 return NULL; 1247 } 1248 1249 mp = rt->mem_pool; 1250 1251 ls->sockaddr = nxt_sockaddr_create(mp, &sa->u.sockaddr, sa->socklen, 1252 sa->length); 1253 if (ls->sockaddr == NULL) { 1254 return NULL; 1255 } 1256 1257 ls->sockaddr->type = sa->type; 1258 1259 nxt_sockaddr_text(ls->sockaddr); 1260 1261 ls->socket = -1; 1262 ls->backlog = NXT_LISTEN_BACKLOG; 1263 1264 return ls; 1265 } 1266 1267 1268 static nxt_int_t 1269 nxt_runtime_hostname(nxt_task_t *task, nxt_runtime_t *rt) 1270 { 1271 size_t length; 1272 char hostname[NXT_MAXHOSTNAMELEN + 1]; 1273 1274 if (gethostname(hostname, NXT_MAXHOSTNAMELEN) != 0) { 1275 nxt_log(task, NXT_LOG_CRIT, "gethostname() failed %E", nxt_errno); 1276 return NXT_ERROR; 1277 } 1278 1279 /* 1280 * Linux gethostname(2): 1281 * 1282 * If the null-terminated hostname is too large to fit, 1283 * then the name is truncated, and no error is returned. 1284 * 1285 * For this reason an additional byte is reserved in the buffer. 1286 */ 1287 hostname[NXT_MAXHOSTNAMELEN] = '\0'; 1288 1289 length = nxt_strlen(hostname); 1290 rt->hostname.length = length; 1291 1292 rt->hostname.start = nxt_mp_nget(rt->mem_pool, length); 1293 1294 if (rt->hostname.start != NULL) { 1295 nxt_memcpy_lowcase(rt->hostname.start, (u_char *) hostname, length); 1296 return NXT_OK; 1297 } 1298 1299 return NXT_ERROR; 1300 } 1301 1302 1303 static nxt_int_t 1304 nxt_runtime_log_files_init(nxt_runtime_t *rt) 1305 { 1306 nxt_file_t *file; 1307 nxt_list_t *log_files; 1308 1309 log_files = nxt_list_create(rt->mem_pool, 1, sizeof(nxt_file_t)); 1310 1311 if (nxt_fast_path(log_files != NULL)) { 1312 rt->log_files = log_files; 1313 1314 /* Preallocate the main log. This allocation cannot fail. */ 1315 file = nxt_list_zero_add(log_files); 1316 1317 file->fd = NXT_FILE_INVALID; 1318 file->log_level = NXT_LOG_CRIT; 1319 1320 return NXT_OK; 1321 } 1322 1323 return NXT_ERROR; 1324 } 1325 1326 1327 nxt_file_t * 1328 nxt_runtime_log_file_add(nxt_runtime_t *rt, nxt_str_t *name) 1329 { 1330 nxt_int_t ret; 1331 nxt_file_t *file; 1332 nxt_file_name_str_t file_name; 1333 1334 ret = nxt_file_name_create(rt->mem_pool, &file_name, "V%Z", name); 1335 1336 if (nxt_slow_path(ret != NXT_OK)) { 1337 return NULL; 1338 } 1339 1340 nxt_list_each(file, rt->log_files) { 1341 1342 /* STUB: hardecoded case sensitive/insensitive. */ 1343 1344 if (file->name != NULL 1345 && nxt_file_name_eq(file->name, file_name.start)) 1346 { 1347 return file; 1348 } 1349 1350 } nxt_list_loop; 1351 1352 file = nxt_list_zero_add(rt->log_files); 1353 1354 if (nxt_slow_path(file == NULL)) { 1355 return NULL; 1356 } 1357 1358 file->fd = NXT_FILE_INVALID; 1359 file->log_level = NXT_LOG_CRIT; 1360 file->name = file_name.start; 1361 1362 return file; 1363 } 1364 1365 1366 static nxt_int_t 1367 nxt_runtime_log_files_create(nxt_task_t *task, nxt_runtime_t *rt) 1368 { 1369 nxt_int_t ret; 1370 nxt_file_t *file; 1371 1372 nxt_list_each(file, rt->log_files) { 1373 1374 ret = nxt_file_open(task, file, O_WRONLY | O_APPEND, O_CREAT, 1375 NXT_FILE_OWNER_ACCESS); 1376 1377 if (ret != NXT_OK) { 1378 return NXT_ERROR; 1379 } 1380 1381 } nxt_list_loop; 1382 1383 file = nxt_list_first(rt->log_files); 1384 1385 return nxt_file_stderr(file); 1386 } 1387 1388 1389 nxt_int_t 1390 nxt_runtime_listen_sockets_create(nxt_task_t *task, nxt_runtime_t *rt) 1391 { 1392 nxt_int_t ret; 1393 nxt_uint_t c, p, ncurr, nprev; 1394 nxt_listen_socket_t *curr, *prev; 1395 1396 curr = rt->listen_sockets->elts; 1397 ncurr = rt->listen_sockets->nelts; 1398 1399 if (rt->inherited_sockets != NULL) { 1400 prev = rt->inherited_sockets->elts; 1401 nprev = rt->inherited_sockets->nelts; 1402 1403 } else { 1404 prev = NULL; 1405 nprev = 0; 1406 } 1407 1408 for (c = 0; c < ncurr; c++) { 1409 1410 for (p = 0; p < nprev; p++) { 1411 1412 if (nxt_sockaddr_cmp(curr[c].sockaddr, prev[p].sockaddr)) { 1413 1414 ret = nxt_listen_socket_update(task, &curr[c], &prev[p]); 1415 if (ret != NXT_OK) { 1416 return NXT_ERROR; 1417 } 1418 1419 goto next; 1420 } 1421 } 1422 1423 if (nxt_listen_socket_create(task, &curr[c], 0) != NXT_OK) { 1424 return NXT_ERROR; 1425 } 1426 1427 next: 1428 1429 continue; 1430 } 1431 1432 return NXT_OK; 1433 } 1434 1435 1436 nxt_int_t 1437 nxt_runtime_listen_sockets_enable(nxt_task_t *task, nxt_runtime_t *rt) 1438 { 1439 nxt_uint_t i, n; 1440 nxt_listen_socket_t *ls; 1441 1442 ls = rt->listen_sockets->elts; 1443 n = rt->listen_sockets->nelts; 1444 1445 for (i = 0; i < n; i++) { 1446 if (ls[i].flags == NXT_NONBLOCK) { 1447 if (nxt_listen_event(task, &ls[i]) == NULL) { 1448 return NXT_ERROR; 1449 } 1450 } 1451 } 1452 1453 return NXT_OK; 1454 } 1455 1456 1457 nxt_str_t * 1458 nxt_current_directory(nxt_mp_t *mp) 1459 { 1460 size_t length; 1461 u_char *p; 1462 nxt_str_t *name; 1463 char buf[NXT_MAX_PATH_LEN]; 1464 1465 length = nxt_dir_current(buf, NXT_MAX_PATH_LEN); 1466 1467 if (nxt_fast_path(length != 0)) { 1468 name = nxt_str_alloc(mp, length + 1); 1469 1470 if (nxt_fast_path(name != NULL)) { 1471 p = nxt_cpymem(name->start, buf, length); 1472 *p = '/'; 1473 1474 return name; 1475 } 1476 } 1477 1478 return NULL; 1479 } 1480 1481 1482 static nxt_int_t 1483 nxt_runtime_pid_file_create(nxt_task_t *task, nxt_file_name_t *pid_file) 1484 { 1485 ssize_t length; 1486 nxt_int_t n; 1487 nxt_file_t file; 1488 u_char pid[NXT_INT64_T_LEN + NXT_LINEFEED_SIZE]; 1489 1490 nxt_memzero(&file, sizeof(nxt_file_t)); 1491 1492 file.name = pid_file; 1493 1494 n = nxt_file_open(task, &file, O_WRONLY, O_CREAT | O_TRUNC, 1495 NXT_FILE_DEFAULT_ACCESS); 1496 1497 if (n != NXT_OK) { 1498 return NXT_ERROR; 1499 } 1500 1501 length = nxt_sprintf(pid, pid + sizeof(pid), "%PI%n", nxt_pid) - pid; 1502 1503 if (nxt_file_write(&file, pid, length, 0) != length) { 1504 return NXT_ERROR; 1505 } 1506 1507 nxt_file_close(task, &file); 1508 1509 return NXT_OK; 1510 } 1511 1512 1513 nxt_process_t * 1514 nxt_runtime_process_new(nxt_runtime_t *rt) 1515 { 1516 nxt_process_t *process; 1517 1518 /* TODO: memory failures. */ 1519 1520 process = nxt_mp_zalloc(rt->mem_pool, sizeof(nxt_process_t)); 1521 if (nxt_slow_path(process == NULL)) { 1522 return NULL; 1523 } 1524 1525 nxt_queue_init(&process->ports); 1526 1527 nxt_thread_mutex_create(&process->incoming_mutex); 1528 nxt_thread_mutex_create(&process->outgoing_mutex); 1529 nxt_thread_mutex_create(&process->cp_mutex); 1530 1531 return process; 1532 } 1533 1534 1535 static void 1536 nxt_runtime_process_destroy(nxt_runtime_t *rt, nxt_process_t *process) 1537 { 1538 nxt_assert(process->port_cleanups == 0); 1539 nxt_assert(process->registered == 0); 1540 1541 nxt_port_mmaps_destroy(process->incoming, 1); 1542 nxt_port_mmaps_destroy(process->outgoing, 1); 1543 1544 if (process->cp_mem_pool != NULL) { 1545 nxt_mp_thread_adopt(process->cp_mem_pool); 1546 1547 nxt_mp_destroy(process->cp_mem_pool); 1548 } 1549 1550 nxt_thread_mutex_destroy(&process->incoming_mutex); 1551 nxt_thread_mutex_destroy(&process->outgoing_mutex); 1552 nxt_thread_mutex_destroy(&process->cp_mutex); 1553 1554 nxt_mp_free(rt->mem_pool, process); 1555 } 1556 1557 1558 static nxt_int_t 1559 nxt_runtime_lvlhsh_pid_test(nxt_lvlhsh_query_t *lhq, void *data) 1560 { 1561 nxt_process_t *process; 1562 1563 process = data; 1564 1565 if (lhq->key.length == sizeof(nxt_pid_t) && 1566 *(nxt_pid_t *) lhq->key.start == process->pid) { 1567 return NXT_OK; 1568 } 1569 1570 return NXT_DECLINED; 1571 } 1572 1573 static const nxt_lvlhsh_proto_t lvlhsh_processes_proto nxt_aligned(64) = { 1574 NXT_LVLHSH_DEFAULT, 1575 nxt_runtime_lvlhsh_pid_test, 1576 nxt_lvlhsh_alloc, 1577 nxt_lvlhsh_free, 1578 }; 1579 1580 1581 nxt_inline void 1582 nxt_runtime_process_lhq_pid(nxt_lvlhsh_query_t *lhq, nxt_pid_t *pid) 1583 { 1584 lhq->key_hash = nxt_murmur_hash2(pid, sizeof(*pid)); 1585 lhq->key.length = sizeof(*pid); 1586 lhq->key.start = (u_char *) pid; 1587 lhq->proto = &lvlhsh_processes_proto; 1588 } 1589 1590 1591 nxt_process_t * 1592 nxt_runtime_process_find(nxt_runtime_t *rt, nxt_pid_t pid) 1593 { 1594 nxt_process_t *process; 1595 nxt_lvlhsh_query_t lhq; 1596 1597 process = NULL; 1598 1599 nxt_runtime_process_lhq_pid(&lhq, &pid); 1600 1601 nxt_thread_mutex_lock(&rt->processes_mutex); 1602 1603 if (nxt_lvlhsh_find(&rt->processes, &lhq) == NXT_OK) { 1604 process = lhq.value; 1605 1606 } else { 1607 nxt_thread_log_debug("process %PI not found", pid); 1608 } 1609 1610 nxt_thread_mutex_unlock(&rt->processes_mutex); 1611 1612 return process; 1613 } 1614 1615 1616 nxt_process_t * 1617 nxt_runtime_process_get(nxt_runtime_t *rt, nxt_pid_t pid) 1618 { 1619 nxt_process_t *process; 1620 nxt_lvlhsh_query_t lhq; 1621 1622 nxt_runtime_process_lhq_pid(&lhq, &pid); 1623 1624 nxt_thread_mutex_lock(&rt->processes_mutex); 1625 1626 if (nxt_lvlhsh_find(&rt->processes, &lhq) == NXT_OK) { 1627 nxt_thread_log_debug("process %PI found", pid); 1628 1629 nxt_thread_mutex_unlock(&rt->processes_mutex); 1630 return lhq.value; 1631 } 1632 1633 process = nxt_runtime_process_new(rt); 1634 if (nxt_slow_path(process == NULL)) { 1635 return NULL; 1636 } 1637 1638 process->pid = pid; 1639 1640 lhq.replace = 0; 1641 lhq.value = process; 1642 lhq.pool = rt->mem_pool; 1643 1644 switch (nxt_lvlhsh_insert(&rt->processes, &lhq)) { 1645 1646 case NXT_OK: 1647 if (rt->nprocesses == 0) { 1648 rt->mprocess = process; 1649 } 1650 1651 rt->nprocesses++; 1652 1653 process->registered = 1; 1654 1655 nxt_thread_log_debug("process %PI insert", pid); 1656 break; 1657 1658 default: 1659 nxt_thread_log_debug("process %PI insert failed", pid); 1660 break; 1661 } 1662 1663 nxt_thread_mutex_unlock(&rt->processes_mutex); 1664 1665 return process; 1666 } 1667 1668 1669 void 1670 nxt_runtime_process_add(nxt_runtime_t *rt, nxt_process_t *process) 1671 { 1672 nxt_port_t *port; 1673 nxt_lvlhsh_query_t lhq; 1674 1675 nxt_assert(process->registered == 0); 1676 1677 nxt_runtime_process_lhq_pid(&lhq, &process->pid); 1678 1679 lhq.replace = 0; 1680 lhq.value = process; 1681 lhq.pool = rt->mem_pool; 1682 1683 nxt_thread_mutex_lock(&rt->processes_mutex); 1684 1685 switch (nxt_lvlhsh_insert(&rt->processes, &lhq)) { 1686 1687 case NXT_OK: 1688 if (rt->nprocesses == 0) { 1689 rt->mprocess = process; 1690 } 1691 1692 rt->nprocesses++; 1693 1694 nxt_process_port_each(process, port) { 1695 1696 port->pid = process->pid; 1697 1698 nxt_runtime_port_add(rt, port); 1699 1700 } nxt_process_port_loop; 1701 1702 process->registered = 1; 1703 1704 nxt_thread_log_debug("process %PI added", process->pid); 1705 break; 1706 1707 default: 1708 nxt_thread_log_debug("process %PI failed to add", process->pid); 1709 break; 1710 } 1711 1712 nxt_thread_mutex_unlock(&rt->processes_mutex); 1713 } 1714 1715 1716 static nxt_process_t * 1717 nxt_runtime_process_remove_pid(nxt_runtime_t *rt, nxt_pid_t pid) 1718 { 1719 nxt_process_t *process; 1720 nxt_lvlhsh_query_t lhq; 1721 1722 process = NULL; 1723 1724 nxt_runtime_process_lhq_pid(&lhq, &pid); 1725 1726 lhq.pool = rt->mem_pool; 1727 1728 nxt_thread_mutex_lock(&rt->processes_mutex); 1729 1730 switch (nxt_lvlhsh_delete(&rt->processes, &lhq)) { 1731 1732 case NXT_OK: 1733 rt->nprocesses--; 1734 1735 process = lhq.value; 1736 1737 process->registered = 0; 1738 1739 nxt_thread_log_debug("process %PI removed", pid); 1740 break; 1741 1742 default: 1743 nxt_thread_log_debug("process %PI remove failed", pid); 1744 break; 1745 } 1746 1747 nxt_thread_mutex_unlock(&rt->processes_mutex); 1748 1749 return process; 1750 } 1751 1752 1753 void 1754 nxt_runtime_process_remove(nxt_runtime_t *rt, nxt_process_t *process) 1755 { 1756 nxt_port_t *port; 1757 1758 if (process->port_cleanups == 0) { 1759 if (process->registered == 1) { 1760 nxt_runtime_process_remove_pid(rt, process->pid); 1761 } 1762 1763 nxt_runtime_process_destroy(rt, process); 1764 1765 } else { 1766 nxt_process_port_each(process, port) { 1767 1768 nxt_runtime_port_remove(rt, port); 1769 1770 nxt_port_release(port); 1771 1772 } nxt_process_port_loop; 1773 } 1774 } 1775 1776 1777 nxt_process_t * 1778 nxt_runtime_process_first(nxt_runtime_t *rt, nxt_lvlhsh_each_t *lhe) 1779 { 1780 nxt_memzero(lhe, sizeof(nxt_lvlhsh_each_t)); 1781 1782 lhe->proto = &lvlhsh_processes_proto; 1783 1784 return nxt_runtime_process_next(rt, lhe); 1785 } 1786 1787 1788 nxt_port_t * 1789 nxt_runtime_port_first(nxt_runtime_t *rt, nxt_lvlhsh_each_t *lhe) 1790 { 1791 return nxt_port_hash_first(&rt->ports, lhe); 1792 } 1793 1794 1795 void 1796 nxt_runtime_port_add(nxt_runtime_t *rt, nxt_port_t *port) 1797 { 1798 nxt_port_hash_add(&rt->ports, rt->mem_pool, port); 1799 1800 rt->port_by_type[port->type] = port; 1801 } 1802 1803 1804 void 1805 nxt_runtime_port_remove(nxt_runtime_t *rt, nxt_port_t *port) 1806 { 1807 nxt_port_hash_remove(&rt->ports, rt->mem_pool, port); 1808 1809 if (rt->port_by_type[port->type] == port) { 1810 rt->port_by_type[port->type] = NULL; 1811 } 1812 } 1813 1814 1815 nxt_port_t * 1816 nxt_runtime_port_find(nxt_runtime_t *rt, nxt_pid_t pid, 1817 nxt_port_id_t port_id) 1818 { 1819 return nxt_port_hash_find(&rt->ports, pid, port_id); 1820 } 1821