Mercurial > hg > nginx
view src/event/modules/ngx_rtsig_module.c @ 485:4ebe09b07e30 release-0.1.17
nginx-0.1.17-RELEASE import
*) Change: the ngx_http_rewrite_module was rewritten from the scratch.
Now it is possible to redirect, to return the error codes, to check
the variables and referrers. The directives can be used inside
locations. The redirect directive was canceled.
*) Feature: the ngx_http_geo_module.
*) Feature: the proxy_set_x_var and fastcgi_set_var directives.
*) Bugfix: the location configuration with "=" modifier may be used in
another location.
*) Bugfix: the correct content type was set only for requests that use
small caps letters in extension.
*) Bugfix: if the proxy_pass or fastcgi_pass directives were set in the
location, and access was denied, and the error was redirected to a
static page, then the segmentation fault occurred.
*) Bugfix: if in a proxied "Location" header was a relative URL, then a
host name and a slash were added to them; the bug had appeared in
0.1.14.
*) Bugfix: the system error message was not logged on Linux.
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Thu, 03 Feb 2005 19:33:37 +0000 |
parents | 2ff194b74f1e |
children | 975f62e77f02 |
line wrap: on
line source
/* * Copyright (C) Igor Sysoev */ #include <ngx_config.h> #include <ngx_core.h> #include <ngx_event.h> #if (NGX_TEST_BUILD_RTSIG) #define F_SETSIG 10 #define SIGRTMIN 33 #define si_fd __spare__[0] #define KERN_RTSIGNR 30 #define KERN_RTSIGMAX 31 int sigtimedwait(const sigset_t *set, siginfo_t *info, const struct timespec *timeout) { return -1; } int ngx_linux_rtsig_max; #endif typedef struct { int signo; ngx_int_t overflow_events; ngx_int_t overflow_test; ngx_int_t overflow_threshold; } ngx_rtsig_conf_t; extern ngx_event_module_t ngx_poll_module_ctx; static ngx_int_t ngx_rtsig_init(ngx_cycle_t *cycle); static void ngx_rtsig_done(ngx_cycle_t *cycle); static ngx_int_t ngx_rtsig_add_connection(ngx_connection_t *c); static ngx_int_t ngx_rtsig_del_connection(ngx_connection_t *c, u_int flags); static ngx_int_t ngx_rtsig_process_events(ngx_cycle_t *cycle); static ngx_int_t ngx_rtsig_process_overflow(ngx_cycle_t *cycle); static void *ngx_rtsig_create_conf(ngx_cycle_t *cycle); static char *ngx_rtsig_init_conf(ngx_cycle_t *cycle, void *conf); static char *ngx_check_ngx_overflow_threshold_bounds(ngx_conf_t *cf, void *post, void *data); static sigset_t set; static ngx_uint_t overflow, overflow_current; static struct pollfd *overflow_list; static ngx_str_t rtsig_name = ngx_string("rtsig"); static ngx_conf_num_bounds_t ngx_overflow_threshold_bounds = { ngx_check_ngx_overflow_threshold_bounds, 2, 10 }; static ngx_command_t ngx_rtsig_commands[] = { {ngx_string("rtsig_signo"), NGX_EVENT_CONF|NGX_CONF_TAKE1, ngx_conf_set_num_slot, 0, offsetof(ngx_rtsig_conf_t, signo), NULL}, {ngx_string("rtsig_overflow_events"), NGX_EVENT_CONF|NGX_CONF_TAKE1, ngx_conf_set_num_slot, 0, offsetof(ngx_rtsig_conf_t, overflow_events), NULL}, {ngx_string("rtsig_overflow_test"), NGX_EVENT_CONF|NGX_CONF_TAKE1, ngx_conf_set_num_slot, 0, offsetof(ngx_rtsig_conf_t, overflow_test), NULL}, {ngx_string("rtsig_overflow_threshold"), NGX_EVENT_CONF|NGX_CONF_TAKE1, ngx_conf_set_num_slot, 0, offsetof(ngx_rtsig_conf_t, overflow_threshold), &ngx_overflow_threshold_bounds}, ngx_null_command }; ngx_event_module_t ngx_rtsig_module_ctx = { &rtsig_name, ngx_rtsig_create_conf, /* create configuration */ ngx_rtsig_init_conf, /* init configuration */ { NULL, /* add an event */ NULL, /* delete an event */ NULL, /* enable an event */ NULL, /* disable an event */ ngx_rtsig_add_connection, /* add an connection */ ngx_rtsig_del_connection, /* delete an connection */ NULL, /* process the changes */ ngx_rtsig_process_events, /* process the events */ ngx_rtsig_init, /* init the events */ ngx_rtsig_done, /* done the events */ } }; ngx_module_t ngx_rtsig_module = { NGX_MODULE, &ngx_rtsig_module_ctx, /* module context */ ngx_rtsig_commands, /* module directives */ NGX_EVENT_MODULE, /* module type */ NULL, /* init module */ NULL /* init process */ }; static ngx_int_t ngx_rtsig_init(ngx_cycle_t *cycle) { ngx_rtsig_conf_t *rtscf; rtscf = ngx_event_get_conf(cycle->conf_ctx, ngx_rtsig_module); sigemptyset(&set); sigaddset(&set, rtscf->signo); sigaddset(&set, rtscf->signo + 1); sigaddset(&set, SIGIO); if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "sigprocmask() failed"); return NGX_ERROR; } if (overflow_list) { ngx_free(overflow_list); } overflow_list = ngx_alloc(sizeof(struct pollfd) * rtscf->overflow_events, cycle->log); if (overflow_list == NULL) { return NGX_ERROR; } ngx_io = ngx_os_io; ngx_event_actions = ngx_rtsig_module_ctx.actions; ngx_event_flags = NGX_USE_RTSIG_EVENT|NGX_USE_GREEDY_EVENT; return NGX_OK; } static void ngx_rtsig_done(ngx_cycle_t *cycle) { ngx_free(overflow_list); overflow_list = NULL; } static ngx_int_t ngx_rtsig_add_connection(ngx_connection_t *c) { int signo; ngx_rtsig_conf_t *rtscf; if (c->read->accept && c->read->disabled) { ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "rtsig enable connection: fd:%d", c->fd); if (fcntl(c->fd, F_SETOWN, ngx_pid) == -1) { ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, "fcntl(F_SETOWN) failed"); return NGX_ERROR; } c->read->active = 1; c->read->disabled = 0; } rtscf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_rtsig_module); signo = rtscf->signo + c->read->instance; ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, "rtsig add connection: fd:%d signo:%d", c->fd, signo); if (fcntl(c->fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC) == -1) { ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, "fcntl(O_RDWR|O_NONBLOCK|O_ASYNC) failed"); return NGX_ERROR; } if (fcntl(c->fd, F_SETSIG, signo) == -1) { ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, "fcntl(F_SETSIG) failed"); return NGX_ERROR; } if (fcntl(c->fd, F_SETOWN, ngx_pid) == -1) { ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, "fcntl(F_SETOWN) failed"); return NGX_ERROR; } #if (NGX_HAVE_ONESIGFD) if (fcntl(c->fd, F_SETAUXFL, O_ONESIGFD) == -1) { ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, "fcntl(F_SETAUXFL) failed"); return NGX_ERROR; } #endif c->read->active = 1; c->write->active = 1; return NGX_OK; } static ngx_int_t ngx_rtsig_del_connection(ngx_connection_t *c, u_int flags) { ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "rtsig del connection: fd:%d", c->fd); if ((flags & NGX_DISABLE_EVENT) && c->read->accept) { ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "rtsig disable connection: fd:%d", c->fd); c->read->active = 0; c->read->disabled = 1; return NGX_OK; } if (flags & NGX_CLOSE_EVENT) { c->read->active = 0; c->write->active = 0; return NGX_OK; } if (fcntl(c->fd, F_SETFL, O_RDWR|O_NONBLOCK) == -1) { ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, "fcntl(O_RDWR|O_NONBLOCK) failed"); return NGX_ERROR; } c->read->active = 0; c->write->active = 0; return NGX_OK; } ngx_int_t ngx_rtsig_process_events(ngx_cycle_t *cycle) { int signo; ngx_int_t instance, i; ngx_uint_t expire; size_t n; ngx_msec_t timer; ngx_err_t err; siginfo_t si; ngx_event_t *rev, *wev; struct timeval tv; struct timespec ts, *tp; struct sigaction sa; ngx_epoch_msec_t delta; ngx_connection_t *c; ngx_rtsig_conf_t *rtscf; if (overflow) { timer = 0; expire = 0; } else { for ( ;; ) { timer = ngx_event_find_timer(); #if (NGX_THREADS) if (timer == NGX_TIMER_ERROR) { return NGX_ERROR; } if (timer == NGX_TIMER_INFINITE || timer > 500) { timer = 500; break; } #endif if (timer != 0) { break; } ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "rtsig expired timer"); ngx_event_expire_timers((ngx_msec_t) (ngx_elapsed_msec - ngx_old_elapsed_msec)); if (ngx_posted_events && ngx_threaded) { ngx_wakeup_worker_thread(cycle); } } expire = 1; if (ngx_accept_mutex) { if (ngx_accept_disabled > 0) { ngx_accept_disabled--; } else { ngx_accept_mutex_held = 0; if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) { return NGX_ERROR; } if (ngx_accept_mutex_held == 0 && (timer == NGX_TIMER_INFINITE || timer > ngx_accept_mutex_delay)) { timer = ngx_accept_mutex_delay; expire = 0; } } } } if (timer == NGX_TIMER_INFINITE) { tp = NULL; expire = 0; } else { ts.tv_sec = timer / 1000; ts.tv_nsec = (timer % 1000) * 1000000; tp = &ts; } ngx_old_elapsed_msec = ngx_elapsed_msec; ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "rtsig timer: %d", timer); /* Linux's sigwaitinfo() is sigtimedwait() with the NULL timeout pointer */ signo = sigtimedwait(&set, &si, tp); if (signo == -1) { err = ngx_errno; ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, err, "rtsig signo:%d", signo); if (err == NGX_EAGAIN) { if (timer == NGX_TIMER_INFINITE) { ngx_accept_mutex_unlock(); ngx_log_error(NGX_LOG_ALERT, cycle->log, err, "sigtimedwait() returned EAGAIN without timeout"); return NGX_ERROR; } err = 0; } } else { err = 0; ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "rtsig signo:%d fd:%d band:%04Xd", signo, si.si_fd, si.si_band); } ngx_gettimeofday(&tv); ngx_time_update(tv.tv_sec); delta = ngx_elapsed_msec; ngx_elapsed_msec = (ngx_epoch_msec_t) tv.tv_sec * 1000 + tv.tv_usec / 1000 - ngx_start_msec; if (err) { ngx_accept_mutex_unlock(); ngx_log_error((err == NGX_EINTR) ? NGX_LOG_INFO : NGX_LOG_ALERT, cycle->log, err, "sigtimedwait() failed"); return NGX_ERROR; } if (timer != NGX_TIMER_INFINITE) { delta = ngx_elapsed_msec - delta; ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "rtsig timer: %d, delta: %d", timer, (int) delta); } rtscf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_rtsig_module); if (signo == rtscf->signo || signo == rtscf->signo + 1) { if (overflow && (ngx_uint_t) si.si_fd > overflow_current) { return NGX_OK; } /* TODO: old_cycles */ c = &ngx_cycle->connections[si.si_fd]; instance = signo - rtscf->signo; rev = c->read; if (c->read->instance != instance) { /* * the stale event from a file descriptor * that was just closed in this iteration */ ngx_accept_mutex_unlock(); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "rtsig: stale event %p", c); return NGX_OK; } if (si.si_band & (POLLIN|POLLHUP|POLLERR)) { if (rev->active) { if (ngx_threaded && !rev->accept) { if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) { ngx_accept_mutex_unlock(); return NGX_ERROR; } rev->posted_ready = 1; ngx_post_event(rev); ngx_mutex_unlock(ngx_posted_events_mutex); } else { rev->ready = 1; if (!ngx_threaded && !ngx_accept_mutex_held) { rev->event_handler(rev); } else if (rev->accept) { if (ngx_accept_disabled <= 0) { rev->event_handler(rev); } } else { ngx_post_event(rev); } } } } wev = c->write; if (si.si_band & (POLLOUT|POLLHUP|POLLERR)) { if (wev->active) { if (ngx_threaded) { if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) { ngx_accept_mutex_unlock(); return NGX_ERROR; } wev->posted_ready = 1; ngx_post_event(wev); ngx_mutex_unlock(ngx_posted_events_mutex); } else { wev->ready = 1; if (!ngx_threaded && !ngx_accept_mutex_held) { wev->event_handler(wev); } else { ngx_post_event(wev); } } } } } else if (signo == SIGIO) { ngx_accept_mutex_unlock(); ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "rt signal queue overflowed"); /* flush the RT signal queue */ ngx_memzero(&sa, sizeof(struct sigaction)); sa.sa_handler = SIG_DFL; sigemptyset(&sa.sa_mask); if (sigaction(rtscf->signo, &sa, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "sigaction(%d, SIG_DFL) failed", rtscf->signo); } if (sigaction(rtscf->signo + 1, &sa, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "sigaction(%d, SIG_DFL) failed", rtscf->signo + 1); } overflow = 1; overflow_current = 0; ngx_event_actions.process_events = ngx_rtsig_process_overflow; return NGX_ERROR; } else if (signo != -1) { ngx_accept_mutex_unlock(); ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "sigtimedwait() returned unexpected signal: %d", signo); return NGX_ERROR; } ngx_accept_mutex_unlock(); if (expire && delta) { ngx_event_expire_timers((ngx_msec_t) delta); } if (ngx_posted_events) { if (ngx_threaded) { ngx_wakeup_worker_thread(cycle); } else { ngx_event_process_posted(cycle); } } if (signo == -1) { return NGX_AGAIN; } else { return NGX_OK; } } /* TODO: old cylces */ static ngx_int_t ngx_rtsig_process_overflow(ngx_cycle_t *cycle) { int name[2], rtsig_max, rtsig_nr, events, ready; size_t len; ngx_int_t tested, n, i; ngx_err_t err; ngx_event_t *rev, *wev; ngx_connection_t *c; ngx_rtsig_conf_t *rtscf; rtscf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_rtsig_module); tested = 0; for ( ;; ) { n = 0; while (n < rtscf->overflow_events) { if (overflow_current == cycle->connection_n) { break; } c = &cycle->connections[overflow_current++]; if (c->fd == -1) { continue; } events = 0; if (c->read->active && c->read->event_handler) { events |= POLLIN; } if (c->write->active && c->write->event_handler) { events |= POLLOUT; } if (events == 0) { continue; } overflow_list[n].fd = c->fd; overflow_list[n].events = events; overflow_list[n].revents = 0; n++; } if (n == 0) { break; } for ( ;; ) { ready = poll(overflow_list, n, 0); if (ready == -1) { err = ngx_errno; ngx_log_error((err == NGX_EINTR) ? NGX_LOG_INFO : NGX_LOG_ALERT, cycle->log, 0, "poll() failed while the overflow recover"); if (err == NGX_EINTR) { continue; } } break; } if (ready <= 0) { continue; } if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) { return NGX_ERROR; } for (i = 0; i < n; i++) { c = &cycle->connections[overflow_list[i].fd]; rev = c->read; if (rev->active && !rev->closed && rev->event_handler && (overflow_list[i].revents & (POLLIN|POLLERR|POLLHUP|POLLNVAL))) { tested++; if (ngx_threaded) { rev->posted_ready = 1; ngx_post_event(rev); } else { rev->ready = 1; rev->event_handler(rev); } } wev = c->write; if (wev->active && !wev->closed && wev->event_handler && (overflow_list[i].revents & (POLLOUT|POLLERR|POLLHUP|POLLNVAL))) { tested++; if (ngx_threaded) { wev->posted_ready = 1; ngx_post_event(wev); } else { wev->ready = 1; wev->event_handler(wev); } } } ngx_mutex_unlock(ngx_posted_events_mutex); if (tested >= rtscf->overflow_test) { if (ngx_linux_rtsig_max) { /* * Check the current rt queue length to prevent * the new overflow. * * Learn the /proc/sys/kernel/rtsig-max value because * it can be changed since the last checking. */ name[0] = CTL_KERN; name[1] = KERN_RTSIGMAX; len = sizeof(rtsig_max); if (sysctl(name, sizeof(name), &rtsig_max, &len, NULL, 0) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, errno, "sysctl(KERN_RTSIGMAX) failed"); return NGX_ERROR; } name[0] = CTL_KERN; name[1] = KERN_RTSIGNR; len = sizeof(rtsig_nr); if (sysctl(name, sizeof(name), &rtsig_nr, &len, NULL, 0) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, errno, "sysctl(KERN_RTSIGNR) failed"); return NGX_ERROR; } /* * drain the rt signal queue if the /proc/sys/kernel/rtsig-nr * is bigger than * /proc/sys/kernel/rtsig-max / rtsig_overflow_threshold */ if (rtsig_max / rtscf->overflow_threshold < rtsig_nr) { ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "rtsig queue state: %d/%d", rtsig_nr, rtsig_max); while (ngx_rtsig_process_events(cycle) == NGX_OK) { /* void */ } } } else { /* * Linux has not KERN_RTSIGMAX since 2.6.6-mm2 * so drain the rt signal queue unconditionally */ while (ngx_rtsig_process_events(cycle) == NGX_OK) { /* void */ } } tested = 0; } } if (ngx_posted_events) { if (ngx_threaded) { ngx_wakeup_worker_thread(cycle); } else { ngx_event_process_posted(cycle); } } ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "rt signal queue overflow recovered"); overflow = 0; ngx_event_actions.process_events = ngx_rtsig_process_events; return NGX_OK; } static void *ngx_rtsig_create_conf(ngx_cycle_t *cycle) { ngx_rtsig_conf_t *rtscf; ngx_test_null(rtscf, ngx_palloc(cycle->pool, sizeof(ngx_rtsig_conf_t)), NGX_CONF_ERROR); rtscf->signo = NGX_CONF_UNSET; rtscf->overflow_events = NGX_CONF_UNSET; rtscf->overflow_test = NGX_CONF_UNSET; rtscf->overflow_threshold = NGX_CONF_UNSET; return rtscf; } static char *ngx_rtsig_init_conf(ngx_cycle_t *cycle, void *conf) { ngx_rtsig_conf_t *rtscf = conf; /* LinuxThreads use the first 3 RT signals */ ngx_conf_init_value(rtscf->signo, SIGRTMIN + 10); ngx_conf_init_value(rtscf->overflow_events, 16); ngx_conf_init_value(rtscf->overflow_test, 32); ngx_conf_init_value(rtscf->overflow_threshold, 10); return NGX_CONF_OK; } static char *ngx_check_ngx_overflow_threshold_bounds(ngx_conf_t *cf, void *post, void *data) { if (ngx_linux_rtsig_max) { return ngx_conf_check_num_bounds(cf, post, data); } ngx_conf_log_error(NGX_LOG_WARN, cf, 0, "\"rtsig_overflow_threshold\" is not supported " "since Linux 2.6.6-mm2, ignored"); return NGX_CONF_OK; }