ngx_int_t ngx_http_echo_exec_echo_blocking_sleep(ngx_http_request_t *r, ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) { ngx_str_t *computed_arg; ngx_str_t *computed_arg_elts; float delay; /* in sec */ computed_arg_elts = computed_args->elts; computed_arg = &computed_arg_elts[0]; delay = atof( (char*) computed_arg->data ); if (delay < 0.001) { /* should be bigger than 1 msec */ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "invalid sleep duration \"%V\"", &computed_arg_elts[0]); return NGX_HTTP_BAD_REQUEST; } dd("blocking DELAY = %.02lf sec", delay); ngx_msleep((ngx_msec_t) (1000 * delay)); return NGX_OK; }
ngx_int_t ngx_http_echo_exec_echo_blocking_sleep(ngx_http_request_t *r, ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) { ngx_str_t *computed_arg; ngx_str_t *computed_arg_elts; ngx_int_t delay; /* in msec */ computed_arg_elts = computed_args->elts; computed_arg = &computed_arg_elts[0]; delay = ngx_atofp(computed_arg->data, computed_arg->len, 3); if (delay == NGX_ERROR) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "invalid sleep duration \"%V\"", &computed_arg_elts[0]); return NGX_HTTP_BAD_REQUEST; } dd("blocking delay: %lu ms", (unsigned long) delay); ngx_msleep((ngx_msec_t) delay); return NGX_OK; }
static ngx_int_t ngx_http_file_cache_manager_sleep(ngx_http_file_cache_t *cache) { ngx_msec_t elapsed; if (cache->files++ > 100) { ngx_time_update(); elapsed = ngx_abs((ngx_msec_int_t) (ngx_current_msec - cache->last)); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "http file cache manager time: %M", elapsed); if (elapsed > 200) { /* * if processing 100 files takes more than 200ms, * it seems that many operations require disk i/o, * therefore sleep 200ms */ ngx_msleep(200); ngx_time_update(); } cache->last = ngx_current_msec; cache->files = 0; } return (ngx_quit || ngx_terminate) ? NGX_ABORT : NGX_OK; }
static ngx_thread_value_t __stdcall ngx_cache_loader_thread(void *data) { ngx_uint_t i; ngx_path_t **path; ngx_cycle_t *cycle; ngx_msleep(60000); cycle = (ngx_cycle_t *) ngx_cycle; path = cycle->paths.elts; for (i = 0; i < cycle->paths.nelts; i++) { if (ngx_terminate || ngx_quit || ngx_exiting) { break; } if (path[i]->loader) { path[i]->loader(path[i]->data); ngx_time_update(); } } return 0; }
static void ngx_http_file_cache_loader_sleep(ngx_http_file_cache_t *cache) { ngx_msleep(cache->loader_sleep); ngx_time_update(); cache->last = ngx_current_msec; cache->files = 0; }
static void ngx_proc_luashm_backup_thread_cycle(void *data) { ngx_proc_luashm_backup_conf_t *pbcf; ngx_cycle_t *cycle; ngx_shm_zone_t *zone; ngx_str_t *name; ngx_uint_t i; ngx_time_t *tp; int64_t now,settimestamp; cycle = data; pbcf = ngx_proc_get_conf(cycle->conf_ctx, ngx_proc_luashm_backup_module); if(pbcf->settimestamp.data == NULL){ pthread_exit((void *)0); return; } while(pbcf->running){ ngx_time_update(); if(ngx_strstr(pbcf->settimestamp.data,":")==NULL){ settimestamp=ngx_atoi(pbcf->settimestamp.data,pbcf->settimestamp.len); }else{ tp = ngx_timeofday(); now = (int64_t) tp->sec * 1000 + tp->msec; settimestamp=GetTick((char*)pbcf->settimestamp.data)*1000; ngx_log_error(NGX_LOG_DEBUG, ngx_cycle->log, 0, "========= now:%lu, settimestamp:%lu =========",now,settimestamp); if(settimestamp<now) settimestamp=(24*60*60*1000)-(now-settimestamp); else settimestamp=settimestamp-now; if(settimestamp==0)settimestamp=1; } ngx_log_error(NGX_LOG_DEBUG, ngx_cycle->log, 0, "========= backup time:%s, sleeptime:%lu =========",pbcf->settimestamp.data,settimestamp); ngx_msleep(settimestamp); if(!pbcf->running)break; i = 0; for (; i < pbcf->shdict_names->nelts;i++) { name = ((ngx_str_t*)pbcf->shdict_names->elts) + i; zone = ngx_http_lua_find_zone(name->data,name->len); dd("shm.name:%s,shm.name_len:%ld,shm.size:%ld ", name->data,name->len,zone->shm.size); ngx_proc_luashm_backup_backup(cycle,zone); } ngx_log_error(NGX_LOG_DEBUG, cycle->log, 0, "luashm_backup %V",&ngx_cached_http_time); ngx_sleep(60); if(!pbcf->running)break; } pthread_exit((void *)0); }
static ngx_int_t ngx_http_mongo_reconnect(ngx_log_t *log, ngx_http_mongo_connection_t *mongo_conn) { volatile int status = MONGO_CONN_FAIL; if (&mongo_conn->conn.connected) { mongo_disconnect(&mongo_conn->conn); ngx_msleep(MONGO_RECONNECT_WAITTIME); status = mongo_reconnect(&mongo_conn->conn); } else { status = MONGO_CONN_FAIL; } switch (status) { case MONGO_CONN_SUCCESS: break; case MONGO_CONN_NO_SOCKET: ngx_log_error(NGX_LOG_ERR, log, 0, "Mongo Exception: No Socket"); return NGX_ERROR; case MONGO_CONN_FAIL: ngx_log_error(NGX_LOG_ERR, log, 0, "Mongo Exception: Connection Failure %s:%i;", mongo_conn->conn.primary->host, mongo_conn->conn.primary->port); return NGX_ERROR; case MONGO_CONN_ADDR_FAIL: ngx_log_error(NGX_LOG_ERR, log, 0, "Mongo Exception: getaddrinfo Failure"); return NGX_ERROR; case MONGO_CONN_NOT_MASTER: ngx_log_error(NGX_LOG_ERR, log, 0, "Mongo Exception: Not Master"); return NGX_ERROR; default: ngx_log_error(NGX_LOG_ERR, log, 0, "Mongo Exception: Unknown Error"); return NGX_ERROR; } return NGX_OK; }
ngx_int_t ngx_open_listening_sockets(ngx_cycle_t *cycle) { ngx_uint_t tries, failed, reuseaddr, i; ngx_err_t err; ngx_log_t *log; ngx_socket_t s; ngx_listening_t *ls; reuseaddr = 1; #if (NGX_SUPPRESS_WARN) failed = 0; #endif log = cycle->log; /* TODO: tries configurable */ for (tries = /* STUB */ 5; tries; tries--) { failed = 0; /* for each listening socket */ ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { if (ls[i].ignore) { continue; } if (ls[i].fd != -1) { continue; } if (ls[i].inherited) { /* TODO: close on exit */ /* TODO: nonblocking */ /* TODO: deferred accept */ continue; } s = ngx_socket(ls[i].family, ls[i].type, ls[i].protocol, ls[i].flags); if (s == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_socket_n " %s failed", ls[i].addr_text.data); return NGX_ERROR; } #if (WIN32) /* * Winsock assignes a socket number divisible by 4 * so to find a connection we divide a socket number by 4. */ if (s % 4) { ngx_log_error(NGX_LOG_EMERG, ls->log, 0, ngx_socket_n " created socket %d", s); return NGX_ERROR; } #endif if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuseaddr, sizeof(int)) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, "setsockopt(SO_REUSEADDR) %s failed", ls[i].addr_text.data); return NGX_ERROR; } /* TODO: close on exit */ if (!(ngx_event_flags & NGX_USE_AIO_EVENT)) { if (ngx_nonblocking(s) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_nonblocking_n " %s failed", ls[i].addr_text.data); return NGX_ERROR; } } #if 0 if (ls[i].nonblocking) { if (ngx_nonblocking(s) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_nonblocking_n " %s failed", ls[i].addr_text.data); return NGX_ERROR; } } #endif if (bind(s, ls[i].sockaddr, ls[i].socklen) == -1) { err = ngx_socket_errno; ngx_log_error(NGX_LOG_EMERG, log, err, "bind() to %s failed", ls[i].addr_text.data); if (err != NGX_EADDRINUSE) return NGX_ERROR; if (ngx_close_socket(s) == -1) ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_close_socket_n " %s failed", ls[i].addr_text.data); failed = 1; continue; } if (listen(s, ls[i].backlog) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, "listen() to %s failed", ls[i].addr_text.data); return NGX_ERROR; } /* TODO: deferred accept */ ls[i].fd = s; } if (!failed) break; /* TODO: delay configurable */ ngx_log_error(NGX_LOG_NOTICE, log, 0, "try again to bind() after 500ms"); ngx_msleep(500); } if (failed) { ngx_log_error(NGX_LOG_EMERG, log, 0, "still can not bind()"); return NGX_ERROR; } return NGX_OK; }
//监听,绑定cycle中listening动态数组指定的相应端口 //cycle是当前进程的ngx_cycle_t结构体指针 ngx_int_t ngx_open_listening_sockets(ngx_cycle_t *cycle) { int reuseaddr; ngx_uint_t i, tries, failed; ngx_err_t err; ngx_log_t *log; ngx_socket_t s; ngx_listening_t *ls; reuseaddr = 1; #if (NGX_SUPPRESS_WARN) failed = 0; #endif log = cycle->log; /* TODO: configurable try number */ for (tries = 5; tries; tries--) { failed = 0; /* for each listening socket */ ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { if (ls[i].ignore) { continue; } if (ls[i].fd != (ngx_socket_t) -1) { continue; } if (ls[i].inherited) { /* TODO: close on exit */ /* TODO: nonblocking */ /* TODO: deferred accept */ continue; } s = ngx_socket(ls[i].sockaddr->sa_family, ls[i].type, 0); if (s == (ngx_socket_t) -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_socket_n " %V failed", &ls[i].addr_text); return NGX_ERROR; } if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuseaddr, sizeof(int)) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, "setsockopt(SO_REUSEADDR) %V failed", &ls[i].addr_text); if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_close_socket_n " %V failed", &ls[i].addr_text); } return NGX_ERROR; } #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) if (ls[i].sockaddr->sa_family == AF_INET6) { int ipv6only; ipv6only = ls[i].ipv6only; if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (const void *) &ipv6only, sizeof(int)) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, "setsockopt(IPV6_V6ONLY) %V failed, ignored", &ls[i].addr_text); } } #endif /* TODO: close on exit */ if (!(ngx_event_flags & NGX_USE_IOCP_EVENT)) { if (ngx_nonblocking(s) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_nonblocking_n " %V failed", &ls[i].addr_text); if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_close_socket_n " %V failed", &ls[i].addr_text); } return NGX_ERROR; } } ngx_log_debug2(NGX_LOG_DEBUG_CORE, log, 0, "bind() %V #%d ", &ls[i].addr_text, s); if (bind(s, ls[i].sockaddr, ls[i].socklen) == -1) { err = ngx_socket_errno; if (err != NGX_EADDRINUSE || !ngx_test_config) { ngx_log_error(NGX_LOG_EMERG, log, err, "bind() to %V failed", &ls[i].addr_text); } if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_close_socket_n " %V failed", &ls[i].addr_text); } if (err != NGX_EADDRINUSE) { return NGX_ERROR; } if (!ngx_test_config) { failed = 1; } continue; } #if (NGX_HAVE_UNIX_DOMAIN) if (ls[i].sockaddr->sa_family == AF_UNIX) { mode_t mode; u_char *name; name = ls[i].addr_text.data + sizeof("unix:") - 1; mode = (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); if (chmod((char *) name, mode) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "chmod() \"%s\" failed", name); } if (ngx_test_config) { if (ngx_delete_file(name) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, ngx_delete_file_n " %s failed", name); } } } #endif if (listen(s, ls[i].backlog) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, "listen() to %V, backlog %d failed", &ls[i].addr_text, ls[i].backlog); if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_close_socket_n " %V failed", &ls[i].addr_text); } return NGX_ERROR; } ls[i].listen = 1; ls[i].fd = s; } if (!failed) { break; } /* TODO: delay configurable */ ngx_log_error(NGX_LOG_NOTICE, log, 0, "try again to bind() after 500ms"); ngx_msleep(500); } if (failed) { ngx_log_error(NGX_LOG_EMERG, log, 0, "still could not bind()"); return NGX_ERROR; } return NGX_OK; }
void ngx_master_process_cycle(ngx_cycle_t *cycle) { char *title; u_char *p; size_t size; ngx_int_t i; ngx_uint_t n, sigio; sigset_t set; struct itimerval itv; ngx_uint_t live; ngx_msec_t delay; ngx_listening_t *ls; ngx_core_conf_t *ccf; sigemptyset(&set); sigaddset(&set, SIGCHLD); sigaddset(&set, SIGALRM); sigaddset(&set, SIGIO); sigaddset(&set, SIGINT); sigaddset(&set, ngx_signal_value(NGX_RECONFIGURE_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_REOPEN_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_NOACCEPT_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_TERMINATE_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_CHANGEBIN_SIGNAL)); if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "sigprocmask() failed"); } sigemptyset(&set); size = sizeof(master_process); for (i = 0; i < ngx_argc; i++) { size += ngx_strlen(ngx_argv[i]) + 1; } title = ngx_pnalloc(cycle->pool, size); p = ngx_cpymem(title, master_process, sizeof(master_process) - 1); for (i = 0; i < ngx_argc; i++) { *p++ = ' '; p = ngx_cpystrn(p, (u_char *) ngx_argv[i], size); } ngx_setproctitle(title); ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); ngx_start_cache_manager_processes(cycle, 0); ngx_new_binary = 0; delay = 0; sigio = 0; live = 1; for ( ;; ) { if (delay) { if (ngx_sigalrm) { sigio = 0; delay *= 2; ngx_sigalrm = 0; } ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "termination cycle: %d", delay); itv.it_interval.tv_sec = 0; itv.it_interval.tv_usec = 0; itv.it_value.tv_sec = delay / 1000; itv.it_value.tv_usec = (delay % 1000 ) * 1000; if (setitimer(ITIMER_REAL, &itv, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setitimer() failed"); } } ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "sigsuspend"); sigsuspend(&set); ngx_time_update(); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "wake up, sigio %i", sigio); if (ngx_reap) { ngx_reap = 0; ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "reap children"); live = ngx_reap_children(cycle); } if (!live && (ngx_terminate || ngx_quit)) { ngx_master_process_exit(cycle); } if (ngx_terminate) { if (delay == 0) { delay = 50; } if (sigio) { sigio--; continue; } sigio = ccf->worker_processes + 2 /* cache processes */; if (delay > 1000) { ngx_signal_worker_processes(cycle, SIGKILL); } else { ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_TERMINATE_SIGNAL)); } continue; } if (ngx_quit) { ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); ls = cycle->listening.elts; for (n = 0; n < cycle->listening.nelts; n++) { if (ngx_close_socket(ls[n].fd) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, ngx_close_socket_n " %V failed", &ls[n].addr_text); } } cycle->listening.nelts = 0; continue; } if (ngx_reconfigure) { ngx_reconfigure = 0; if (ngx_new_binary) { ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); ngx_start_cache_manager_processes(cycle, 0); ngx_noaccepting = 0; continue; } ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reconfiguring"); cycle = ngx_init_cycle(cycle); if (cycle == NULL) { cycle = (ngx_cycle_t *) ngx_cycle; continue; } ngx_cycle = cycle; ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_JUST_RESPAWN); ngx_start_cache_manager_processes(cycle, 1); /* allow new processes to start */ ngx_msleep(100); live = 1; ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); } if (ngx_restart) { ngx_restart = 0; ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); ngx_start_cache_manager_processes(cycle, 0); live = 1; } if (ngx_reopen) { ngx_reopen = 0; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs"); ngx_reopen_files(cycle, ccf->user); ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_REOPEN_SIGNAL)); } if (ngx_change_binary) { ngx_change_binary = 0; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "changing binary"); ngx_new_binary = ngx_exec_new_binary(cycle, ngx_argv); } if (ngx_noaccept) { ngx_noaccept = 0; ngx_noaccepting = 1; ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); } } }
ngx_int_t ngx_open_listening_sockets(ngx_cycle_t *cycle) { int reuseaddr; ngx_uint_t i, tries, failed; ngx_err_t err; ngx_log_t *log; ngx_socket_t s; ngx_listening_t *ls; reuseaddr = 1; #if (NGX_SUPPRESS_WARN) failed = 0; #endif log = cycle->log; /* TODO: configurable try number */ for (tries = 5; tries; tries--) { failed = 0; /* for each listening socket */ ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { if (ls[i].ignore) { continue; } if (ls[i].fd != -1) { continue; } if (ls[i].inherited) { /* TODO: close on exit */ /* TODO: nonblocking */ /* TODO: deferred accept */ continue; } s = ngx_socket(ls[i].sockaddr->sa_family, ls[i].type, 0); if (s == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_socket_n " %V failed", &ls[i].addr_text); return NGX_ERROR; } if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuseaddr, sizeof(int)) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, "setsockopt(SO_REUSEADDR) %V failed", &ls[i].addr_text); if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_close_socket_n " %V failed", &ls[i].addr_text); } return NGX_ERROR; } /* TODO: close on exit */ if (!(ngx_event_flags & NGX_USE_AIO_EVENT)) { if (ngx_nonblocking(s) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_nonblocking_n " %V failed", &ls[i].addr_text); if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_close_socket_n " %V failed", &ls[i].addr_text); } return NGX_ERROR; } } ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0, "bind() %V #%d ", &ls[i].addr_text, s); if (bind(s, ls[i].sockaddr, ls[i].socklen) == -1) { err = ngx_socket_errno; if (err == NGX_EADDRINUSE && ngx_test_config) { continue; } ngx_log_error(NGX_LOG_EMERG, log, err, "bind() to %V failed", &ls[i].addr_text); if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_close_socket_n " %V failed", &ls[i].addr_text); } if (err != NGX_EADDRINUSE) { return NGX_ERROR; } failed = 1; continue; } if (listen(s, ls[i].backlog) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, "listen() to %V, backlog %d failed", &ls[i].addr_text, ls[i].backlog); if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_close_socket_n " %V failed", &ls[i].addr_text); } return NGX_ERROR; } ls[i].listen = 1; ls[i].fd = s; } if (!failed) { break; } /* TODO: delay configurable */ ngx_log_error(NGX_LOG_NOTICE, log, 0, "try again to bind() after 500ms"); ngx_msleep(500); } if (failed) { ngx_log_error(NGX_LOG_EMERG, log, 0, "still could not bind()"); return NGX_ERROR; } return NGX_OK; }
// http://www.xuebuyuan.com/557917.html // http://blog.csdn.net/lu_ming/article/details/5144427 // http://blog.csdn.net/lengzijian/article/details/7587740 void ngx_master_process_cycle(ngx_cycle_t *cycle) { char *title; u_char *p; size_t size; ngx_int_t i; ngx_uint_t n, sigio; sigset_t set; struct itimerval itv; ngx_uint_t live; ngx_msec_t delay; ngx_listening_t *ls; ngx_core_conf_t *ccf; // block these signals sigemptyset(&set); sigaddset(&set, SIGCHLD); sigaddset(&set, SIGALRM); sigaddset(&set, SIGIO); sigaddset(&set, SIGINT); sigaddset(&set, ngx_signal_value(NGX_RECONFIGURE_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_REOPEN_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_NOACCEPT_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_TERMINATE_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_CHANGEBIN_SIGNAL)); if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "sigprocmask() failed"); } sigemptyset(&set); // set title = "master process" + argv[0] + argv[1] + ... size = sizeof(master_process); for (i = 0; i < ngx_argc; i++) { size += ngx_strlen(ngx_argv[i]) + 1; } title = ngx_pnalloc(cycle->pool, size); p = ngx_cpymem(title, master_process, sizeof(master_process) - 1); for (i = 0; i < ngx_argc; i++) { *p++ = ' '; p = ngx_cpystrn(p, (u_char *) ngx_argv[i], size); } ngx_setproctitle(title); // Start workers and cache_manager ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); ngx_start_cache_manager_processes(cycle, 0); ngx_new_binary = 0; delay = 0; sigio = 0; live = 1; for ( ;; ) { if (delay) { if (ngx_sigalrm) { sigio = 0; delay *= 2; ngx_sigalrm = 0; } ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "termination cycle: %d", delay); itv.it_interval.tv_sec = 0; itv.it_interval.tv_usec = 0; itv.it_value.tv_sec = delay / 1000; itv.it_value.tv_usec = (delay % 1000 ) * 1000; if (setitimer(ITIMER_REAL, &itv, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setitimer() failed"); } } ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "sigsuspend"); // sigsuspend() temporarily replaces the signal mask of the calling // process with the mask given by mask and then suspends the process // until delivery of a signal whose action is to invoke a // signal handler or to terminate a process. sigsuspend(&set); ngx_time_update(); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "wake up, sigio %i", sigio); if (ngx_reap) { ngx_reap = 0; ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "reap children"); live = ngx_reap_children(cycle); } if (!live && (ngx_terminate || ngx_quit)) { ngx_master_process_exit(cycle); } // on SIGINT set ngx_terminate = 1 if (ngx_terminate) { if (delay == 0) { delay = 50; } if (sigio) { sigio--; continue; } sigio = ccf->worker_processes + 2 /* cache processes */; if (delay > 1000) { ngx_signal_worker_processes(cycle, SIGKILL); } else { ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_TERMINATE_SIGNAL)); } continue; } if (ngx_quit) { ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); ls = cycle->listening.elts; for (n = 0; n < cycle->listening.nelts; n++) { if (ngx_close_socket(ls[n].fd) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, ngx_close_socket_n " %V failed", &ls[n].addr_text); } } cycle->listening.nelts = 0; continue; } if (ngx_reconfigure) { ngx_reconfigure = 0; if (ngx_new_binary) { ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); ngx_start_cache_manager_processes(cycle, 0); ngx_noaccepting = 0; continue; } ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reconfiguring"); cycle = ngx_init_cycle(cycle); if (cycle == NULL) { cycle = (ngx_cycle_t *) ngx_cycle; continue; } ngx_cycle = cycle; ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_JUST_RESPAWN); ngx_start_cache_manager_processes(cycle, 1); // Nginx won't guarantee the new workers will be ready to accept // new connections before sending shutdown signals to old workers. // If the new works takes more than 100ms to startup, then there is // a risk that the old workers are shutdown but new workers are still // not ready, as a result, new connections will be pending until a new // worker is ready to handle. /* allow new processes to start */ ngx_msleep(100); live = 1; ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); } if (ngx_restart) { ngx_restart = 0; ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); ngx_start_cache_manager_processes(cycle, 0); live = 1; } if (ngx_reopen) { ngx_reopen = 0; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs"); ngx_reopen_files(cycle, ccf->user); ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_REOPEN_SIGNAL)); } if (ngx_change_binary) { ngx_change_binary = 0; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "changing binary"); ngx_new_binary = ngx_exec_new_binary(cycle, ngx_argv); } if (ngx_noaccept) { ngx_noaccept = 0; ngx_noaccepting = 1; ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); } } }
// main()函数里调用,启动worker进程 // 监听信号 // 核心操作是sigsuspend,暂时挂起进程,不占用CPU,只有收到信号时才被唤醒 void ngx_master_process_cycle(ngx_cycle_t *cycle) { char *title; u_char *p; size_t size; ngx_int_t i; ngx_uint_t n, sigio; sigset_t set; struct itimerval itv; ngx_uint_t live; ngx_msec_t delay; ngx_listening_t *ls; ngx_core_conf_t *ccf; // 添加master进程关注的信号 sigemptyset(&set); sigaddset(&set, SIGCHLD); sigaddset(&set, SIGALRM); sigaddset(&set, SIGIO); sigaddset(&set, SIGINT); sigaddset(&set, ngx_signal_value(NGX_RECONFIGURE_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_REOPEN_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_NOACCEPT_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_TERMINATE_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_CHANGEBIN_SIGNAL)); if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "sigprocmask() failed"); } sigemptyset(&set); // static u_char master_process[] = "master process"; // 计算master进程的名字 size = sizeof(master_process); // 加上命令行参数,注意使用的是nginx拷贝后的参数 for (i = 0; i < ngx_argc; i++) { size += ngx_strlen(ngx_argv[i]) + 1; } // 分配名字的内存 title = ngx_pnalloc(cycle->pool, size); if (title == NULL) { /* fatal */ exit(2); } // 拷贝字符串 p = ngx_cpymem(title, master_process, sizeof(master_process) - 1); for (i = 0; i < ngx_argc; i++) { *p++ = ' '; p = ngx_cpystrn(p, (u_char *) ngx_argv[i], size); } // 设置进程名 ngx_setproctitle(title); // 取core模块配置 ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); // 启动worker进程,数量由配置决定,即worker_processes指令 // #define NGX_PROCESS_RESPAWN -3 ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); // cache进程 ngx_start_cache_manager_processes(cycle, 0); ngx_new_binary = 0; delay = 0; //延时的计数器 sigio = 0; live = 1; //是否有存活的子进程 // master进程的无限循环,只处理信号 // 主要调用ngx_signal_worker_processes()发送信号 // ngx_start_worker_processes()产生新子进程 for ( ;; ) { // 延时等待子进程关闭,每次进入加倍等待 if (delay) { if (ngx_sigalrm) { sigio = 0; delay *= 2; //延时加倍 ngx_sigalrm = 0; } ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "termination cycle: %d", delay); itv.it_interval.tv_sec = 0; itv.it_interval.tv_usec = 0; itv.it_value.tv_sec = delay / 1000; itv.it_value.tv_usec = (delay % 1000 ) * 1000; // 系统调用,设置发送SIGALRM的时间间隔 if (setitimer(ITIMER_REAL, &itv, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setitimer() failed"); } } ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "sigsuspend"); // 核心操作是sigsuspend,暂时挂起进程,不占用CPU,只有收到信号时才被唤醒 // 收到SIGALRM就检查子进程是否都已经处理完了 sigsuspend(&set); // 更新一下时间 ngx_time_update(); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "wake up, sigio %i", sigio); // 子进程可能发生了意外结束 // 在os/unix/ngx_process.c ngx_signal_handler()里设置 if (ngx_reap) { ngx_reap = 0; ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "reap children"); // 重新产生子进程 live = ngx_reap_children(cycle); } // 无存活子进程且收到stop/quit信号 if (!live && (ngx_terminate || ngx_quit)) { // 删除pid,模块清理,关闭监听端口 // 内部直接exit(0)退出 ngx_master_process_exit(cycle); } // 收到了-s stop,停止进程 if (ngx_terminate) { // 延时等待子进程关闭 if (delay == 0) { delay = 50; } if (sigio) { sigio--; continue; } sigio = ccf->worker_processes + 2 /* cache processes */; if (delay > 1000) { // 超时太多,直接发送SIGKILL杀死进程 // master进程调用,遍历ngx_processes数组,用kill发送信号 ngx_signal_worker_processes(cycle, SIGKILL); } else { // master进程调用,遍历ngx_processes数组,用kill发送信号 // 走到worker进程的ngx_signal_handler() // 然后再是ngx_worker_process_cycle()的ngx_terminate ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_TERMINATE_SIGNAL)); } // 等待SIGALRM信号,检查子进程是否都结束 continue; } // 收到了-s quit,关闭监听端口后再停止进程(优雅关闭) if (ngx_quit) { // master进程调用,遍历ngx_processes数组,用kill发送信号 // 走到worker进程的ngx_signal_handler() // 然后再是ngx_worker_process_cycle()的ngx_quit ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); // 关闭所有监听端口 ls = cycle->listening.elts; for (n = 0; n < cycle->listening.nelts; n++) { if (ngx_close_socket(ls[n].fd) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, ngx_close_socket_n " %V failed", &ls[n].addr_text); } } cycle->listening.nelts = 0; continue; } // 收到了-s reload重新配置 if (ngx_reconfigure) { ngx_reconfigure = 0; // 启动新的nginx二进制 if (ngx_new_binary) { // 启动worker进程,数量由配置决定,即worker_processes指令 // 调用时传递的是#define NGX_PROCESS_RESPAWN -3 ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); ngx_start_cache_manager_processes(cycle, 0); ngx_noaccepting = 0; continue; } ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reconfiguring"); // nginx可执行程序不变,以当前cycle重新初始化 cycle = ngx_init_cycle(cycle); if (cycle == NULL) { cycle = (ngx_cycle_t *) ngx_cycle; continue; } ngx_cycle = cycle; ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); // 启动worker进程,数量由配置决定,即worker_processes指令 // 调用时传递的是#define NGX_PROCESS_JUST_RESPAWN -2 // 这样新启动的进程不会发送shutdown信号 ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_JUST_RESPAWN); ngx_start_cache_manager_processes(cycle, 1); /* allow new processes to start */ // 阻塞等待100毫秒 ngx_msleep(100); // 设置进程存活标志 live = 1; // 关闭原来的worker进程 // 新启动的进程不会发送shutdown信号 // master进程调用,遍历ngx_processes数组,用kill发送信号 // 走到worker进程的ngx_signal_handler() // 然后再是ngx_worker_process_cycle()的ngx_quit ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); } if (ngx_restart) { ngx_restart = 0; // 启动worker进程,数量由配置决定,即worker_processes指令 // 调用时传递的是#define NGX_PROCESS_RESPAWN -3 ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); ngx_start_cache_manager_processes(cycle, 0); // 设置进程存活标志 live = 1; } if (ngx_reopen) { ngx_reopen = 0; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs"); ngx_reopen_files(cycle, ccf->user); ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_REOPEN_SIGNAL)); } if (ngx_change_binary) { ngx_change_binary = 0; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "changing binary"); ngx_new_binary = ngx_exec_new_binary(cycle, ngx_argv); } if (ngx_noaccept) { ngx_noaccept = 0; ngx_noaccepting = 1; ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); } } //master进程无限循环结束 }
ngx_int_t ngx_tcp_open_listening_socket(ngx_listening_t *ls) { int reuseaddr; ngx_uint_t tries, failed; ngx_err_t err; ngx_log_t *log; ngx_socket_t s; reuseaddr = 1; log = ls->logp; for (tries = 5; tries; tries--) { failed = 0; if (ls->ignore) { continue; } if (ls->fd != -1) { break; } s = ngx_socket(ls->sockaddr->sa_family, ls->type, 0); if (s == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_socket_n " %V failed", &ls->addr_text); return NGX_ERROR; } if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuseaddr, sizeof(int)) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, "setsockopt(SO_REUSEADDR) %V failed", &ls->addr_text); if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_close_socket_n " %V failed", &ls->addr_text); } return NGX_ERROR; } #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) if (ls->sockaddr->sa_family == AF_INET6) { int ipv6only; ipv6only = ls->ipv6only; if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (const void *) &ipv6only, sizeof(int)) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, "setsockopt(IPV6_V6ONLY) %V failed, ignored", &ls->addr_text); } } #endif /* TODO: close on exit */ if (!(ngx_event_flags & NGX_USE_AIO_EVENT)) { if (ngx_nonblocking(s) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_nonblocking_n " %V failed", &ls->addr_text); if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_close_socket_n " %V failed", &ls->addr_text); } return NGX_ERROR; } } ngx_log_debug2(NGX_LOG_DEBUG_CORE, log, 0, "bind() %V #%d ", &ls->addr_text, s); #if (NGX_HAVE_UNIX_DOMAIN) { u_char *name; name = ls->addr_text.data + sizeof("unix:") - 1; unlink((const char *)name); } #endif if (bind(s, ls->sockaddr, ls->socklen) == -1) { err = ngx_socket_errno; if (err == NGX_EADDRINUSE && ngx_test_config) { continue; } ngx_log_error(NGX_LOG_EMERG, log, err, "bind() to %V failed", &ls->addr_text); if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_close_socket_n " %V failed", &ls->addr_text); } if (err != NGX_EADDRINUSE) { return NGX_ERROR; } failed = 1; break; } #if (NGX_HAVE_UNIX_DOMAIN) if (ls->sockaddr->sa_family == AF_UNIX) { mode_t mode; u_char *name; name = ls->addr_text.data + sizeof("unix:") - 1; mode = (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); if (chmod((char *) name, mode) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "chmod() \"%s\" failed", name); } if (ngx_test_config) { if (ngx_delete_file(name) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, ngx_delete_file_n " %s failed", name); } } } #endif if (listen(s, ls->backlog) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, "listen() to %V, backlog %d failed", &ls->addr_text, ls->backlog); if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_close_socket_n " %V failed", &ls->addr_text); } return NGX_ERROR; } ls->listen = 1; ls->fd = s; if (!failed) { break; } /* TODO: delay configurable */ ngx_log_error(NGX_LOG_NOTICE, log, 0, "try again to bind() after 500ms"); ngx_msleep(500); } if (failed) { ngx_log_error(NGX_LOG_EMERG, log, 0, "still could not bind()"); return NGX_ERROR; } return NGX_OK; }
static void ngx_procs_cycle(ngx_cycle_t *cycle, void *data) { ngx_int_t rc; ngx_uint_t i; ngx_module_t *module; ngx_proc_args_t *args; ngx_proc_conf_t *cpcf; ngx_connection_t *c; ngx_proc_module_t *ctx; args = data; module = args->module; cpcf = args->proc_conf; ctx = module->ctx; ngx_process = NGX_PROCESS_PROC; ngx_setproctitle((char *) ctx->name.data); ngx_msleep(cpcf->delay_start); ngx_procs_process_init(cycle, ctx, cpcf->priority); ngx_close_listening_sockets(cycle); ngx_use_accept_mutex = 0; for ( ;; ) { if (ngx_exiting || ngx_quit) { ngx_exiting = 1; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "process %V gracefully shutting down", &ctx->name); ngx_setproctitle("processes are shutting down"); c = cycle->connections; for (i = 0; i < cycle->connection_n; i++) { if (c[i].fd != -1 && c[i].idle) { c[i].close = 1; c[i].read->handler(c[i].read); } } ngx_procs_process_exit(cycle, ctx); } if (ngx_terminate) { ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "process %V exiting", &ctx->name); ngx_procs_process_exit(cycle, ctx); } if (ngx_reopen) { ngx_reopen = 0; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs"); ngx_reopen_files(cycle, -1); } if (ctx->loop) { rc = ctx->loop(cycle); if (rc != NGX_OK) { break; } } ngx_time_update(); ngx_process_events_and_timers(cycle); } ngx_procs_process_exit(cycle, ctx); }
/* * 主要工作: * 主进程设置信号堵塞 * 设置进程标题 * 启动worker进程 * 启动缓存索引重建(cache loader)进程及管理(Cache Manager)进程 * 主进程循环处理信号 * */ void ngx_master_process_cycle(ngx_cycle_t *cycle) { char *title; u_char *p; size_t size; ngx_int_t i; ngx_uint_t n, sigio; sigset_t set; struct itimerval itv; ngx_uint_t live; ngx_msec_t delay; /*保存的是等待工作进程退出的时间*/ ngx_listening_t *ls; ngx_core_conf_t *ccf; /*将下列信号添加到信号集set中*/ sigemptyset(&set); sigaddset(&set, SIGCHLD); sigaddset(&set, SIGALRM); sigaddset(&set, SIGIO); sigaddset(&set, SIGINT); sigaddset(&set, ngx_signal_value(NGX_RECONFIGURE_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_REOPEN_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_NOACCEPT_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_TERMINATE_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_CHANGEBIN_SIGNAL)); /*将信号集set覆盖为当前进程的信号集*/ if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "sigprocmask() failed"); } sigemptyset(&set); /*开始设置进程标题*/ /*计算进程标题的总体长度*/ size = sizeof(master_process); for (i = 0; i < ngx_argc; i++) { size += ngx_strlen(ngx_argv[i]) + 1; } title = ngx_pnalloc(cycle->pool, size); if (title == NULL) { /* fatal */ exit(2); } p = ngx_cpymem(title, master_process, sizeof(master_process) - 1); for (i = 0; i < ngx_argc; i++) { *p++ = ' '; p = ngx_cpystrn(p, (u_char *) ngx_argv[i], size); } /*设置进程标题*/ ngx_setproctitle(title); /*获取核心模块上下文*/ ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); /*启动工作进程*/ ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); /*启动缓存索引重建进程,该进程在整个Nginx服务器运行过程中只存在很短的时间,主要用来遍历磁盘上的缓存数据,在内存中建立数据索引,提高Nginx服务器检索缓存的效率*/ ngx_start_cache_manager_processes(cycle, 0); ngx_new_binary = 0; delay = 0; sigio = 0; live = 1; for ( ;; ) { if (delay) { /*等待工作进程退出的时间*/ if (ngx_sigalrm) { sigio = 0; delay *= 2; ngx_sigalrm = 0; } ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "termination cycle: %M", delay); /*初始化一个定时器*/ itv.it_interval.tv_sec = 0; itv.it_interval.tv_usec = 0; itv.it_value.tv_sec = delay / 1000; itv.it_value.tv_usec = (delay % 1000 ) * 1000; if (setitimer(ITIMER_REAL, &itv, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setitimer() failed"); } } ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "sigsuspend"); /*挂起进程,等待接收到信号,在不向主进程发送信号的情况下,该进程将一直挂起在这里等待*/ sigsuspend(&set); /*更新缓冲时间*/ ngx_time_update(); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "wake up, sigio %i", sigio); /*如果有工作进程异常退出,则调用ngx_reap_children()重启该工作进程*/ if (ngx_reap) { ngx_reap = 0; ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "reap children"); /*重启工作进程*/ live = ngx_reap_children(cycle); } /*如果主进程接收到的是NGX_CMD_TERMINATE信号、SIGTERM信号、SIGINT信号(ngx_terminate=1)或者收到的是NGX_CMD_QUIT信号、SIGQUIT信号(ngx_quit=1),并且工作进程退出,则主进程调用ngx_master_process_exit()函数退出*/ if (!live && (ngx_terminate || ngx_quit)) { ngx_master_process_exit(cycle); } /*处理SIGINT信号*/ if (ngx_terminate) { if (delay == 0) { delay = 50; } if (sigio) { sigio--; continue; } /*包括两个管理内存索引的进程*/ sigio = ccf->worker_processes + 2 /* cache processes */; /*超时1s,直接终止工作进程*/ if (delay > 1000) { ngx_signal_worker_processes(cycle, SIGKILL); } else { /*工作进程正常退出*/ ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_TERMINATE_SIGNAL)); } continue; } /*处理SIGQUIT信号*/ if (ngx_quit) { ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); /*关闭所有的socket*/ ls = cycle->listening.elts; for (n = 0; n < cycle->listening.nelts; n++) { if (ngx_close_socket(ls[n].fd) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, ngx_close_socket_n " %V failed", &ls[n].addr_text); } } cycle->listening.nelts = 0; continue; } /*处理SIGHUP信号*/ if (ngx_reconfigure) { ngx_reconfigure = 0; /*热升级(平滑升级,不用停止服务)*/ /*当ngx_new_binary=1时,说明主进程本身需要升级,但是不需要重新初始化Nginx配置,因此可以直接调用ngx_start_worker_processes()函数重启工作进程和缓存索引管理进程*/ /*当ngx_new_binary!=1时,则说明时Nginx服务器配置改变,需要调用ngx_init_cycle()函数初始化Nginx配置,并按照新的配置启动工作进程和缓存索引管理进程,向之前的所有进程发送NGX_SHUTDOWN_SIGNAL信号,这样旧实现了Nginx服务器的平滑升级*/ if (ngx_new_binary) { ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); ngx_start_cache_manager_processes(cycle, 0); ngx_noaccepting = 0; continue; } ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reconfiguring"); /*建立信的cycle结构*/ cycle = ngx_init_cycle(cycle); if (cycle == NULL) { cycle = (ngx_cycle_t *) ngx_cycle; continue; } /*读取Nginx配置*/ ngx_cycle = cycle; ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); /*创建工作进程*/ ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_JUST_RESPAWN); /*创建缓存管理进程*/ ngx_start_cache_manager_processes(cycle, 1); /* allow new processes to start */ ngx_msleep(100); live = 1; /*关闭旧的Nginx进程*/ ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); } /*重启工作进程*/ /*只有一种情况可以将ngx_restart变量赋值为1,就是在调用ngx_reap_children()函数重启工作进程的时候,当主进程接收到NGX_NOACCEPT_SIGNAL信号(不再接收请求,退出工作进程)时,会设置全局变量ngx_noaccept为1,然后再Nginx初始化信号设置时会将全局变量ngx_noaccepting设置为1,于是在ngx_reap_children()函数中就会将ngx_restart变量设置为1,进而执行下面的if语句中的代码,重启工作进程和缓存索引管理进程*/ if (ngx_restart) { ngx_restart = 0; /*启动工作进程*/ ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); /*启动缓存索引管理进程刷新缓存索引*/ ngx_start_cache_manager_processes(cycle, 0); live = 1; } /*处理SIGUSR1信号,该信号用于重新打开日志文件*/ if (ngx_reopen) { ngx_reopen = 0; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs"); ngx_reopen_files(cycle, ccf->user); ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_REOPEN_SIGNAL)); } /*处理SIGUSR2信号,热代码切换*/ if (ngx_change_binary) { ngx_change_binary = 0; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "changing binary"); ngx_new_binary = ngx_exec_new_binary(cycle, ngx_argv); } /*处理NGX_NOACCEPT_SIGNAL信号*/ if (ngx_noaccept) { ngx_noaccept = 0; ngx_noaccepting = 1; /*退出工作进程,不再接收网络请求*/ ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); } } }
ngx_int_t ngx_open_listening_sockets(ngx_cycle_t *cycle) { int reuseaddr; ngx_uint_t i, tries, failed; ngx_err_t err; ngx_log_t *log; ngx_socket_t s; ngx_listening_t *ls; reuseaddr = 1; #if (NGX_SUPPRESS_WARN) failed = 0; #endif log = cycle->log; /* TODO: configurable try number */ for (tries = 5; tries; tries--) { //bind和listen最多从实5次 failed = 0; /* for each listening socket */ ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { if (ls[i].ignore) { continue; } #if (NGX_HAVE_REUSEPORT) if (ls[i].add_reuseport) { /* * to allow transition from a socket without SO_REUSEPORT * to multiple sockets with SO_REUSEPORT, we have to set * SO_REUSEPORT on the old socket before opening new ones */ int reuseport = 1; if (setsockopt(ls[i].fd, SOL_SOCKET, SO_REUSEPORT, (const void *) &reuseport, sizeof(int)) //端口复用需要内核支持 == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, "setsockopt(SO_REUSEPORT) %V failed, ignored", &ls[i].addr_text); } ls[i].add_reuseport = 0; } #endif if (ls[i].fd != (ngx_socket_t) -1) { continue; } if (ls[i].inherited) { /* TODO: close on exit */ /* TODO: nonblocking */ /* TODO: deferred accept */ continue; } s = ngx_socket(ls[i].sockaddr->sa_family, ls[i].type, 0); if (s == (ngx_socket_t) -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_socket_n " %V failed", &ls[i].addr_text); return NGX_ERROR; } /* 默认情况下,server重启,调用socket,bind,然后listen,会失败.因为该端口正在被使用.如果设定SO_REUSEADDR,那么server重启才会成功.因此, 所有的TCP server都必须设定此选项,用以应对server重启的现象. */ if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuseaddr, sizeof(int)) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, "setsockopt(SO_REUSEADDR) %V failed, close sock:%d", &ls[i].addr_text, s); if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_close_socket_n " %V failed", &ls[i].addr_text); } return NGX_ERROR; } #if (NGX_HAVE_REUSEPORT) if (ls[i].reuseport) { int reuseport; reuseport = 1; if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, (const void *) &reuseport, sizeof(int)) //端口复用需要内核支持 == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, "setsockopt(SO_REUSEPORT) %V failed, ignored, close sock:%d", &ls[i].addr_text, s); if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_close_socket_n " %V failed", &ls[i].addr_text); } return NGX_ERROR; } } #endif #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) if (ls[i].sockaddr->sa_family == AF_INET6) { int ipv6only; ipv6only = ls[i].ipv6only; if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (const void *) &ipv6only, sizeof(int)) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, "setsockopt(IPV6_V6ONLY) %V failed, ignored", &ls[i].addr_text); } } #endif /* TODO: close on exit */ if (!(ngx_event_flags & NGX_USE_IOCP_EVENT)) { if (ngx_nonblocking(s) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_nonblocking_n " %V failed, close sock:%d", &ls[i].addr_text,s); if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_close_socket_n " %V failed", &ls[i].addr_text); } return NGX_ERROR; } } ngx_log_debug2(NGX_LOG_DEBUG_CORE, log, 0, "bind() %V #%d ", &ls[i].addr_text, s); if (bind(s, ls[i].sockaddr, ls[i].socklen) == -1) { err = ngx_socket_errno; if (err != NGX_EADDRINUSE || !ngx_test_config) { ngx_log_error(NGX_LOG_EMERG, log, err, "bind() to %V failed", &ls[i].addr_text); } ngx_log_error(NGX_LOG_EMERG, log, err, "close socket:%d", s); if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_close_socket_n " %V failed", &ls[i].addr_text); } if (err != NGX_EADDRINUSE) { return NGX_ERROR; } if (!ngx_test_config) { failed = 1; } continue; } #if (NGX_HAVE_UNIX_DOMAIN) if (ls[i].sockaddr->sa_family == AF_UNIX) { mode_t mode; u_char *name; name = ls[i].addr_text.data + sizeof("unix:") - 1; mode = (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); if (chmod((char *) name, mode) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "chmod() \"%s\" failed", name); } if (ngx_test_config) { if (ngx_delete_file(name) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, ngx_delete_file_n " %s failed", name); } } } #endif if (listen(s, ls[i].backlog) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, "listen() to %V, backlog %d failed", &ls[i].addr_text, ls[i].backlog); ngx_log_error(NGX_LOG_EMERG, log, err, "close socket:%d", s); if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_close_socket_n " %V failed", &ls[i].addr_text); } return NGX_ERROR; } ls[i].listen = 1; ls[i].fd = s; } if (!failed) { break; } /* TODO: delay configurable */ ngx_log_error(NGX_LOG_NOTICE, log, 0, "try again to bind() after 500ms"); ngx_msleep(500); } if (failed) { ngx_log_error(NGX_LOG_EMERG, log, 0, "still could not bind()"); return NGX_ERROR; } return NGX_OK; }
// 启动后master进程在这个函数进入死循环 void ngx_master_process_cycle(ngx_cycle_t *cycle) { char *title; u_char *p; size_t size; ngx_int_t i; ngx_uint_t n, sigio; sigset_t set; struct itimerval itv; ngx_uint_t live; ngx_msec_t delay; ngx_listening_t *ls; ngx_core_conf_t *ccf; sigemptyset(&set); sigaddset(&set, SIGCHLD); sigaddset(&set, SIGALRM); sigaddset(&set, SIGIO); sigaddset(&set, SIGINT); sigaddset(&set, ngx_signal_value(NGX_RECONFIGURE_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_REOPEN_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_NOACCEPT_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_TERMINATE_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_CHANGEBIN_SIGNAL)); // 让master进程只有在sigsuspend()里才会捕捉参数set里的信号。 if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "sigprocmask() failed"); } sigemptyset(&set); // 设置ps命令显示的进程标题 size = sizeof(master_process); for (i = 0; i < ngx_argc; i++) { size += ngx_strlen(ngx_argv[i]) + 1; } title = ngx_pnalloc(cycle->pool, size); p = ngx_cpymem(title, master_process, sizeof(master_process) - 1); for (i = 0; i < ngx_argc; i++) { *p++ = ' '; p = ngx_cpystrn(p, (u_char *) ngx_argv[i], size); } ngx_setproctitle(title); ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); // 启动worker进程 ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); // 配置文件配置了相关功能时打开cache manager或cache loader进程, ngx_start_cache_manager_processes(cycle, 0); ngx_new_binary = 0; delay = 0; sigio = 0; live = 1; for ( ;; ) { if (delay) { // 收到退出信号后会使用这个分支, // 作用是定时检查是否还有活跃子进程,如果没有就退出master进程 if (ngx_sigalrm) { sigio = 0; delay *= 2; ngx_sigalrm = 0; } ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "termination cycle: %d", delay); itv.it_interval.tv_sec = 0; itv.it_interval.tv_usec = 0; itv.it_value.tv_sec = delay / 1000; itv.it_value.tv_usec = (delay % 1000 ) * 1000; if (setitimer(ITIMER_REAL, &itv, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setitimer() failed"); } } ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "sigsuspend"); // 当没有收到信号时进程会在这个函数里休眠, 当收到信号后如果有信号处理函数先运行信号处理函数, // 然后向下运行。 sigsuspend(&set); // 更新记录当前时间的全局变量。 ngx_time_update(); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "wake up, sigio %i", sigio); if (ngx_reap) { // master进程的子进程结束时,master进程收到SIGCHLD信号后,ngx_reap被置1。 ngx_reap = 0; ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "reap children"); live = ngx_reap_children(cycle); } if (!live && (ngx_terminate || ngx_quit)) { // 收到退出信号且已经没有活跃子进程后便退出 ngx_master_process_exit(cycle); } if (ngx_terminate) { // 收到SIGINT,SIGTERM信号后,直接关闭nginx, // 首先给子进程发送关闭信号,1秒还没有关完就强制关闭所有子进程 if (delay == 0) { delay = 50; } if (sigio) { sigio--; continue; } sigio = ccf->worker_processes + 2 /* cache processes */; if (delay > 1000) { ngx_signal_worker_processes(cycle, SIGKILL); } else { ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_TERMINATE_SIGNAL)); } continue; } if (ngx_quit) { // 收到SIGQUIT信号后,优雅关闭Nginx, // 待所有worker进程将已经连接的请求处理完后在退出 ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); ls = cycle->listening.elts; for (n = 0; n < cycle->listening.nelts; n++) { if (ngx_close_socket(ls[n].fd) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, ngx_close_socket_n " %V failed", &ls[n].addr_text); } } cycle->listening.nelts = 0; continue; } if (ngx_reconfigure) { // 收到SIGHUP信号后,ngx_reconfigure在信号处理函数中被置1,执行让新配置文件生效的操作。 ngx_reconfigure = 0; if (ngx_new_binary) { // 在不重新载入配置文件的情况下启动工作进程。 ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); ngx_start_cache_manager_processes(cycle, 0); ngx_noaccepting = 0; continue; } ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reconfiguring"); cycle = ngx_init_cycle(cycle); if (cycle == NULL) { cycle = (ngx_cycle_t *) ngx_cycle; continue; } ngx_cycle = cycle; ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_JUST_RESPAWN); ngx_start_cache_manager_processes(cycle, 1); /* allow new processes to start */ ngx_msleep(100); live = 1; ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); } if (ngx_restart) { // 好像是平滑升级时,新起的nginx意外退出了,要在把之前nginx的工作进程在重新启动 ngx_restart = 0; ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); ngx_start_cache_manager_processes(cycle, 0); live = 1; } if (ngx_reopen) { // 重新打开日志文件 ngx_reopen = 0; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs"); ngx_reopen_files(cycle, ccf->user); ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_REOPEN_SIGNAL)); } if (ngx_change_binary) { // 启动新的nignx,使新旧nginx同时工作 ngx_change_binary = 0; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "changing binary"); ngx_new_binary = ngx_exec_new_binary(cycle, ngx_argv); } if (ngx_noaccept) { // 收到sigwinch信号后优雅关闭所有子进程 ngx_noaccept = 0; ngx_noaccepting = 1; ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); } } }
/* * master进程主循环 */ void ngx_master_process_cycle(ngx_cycle_t *cycle) { char *title; u_char *p; size_t size; ngx_int_t i; ngx_uint_t n, sigio; sigset_t set; struct itimerval itv; ngx_uint_t live; ngx_msec_t delay; ngx_listening_t *ls; ngx_core_conf_t *ccf; sigemptyset(&set); sigaddset(&set, SIGCHLD); sigaddset(&set, SIGALRM); sigaddset(&set, SIGIO); sigaddset(&set, SIGINT); sigaddset(&set, ngx_signal_value(NGX_RECONFIGURE_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_REOPEN_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_NOACCEPT_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_TERMINATE_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_CHANGEBIN_SIGNAL)); /* 进程屏蔽set中的信号 */ if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "sigprocmask() failed"); } sigemptyset(&set); size = sizeof(master_process); for (i = 0; i < ngx_argc; i++) { size += ngx_strlen(ngx_argv[i]) + 1; } title = ngx_pnalloc(cycle->pool, size); if (title == NULL) { /* fatal */ exit(2); } p = ngx_cpymem(title, master_process, sizeof(master_process) - 1); for (i = 0; i < ngx_argc; i++) { *p++ = ' '; p = ngx_cpystrn(p, (u_char *) ngx_argv[i], size); } /* 修改进程名 */ ngx_setproctitle(title); ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); /* 启动work进程 */ ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); ngx_start_cache_manager_processes(cycle, 0); ngx_new_binary = 0; delay = 0; sigio = 0; live = 1; /* 标记是否还有活着的子进程*/ for ( ;; ) { //delay用来设置等待worker终止的时间,master接收了终止信号后 //首先发送终止信号给worker,然后等待work终止 if (delay) { if (ngx_sigalrm) { sigio = 0; delay *= 2; ngx_sigalrm = 0; } ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "termination cycle: %d", delay); itv.it_interval.tv_sec = 0; itv.it_interval.tv_usec = 0; itv.it_value.tv_sec = delay / 1000; itv.it_value.tv_usec = (delay % 1000 ) * 1000; /* 应为itv.it_interval 为0 定时器只触发一次 */ if (setitimer(ITIMER_REAL, &itv, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setitimer() failed"); } } ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "sigsuspend"); /* 将进程的屏蔽信号集置空,然后进程挂起等待信号进入,信号处理程序处理完进入的信号后 恢复屏蔽信号集,最后sigsuspend返回 */ sigsuspend(&set); ngx_time_update(); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "wake up, sigio %i", sigio); /* 当master收到work进程结束信号,回收子进程 */ if (ngx_reap) { ngx_reap = 0; ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "reap children"); live = ngx_reap_children(cycle); } /* live为1表示有子进程在运行,为0代表,所有子进程都退出了 */ if (!live && (ngx_terminate || ngx_quit)) { /* 没有子进程了 且收到终止或退出信号*/ ngx_master_process_exit(cycle); } /* master收到终止信号*/ if (ngx_terminate) { if (delay == 0) { delay = 50; } if (sigio) { sigio--; continue; } sigio = ccf->worker_processes + 2 /* cache processes */; if (delay > 1000) { /* 延时已到,给所有worker发送SIGKILL信号,强制杀死worker */ ngx_signal_worker_processes(cycle, SIGKILL); } else { /* 通知work进程终止 */ ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_TERMINATE_SIGNAL)); } continue; } /* 通知工作线程退出,并关闭所有监听套接口 */ if (ngx_quit) { ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); ls = cycle->listening.elts; for (n = 0; n < cycle->listening.nelts; n++) { if (ngx_close_socket(ls[n].fd) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, ngx_close_socket_n " %V failed", &ls[n].addr_text); } } cycle->listening.nelts = 0; continue; } if (ngx_reconfigure) { ngx_reconfigure = 0; /* 代码已被替换,重启worker,不需要重新初始化配置。 */ if (ngx_new_binary) { ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); ngx_start_cache_manager_processes(cycle, 0); ngx_noaccepting = 0; continue; } ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reconfiguring"); //重新初始化配置 cycle = ngx_init_cycle(cycle); if (cycle == NULL) { cycle = (ngx_cycle_t *) ngx_cycle; continue; } ngx_cycle = cycle; ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_JUST_RESPAWN); ngx_start_cache_manager_processes(cycle, 1); /* allow new processes to start */ ngx_msleep(100); live = 1; ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); } /* 重新创建work进程 当ngx_noaccepting==1时,会把ngx_restart设为1,重启worker */ if (ngx_restart) { ngx_restart = 0; ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); ngx_start_cache_manager_processes(cycle, 0); live = 1; } /* 从新打开日志文件 */ if (ngx_reopen) { ngx_reopen = 0; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs"); ngx_reopen_files(cycle, ccf->user); ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_REOPEN_SIGNAL)); } /* 热替换 */ if (ngx_change_binary) { ngx_change_binary = 0; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "changing binary"); ngx_new_binary = ngx_exec_new_binary(cycle, ngx_argv); } /* 通知work进程停止accept新连接,work进程退出 */ if (ngx_noaccept) { ngx_noaccept = 0; ngx_noaccepting = 1; ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); } } }
static ngx_int_t ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags) { int ready, nready; ngx_err_t err; ngx_uint_t i, found; ngx_event_t *ev, **queue; struct timeval tv, *tp; ngx_connection_t *c; #if (NGX_DEBUG) if (cycle->log->log_level & NGX_LOG_DEBUG_ALL) { for (i = 0; i < nevents; i++) { ev = event_index[i]; c = ev->data; ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "select event: fd:%d wr:%d", c->fd, ev->write); } } #endif if (timer == NGX_TIMER_INFINITE) { tp = NULL; } else { tv.tv_sec = (long) (timer / 1000); tv.tv_usec = (long) ((timer % 1000) * 1000); tp = &tv; } ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "select timer: %M", timer); work_read_fd_set = master_read_fd_set; work_write_fd_set = master_write_fd_set; if (max_read || max_write) { ready = select(0, &work_read_fd_set, &work_write_fd_set, NULL, tp); } else { /* * Winsock select() requires that at least one descriptor set must be * be non-null, and any non-null descriptor set must contain at least * one handle to a socket. Otherwise select() returns WSAEINVAL. */ ngx_msleep(timer); ready = 0; } err = (ready == -1) ? ngx_socket_errno : 0; if (flags & NGX_UPDATE_TIME) { ngx_time_update(); } ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "select ready %d", ready); if (err) { ngx_log_error(NGX_LOG_ALERT, cycle->log, err, "select() failed"); if (err == WSAENOTSOCK) { ngx_select_repair_fd_sets(cycle); } return NGX_ERROR; } if (ready == 0) { if (timer != NGX_TIMER_INFINITE) { return NGX_OK; } ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "select() returned no events without timeout"); return NGX_ERROR; } ngx_mutex_lock(ngx_posted_events_mutex); nready = 0; for (i = 0; i < nevents; i++) { ev = event_index[i]; c = ev->data; found = 0; if (ev->write) { if (FD_ISSET(c->fd, &work_write_fd_set)) { found = 1; ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "select write %d", c->fd); } } else { if (FD_ISSET(c->fd, &work_read_fd_set)) { found = 1; ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "select read %d", c->fd); } } if (found) { ev->ready = 1; queue = (ngx_event_t **) (ev->accept ? &ngx_posted_accept_events: &ngx_posted_events); ngx_locked_post_event(ev, queue); nready++; } } ngx_mutex_unlock(ngx_posted_events_mutex); if (ready != nready) { ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "select ready != events: %d:%d", ready, nready); ngx_select_repair_fd_sets(cycle); } return NGX_OK; }
void ngx_master_process_cycle(ngx_cycle_t *cycle) { u_long nev, ev, timeout; ngx_err_t err; ngx_int_t n; ngx_msec_t timer; ngx_uint_t live; HANDLE events[MAXIMUM_WAIT_OBJECTS]; ngx_process_init(cycle); ngx_sprintf((u_char *) ngx_master_process_event_name, "ngx_master_%s%Z", ngx_unique); if (ngx_process == NGX_PROCESS_WORKER) { if (FreeConsole() == 0) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "FreeConsole() failed"); } ngx_worker_process_cycle(cycle, ngx_master_process_event_name); return; } ngx_log_debug0(NGX_LOG_DEBUG_CORE, cycle->log, 0, "master started"); ngx_console_init(cycle); SetEnvironmentVariable("ngx_unique", ngx_unique); ngx_master_process_event = CreateEvent(NULL, 1, 0, ngx_master_process_event_name); if (ngx_master_process_event == NULL) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "CreateEvent(\"%s\") failed", ngx_master_process_event_name); exit(2); } if (ngx_create_signal_events(cycle) != NGX_OK) { exit(2); } ngx_sprintf((u_char *) ngx_cache_manager_mutex_name, "ngx_cache_manager_mutex_%s%Z", ngx_unique); ngx_cache_manager_mutex = CreateMutex(NULL, 0, ngx_cache_manager_mutex_name); if (ngx_cache_manager_mutex == NULL) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "CreateMutex(\"%s\") failed", ngx_cache_manager_mutex_name); exit(2); } events[0] = ngx_stop_event; events[1] = ngx_quit_event; events[2] = ngx_reopen_event; events[3] = ngx_reload_event; // ngx_close_listening_sockets(cycle); ngx_set_inherited_listen_sockets(cycle); if (ngx_start_worker_processes(cycle, NGX_PROCESS_RESPAWN) == 0) { exit(2); } timer = 0; timeout = INFINITE; for ( ;; ) { nev = 4; for (n = 0; n < ngx_last_process; n++) { if (ngx_processes[n].handle) { events[nev++] = ngx_processes[n].handle; } } if (timer) { timeout = timer > ngx_current_msec ? timer - ngx_current_msec : 0; } ev = WaitForMultipleObjects(nev, events, 0, timeout); err = ngx_errno; ngx_time_update(); ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0, "master WaitForMultipleObjects: %ul", ev); if (ev == WAIT_OBJECT_0) { ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting"); if (ResetEvent(ngx_stop_event) == 0) { ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "ResetEvent(\"%s\") failed", ngx_stop_event_name); } if (timer == 0) { timer = ngx_current_msec + 5000; } ngx_terminate = 1; ngx_quit_worker_processes(cycle, 0); continue; } if (ev == WAIT_OBJECT_0 + 1) { ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "shutting down"); if (ResetEvent(ngx_quit_event) == 0) { ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "ResetEvent(\"%s\") failed", ngx_quit_event_name); } ngx_quit = 1; ngx_quit_worker_processes(cycle, 0); continue; } if (ev == WAIT_OBJECT_0 + 2) { ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs"); if (ResetEvent(ngx_reopen_event) == 0) { ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "ResetEvent(\"%s\") failed", ngx_reopen_event_name); } ngx_reopen_files(cycle, -1); ngx_reopen_worker_processes(cycle); continue; } if (ev == WAIT_OBJECT_0 + 3) { ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reconfiguring"); if (ResetEvent(ngx_reload_event) == 0) { ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "ResetEvent(\"%s\") failed", ngx_reload_event_name); } /* 这个方案暂时已经可用了。不好的地方就是不能重启端口。如果端口配置有变化,就会有毛病。 cycle = ngx_init_cycle(cycle); if (cycle == NULL) { cycle = (ngx_cycle_t *) ngx_cycle; continue; } ngx_cycle = cycle; //ngx_close_listening_sockets(cycle); if (ngx_start_worker_processes(cycle, NGX_PROCESS_JUST_RESPAWN)) { ngx_quit_worker_processes(cycle, 1); } */ /*---code 这里代码是先退掉所有工作进程,然后关闭listen 端口,再reload 配置,重启端口,重启工作进程*/ ngx_quit_worker_processes(cycle, 0); ngx_close_listening_sockets(cycle); ngx_msleep(500); cycle = ngx_init_cycle(cycle); if (cycle == NULL) { cycle = (ngx_cycle_t *) ngx_cycle; continue; } ngx_cycle = cycle; if (ngx_open_listening_sockets(cycle) != NGX_OK) { ngx_log_error(NGX_LOG_ALERT, cycle->log, err, "reload ngx_open_listening_sockets() failed"); ngx_quit = 1; continue; } ngx_set_inherited_listen_sockets(cycle); if (ngx_start_worker_processes(cycle, NGX_PROCESS_RESPAWN) == 0) { exit(2); } /*---code --- end*/ continue; } if (ev > WAIT_OBJECT_0 + 3 && ev < WAIT_OBJECT_0 + nev) { ngx_log_debug0(NGX_LOG_DEBUG_CORE, cycle->log, 0, "reap worker"); live = ngx_reap_worker(cycle, events[ev]); if (!live && (ngx_terminate || ngx_quit)) { ngx_master_process_exit(cycle); } continue; } if (ev == WAIT_TIMEOUT) { ngx_terminate_worker_processes(cycle); ngx_master_process_exit(cycle); } if (ev == WAIT_FAILED) { ngx_log_error(NGX_LOG_ALERT, cycle->log, err, "WaitForMultipleObjects() failed"); continue; } ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "WaitForMultipleObjects() returned unexpected value %ul", ev); } }
void msleep(ngx_uint_t msec) const { ngx_msleep(msec); }