# HG changeset patch # User Igor Sysoev # Date 1073336148 0 # Node ID 05592fd7a4367dcf70e210f138be7a41e74b97b4 # Parent c5d1cdcb04ece13d008fd3e5678de482516b7d3e nginx-0.0.1-2004-01-05-23:55:48 import diff --git a/auto/sources b/auto/sources --- a/auto/sources +++ b/auto/sources @@ -19,6 +19,7 @@ CORE_DEPS="src/core/nginx.h \ src/core/ngx_rbtree.h \ src/core/ngx_times.h \ src/core/ngx_connection.h \ + src/core/ngx_cycle.h \ src/core/ngx_conf_file.h \ src/core/ngx_garbage_collector.h" @@ -34,6 +35,8 @@ CORE_SRCS="src/core/nginx.c \ src/core/ngx_file.c \ src/core/ngx_rbtree.c \ src/core/ngx_times.c \ + src/core/ngx_connection.c \ + src/core/ngx_cycle.c \ src/core/ngx_conf_file.c \ src/core/ngx_garbage_collector.c" diff --git a/auto/unix b/auto/unix --- a/auto/unix +++ b/auto/unix @@ -83,10 +83,10 @@ n = pwrite(1, buf, 1, 0)" . auto/func -ngx_func="strsignal()" -ngx_func_inc="#include " -ngx_func_test="char *s = strsignal(1)" -. auto/func +#ngx_func="strsignal()" +#ngx_func_inc="#include " +#ngx_func_test="char *s = strsignal(1)" +#. auto/func ngx_func="strerror_r()" diff --git a/src/core/nginx.c b/src/core/nginx.c --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -5,18 +5,15 @@ #include -/* STUB */ -void stub_init(ngx_cycle_t *cycle); - - - -static ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle, ngx_log_t *log); -static int ngx_open_listening_sockets(ngx_cycle_t *cycle, ngx_log_t *log); -static void ngx_clean_old_cycles(ngx_event_t *ev); +static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data); +static void ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv); +static ngx_int_t ngx_core_module_init(ngx_cycle_t *cycle); typedef struct { + ngx_str_t user; int daemon; + int single; ngx_str_t pid; } ngx_core_conf_t; @@ -25,6 +22,13 @@ static ngx_str_t core_name = ngx_string static ngx_command_t ngx_core_commands[] = { + { ngx_string("user"), + NGX_MAIN_CONF|NGX_CONF_TAKE1, + ngx_conf_set_core_str_slot, + 0, + offsetof(ngx_core_conf_t, user), + NULL }, + { ngx_string("daemon"), NGX_MAIN_CONF|NGX_CONF_TAKE1, ngx_conf_set_core_flag_slot, @@ -32,6 +36,13 @@ static ngx_command_t ngx_core_commands[ offsetof(ngx_core_conf_t, daemon), NULL }, + { ngx_string("single_process"), + NGX_MAIN_CONF|NGX_CONF_TAKE1, + ngx_conf_set_core_flag_slot, + 0, + offsetof(ngx_core_conf_t, single), + NULL }, + ngx_null_command }; @@ -41,44 +52,46 @@ ngx_module_t ngx_core_module = { &core_name, /* module context */ ngx_core_commands, /* module directives */ NGX_CORE_MODULE, /* module type */ - NULL, /* init module */ + ngx_core_module_init, /* init module */ NULL /* init child */ }; -int ngx_max_module; -ngx_os_io_t ngx_io; - -volatile ngx_cycle_t *ngx_cycle; -ngx_array_t ngx_old_cycles; - -static ngx_pool_t *ngx_temp_pool; -static ngx_event_t ngx_cleaner_event; +ngx_int_t ngx_max_module; -/* STUB NAME */ -static ngx_connection_t dumb; +/* STUB */ +uid_t user; u_int ngx_connection_counter; +ngx_int_t ngx_master; +ngx_int_t ngx_single; -int done; -int restart; -int rotate; + +ngx_int_t ngx_respawn; +ngx_int_t ngx_terminate; +ngx_int_t ngx_quit; +ngx_int_t ngx_reconfigure; +ngx_int_t ngx_reopen; +ngx_int_t ngx_change_binary; -int main(int argc, char *const *argv) +int main(int argc, char *const *argv, char **envp) { - int i; - ngx_fd_t fd; - ngx_log_t *log; - ngx_cycle_t *cycle, init_cycle; - ngx_open_file_t *file; + struct timeval tv; + ngx_fd_t fd; + ngx_int_t i; + ngx_err_t err; + ngx_log_t *log; + ngx_cycle_t *cycle, init_cycle; + ngx_open_file_t *file; + ngx_core_conf_t *ccf; #if !(WIN32) - size_t len; - char pid[/* STUB */ 10]; - ngx_file_t pidfile; - ngx_core_conf_t *ccf; + size_t len; + char pid[/* STUB */ 10]; + ngx_file_t pidfile; + struct passwd *pwd; #endif #if __FreeBSD__ @@ -94,7 +107,6 @@ int main(int argc, char *const *argv) log = ngx_log_init_errlog(); - /* init_cycle->log is required for signal handlers */ ngx_memzero(&init_cycle, sizeof(ngx_cycle_t)); @@ -110,16 +122,46 @@ int main(int argc, char *const *argv) ngx_modules[i]->index = ngx_max_module++; } - cycle = ngx_init_cycle(NULL, log); + if (!(init_cycle.pool = ngx_create_pool(1024, log))) { + return 1; + } + + if (ngx_set_inherited_sockets(&init_cycle, envp) == NGX_ERROR) { + return 1; + } + + cycle = ngx_init_cycle(&init_cycle); if (cycle == NULL) { return 1; } ngx_cycle = cycle; + ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); + + if (ccf->single == 1) { + ngx_master = 0; + ngx_single = 1; + + } else { + ngx_master = 1; + ngx_single = 0; + } + #if !(WIN32) - ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); + /* STUB */ + if (ccf->user.len) { + pwd = getpwnam(ccf->user.data); + if (pwd == NULL) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + "getpwnam(%s) failed", ccf->user); + return 1; + } + + user = pwd->pw_uid; + } + /* */ if (ccf->daemon != 0) { if (ngx_daemon(cycle->log) == NGX_ERROR) { @@ -162,48 +204,64 @@ int main(int argc, char *const *argv) #endif - /* life cycle */ + /* a life cycle */ for ( ;; ) { -#if 0 - /* STUB */ cycle->log->log_level = NGX_LOG_DEBUG|NGX_LOG_DEBUG_HTTP; -#endif + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "new cycle"); -#if 0 - -#if !(WIN32) - ngx_spawn_process(cycle->log); -#endif + if (ngx_master) { + ngx_spawn_process(cycle, ngx_worker_process_cycle, NULL, + "worker process", NGX_PROCESS_RESPAWN); - stub_init(cycle); -#endif - - /* TODO: forks */ + } else { + ngx_init_temp_number(); - ngx_init_temp_number(); - - for (i = 0; ngx_modules[i]; i++) { - if (ngx_modules[i]->init_child) { - if (ngx_modules[i]->init_child(cycle) == NGX_ERROR) { - /* fatal */ - exit(1); + for (i = 0; ngx_modules[i]; i++) { + if (ngx_modules[i]->init_process) { + if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) { + /* fatal */ + exit(1); + } } } } - /* TODO: threads */ +#if 0 + reconfigure = 0; + reopen = 0; +#endif - restart = 0; - rotate = 0; + /* a cycle with the same configuration */ for ( ;; ) { + /* an event loop */ + for ( ;; ) { - ngx_log_debug(cycle->log, "worker cycle"); + + err = 0; + + if (ngx_single) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "worker cycle"); + + ngx_process_events(cycle->log); - ngx_process_events(cycle->log); + } else { + ngx_set_errno(0); + ngx_msleep(1000); + err = ngx_errno; + + ngx_gettimeofday(&tv); + ngx_time_update(tv.tv_sec); - if (done) { + if (err) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, err, + "sleep() exited"); + } + } + + if (ngx_quit || ngx_terminate) { #if !(WIN32) if (ngx_delete_file(pidfile.name.data) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, @@ -212,90 +270,70 @@ int main(int argc, char *const *argv) } #endif - ngx_log_error(NGX_LOG_INFO, - cycle->log, 0, "exiting"); + ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "exiting"); + + if (ngx_master) { + ngx_signal_processes(cycle, + ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); + + /* TODO: wait workers */ + + ngx_msleep(1000); + + ngx_gettimeofday(&tv); + ngx_time_update(tv.tv_sec); + } + + ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "exit"); exit(0); } - if (rotate) { - ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "reopen logs"); - - file = cycle->open_files.elts; - for (i = 0; i < cycle->open_files.nelts; i++) { - if (file[i].name.data == NULL) { - continue; - } - - fd = ngx_open_file(file[i].name.data, - NGX_FILE_RDWR, - NGX_FILE_CREATE_OR_OPEN|NGX_FILE_APPEND); - -ngx_log_debug(log, "REOPEN: %d:%d:%s" _ fd _ file[i].fd _ file[i].name.data); - - if (fd == NGX_INVALID_FILE) { - ngx_log_error(NGX_LOG_EMERG, - cycle->log, ngx_errno, - ngx_open_file_n " \"%s\" failed", - file[i].name.data); - continue; - } - -#if (WIN32) - if (ngx_file_append_mode(fd) == NGX_ERROR) { - ngx_log_error(NGX_LOG_EMERG, - cycle->log, ngx_errno, - ngx_file_append_mode_n - " \"%s\" failed", - file[i].name.data); - - if (ngx_close_file(fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_EMERG, - cycle->log, ngx_errno, - ngx_close_file_n " \"%s\" failed", - file[i].name.data); - } - - continue; - } -#endif - - if (ngx_close_file(file[i].fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_EMERG, - cycle->log, ngx_errno, - ngx_close_file_n " \"%s\" failed", - file[i].name.data); - } - - file[i].fd = fd; - } - - rotate = 0; + if (err == NGX_EINTR) { + ngx_respawn_processes(cycle); } - if (restart) { - ngx_log_debug(cycle->log, "restart"); + if (ngx_change_binary) { + ngx_change_binary = 0; + ngx_log_error(NGX_LOG_INFO, cycle->log, 0, + "changing binary"); + ngx_exec_new_binary(cycle, argv); + /* TODO: quit workers */ + } + + if (ngx_reconfigure) { + ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "reconfiguring"); break; } + if (ngx_reopen) { + ngx_log_error(NGX_LOG_INFO, cycle->log, 0, + "reopening logs"); + ngx_reopen_files(cycle); + ngx_reopen = 0; + } + } - cycle = ngx_init_cycle(cycle, cycle->log); + cycle = ngx_init_cycle(cycle); if (cycle == NULL) { cycle = (ngx_cycle_t *) ngx_cycle; continue; } ngx_cycle = cycle; + ngx_reconfigure = 0; break; } } } +#if 0 -static ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle, ngx_log_t *log) +static ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle) { - int i, n, failed; + ngx_int_t i, n, failed; ngx_str_t conf_file; + ngx_log_t *log; ngx_conf_t conf; ngx_pool_t *pool; ngx_cycle_t *cycle, **old; @@ -304,6 +342,7 @@ static ngx_cycle_t *ngx_init_cycle(ngx_c ngx_open_file_t *file; ngx_listening_t *ls, *nls; + log = old_cycle->log; if (!(pool = ngx_create_pool(16 * 1024, log))) { return NULL; @@ -318,7 +357,7 @@ static ngx_cycle_t *ngx_init_cycle(ngx_c cycle->old_cycle = old_cycle; - n = old_cycle ? old_cycle->pathes.nelts : 10; + n = old_cycle->pathes.nelts ? old_cycle->pathes.nelts : 10; if (!(cycle->pathes.elts = ngx_pcalloc(pool, n * sizeof(ngx_path_t *)))) { ngx_destroy_pool(pool); return NULL; @@ -329,7 +368,7 @@ static ngx_cycle_t *ngx_init_cycle(ngx_c cycle->pathes.pool = pool; - n = old_cycle ? old_cycle->open_files.nelts : 20; + n = old_cycle->open_files.nelts ? old_cycle->open_files.nelts : 20; cycle->open_files.elts = ngx_pcalloc(pool, n * sizeof(ngx_open_file_t)); if (cycle->open_files.elts == NULL) { ngx_destroy_pool(pool); @@ -347,7 +386,7 @@ static ngx_cycle_t *ngx_init_cycle(ngx_c } - n = old_cycle ? old_cycle->listening.nelts : 10; + n = old_cycle->listening.nelts ? old_cycle->listening.nelts : 10; cycle->listening.elts = ngx_pcalloc(pool, n * sizeof(ngx_listening_t)); if (cycle->listening.elts == NULL) { ngx_destroy_pool(pool); @@ -375,6 +414,7 @@ static ngx_cycle_t *ngx_init_cycle(ngx_c * ccf->pid = NULL; */ ccf->daemon = -1; + ccf->single = -1; ((void **)(cycle->conf_ctx))[ngx_core_module.index] = ccf; @@ -435,12 +475,8 @@ ngx_log_debug(log, "OPEN: %d:%s" _ file[ #endif } -#if 0 - /* STUB */ cycle->log->log_level = NGX_LOG_DEBUG; -#endif - if (!failed) { - if (old_cycle) { + if (old_cycle->listening.nelts) { ls = old_cycle->listening.elts; for (i = 0; i < old_cycle->listening.nelts; i++) { ls[i].remain = 0; @@ -449,6 +485,15 @@ ngx_log_debug(log, "OPEN: %d:%s" _ file[ nls = cycle->listening.elts; for (n = 0; n < cycle->listening.nelts; n++) { for (i = 0; i < old_cycle->listening.nelts; i++) { + if (ls[i].ignore) { + continue; + } + + ngx_log_error(NGX_LOG_INFO, log, 0, + "%X, %X", + *(int *) ls[i].sockaddr, + *(int *) nls[n].sockaddr); + if (ngx_memcmp(nls[n].sockaddr, ls[i].sockaddr, ls[i].socklen) == 0) { @@ -492,7 +537,7 @@ ngx_log_debug(log, "OPEN: %d:%s" _ file[ } if (!failed) { - if (ngx_open_listening_sockets(cycle, log) == NGX_ERROR) { + if (ngx_open_listening_sockets(cycle) == NGX_ERROR) { failed = 1; } } @@ -536,9 +581,6 @@ ngx_log_debug(log, "OPEN: %d:%s" _ file[ pool->log = cycle->log; -#if 1 - /* STUB */ cycle->one_process = 1; -#endif for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->init_module) { @@ -549,9 +591,9 @@ ngx_log_debug(log, "OPEN: %d:%s" _ file[ } } - if (old_cycle == NULL) { - return cycle; - } + /* close and delete stuff that lefts from an old cycle */ + + /* close the unneeded listening sockets */ ls = old_cycle->listening.elts; for (i = 0; i < old_cycle->listening.nelts; i++) { @@ -566,6 +608,9 @@ ngx_log_debug(log, "OPEN: %d:%s" _ file[ } } + + /* close the unneeded open files */ + file = old_cycle->open_files.elts; for (i = 0; i < old_cycle->open_files.nelts; i++) { if (file[i].fd == NGX_INVALID_FILE) { @@ -579,8 +624,13 @@ ngx_log_debug(log, "OPEN: %d:%s" _ file[ } } + if (old_cycle->connections == NULL) { + /* an old cycle is an init cycle */ + ngx_destroy_pool(old_cycle->pool); + return cycle; + } - if (!old_cycle->one_process) { + if (master) { ngx_destroy_pool(old_cycle->pool); return cycle; } @@ -626,190 +676,233 @@ ngx_log_debug(log, "OPEN: %d:%s" _ file[ return cycle; } - -static int ngx_open_listening_sockets(ngx_cycle_t *cycle, ngx_log_t *log) -{ - int times, failed, reuseaddr, i; - ngx_err_t err; - ngx_socket_t s; - ngx_listening_t *ls; - - reuseaddr = 1; -#if (NGX_SUPPRESS_WARN) - failed = 0; #endif - /* TODO: times configurable */ - for (times = 10; times; times--) { - failed = 0; +#if 0 - /* for each listening socket */ +static ngx_int_t ngx_set_inherited_sockets(ngx_cycle_t *cycle, char **envp) +{ + char *p, *v; + ngx_socket_t s; + ngx_listening_t *ls; + struct sockaddr_in *addr_in; - ls = cycle->listening.elts; - for (i = 0; i < cycle->listening.nelts; i++) { + for ( /* void */ ; *envp; envp++) { + if (ngx_strncmp(*envp, NGINX_VAR, NGINX_VAR_LEN) != 0) { + continue; + } + + ngx_log_error(NGX_LOG_INFO, cycle->log, 0, + "using inherited sockets from \"%s\"", *envp); - if (ls[i].fd != -1) { - continue; - } - - if (ls[i].inherited) { + ngx_init_array(cycle->listening, cycle->pool, + 10, sizeof(ngx_listening_t), NGX_ERROR); - /* TODO: close on exit */ - /* TODO: nonblocking */ - /* TODO: deferred accept */ + for (p = *envp + NGINX_VAR_LEN, v = p; *p; p++) { + if (*p == ':' || *p == ';') { + s = ngx_atoi(v, p - v); + if (s == NGX_ERROR) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, + "invalid socket number \"%s\" " + "in NGINX enviroment variable, " + "ignoring the rest of the variable", v); + break; + } + v = p + 1; - continue; - } + if (!(ls = ngx_push_array(&cycle->listening))) { + return NGX_ERROR; + } - s = ngx_socket(ls[i].family, ls[i].type, ls[i].protocol, - ls[i].flags); + ls->fd = s; - 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; - } + /* AF_INET only */ + + ls->sockaddr = ngx_palloc(cycle->pool, + sizeof(struct sockaddr_in)); + if (ls->sockaddr == NULL) { + 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. - */ + ls->socklen = sizeof(struct sockaddr_in); + if (getsockname(s, ls->sockaddr, &ls->socklen) == -1) { + ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno, + "getsockname() of the inherited " + "socket #%d failed", s); + ls->ignore = 1; + continue; + } + + addr_in = (struct sockaddr_in *) ls->sockaddr; - if (s % 4) { - ngx_log_error(NGX_LOG_EMERG, ls->log, 0, - ngx_socket_n " created socket %d", s); - return NGX_ERROR; - } -#endif + if (addr_in->sin_family != AF_INET) { + ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno, + "the inherited socket #%d has " + "unsupported family", s); + ls->ignore = 1; + continue; + } + ls->addr_text_max_len = INET_ADDRSTRLEN; - 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; - } + ls->addr_text.data = ngx_palloc(cycle->pool, + ls->addr_text_max_len); + if (ls->addr_text.data == NULL) { + return NGX_ERROR; + } - /* TODO: close on exit */ + addr_in->sin_len = 0; - 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); + ls->family = addr_in->sin_family; + ls->addr_text.len = ngx_sock_ntop(ls->family, ls->sockaddr, + ls->addr_text.data, + ls->addr_text_max_len); + if (ls->addr_text.len == 0) { 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; + break; } return NGX_OK; } +#endif -static void ngx_clean_old_cycles(ngx_event_t *ev) + +static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data) { - int i, n, found, live; - ngx_log_t *log; - ngx_cycle_t **cycle; + ngx_int_t i; + ngx_listening_t *ls; - log = ngx_cycle->log; - ngx_temp_pool->log = log; + if (user) { + if (setuid(user) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "setuid() failed"); + /* fatal */ + exit(1); + } + } + + ngx_init_temp_number(); - ngx_log_debug(log, "clean old cycles"); - - live = 0; + /* + * disable deleting previous events for the listening sockets because + * in the worker processes there are no events at all at this point + */ + ls = cycle->listening.elts; + for (i = 0; i < cycle->listening.nelts; i++) { + ls[i].remain = 0; + } - cycle = ngx_old_cycles.elts; - for (i = 0; i < ngx_old_cycles.nelts; i++) { + for (i = 0; ngx_modules[i]; i++) { + if (ngx_modules[i]->init_process) { + if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) { + /* fatal */ + exit(1); + } + } + } + + /* TODO: threads: start ngx_worker_thread_cycle() */ - if (cycle[i] == NULL) { - continue; + for ( ;; ) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "worker cycle"); + + ngx_process_events(cycle->log); + + if (ngx_terminate) { + ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "exiting"); + exit(0); + } + + if (ngx_quit) { + ngx_log_error(NGX_LOG_INFO, cycle->log, 0, + "gracefully shutdowning"); + break; } - found = 0; + if (ngx_reopen) { + ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "reopen logs"); + ngx_reopen_files(cycle); + ngx_reopen = 0; + } + } - for (n = 0; n < cycle[i]->connection_n; n++) { - if (cycle[i]->connections[n].fd != -1) { - found = 1; - ngx_log_debug(log, "live fd: %d" _ n); - break; - } - } + ngx_close_listening_sockets(cycle); - if (found) { - live = 1; - continue; + for ( ;; ) { + if (ngx_event_timer_rbtree == &ngx_event_timer_sentinel) { + ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "exiting"); + exit(0); } - ngx_log_debug(log, "clean old cycle: %d" _ i); - ngx_destroy_pool(cycle[i]->pool); - cycle[i] = NULL; + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "worker cycle"); + + ngx_process_events(cycle->log); + } +} + + +static void ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv) +{ + char *env[2], *var, *p; + ngx_int_t i; + ngx_exec_ctx_t ctx; + ngx_listening_t *ls; + + ctx.path = argv[0]; + ctx.name = "new binary process"; + ctx.argv = argv; + + var = ngx_alloc(NGINX_VAR_LEN + + cycle->listening.nelts * (NGX_INT32_LEN + 1) + 1, + cycle->log); + + p = ngx_cpymem(var, NGINX_VAR, NGINX_VAR_LEN); + + ls = cycle->listening.elts; + for (i = 0; i < cycle->listening.nelts; i++) { + p += ngx_snprintf(p, NGX_INT32_LEN + 2, "%u;", ls[i].fd); } - ngx_log_debug(log, "old cycles status: %d" _ live); + env[0] = var; + env[1] = NULL; + ctx.envp = (char *const *) &env; + + ngx_exec(cycle, &ctx); - if (live) { - ngx_log_debug(log, "TIMER"); - ngx_add_timer(ev, 30000); + ngx_free(var); +} + + +static ngx_int_t ngx_core_module_init(ngx_cycle_t *cycle) +{ + ngx_core_conf_t *ccf; - } else { - ngx_destroy_pool(ngx_temp_pool); - ngx_temp_pool = NULL; - ngx_old_cycles.nelts = 0; + /* + * ngx_core_module has a special init procedure: it is called by + * ngx_init_cycle() before the configuration file parsing to create + * ngx_core_module configuration and to set its default parameters + */ + + if (((void **)(cycle->conf_ctx))[ngx_core_module.index] != NULL) { + return NGX_OK; } + + if (!(ccf = ngx_pcalloc(cycle->pool, sizeof(ngx_core_conf_t)))) { + return NGX_ERROR; + } + /* set by pcalloc() + * + * ccf->pid = NULL; + */ + ccf->daemon = -1; + ccf->single = -1; + + ((void **)(cycle->conf_ctx))[ngx_core_module.index] = ccf; + + return NGX_OK; } diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -2,16 +2,19 @@ #define _NGINX_H_INCLUDED_ -#define NGINX_VER "nginx/0.0.1" -#define NGINX_CONF "nginx.conf" -#define NGINX_PID "nginx.pid" +#define NGINX_VER "nginx/0.0.1" +#define NGINX_CONF "nginx.conf" +#define NGINX_PID "nginx.pid" +#define NGINX_VAR "NGINX=" +#define NGINX_VAR_LEN (sizeof(NGINX_VAR) - 1) -extern int ngx_max_module; -extern u_int ngx_connection_counter; +extern ngx_module_t ngx_core_module; -extern ngx_module_t ngx_core_module; +extern ngx_uint_t ngx_connection_counter; +extern ngx_int_t ngx_master; +extern ngx_int_t ngx_single; #endif /* _NGINX_H_INCLUDED_ */ diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c --- a/src/core/ngx_conf_file.c +++ b/src/core/ngx_conf_file.c @@ -571,6 +571,13 @@ char *ngx_conf_set_core_flag_slot(ngx_co } +char *ngx_conf_set_core_str_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + return ngx_conf_set_str_slot(cf, cmd, *(void **)conf); +} + + char *ngx_conf_set_flag_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *p = conf; diff --git a/src/core/ngx_conf_file.h b/src/core/ngx_conf_file.h --- a/src/core/ngx_conf_file.h +++ b/src/core/ngx_conf_file.h @@ -85,26 +85,6 @@ struct ngx_open_file_s { }; -struct ngx_cycle_s { - void ****conf_ctx; - ngx_pool_t *pool; - ngx_log_t *log; - ngx_array_t listening; - ngx_array_t open_files; - ngx_array_t pathes; - - int connection_n; - ngx_connection_t *connections; - ngx_event_t *read_events; - ngx_event_t *write_events; - - ngx_cycle_t *cycle; - ngx_cycle_t *old_cycle; - - unsigned one_process:1; -}; - - struct ngx_module_s { int ctx_index; int index; @@ -112,7 +92,10 @@ struct ngx_module_s { ngx_command_t *commands; int type; int (*init_module)(ngx_cycle_t *cycle); - int (*init_child)(ngx_cycle_t *cycle); + int (*init_process)(ngx_cycle_t *cycle); +#if 0 + int (*init_thread)(ngx_cycle_t *cycle); +#endif }; @@ -271,11 +254,12 @@ char *ngx_conf_set_bitmask_slot(ngx_conf char *ngx_conf_set_core_flag_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char *ngx_conf_set_core_str_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); -extern ngx_module_t *ngx_modules[]; -extern volatile ngx_cycle_t *ngx_cycle; -extern ngx_array_t ngx_old_cycles; +extern ngx_int_t ngx_max_module; +extern ngx_module_t *ngx_modules[]; #endif /* _NGX_HTTP_CONF_FILE_H_INCLUDED_ */ diff --git a/src/core/ngx_config.h b/src/core/ngx_config.h --- a/src/core/ngx_config.h +++ b/src/core/ngx_config.h @@ -59,14 +59,16 @@ typedef u_int ngx_uint_t; #if !(WIN32) -#define ngx_signal_helper(n) SIG##n -#define ngx_signal_value(n) ngx_signal_helper(n) +#define ngx_signal_helper(n) SIG##n +#define ngx_signal_value(n) ngx_signal_helper(n) /* TODO: #ifndef */ -#define NGX_RESTART_SIGNAL HUP -#define NGX_ROTATE_SIGNAL USR1 -#define NGX_SHUTDOWN_SIGNAL TERM -#define NGX_INTERRUPT_SIGNAL INT +#define NGX_RECONFIGURE_SIGNAL HUP +#define NGX_REOPEN_SIGNAL USR1 +#define NGX_SHUTDOWN_SIGNAL QUIT +#define NGX_TERMINATE_SIGNAL TERM +#define NGX_INTERRUPT_SIGNAL INT +#define NGX_CHANGEBIN_SIGNAL USR2 #endif @@ -76,6 +78,13 @@ typedef u_int ngx_uint_t; #define NGX_INVALID_ARRAY_INDEX 0x80000000 +/* TODO: auto */ +#define NGX_INT32_LEN sizeof("-2147483648") - 1 +#define NGX_TIME_T_LEN sizeof("-2147483648") - 1 +#define NGX_OFF_T_LEN sizeof("-9223372036854775808") - 1 + + + /* TODO: auto_conf */ #define NGX_ALIGN (sizeof(unsigned long) - 1) /* platform word */ #define NGX_ALIGN_CAST (unsigned long) /* size of the pointer */ diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c new file mode 100644 --- /dev/null +++ b/src/core/ngx_connection.c @@ -0,0 +1,275 @@ + +#include +#include +#include +/* STUB */ +#include + + +ngx_os_io_t ngx_io; + + +ngx_int_t ngx_set_inherited_sockets(ngx_cycle_t *cycle, char **envp) +{ + char *p, *v; + ngx_socket_t s; + ngx_listening_t *ls; + struct sockaddr_in *addr_in; + + for ( /* void */ ; *envp; envp++) { + if (ngx_strncmp(*envp, NGINX_VAR, NGINX_VAR_LEN) != 0) { + continue; + } + + ngx_log_error(NGX_LOG_INFO, cycle->log, 0, + "using inherited sockets from \"%s\"", *envp); + + ngx_init_array(cycle->listening, cycle->pool, + 10, sizeof(ngx_listening_t), NGX_ERROR); + + for (p = *envp + NGINX_VAR_LEN, v = p; *p; p++) { + if (*p == ':' || *p == ';') { + s = ngx_atoi(v, p - v); + if (s == NGX_ERROR) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, + "invalid socket number \"%s\" " + "in NGINX enviroment variable, " + "ignoring the rest of the variable", v); + break; + } + v = p + 1; + + if (!(ls = ngx_push_array(&cycle->listening))) { + return NGX_ERROR; + } + + ls->fd = s; + + /* AF_INET only */ + + ls->sockaddr = ngx_palloc(cycle->pool, + sizeof(struct sockaddr_in)); + if (ls->sockaddr == NULL) { + return NGX_ERROR; + } + + ls->socklen = sizeof(struct sockaddr_in); + if (getsockname(s, ls->sockaddr, &ls->socklen) == -1) { + ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno, + "getsockname() of the inherited " + "socket #%d failed", s); + ls->ignore = 1; + continue; + } + + addr_in = (struct sockaddr_in *) ls->sockaddr; + + if (addr_in->sin_family != AF_INET) { + ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno, + "the inherited socket #%d has " + "unsupported family", s); + ls->ignore = 1; + continue; + } + ls->addr_text_max_len = INET_ADDRSTRLEN; + + ls->addr_text.data = ngx_palloc(cycle->pool, + ls->addr_text_max_len); + if (ls->addr_text.data == NULL) { + return NGX_ERROR; + } + + addr_in->sin_len = 0; + + ls->family = addr_in->sin_family; + ls->addr_text.len = ngx_sock_ntop(ls->family, ls->sockaddr, + ls->addr_text.data, + ls->addr_text_max_len); + if (ls->addr_text.len == 0) { + return NGX_ERROR; + } + } + } + + break; + } + + return NGX_OK; +} + + +ngx_int_t ngx_open_listening_sockets(ngx_cycle_t *cycle) +{ + int 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 = 10; 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; +} + + +void ngx_close_listening_sockets(ngx_cycle_t *cycle) +{ + ngx_int_t i; + ngx_socket_t fd; + ngx_listening_t *ls; + + if (ngx_event_flags & NGX_USE_IOCP_EVENT) { + return; + } + + ls = cycle->listening.elts; + for (i = 0; i < cycle->listening.nelts; i++) { + fd = ls[i].fd; + +#if (WIN32) + /* + * Winsock assignes a socket number divisible by 4 + * so to find a connection we divide a socket number by 4. + */ + + fd /= 4; +#endif + + ngx_del_event(&cycle->read_events[fd], NGX_READ_EVENT, NGX_CLOSE_EVENT); + + if (ngx_close_socket(ls[i].fd) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, + ngx_close_socket_n " %s failed", + ls[i].addr_text.data); + } + + cycle->connections[fd].fd = -1; + } +} diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -36,6 +36,7 @@ typedef struct { unsigned new:1; unsigned remain:1; + unsigned ignore:1; unsigned bound:1; /* already bound */ unsigned inherited:1; /* inherited from previous process */ @@ -85,13 +86,18 @@ struct ngx_connection_s { unsigned pipeline:1; unsigned unexpected_eof:1; - unsigned tcp_nopush:1; + signed tcp_nopush:2; #if (HAVE_IOCP) unsigned accept_context_updated:1; #endif }; +ngx_int_t ngx_set_inherited_sockets(ngx_cycle_t *cycle, char **envp); +ngx_int_t ngx_open_listening_sockets(ngx_cycle_t *cycle); +void ngx_close_listening_sockets(ngx_cycle_t *cycle); + + extern ngx_os_io_t ngx_io; diff --git a/src/core/ngx_core.h b/src/core/ngx_core.h --- a/src/core/ngx_core.h +++ b/src/core/ngx_core.h @@ -37,6 +37,7 @@ typedef struct ngx_connection_s ngx_con #include #include #include +#include #include #include #include diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c new file mode 100644 --- /dev/null +++ b/src/core/ngx_cycle.c @@ -0,0 +1,743 @@ + +#include +#include +#include +/* STUB */ +#include + + +static void ngx_clean_old_cycles(ngx_event_t *ev); + + +volatile ngx_cycle_t *ngx_cycle; +ngx_array_t ngx_old_cycles; + +static ngx_pool_t *ngx_temp_pool; +static ngx_event_t ngx_cleaner_event; + + +/* STUB NAME */ +static ngx_connection_t dumb; +/* STUB */ + + +ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle) +{ + ngx_int_t i, n, failed; + ngx_str_t conf_file; + ngx_log_t *log; + ngx_conf_t conf; + ngx_pool_t *pool; + ngx_cycle_t *cycle, **old; + ngx_socket_t fd; + ngx_open_file_t *file; + ngx_listening_t *ls, *nls; + + log = old_cycle->log; + + if (!(pool = ngx_create_pool(16 * 1024, log))) { + return NULL; + } + + if (!(cycle = ngx_pcalloc(pool, sizeof(ngx_cycle_t)))) { + ngx_destroy_pool(pool); + return NULL; + } + cycle->pool = pool; + + cycle->old_cycle = old_cycle; + + + n = old_cycle->pathes.nelts ? old_cycle->pathes.nelts : 10; + if (!(cycle->pathes.elts = ngx_pcalloc(pool, n * sizeof(ngx_path_t *)))) { + ngx_destroy_pool(pool); + return NULL; + } + cycle->pathes.nelts = 0; + cycle->pathes.size = sizeof(ngx_path_t *); + cycle->pathes.nalloc = n; + cycle->pathes.pool = pool; + + + n = old_cycle->open_files.nelts ? old_cycle->open_files.nelts : 20; + cycle->open_files.elts = ngx_pcalloc(pool, n * sizeof(ngx_open_file_t)); + if (cycle->open_files.elts == NULL) { + ngx_destroy_pool(pool); + return NULL; + } + cycle->open_files.nelts = 0; + cycle->open_files.size = sizeof(ngx_open_file_t); + cycle->open_files.nalloc = n; + cycle->open_files.pool = pool; + + + if (!(cycle->log = ngx_log_create_errlog(cycle, NULL))) { + ngx_destroy_pool(pool); + return NULL; + } + + + n = old_cycle->listening.nelts ? old_cycle->listening.nelts : 10; + cycle->listening.elts = ngx_pcalloc(pool, n * sizeof(ngx_listening_t)); + if (cycle->listening.elts == NULL) { + ngx_destroy_pool(pool); + return NULL; + } + cycle->listening.nelts = 0; + cycle->listening.size = sizeof(ngx_listening_t); + cycle->listening.nalloc = n; + cycle->listening.pool = pool; + + + cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *)); + if (cycle->conf_ctx == NULL) { + ngx_destroy_pool(pool); + return NULL; + } + + + if (ngx_core_module.init_module(cycle) == NGX_ERROR) { + ngx_destroy_pool(pool); + return NULL; + } + + + ngx_memzero(&conf, sizeof(ngx_conf_t)); + /* STUB: init array ? */ + conf.args = ngx_create_array(pool, 10, sizeof(ngx_str_t)); + if (conf.args == NULL) { + ngx_destroy_pool(pool); + return NULL; + } + + conf.ctx = cycle->conf_ctx; + conf.cycle = cycle; + /* STUB */ conf.pool = cycle->pool; + conf.log = log; + conf.module_type = NGX_CORE_MODULE; + conf.cmd_type = NGX_MAIN_CONF; + + conf_file.len = sizeof(NGINX_CONF) - 1; + conf_file.data = NGINX_CONF; + + if (ngx_conf_parse(&conf, &conf_file) != NGX_CONF_OK) { + ngx_destroy_pool(pool); + return NULL; + } + + + failed = 0; + + file = cycle->open_files.elts; + for (i = 0; i < cycle->open_files.nelts; i++) { + if (file[i].name.data == NULL) { + continue; + } + + file[i].fd = ngx_open_file(file[i].name.data, + NGX_FILE_RDWR, + NGX_FILE_CREATE_OR_OPEN|NGX_FILE_APPEND); + +ngx_log_debug(log, "OPEN: %d:%s" _ file[i].fd _ file[i].name.data); + + if (file[i].fd == NGX_INVALID_FILE) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, + ngx_open_file_n " \"%s\" failed", + file[i].name.data); + failed = 1; + break; + } + +#if (WIN32) + if (ngx_file_append_mode(file[i].fd) == NGX_ERROR) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, + ngx_file_append_mode_n " \"%s\" failed", + file[i].name.data); + failed = 1; + break; + } +#endif + } + + if (!failed) { + if (old_cycle->listening.nelts) { + ls = old_cycle->listening.elts; + for (i = 0; i < old_cycle->listening.nelts; i++) { + ls[i].remain = 0; + } + + nls = cycle->listening.elts; + for (n = 0; n < cycle->listening.nelts; n++) { + for (i = 0; i < old_cycle->listening.nelts; i++) { + if (ls[i].ignore) { + continue; + } + + ngx_log_error(NGX_LOG_INFO, log, 0, + "%X, %X", + *(int *) ls[i].sockaddr, + *(int *) nls[n].sockaddr); + + if (ngx_memcmp(nls[n].sockaddr, + ls[i].sockaddr, ls[i].socklen) == 0) + { + fd = ls[i].fd; +#if (WIN32) + /* + * Winsock assignes a socket number divisible by 4 so + * to find a connection we divide a socket number by 4. + */ + + fd /= 4; +#endif + if (fd >= (ngx_socket_t) cycle->connection_n) { + ngx_log_error(NGX_LOG_EMERG, log, 0, + "%d connections is not enough to hold " + "an open listening socket on %s, " + "required at least %d connections", + cycle->connection_n, + ls[i].addr_text.data, fd); + failed = 1; + break; + } + + nls[n].fd = ls[i].fd; + nls[i].remain = 1; + ls[i].remain = 1; + break; + } + } + + if (nls[n].fd == -1) { + nls[n].new = 1; + } + } + + } else { + ls = cycle->listening.elts; + for (i = 0; i < cycle->listening.nelts; i++) { + ls[i].new = 1; + } + } + + if (!failed) { + if (ngx_open_listening_sockets(cycle) == NGX_ERROR) { + failed = 1; + } + } + } + + if (failed) { + + /* rollback the new cycle configuration */ + + file = cycle->open_files.elts; + for (i = 0; i < cycle->open_files.nelts; i++) { + if (file[i].fd == NGX_INVALID_FILE) { + continue; + } + + if (ngx_close_file(file[i].fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, + ngx_close_file_n " \"%s\" failed", + file[i].name.data); + } + } + + ls = cycle->listening.elts; + for (i = 0; i < cycle->listening.nelts; i++) { + if (ls[i].new && ls[i].fd == -1) { + continue; + } + + if (ngx_close_socket(ls[i].fd) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + ngx_close_socket_n " %s failed", + ls[i].addr_text.data); + } + } + + ngx_destroy_pool(pool); + return NULL; + } + + /* commit the new cycle configuration */ + + pool->log = cycle->log; + + + for (i = 0; ngx_modules[i]; i++) { + if (ngx_modules[i]->init_module) { + if (ngx_modules[i]->init_module(cycle) == NGX_ERROR) { + /* fatal */ + exit(1); + } + } + } + + /* close and delete stuff that lefts from an old cycle */ + + /* close the unneeded listening sockets */ + + ls = old_cycle->listening.elts; + for (i = 0; i < old_cycle->listening.nelts; i++) { + if (ls[i].remain) { + continue; + } + + if (ngx_close_socket(ls[i].fd) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + ngx_close_socket_n " %s failed", + ls[i].addr_text.data); + } + } + + + /* close the unneeded open files */ + + file = old_cycle->open_files.elts; + for (i = 0; i < old_cycle->open_files.nelts; i++) { + if (file[i].fd == NGX_INVALID_FILE) { + continue; + } + + if (ngx_close_file(file[i].fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, + ngx_close_file_n " \"%s\" failed", + file[i].name.data); + } + } + + if (old_cycle->connections == NULL) { + /* an old cycle is an init cycle */ + ngx_destroy_pool(old_cycle->pool); + return cycle; + } + + if (ngx_master) { + ngx_destroy_pool(old_cycle->pool); + return cycle; + } + + if (ngx_temp_pool == NULL) { + ngx_temp_pool = ngx_create_pool(128, cycle->log); + if (ngx_temp_pool == NULL) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, + "can not create ngx_temp_pool"); + exit(1); + } + + n = 10; + ngx_old_cycles.elts = ngx_pcalloc(ngx_temp_pool, + n * sizeof(ngx_cycle_t *)); + if (ngx_old_cycles.elts == NULL) { + exit(1); + } + ngx_old_cycles.nelts = 0; + ngx_old_cycles.size = sizeof(ngx_cycle_t *); + ngx_old_cycles.nalloc = n; + ngx_old_cycles.pool = ngx_temp_pool; + + ngx_cleaner_event.event_handler = ngx_clean_old_cycles; + ngx_cleaner_event.log = cycle->log; + ngx_cleaner_event.data = &dumb; + dumb.fd = (ngx_socket_t) -1; + } + + ngx_temp_pool->log = cycle->log; + + old = ngx_push_array(&ngx_old_cycles); + if (old == NULL) { + exit(1); + } + *old = old_cycle; + + if (!ngx_cleaner_event.timer_set) { + ngx_add_timer(&ngx_cleaner_event, 30000); + ngx_cleaner_event.timer_set = 1; + } + + return cycle; +} + + +#if 0 + + +static ngx_int_t ngx_set_inherited_sockets(ngx_cycle_t *cycle, char **envp) +{ + char *p, *v; + ngx_socket_t s; + ngx_listening_t *ls; + struct sockaddr_in *addr_in; + + for ( /* void */ ; *envp; envp++) { + if (ngx_strncmp(*envp, NGINX_VAR, NGINX_VAR_LEN) != 0) { + continue; + } + + ngx_log_error(NGX_LOG_INFO, cycle->log, 0, + "using inherited sockets from \"%s\"", *envp); + + ngx_init_array(cycle->listening, cycle->pool, + 10, sizeof(ngx_listening_t), NGX_ERROR); + + for (p = *envp + NGINX_VAR_LEN, v = p; *p; p++) { + if (*p == ':' || *p == ';') { + s = ngx_atoi(v, p - v); + if (s == NGX_ERROR) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, + "invalid socket number \"%s\" " + "in NGINX enviroment variable, " + "ignoring the rest of the variable", v); + break; + } + v = p + 1; + + if (!(ls = ngx_push_array(&cycle->listening))) { + return NGX_ERROR; + } + + ls->fd = s; + + /* AF_INET only */ + + ls->sockaddr = ngx_palloc(cycle->pool, + sizeof(struct sockaddr_in)); + if (ls->sockaddr == NULL) { + return NGX_ERROR; + } + + ls->socklen = sizeof(struct sockaddr_in); + if (getsockname(s, ls->sockaddr, &ls->socklen) == -1) { + ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno, + "getsockname() of the inherited " + "socket #%d failed", s); + ls->ignore = 1; + continue; + } + + addr_in = (struct sockaddr_in *) ls->sockaddr; + + if (addr_in->sin_family != AF_INET) { + ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno, + "the inherited socket #%d has " + "unsupported family", s); + ls->ignore = 1; + continue; + } + ls->addr_text_max_len = INET_ADDRSTRLEN; + + ls->addr_text.data = ngx_palloc(cycle->pool, + ls->addr_text_max_len); + if (ls->addr_text.data == NULL) { + return NGX_ERROR; + } + + addr_in->sin_len = 0; + + ls->family = addr_in->sin_family; + ls->addr_text.len = ngx_sock_ntop(ls->family, ls->sockaddr, + ls->addr_text.data, + ls->addr_text_max_len); + if (ls->addr_text.len == 0) { + return NGX_ERROR; + } + } + } + + break; + } + + return NGX_OK; +} + + +static ngx_int_t ngx_open_listening_sockets(ngx_cycle_t *cycle) +{ + int 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 = 10; 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; +} + + +#endif + + +void ngx_reopen_files(ngx_cycle_t *cycle) +{ + ngx_fd_t fd; + ngx_int_t i; + ngx_open_file_t *file; + + file = cycle->open_files.elts; + for (i = 0; i < cycle->open_files.nelts; i++) { + if (file[i].name.data == NULL) { + continue; + } + + fd = ngx_open_file(file[i].name.data, NGX_FILE_RDWR, + NGX_FILE_CREATE_OR_OPEN|NGX_FILE_APPEND); + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "reopen file \"%s\", old:%d new:%d", + file[i].name.data, file[i].fd, fd); + + if (fd == NGX_INVALID_FILE) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + ngx_open_file_n " \"%s\" failed", file[i].name.data); + continue; + } + +#if (WIN32) + if (ngx_file_append_mode(fd) == NGX_ERROR) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + ngx_file_append_mode_n " \"%s\" failed", + file[i].name.data); + + if (ngx_close_file(fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", + file[i].name.data); + } + + continue; + } +#endif + + if (ngx_close_file(file[i].fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", + file[i].name.data); + } + + file[i].fd = fd; + } +} + + +#if 0 + +static void ngx_close_listening_sockets(ngx_cycle_t *cycle) +{ + ngx_int_t i; + ngx_socket_t fd; + ngx_listening_t *ls; + + if (ngx_event_flags & NGX_USE_IOCP_EVENT) { + return; + } + + ls = cycle->listening.elts; + for (i = 0; i < cycle->listening.nelts; i++) { + fd = ls[i].fd; + +#if (WIN32) + /* + * Winsock assignes a socket number divisible by 4 + * so to find a connection we divide a socket number by 4. + */ + + fd /= 4; +#endif + + ngx_del_event(&cycle->read_events[fd], NGX_READ_EVENT, NGX_CLOSE_EVENT); + + if (ngx_close_socket(ls[i].fd) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, + ngx_close_socket_n " %s failed", + ls[i].addr_text.data); + } + + cycle->connections[fd].fd = -1; + } +} + +#endif + + +static void ngx_clean_old_cycles(ngx_event_t *ev) +{ + int i, n, found, live; + ngx_log_t *log; + ngx_cycle_t **cycle; + + log = ngx_cycle->log; + ngx_temp_pool->log = log; + + ngx_log_debug(log, "clean old cycles"); + + live = 0; + + cycle = ngx_old_cycles.elts; + for (i = 0; i < ngx_old_cycles.nelts; i++) { + + if (cycle[i] == NULL) { + continue; + } + + found = 0; + + for (n = 0; n < cycle[i]->connection_n; n++) { + if (cycle[i]->connections[n].fd != -1) { + found = 1; + ngx_log_debug(log, "live fd: %d" _ n); + break; + } + } + + if (found) { + live = 1; + continue; + } + + ngx_log_debug(log, "clean old cycle: %d" _ i); + ngx_destroy_pool(cycle[i]->pool); + cycle[i] = NULL; + } + + ngx_log_debug(log, "old cycles status: %d" _ live); + + if (live) { + ngx_log_debug(log, "TIMER"); + ngx_add_timer(ev, 30000); + + } else { + ngx_destroy_pool(ngx_temp_pool); + ngx_temp_pool = NULL; + ngx_old_cycles.nelts = 0; + } +} diff --git a/src/core/ngx_cycle.h b/src/core/ngx_cycle.h new file mode 100644 --- /dev/null +++ b/src/core/ngx_cycle.h @@ -0,0 +1,36 @@ +#ifndef _NGX_CYCLE_H_INCLUDED_ +#define _NGX_CYCLE_H_INCLUDED_ + + +#include +#include + + +struct ngx_cycle_s { + void ****conf_ctx; + ngx_pool_t *pool; + ngx_log_t *log; + ngx_array_t listening; + ngx_array_t open_files; + ngx_array_t pathes; + + int connection_n; + ngx_connection_t *connections; + ngx_event_t *read_events; + ngx_event_t *write_events; + + ngx_cycle_t *old_cycle; + + unsigned one_process:1; +}; + + +ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle); +void ngx_reopen_files(ngx_cycle_t *cycle); + + +extern volatile ngx_cycle_t *ngx_cycle; +extern ngx_array_t ngx_old_cycles; + + +#endif /* _NGX_CYCLE_H_INCLUDED_ */ diff --git a/src/core/ngx_log.c b/src/core/ngx_log.c --- a/src/core/ngx_log.c +++ b/src/core/ngx_log.c @@ -52,7 +52,7 @@ static const char *err_levels[] = { }; static const char *debug_levels[] = { - "debug", "debug_alloc", "debug_event", "debug_http" + "debug", "debug_core", "debug_alloc", "debug_event", "debug_http" }; diff --git a/src/core/ngx_log.h b/src/core/ngx_log.h --- a/src/core/ngx_log.h +++ b/src/core/ngx_log.h @@ -16,9 +16,10 @@ #define NGX_LOG_INFO 7 #define NGX_LOG_DEBUG 8 -#define NGX_LOG_DEBUG_ALLOC 0x10 -#define NGX_LOG_DEBUG_EVENT 0x20 -#define NGX_LOG_DEBUG_HTTP 0x40 +#define NGX_LOG_DEBUG_CORE 0x10 +#define NGX_LOG_DEBUG_ALLOC 0x20 +#define NGX_LOG_DEBUG_EVENT 0x40 +#define NGX_LOG_DEBUG_HTTP 0x80 #define NGX_LOG_DEBUG_FIRST NGX_LOG_DEBUG #define NGX_LOG_DEBUG_LAST NGX_LOG_DEBUG_HTTP diff --git a/src/core/ngx_times.c b/src/core/ngx_times.c --- a/src/core/ngx_times.c +++ b/src/core/ngx_times.c @@ -39,19 +39,25 @@ void ngx_time_init() ngx_cached_http_log_time.data = cached_http_log_time; ngx_gettimeofday(&tv); - ngx_cached_time = tv.tv_sec; + ngx_cached_time = 0; ngx_start_msec = tv.tv_sec * 1000 + tv.tv_usec / 1000; ngx_old_elapsed_msec = 0; ngx_elapsed_msec = 0; - ngx_time_update(); + ngx_time_update(tv.tv_sec); } -void ngx_time_update() +void ngx_time_update(time_t s) { ngx_tm_t tm; + if (ngx_cached_time == s) { + return; + } + + ngx_cached_time = s; + ngx_gmtime(ngx_cached_time, &ngx_cached_gmtime); ngx_cached_http_time.len = ngx_snprintf(ngx_cached_http_time.data, diff --git a/src/core/ngx_times.h b/src/core/ngx_times.h --- a/src/core/ngx_times.h +++ b/src/core/ngx_times.h @@ -7,7 +7,7 @@ void ngx_time_init(); -void ngx_time_update(); +void ngx_time_update(time_t s); size_t ngx_http_time(char *buf, time_t t); void ngx_gmtime(time_t t, ngx_tm_t *tp); diff --git a/src/event/modules/ngx_kqueue_module.c b/src/event/modules/ngx_kqueue_module.c --- a/src/event/modules/ngx_kqueue_module.c +++ b/src/event/modules/ngx_kqueue_module.c @@ -92,9 +92,6 @@ static int ngx_kqueue_init(ngx_cycle_t * kcf = ngx_event_get_conf(cycle->conf_ctx, ngx_kqueue_module); -ngx_log_debug(cycle->log, "CH: %d" _ kcf->changes); -ngx_log_debug(cycle->log, "EV: %d" _ kcf->events); - if (ngx_kqueue == -1) { ngx_kqueue = kqueue(); @@ -196,6 +193,7 @@ static int ngx_kqueue_add_event(ngx_even ngx_connection_t *c; ev->active = 1; + ev->disabled = 0; ev->oneshot = (flags & NGX_ONESHOT_EVENT) ? 1 : 0; if (nchanges > 0 @@ -205,16 +203,14 @@ static int ngx_kqueue_add_event(ngx_even { if (change_list[ev->index].flags == EV_DISABLE) { -#if (NGX_DEBUG_EVENT) - ngx_connection_t *c = (ngx_connection_t *) ev->data; - ngx_log_debug(ev->log, "kqueue event activated: %d: ft:%d" _ - c->fd _ event); -#endif + /* + * if the EV_DISABLE is still not passed to a kernel + * we will not pass it + */ - /* - * if the EV_DISABLE is still not passed to a kernel - * we will not pass it - */ + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, + "kevent activated: %d: ft:%d", + ngx_event_ident(ev->data), event); if (ev->index < (u_int) --nchanges) { e = (ngx_event_t *) change_list[nchanges].udata; @@ -241,17 +237,16 @@ static int ngx_kqueue_del_event(ngx_even ngx_event_t *e; ev->active = 0; + ev->disabled = 0; if (nchanges > 0 && ev->index < (u_int) nchanges && ((uintptr_t) change_list[ev->index].udata & (uintptr_t) ~1) == (uintptr_t) ev) { -#if (NGX_DEBUG_EVENT) - ngx_connection_t *c = (ngx_connection_t *) ev->data; - ngx_log_debug(ev->log, "kqueue event deleted: %d: ft:%d" _ - c->fd _ event); -#endif + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, + "kevent deleted: %d: ft:%d", + ngx_event_ident(ev->data), event); /* if the event is still not passed to a kernel we will not pass it */ @@ -274,6 +269,10 @@ static int ngx_kqueue_del_event(ngx_even return NGX_OK; } + if (flags & NGX_DISABLE_EVENT) { + ev->disabled = 1; + } + return ngx_kqueue_set_event(ev, event, flags & NGX_DISABLE_EVENT ? EV_DISABLE : EV_DELETE); } @@ -346,7 +345,7 @@ static int ngx_kqueue_set_event(ngx_even static int ngx_kqueue_process_events(ngx_log_t *log) { - int events, instance, i; + ngx_int_t events, instance, i; ngx_err_t err; ngx_msec_t timer; ngx_event_t *ev; @@ -391,10 +390,7 @@ static int ngx_kqueue_process_events(ngx #endif ngx_elapsed_msec = tv.tv_sec * 1000 + tv.tv_usec / 1000 - ngx_start_msec; - if (ngx_cached_time != tv.tv_sec) { - ngx_cached_time = tv.tv_sec; - ngx_time_update(); - } + ngx_time_update(tv.tv_sec); if (timer) { delta = ngx_elapsed_msec - delta; @@ -407,12 +403,12 @@ static int ngx_kqueue_process_events(ngx } } -#if (NGX_DEBUG_EVENT) - ngx_log_debug(log, "kevent timer: %d, delta: %d" _ timer _ (int) delta); -#endif + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, log, 0, + "kevent timer: %d, delta: %d", timer, (int) delta); if (err) { - ngx_log_error(NGX_LOG_ALERT, log, err, "kevent() failed"); + ngx_log_error((err == NGX_EINTR) ? NGX_LOG_INFO : NGX_LOG_ALERT, + log, err, "kevent() failed"); return NGX_ERROR; } diff --git a/src/event/modules/ngx_poll_module.c b/src/event/modules/ngx_poll_module.c --- a/src/event/modules/ngx_poll_module.c +++ b/src/event/modules/ngx_poll_module.c @@ -262,11 +262,7 @@ static int ngx_poll_process_events(ngx_l ngx_log_debug(log, "poll ready %d" _ ready); ngx_gettimeofday(&tv); - - if (ngx_cached_time != tv.tv_sec) { - ngx_cached_time = tv.tv_sec; - ngx_time_update(); - } + ngx_time_update(tv.tv_sec); if ((int) timer != INFTIM) { delta = tv.tv_sec * 1000 + tv.tv_usec / 1000 - delta; diff --git a/src/event/modules/ngx_select_module.c b/src/event/modules/ngx_select_module.c --- a/src/event/modules/ngx_select_module.c +++ b/src/event/modules/ngx_select_module.c @@ -370,11 +370,7 @@ static int ngx_select_process_events(ngx #else /* HAVE_SELECT_CHANGE_TIMEOUT */ ngx_gettimeofday(&tv); - - if (ngx_cached_time != tv.tv_sec) { - ngx_cached_time = tv.tv_sec; - ngx_time_update(); - } + ngx_time_update(tv.tv_sec); if (timer) { delta = tv.tv_sec * 1000 + tv.tv_usec / 1000 - delta; diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -222,7 +222,8 @@ static int ngx_event_init(ngx_cycle_t *c */ if (ngx_del_event(&cycle->old_cycle->read_events[fd], - NGX_READ_EVENT, 0) == NGX_ERROR) { + NGX_READ_EVENT, NGX_CLOSE_EVENT) == NGX_ERROR) + { return NGX_ERROR; } diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h --- a/src/event/ngx_event.h +++ b/src/event/ngx_event.h @@ -20,6 +20,14 @@ typedef struct { #endif +typedef enum { + NGX_ERROR_CRIT = 0, + NGX_ERROR_ERR, + NGX_ERROR_INFO, + NGX_ERROR_IGNORE_ECONNRESET +} ngx_event_log_error_e; + + struct ngx_event_s { void *data; /* TODO rename to handler */ @@ -36,8 +44,8 @@ struct ngx_event_s { /* * The inline of "ngx_rbtree_t rbtree;". * - * It allows to pack the rbtree_color and the variuos event bit flags into - * the single "int". We also use "unsigned char" and then "usigned short" + * It allows to pack the rbtree_color and the various event bit flags into + * the single "int". We also use "unsigned char" and then "unsigned short" * because otherwise MSVC 6.0 uses an additional "int" for the bit flags. * We use "char rbtree_color" instead of "unsigned int rbtree_color:1" * because it preserves the bits order on the big endian platforms. @@ -62,14 +70,16 @@ struct ngx_event_s { */ unsigned char active:1; + unsigned char disabled:1; + /* the ready event; in aio mode 0 means that no operation can be posted */ unsigned char ready:1; /* aio operation is complete */ unsigned char complete:1; - unsigned char eof:1; - unsigned char error:1; + unsigned short eof:1; + unsigned short error:1; unsigned short timedout:1; unsigned short timer_set:1; @@ -78,7 +88,7 @@ struct ngx_event_s { unsigned short read_discarded:1; - unsigned short ignore_econnreset:1; + unsigned short log_error:2; /* ngx_event_log_error_e */ unsigned short unexpected_eof:1; unsigned short deferred_accept:1; @@ -371,6 +381,9 @@ int ngx_event_post_acceptex(ngx_listenin #endif +/* used in ngx_log_debugX() */ +#define ngx_event_ident(p) ((ngx_connection_t *) (p))->fd + #include diff --git a/src/event/ngx_event_timer.c b/src/event/ngx_event_timer.c --- a/src/event/ngx_event_timer.c +++ b/src/event/ngx_event_timer.c @@ -16,7 +16,7 @@ ngx_rbtree_t ngx_event_timer_sentinel; int ngx_event_timer_init(ngx_cycle_t *cycle) { - if (cycle->old_cycle) { + if (ngx_event_timer_rbtree) { return NGX_OK; } diff --git a/src/event/ngx_event_timer.h b/src/event/ngx_event_timer.h --- a/src/event/ngx_event_timer.h +++ b/src/event/ngx_event_timer.h @@ -33,9 +33,6 @@ extern ngx_rbtree_t *ngx_event_timer_rb extern ngx_rbtree_t ngx_event_timer_sentinel; -#define ngx_event_ident(p) ((ngx_connection_t *) (p))->fd - - ngx_inline static void ngx_event_del_timer(ngx_event_t *ev) { ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, diff --git a/src/http/modules/ngx_http_rewrite_handler.c b/src/http/modules/ngx_http_rewrite_handler.c --- a/src/http/modules/ngx_http_rewrite_handler.c +++ b/src/http/modules/ngx_http_rewrite_handler.c @@ -113,7 +113,7 @@ static ngx_int_t ngx_http_rewrite_handle if (rc == NGX_DECLINED) { if (scf->log) { ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0, - "\"%s\" is not matched", rule[i].re_name.data); + "\"%s\" does not match", rule[i].re_name.data); } continue; @@ -129,7 +129,7 @@ static ngx_int_t ngx_http_rewrite_handle if (scf->log) { ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0, - "\"%s\" matched", rule[i].re_name.data); + "\"%s\" matches", rule[i].re_name.data); } uri.len = rule[i].size; @@ -301,8 +301,10 @@ static char *ngx_http_rewrite_rule(ngx_c } } - rule->msize++; - rule->msize *= 3; + if (rule->msize) { + rule->msize++; + rule->msize *= 3; + } if (cf->args->nelts > 3) { if (ngx_strcmp(value[3].data, "last") == 0) { diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -148,6 +148,13 @@ static ngx_command_t ngx_http_core_comm offsetof(ngx_http_core_loc_conf_t, sendfile), NULL }, + { ngx_string("tcp_nopush"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_core_loc_conf_t, tcp_nopush), + NULL }, + { ngx_string("send_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, @@ -505,6 +512,11 @@ int ngx_http_find_location_config(ngx_ht r->sendfile = 1; } + if (!clcf->tcp_nopush) { + /* disable TCP_NOPUSH/TCP_CORK use */ + r->connection->tcp_nopush = -1; + } + if (auto_redirect) { if (!(r->headers_out.location = ngx_http_add_header(&r->headers_out, ngx_http_headers_out))) @@ -1128,6 +1140,7 @@ static void *ngx_http_core_create_loc_co lcf->client_body_timeout = NGX_CONF_UNSET; lcf->sendfile = NGX_CONF_UNSET; + lcf->tcp_nopush = NGX_CONF_UNSET; lcf->send_timeout = NGX_CONF_UNSET; lcf->send_lowat = NGX_CONF_UNSET; lcf->discarded_buffer_size = NGX_CONF_UNSET; @@ -1206,6 +1219,7 @@ static char *ngx_http_core_merge_loc_con ngx_conf_merge_msec_value(conf->client_body_timeout, prev->client_body_timeout, 10000); ngx_conf_merge_value(conf->sendfile, prev->sendfile, 0); + ngx_conf_merge_value(conf->tcp_nopush, prev->tcp_nopush, 0); ngx_conf_merge_msec_value(conf->send_timeout, prev->send_timeout, 10000); ngx_conf_merge_size_value(conf->send_lowat, prev->send_lowat, 0); ngx_conf_merge_size_value(conf->discarded_buffer_size, diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -122,6 +122,7 @@ typedef struct { ngx_msec_t client_body_timeout; /* client_body_timeout */ int sendfile; /* sendfile */ + int tcp_nopush; /* tcp_nopush */ ngx_msec_t send_timeout; /* send_timeout */ ssize_t send_lowat; /* send_lowat */ ssize_t discarded_buffer_size; /* discarded_buffer_size */ diff --git a/src/http/ngx_http_log_handler.h b/src/http/ngx_http_log_handler.h --- a/src/http/ngx_http_log_handler.h +++ b/src/http/ngx_http_log_handler.h @@ -15,11 +15,6 @@ typedef char *(*ngx_http_log_op_pt) (ngx #define NGX_HTTP_LOG_ARG (u_int) -1 -/* STUB */ -#define NGX_INT32_LEN sizeof("-2147483648") - 1 -#define NGX_TIME_T_LEN sizeof("-2147483648") - 1 -#define NGX_OFF_T_LEN sizeof("-9223372036854775808") - 1 - typedef struct { size_t len; diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -82,6 +82,7 @@ void ngx_http_init_connection(ngx_connec rev = c->read; rev->event_handler = ngx_http_init_request; + rev->log_error = NGX_ERROR_INFO; if (rev->ready) { /* deferred accept, aio, iocp, epoll */ @@ -896,6 +897,17 @@ void ngx_http_finalize_request(ngx_http_ ngx_del_timer(r->connection->write); } + if (r->connection->read->kq_eof) { +#if (NGX_KQUEUE) + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, + r->connection->read->kq_errno, + "kevent reported about closed connection by client"); +#endif + ngx_http_close_request(r, 0); + ngx_http_close_connection(r->connection); + return; + } + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (r->keepalive != 0 && clcf->keepalive_timeout > 0) { @@ -1203,7 +1215,7 @@ static void ngx_http_set_keepalive(ngx_h ctx->action = "keepalive"; - if (c->tcp_nopush) { + if (c->tcp_nopush == 1) { if (ngx_tcp_push(c->fd) == NGX_ERROR) { ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno, ngx_tcp_push_n " failed"); @@ -1239,10 +1251,10 @@ static void ngx_http_keepalive_handler(n * so we ignore ECONNRESET here. */ - rev->ignore_econnreset = 1; + rev->log_error = NGX_ERROR_IGNORE_ECONNRESET; ngx_set_socket_errno(0); n = ngx_recv(c, c->buffer->last, c->buffer->end - c->buffer->last); - rev->ignore_econnreset = 0; + rev->log_error = NGX_ERROR_INFO; if (n == NGX_AGAIN) { return; @@ -1506,11 +1518,11 @@ void ngx_http_close_connection(ngx_conne ngx_del_conn(c); } else { - if (c->read->active) { + if (c->read->active || c->read->disabled) { ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT); } - if (c->write->active) { + if (c->write->active || c->write->disabled) { ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT); } } diff --git a/src/os/unix/ngx_errno.h b/src/os/unix/ngx_errno.h --- a/src/os/unix/ngx_errno.h +++ b/src/os/unix/ngx_errno.h @@ -20,6 +20,7 @@ typedef int ngx_err_t; #define NGX_EINPROGRESS EINPROGRESS #define NGX_EADDRINUSE EADDRINUSE #define NGX_ECONNRESET ECONNRESET +#define NGX_ENOTCONN ENOTCONN #define NGX_ETIMEDOUT ETIMEDOUT #define NGX_ECANCELED ECANCELED #define NGX_ENOMOREFILES 0 diff --git a/src/os/unix/ngx_freebsd_config.h b/src/os/unix/ngx_freebsd_config.h --- a/src/os/unix/ngx_freebsd_config.h +++ b/src/os/unix/ngx_freebsd_config.h @@ -24,6 +24,7 @@ #include #include #include +#include #include diff --git a/src/os/unix/ngx_freebsd_sendfile_chain.c b/src/os/unix/ngx_freebsd_sendfile_chain.c --- a/src/os/unix/ngx_freebsd_sendfile_chain.c +++ b/src/os/unix/ngx_freebsd_sendfile_chain.c @@ -151,7 +151,7 @@ ngx_chain_t *ngx_freebsd_sendfile_chain( if (file) { - if (ngx_freebsd_use_tcp_nopush && !c->tcp_nopush) { + if (ngx_freebsd_use_tcp_nopush && c->tcp_nopush == 0) { c->tcp_nopush = 1; ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "tcp_nopush"); @@ -191,7 +191,7 @@ ngx_chain_t *ngx_freebsd_sendfile_chain( } else if (err == NGX_EAGAIN) { eagain = 1; - } else if (err == NGX_EPIPE) { + } else if (err == NGX_EPIPE || err == NGX_ENOTCONN) { level = NGX_LOG_INFO; } @@ -202,8 +202,13 @@ ngx_chain_t *ngx_freebsd_sendfile_chain( } else { wev->error = 1; +#if 0 ngx_log_error(level, c->log, err, "sendfile() failed"); +#else + ngx_log_error(level, c->log, err, + "sendfile(#%d) failed", c->fd); +#endif return NGX_CHAIN_ERROR; } } diff --git a/src/os/unix/ngx_linux_sendfile_chain.c b/src/os/unix/ngx_linux_sendfile_chain.c --- a/src/os/unix/ngx_linux_sendfile_chain.c +++ b/src/os/unix/ngx_linux_sendfile_chain.c @@ -6,7 +6,7 @@ /* * On Linux up to 2.4.21 sendfile() (syscall #187) works with 32-bit - * offsets only and the including breaks building if + * offsets only and the including breaks the compiling if * off_t is 64 bit wide. So we use own sendfile() definition where offset * parameter is int32_t and use sendfile() with the file parts below 2G. * @@ -75,14 +75,14 @@ ngx_chain_t *ngx_linux_sendfile_chain(ng /* set TCP_CORK if there is a header before a file */ - if (!c->tcp_nopush + if (!c->tcp_nopush == 0 && header.nelts != 0 && cl && cl->hunk->type & NGX_HUNK_FILE) { c->tcp_nopush = 1; -ngx_log_debug(c->log, "CORK"); + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "tcp_nopush"); if (ngx_tcp_nopush(c->fd) == NGX_ERROR) { ngx_log_error(NGX_LOG_CRIT, c->log, ngx_errno, diff --git a/src/os/unix/ngx_os.h b/src/os/unix/ngx_os.h --- a/src/os/unix/ngx_os.h +++ b/src/os/unix/ngx_os.h @@ -49,9 +49,13 @@ extern int ngx_max_sockets; extern int ngx_inherited_nonblocking; -extern int done; -extern int restart; -extern int rotate; +extern ngx_int_t ngx_master; + +extern ngx_int_t ngx_quit; +extern ngx_int_t ngx_terminate; +extern ngx_int_t ngx_reconfigure; +extern ngx_int_t ngx_reopen; +extern ngx_int_t ngx_change_binary; #ifdef __FreeBSD__ diff --git a/src/os/unix/ngx_posix_init.c b/src/os/unix/ngx_posix_init.c --- a/src/os/unix/ngx_posix_init.c +++ b/src/os/unix/ngx_posix_init.c @@ -8,9 +8,6 @@ int ngx_inherited_nonblocking; void ngx_signal_handler(int signo); -void ngx_exit_signal_handler(int signo); -void ngx_restart_signal_handler(int signo); -void ngx_rotate_signal_handler(int signo); typedef struct { @@ -22,27 +19,37 @@ typedef struct { ngx_signal_t signals[] = { - { ngx_signal_value(NGX_RESTART_SIGNAL), - "SIG" ngx_value(NGX_RESTART_SIGNAL), - "restarting", + { ngx_signal_value(NGX_RECONFIGURE_SIGNAL), + "SIG" ngx_value(NGX_RECONFIGURE_SIGNAL), + ", reconfiguring", ngx_signal_handler }, - { ngx_signal_value(NGX_ROTATE_SIGNAL), - "SIG" ngx_value(NGX_ROTATE_SIGNAL), - "reopen logs", + { ngx_signal_value(NGX_REOPEN_SIGNAL), + "SIG" ngx_value(NGX_REOPEN_SIGNAL), + ", reopen logs", ngx_signal_handler }, { ngx_signal_value(NGX_INTERRUPT_SIGNAL), "SIG" ngx_value(NGX_INTERRUPT_SIGNAL), - "exiting", + ", exiting", + ngx_signal_handler }, + + { ngx_signal_value(NGX_TERMINATE_SIGNAL), + "SIG" ngx_value(NGX_TERMINATE_SIGNAL), + ", exiting", ngx_signal_handler }, { ngx_signal_value(NGX_SHUTDOWN_SIGNAL), "SIG" ngx_value(NGX_SHUTDOWN_SIGNAL), - "shutdowning", + ", shutdowning", ngx_signal_handler }, - { SIGCHLD, "SIGCHLD", NULL, ngx_sigchld_handler }, + { ngx_signal_value(NGX_CHANGEBIN_SIGNAL), + "SIG" ngx_value(NGX_CHANGEBIN_SIGNAL), + ", changing binary", + ngx_signal_handler }, + + { SIGCHLD, "SIGCHLD", "", ngx_signal_handler }, { SIGPIPE, "SIGPIPE, SIG_IGN", NULL, SIG_IGN }, @@ -91,7 +98,8 @@ int ngx_posix_init(ngx_log_t *log) void ngx_signal_handler(int signo) { - ngx_signal_t *sig; + struct timeval tv; + ngx_signal_t *sig; for (sig = signals; sig->signo != 0; sig++) { if (sig->signo == signo) { @@ -99,64 +107,43 @@ void ngx_signal_handler(int signo) } } -#if (HAVE_STRSIGNAL) + ngx_gettimeofday(&tv); + ngx_time_update(tv.tv_sec); ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, - "signal #%d (%s: %s) received, %s", - signo, sig->signame, strsignal(signo), sig->action); -#else - - ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, - "signal #%d (%s) received, %s", + "signal %d (%s) received%s", signo, sig->signame, sig->action); -#endif - switch (signo) { - /* STUB */ - case SIGQUIT: - case SIGABRT: + case SIGCHLD: + ngx_process_get_status(); + break; case ngx_signal_value(NGX_SHUTDOWN_SIGNAL): + ngx_quit = 1; + break; + + case ngx_signal_value(NGX_TERMINATE_SIGNAL): case ngx_signal_value(NGX_INTERRUPT_SIGNAL): - done = 1; + ngx_terminate = 1; break; - case ngx_signal_value(NGX_RESTART_SIGNAL): - restart = 1; + case ngx_signal_value(NGX_RECONFIGURE_SIGNAL): + ngx_reconfigure = 1; break; - case ngx_signal_value(NGX_ROTATE_SIGNAL): - rotate = 1; + case ngx_signal_value(NGX_REOPEN_SIGNAL): + ngx_reopen = 1; + break; + + case ngx_signal_value(NGX_CHANGEBIN_SIGNAL): + ngx_change_binary = 1; break; } } -void ngx_exit_signal_handler(int signo) -{ - char *s; - - s = strsignal(signo); - ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, - "%s signal received, exiting", s); - done = 1; -} - - -void ngx_restart_signal_handler(int signo) -{ - restart = 1; -} - - -void ngx_rotate_signal_handler(int signo) -{ - rotate = 1; -} - - int ngx_posix_post_conf_init(ngx_log_t *log) { ngx_fd_t pp[2]; diff --git a/src/os/unix/ngx_process.c b/src/os/unix/ngx_process.c --- a/src/os/unix/ngx_process.c +++ b/src/os/unix/ngx_process.c @@ -3,73 +3,241 @@ #include -void testone(ngx_log_t *log) -{ - ngx_log_debug(log, "child process"); - ngx_msleep(5000); - exit(0); -} +static void ngx_exec_proc(ngx_cycle_t *cycle, void *data); + +ngx_uint_t ngx_last_process; +ngx_process_t ngx_processes[NGX_MAX_PROCESSES]; -int ngx_spawn_process(ngx_log_t *log) +ngx_int_t ngx_spawn_process(ngx_cycle_t *cycle, + ngx_spawn_proc_pt proc, void *data, + char *name, ngx_int_t respawn) { - pid_t pid; - sigset_t set, oset; + sigset_t set, oset; + ngx_pid_t pid; - sigemptyset(&set); - sigaddset(&set, SIGCHLD); - if (sigprocmask(SIG_BLOCK, &set, &oset) == -1) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "sigprocmask() failed"); + if (respawn < 0) { + sigemptyset(&set); + sigaddset(&set, SIGCHLD); + if (sigprocmask(SIG_BLOCK, &set, &oset) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "sigprocmask() failed while spawning %s", name); + return NGX_ERROR; + } } pid = fork(); + if (pid == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "fork() failed while spawning \"%s\"", name); + } + if (pid == -1 || pid == 0) { if (sigprocmask(SIG_SETMASK, &oset, &set) == -1) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, - "sigprocmask() failed"); + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "sigprocmask() failed while spawning %s", name); + return NGX_ERROR; } } switch (pid) { case -1: - ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "fork() failed"); return NGX_ERROR; case 0: - testone(log); + proc(cycle, data); break; default: break; } -ngx_log_debug(log, "parent process, child: " PID_T_FMT _ pid); + ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0, + "spawn %s: " PID_T_FMT, name, pid); + + if (respawn >= 0) { + ngx_processes[respawn].pid = pid; + ngx_processes[respawn].exited = 0; + return NGX_OK; + } - /* book keeping */ + ngx_processes[ngx_last_process].pid = pid; + ngx_processes[ngx_last_process].proc = proc; + ngx_processes[ngx_last_process].data = data; + ngx_processes[ngx_last_process].name = name; + ngx_processes[ngx_last_process].respawn = + (respawn == NGX_PROCESS_RESPAWN) ? 1 : 0; + ngx_processes[ngx_last_process].detached = + (respawn == NGX_PROCESS_DETACHED) ? 1 : 0; + ngx_processes[ngx_last_process].exited = 0; + ngx_processes[ngx_last_process].exiting = 0; + ngx_last_process++; if (sigprocmask(SIG_SETMASK, &oset, &set) == -1) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "sigprocmask() failed"); + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "sigprocmask() failed while spawning %s", name); + return NGX_ERROR; + } + + return NGX_OK; +} + + +ngx_int_t ngx_exec(ngx_cycle_t *cycle, ngx_exec_ctx_t *ctx) +{ + if (ngx_spawn_process(cycle, ngx_exec_proc, ctx, ctx->name, + NGX_PROCESS_DETACHED) == NGX_ERROR) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "can not spawn %s", ctx->name); + return NGX_ERROR; } return NGX_OK; } +static void ngx_exec_proc(ngx_cycle_t *cycle, void *data) +{ + ngx_exec_ctx_t *ctx = data; + + if (execve(ctx->path, ctx->argv, ctx->envp) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "execve() failed while executing %s \"%s\"", + ctx->name, ctx->path); + } + + exit(1); +} + + +void ngx_signal_processes(ngx_cycle_t *cycle, ngx_int_t signal) +{ + sigset_t set, oset; + ngx_uint_t i; + + sigemptyset(&set); + sigaddset(&set, SIGCHLD); + if (sigprocmask(SIG_BLOCK, &set, &oset) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "sigprocmask() failed while signaling processes"); + return; + } + + for (i = 0; i < ngx_last_process; i++) { + + if (ngx_processes[i].detached) { + continue; + } + + if (ngx_processes[i].exited) { + if (i != --ngx_last_process) { + ngx_processes[i--] = ngx_processes[ngx_last_process]; + } + continue; + } + + ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0, + "kill (" PID_T_FMT ", %d)" , + ngx_processes[i].pid, signal); + + if (kill(ngx_processes[i].pid, signal) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "kill(%d, %d) failed", ngx_processes[i].pid, signal); + continue; + } + + if (signal != ngx_signal_value(NGX_REOPEN_SIGNAL)) { + ngx_processes[i].exiting = 1; + } + } + + if (sigprocmask(SIG_SETMASK, &oset, &set) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "sigprocmask() failed while signaling processes"); + } +} + + +void ngx_respawn_processes(ngx_cycle_t *cycle) +{ + sigset_t set, oset; + ngx_uint_t i; + + sigemptyset(&set); + sigaddset(&set, SIGCHLD); + if (sigprocmask(SIG_BLOCK, &set, &oset) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "sigprocmask() failed while respawning processes"); + return; + } + + /* + * to avoid a race condition we can check and set value of ngx_respawn + * only in signal handler or while SIGCHLD is blocked + */ + + if (ngx_respawn) { + + for (i = 0; i < ngx_last_process; i++) { + if (!ngx_processes[i].exited) { + continue; + } + + if (!ngx_processes[i].respawn) { + if (i != --ngx_last_process) { + ngx_processes[i--] = ngx_processes[ngx_last_process]; + } + continue; + } + + if (ngx_spawn_process(cycle, + ngx_processes[i].proc, ngx_processes[i].data, + ngx_processes[i].name, i) == NGX_ERROR) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "can not respawn %s", ngx_processes[i].name); + } + } + + ngx_respawn = 0; + } + + if (sigprocmask(SIG_SETMASK, &oset, &set) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "sigprocmask() failed while respawning processes"); + } +} + + +#if 0 void ngx_sigchld_handler(int signo) { - int status, one; - pid_t pid; - ngx_err_t err; - struct timeval tv; + int status; + char *process; + ngx_pid_t pid; + ngx_err_t err; + ngx_uint_t i, one; + struct timeval tv; ngx_gettimeofday(&tv); + ngx_time_update(tv.tv_sec); - if (ngx_cached_time != tv.tv_sec) { - ngx_cached_time = tv.tv_sec; - ngx_time_update(); - } + ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, + "signal #%d (SIGCHLD) received", signo); +} +#endif + +void ngx_process_get_status() +{ + int status; + char *process; + ngx_pid_t pid; + ngx_err_t err; + ngx_uint_t i, one; + struct timeval tv; one = 0; for ( ;; ) { @@ -96,18 +264,39 @@ void ngx_sigchld_handler(int signo) } one = 1; + process = ""; - ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, - "process " PID_T_FMT " exited with code %d", pid, status); + for (i = 0; i < ngx_last_process; i++) { + if (ngx_processes[i].pid == pid) { + ngx_processes[i].status = status; - /* TODO: restart handler */ + if (!ngx_processes[i].exiting) { + ngx_processes[i].exited = 1; + + if (ngx_processes[i].respawn) { + ngx_respawn = 1; + } + } -#if 0 - ngx_msleep(2000); -#endif + process = ngx_processes[i].name; + break; + } + } + + if (i == ngx_last_process) { + process = "unknown process"; + } -#if 0 - ngx_spawn_process(ngx_cycle->log); -#endif + if (WTERMSIG(status)) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "%s " PID_T_FMT " exited on signal %d%s", + process, pid, WTERMSIG(status), + WCOREDUMP(status) ? " (core dumped)" : ""); + + } else { + ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, + "%s " PID_T_FMT " exited with code %d", + process, pid, WEXITSTATUS(status)); + } } } diff --git a/src/os/unix/ngx_process.h b/src/os/unix/ngx_process.h --- a/src/os/unix/ngx_process.h +++ b/src/os/unix/ngx_process.h @@ -4,11 +4,51 @@ typedef pid_t ngx_pid_t; -#define ngx_getpid getpid +typedef void (*ngx_spawn_proc_pt) (ngx_cycle_t *cycle, void *data); + +typedef struct { + ngx_pid_t pid; + int status; + + ngx_spawn_proc_pt proc; + void *data; + char *name; + + unsigned respawn:1; + unsigned detached:1; + unsigned exited:1; + unsigned exiting:1; +} ngx_process_t; -int ngx_spawn_process(ngx_log_t *log); -void ngx_sigchld_handler(int signo); +typedef struct { + char *path; + char *name; + char *const *argv; + char *const *envp; +} ngx_exec_ctx_t; + + +#define ngx_getpid getpid + +#define NGX_MAX_PROCESSES 1024 + +#define NGX_PROCESS_RESPAWN -1 +#define NGX_PROCESS_NORESPAWN -2 +#define NGX_PROCESS_DETACHED -3 + + +ngx_int_t ngx_spawn_process(ngx_cycle_t *cycle, + ngx_spawn_proc_pt proc, void *data, + char *name, ngx_int_t respawn); +ngx_int_t ngx_exec(ngx_cycle_t *cycle, ngx_exec_ctx_t *ctx); +void ngx_signal_processes(ngx_cycle_t *cycle, ngx_int_t signal); +void ngx_respawn_processes(ngx_cycle_t *cycle); +void ngx_process_get_status(void); + +extern ngx_int_t ngx_respawn; +extern ngx_uint_t ngx_last_process; +extern ngx_process_t ngx_processes[NGX_MAX_PROCESSES]; #endif /* _NGX_PROCESS_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_recv.c b/src/os/unix/ngx_recv.c --- a/src/os/unix/ngx_recv.c +++ b/src/os/unix/ngx_recv.c @@ -17,8 +17,9 @@ ssize_t ngx_unix_recv(ngx_connection_t * rev = c->read; if (ngx_event_flags & NGX_HAVE_KQUEUE_EVENT) { - ngx_log_debug(c->log, "recv: eof:%d, avail:%d, err:%d" _ - rev->kq_eof _ rev->available _ rev->kq_errno); + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "recv: eof:%d, avail:%d, err:%d", + rev->kq_eof, rev->available, rev->kq_errno); if (rev->available == 0) { if (rev->kq_eof) { @@ -28,7 +29,16 @@ ssize_t ngx_unix_recv(ngx_connection_t * if (rev->kq_errno) { rev->error = 1; ngx_set_socket_errno(rev->kq_errno); - return ngx_unix_recv_error(rev, rev->kq_errno); + ngx_log_error(NGX_LOG_INFO, c->log, rev->kq_errno, + "kevent() reported about closed connection"); + + if (rev->kq_errno == NGX_ECONNRESET + && rev->log_error == NGX_ERROR_IGNORE_ECONNRESET) + { + return 0; + } + + return NGX_ERROR; } return 0; @@ -42,7 +52,7 @@ ssize_t ngx_unix_recv(ngx_connection_t * do { n = recv(c->fd, buf, size, 0); - ngx_log_debug(c->log, "recv: %d:%d" _ n _ size); + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,"recv: %d:%d", n, size); if (n >= 0) { if (ngx_event_flags & NGX_HAVE_KQUEUE_EVENT) { @@ -104,7 +114,7 @@ ssize_t ngx_unix_recv(ngx_connection_t * do { n = recv(c->fd, buf, size, 0); - ngx_log_debug(c->log, "recv: %d:%d" _ n _ size); + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,"recv: %d:%d", n, size); if (n >= 0) { if ((size_t) n < size) { @@ -138,21 +148,33 @@ ssize_t ngx_unix_recv(ngx_connection_t * static int ngx_unix_recv_error(ngx_event_t *rev, ngx_err_t err) { - if (err == NGX_ECONNRESET && rev->ignore_econnreset) { - return 0; - } + ngx_int_t level; - if (err == NGX_EAGAIN) { - ngx_log_error(NGX_LOG_INFO, rev->log, err, "recv() returned EAGAIN"); + if (err == NGX_EAGAIN || err == NGX_EINTR) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, rev->log, err, "recv() not ready"); return NGX_AGAIN; } - if (err == NGX_EINTR) { - ngx_log_error(NGX_LOG_INFO, rev->log, err, "recv() returned EINTR"); - return NGX_EINTR; + if (err == NGX_ECONNRESET) { + + switch (rev->log_error) { + case NGX_ERROR_IGNORE_ECONNRESET: + return 0; + case NGX_ERROR_INFO: + level = NGX_LOG_INFO; + break; + case NGX_ERROR_ERR: + level = NGX_LOG_ERR; + break; + default: + level = NGX_LOG_CRIT; + } + + } else { + level = NGX_LOG_CRIT; } - ngx_log_error(NGX_LOG_ERR, rev->log, err, "recv() failed"); + ngx_log_error(level, rev->log, err, "recv() failed"); return NGX_ERROR; } diff --git a/src/os/win32/ngx_os.h b/src/os/win32/ngx_os.h --- a/src/os/win32/ngx_os.h +++ b/src/os/win32/ngx_os.h @@ -46,8 +46,8 @@ extern int ngx_inherited_nonblo extern int ngx_win32_version; -extern int restart; -extern int rotate; +extern int reconfigure; +extern int reopen;