--- lighttpd-1.4.23/src/mod_fastcgi.c 2009-06-19 12:22:36.000000000 -0500 +++ mod_fastcgi.c 2009-10-14 16:25:27.000000000 -0500 @@ -1,13 +1,3 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include "buffer.h" #include "server.h" #include "keyvalue.h" @@ -25,15 +15,26 @@ #include "stat_cache.h" #include "status_counter.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + #ifdef HAVE_FASTCGI_FASTCGI_H -#include +# include #else -#ifdef HAVE_FASTCGI_H -#include -#else -#include "fastcgi.h" -#endif +# ifdef HAVE_FASTCGI_H +# include +# else +# include "fastcgi.h" +# endif #endif /* HAVE_FASTCGI_FASTCGI_H */ + #include #ifdef HAVE_SYS_FILIO_H @@ -122,23 +123,10 @@ * */ - unsigned short min_procs; unsigned short max_procs; size_t num_procs; /* how many procs are started */ size_t active_procs; /* how many of them are really running */ - unsigned short max_load_per_proc; - - /* - * kick the process from the list if it was not - * used for idle_timeout until min_procs is - * reached. this helps to get the processlist - * small again we had a small peak load. - * - */ - - unsigned short idle_timeout; - /* * time after a disabled remote connection is tried to be re-enabled * @@ -384,6 +372,21 @@ /* ok, we need a prototype */ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents); +static void reset_signals(void) { +#ifdef SIGTTOU + signal(SIGTTOU, SIG_DFL); +#endif +#ifdef SIGTTIN + signal(SIGTTIN, SIG_DFL); +#endif +#ifdef SIGTSTP + signal(SIGTSTP, SIG_DFL); +#endif + signal(SIGHUP, SIG_DFL); + signal(SIGPIPE, SIG_DFL); + signal(SIGUSR1, SIG_DFL); +} + static void fastcgi_status_copy_procname(buffer *b, fcgi_extension_host *host, fcgi_proc *proc) { buffer_copy_string_len(b, CONST_STR_LEN("fastcgi.backend.")); buffer_append_string_buffer(b, host->id); @@ -993,8 +996,6 @@ close(fcgi_fd); } - openDevNull(STDERR_FILENO); - /* we don't need the client socket */ for (i = 3; i < 256; i++) { close(i); @@ -1054,6 +1055,7 @@ *c = '/'; } + reset_signals(); /* exec the cgi */ execve(arg.ptr[0], arg.ptr, env.ptr); @@ -1235,20 +1237,17 @@ { "check-local", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 5 */ { "port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 6 */ - { "min-procs-not-working", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 7 this is broken for now */ - { "max-procs", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 8 */ - { "max-load-per-proc", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 9 */ - { "idle-timeout", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 10 */ - { "disable-time", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 11 */ - - { "bin-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 12 */ - { "bin-copy-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 13 */ - - { "broken-scriptfilename", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 14 */ - { "allow-x-send-file", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 15 */ - { "strip-request-uri", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 16 */ - { "kill-signal", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 17 */ - { "fix-root-scriptname", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 18 */ + { "max-procs", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 7 */ + { "disable-time", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 8 */ + + { "bin-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 9 */ + { "bin-copy-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 10 */ + + { "broken-scriptfilename", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 11 */ + { "allow-x-send-file", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 12 */ + { "strip-request-uri", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 13 */ + { "kill-signal", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 14 */ + { "fix-root-scriptname", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 15 */ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; @@ -1267,12 +1266,9 @@ buffer_copy_string_buffer(host->id, da_host->key); host->check_local = 1; - host->min_procs = 4; host->max_procs = 4; - host->max_load_per_proc = 1; - host->idle_timeout = 60; host->mode = FCGI_RESPONDER; - host->disable_time = 60; + host->disable_time = 1; host->break_scriptfilename_for_php = 0; host->allow_xsendfile = 0; /* handle X-LIGHTTPD-send-file */ host->kill_signal = SIGTERM; @@ -1286,19 +1282,16 @@ fcv[5].destination = &(host->check_local); fcv[6].destination = &(host->port); - fcv[7].destination = &(host->min_procs); - fcv[8].destination = &(host->max_procs); - fcv[9].destination = &(host->max_load_per_proc); - fcv[10].destination = &(host->idle_timeout); - fcv[11].destination = &(host->disable_time); - - fcv[12].destination = host->bin_env; - fcv[13].destination = host->bin_env_copy; - fcv[14].destination = &(host->break_scriptfilename_for_php); - fcv[15].destination = &(host->allow_xsendfile); - fcv[16].destination = host->strip_request_uri; - fcv[17].destination = &(host->kill_signal); - fcv[18].destination = &(host->fix_root_path_name); + fcv[7].destination = &(host->max_procs); + fcv[8].destination = &(host->disable_time); + + fcv[9].destination = host->bin_env; + fcv[10].destination = host->bin_env_copy; + fcv[11].destination = &(host->break_scriptfilename_for_php); + fcv[12].destination = &(host->allow_xsendfile); + fcv[13].destination = host->strip_request_uri; + fcv[14].destination = &(host->kill_signal); + fcv[15].destination = &(host->fix_root_path_name); if (0 != config_insert_values_internal(srv, da_host->value, fcv)) { return HANDLER_ERROR; @@ -1355,23 +1348,16 @@ /* a local socket + self spawning */ size_t pno; - /* HACK: just to make sure the adaptive spawing is disabled */ - host->min_procs = host->max_procs; - - if (host->min_procs > host->max_procs) host->max_procs = host->min_procs; - if (host->max_load_per_proc < 1) host->max_load_per_proc = 0; - if (s->debug) { - log_error_write(srv, __FILE__, __LINE__, "ssbsdsbsdsd", + log_error_write(srv, __FILE__, __LINE__, "ssbsdsbsd", "--- fastcgi spawning local", "\n\tproc:", host->bin_path, "\n\tport:", host->port, "\n\tsocket", host->unixsocket, - "\n\tmin-procs:", host->min_procs, "\n\tmax-procs:", host->max_procs); } - for (pno = 0; pno < host->min_procs; pno++) { + for (pno = 0; pno < host->max_procs; pno++) { fcgi_proc *proc; proc = fastcgi_process_init(); @@ -1391,7 +1377,7 @@ "--- fastcgi spawning", "\n\tport:", host->port, "\n\tsocket", host->unixsocket, - "\n\tcurrent:", pno, "/", host->min_procs); + "\n\tcurrent:", pno, "/", host->max_procs); } if (fcgi_spawn_connection(srv, p, host, proc)) { @@ -1426,7 +1412,6 @@ host->first = proc; - host->min_procs = 1; host->max_procs = 1; } @@ -2739,7 +2724,7 @@ log_error_write(srv, __FILE__, __LINE__, "ssbsdsd", "--- fastcgi spawning", "\n\tsocket", proc->connection_name, - "\n\tcurrent:", 1, "/", host->min_procs); + "\n\tcurrent:", 1, "/", host->max_procs); } if (fcgi_spawn_connection(srv, p, host, proc)) { @@ -2778,18 +2763,12 @@ * - tcp socket (do not check host->host->uses, as it may be not set which means INADDR_LOOPBACK) * - unix socket */ - if (!host || - (!host->port && !host->unixsocket->used)) { - log_error_write(srv, __FILE__, __LINE__, "sxddd", - "write-req: error", - host, - host->host->used, - host->port, - host->unixsocket->used); - - hctx->proc->disabled_until = srv->cur_ts + 10; - hctx->proc->state = PROC_STATE_DIED; - + if (!host) { + log_error_write(srv, __FILE__, __LINE__, "s", "fatal error: host = NULL"); + return HANDLER_ERROR; + } + if ((!host->port && !host->unixsocket->used)) { + log_error_write(srv, __FILE__, __LINE__, "s", "fatal error: neither host->port nor host->unixsocket is set"); return HANDLER_ERROR; } @@ -2803,8 +2782,10 @@ log_error_write(srv, __FILE__, __LINE__, "ss", "getsockopt failed:", strerror(errno)); - hctx->proc->disabled_until = srv->cur_ts + 10; - hctx->proc->state = PROC_STATE_DIED; + if (hctx->host->disable_time) { + hctx->proc->disabled_until = srv->cur_ts + hctx->host->disable_time; + hctx->proc->state = PROC_STATE_DIED; + } return HANDLER_ERROR; } @@ -2817,16 +2798,11 @@ "socket:", hctx->proc->connection_name); } - hctx->proc->disabled_until = srv->cur_ts + 5; - - if (hctx->proc->is_local) { - hctx->proc->state = PROC_STATE_DIED_WAIT_FOR_PID; - } else { + if (hctx->host->disable_time) { + hctx->proc->disabled_until = srv->cur_ts + hctx->host->disable_time; hctx->proc->state = PROC_STATE_DIED; } - hctx->proc->state = PROC_STATE_DIED; - fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc); buffer_append_string_len(p->statuskey, CONST_STR_LEN(".died")); @@ -2910,14 +2886,15 @@ /* cool down the backend, it is overloaded * -> EAGAIN */ - log_error_write(srv, __FILE__, __LINE__, "ssdsd", - "backend is overloaded; we'll disable it for 2 seconds and send the request to another backend instead:", - "reconnects:", hctx->reconnects, - "load:", host->load); - + if (hctx->host->disable_time) { + log_error_write(srv, __FILE__, __LINE__, "sdssdsd", + "backend is overloaded; we'll disable it for", hctx->host->disable_time, "seconds and send the request to another backend instead:", + "reconnects:", hctx->reconnects, + "load:", host->load); - hctx->proc->disabled_until = srv->cur_ts + 2; - hctx->proc->state = PROC_STATE_OVERLOADED; + hctx->proc->disabled_until = srv->cur_ts + hctx->host->disable_time; + hctx->proc->state = PROC_STATE_OVERLOADED; + } fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc); buffer_append_string_len(p->statuskey, CONST_STR_LEN(".overloaded")); @@ -2930,20 +2907,22 @@ * - ECONNREFUSED for tcp-ip sockets * - ENOENT for unix-domain-sockets * - * for check if the host is back in 5 seconds + * for check if the host is back in hctx->host->disable_time seconds * */ - hctx->proc->disabled_until = srv->cur_ts + 5; - if (hctx->proc->is_local) { - hctx->proc->state = PROC_STATE_DIED_WAIT_FOR_PID; - } else { - hctx->proc->state = PROC_STATE_DIED; - } + if (hctx->host->disable_time) { + hctx->proc->disabled_until = srv->cur_ts + hctx->host->disable_time; + if (hctx->proc->is_local) { + hctx->proc->state = PROC_STATE_DIED_WAIT_FOR_PID; + } else { + hctx->proc->state = PROC_STATE_DIED; + } - log_error_write(srv, __FILE__, __LINE__, "ssdsd", - "backend died; we'll disable it for 5 seconds and send the request to another backend instead:", - "reconnects:", hctx->reconnects, - "load:", host->load); + log_error_write(srv, __FILE__, __LINE__, "sdssdsd", + "backend died; we'll disable it for", hctx->host->disable_time, "seconds and send the request to another backend instead:", + "reconnects:", hctx->reconnects, + "load:", host->load); + } fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc); buffer_append_string_len(p->statuskey, CONST_STR_LEN(".died")); @@ -3032,11 +3011,6 @@ "reconnect attempts:", hctx->reconnects); return HANDLER_ERROR; - case EAGAIN: - case EINTR: - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT); - - return HANDLER_WAIT_FOR_EVENT; default: log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed:", strerror(errno), errno); @@ -3266,7 +3240,7 @@ log_error_write(srv, __FILE__, __LINE__, "ssbsdsd", "--- fastcgi spawning", "\n\tsocket", proc->connection_name, - "\n\tcurrent:", 1, "/", host->min_procs); + "\n\tcurrent:", 1, "/", host->max_procs); } if (fcgi_spawn_connection(srv, p, host, proc)) { @@ -3288,18 +3262,18 @@ hctx->reconnects < 5) { fcgi_reconnect(srv, hctx); - log_error_write(srv, __FILE__, __LINE__, "ssbsbs", + log_error_write(srv, __FILE__, __LINE__, "ssbsBSBs", "response not received, request not sent", "on socket:", proc->connection_name, - "for", con->uri.path, ", reconnecting"); + "for", con->uri.path, "?", con->uri.query, ", reconnecting"); return HANDLER_WAIT_FOR_FD; } - log_error_write(srv, __FILE__, __LINE__, "sosbsbs", + log_error_write(srv, __FILE__, __LINE__, "sosbsBSBs", "response not received, request sent:", hctx->wb->bytes_out, "on socket:", proc->connection_name, - "for", con->uri.path, ", closing connection"); + "for", con->uri.path, "?", con->uri.query, ", closing connection"); fcgi_connection_close(srv, hctx); @@ -3311,10 +3285,10 @@ /* response might have been already started, kill the connection */ fcgi_connection_close(srv, hctx); - log_error_write(srv, __FILE__, __LINE__, "ssbsbs", + log_error_write(srv, __FILE__, __LINE__, "ssbsBSBs", "response already sent out, but backend returned error", "on socket:", proc->connection_name, - "for", con->uri.path, ", terminating connection"); + "for", con->uri.path, "?", con->uri.query, ", terminating connection"); connection_set_state(srv, con, CON_STATE_ERROR); } @@ -3364,9 +3338,9 @@ * even if the FCGI_FIN packet is not received yet */ } else { - log_error_write(srv, __FILE__, __LINE__, "sbsbsd", + log_error_write(srv, __FILE__, __LINE__, "sBSbsbsd", "error: unexpected close of fastcgi connection for", - con->uri.path, + con->uri.path, "?", con->uri.query, "(no fastcgi process on socket:", proc->connection_name, "?)", hctx->state); @@ -3489,25 +3463,27 @@ /* check if extension matches */ for (k = 0; k < p->conf.exts->used; k++) { size_t ct_len; /* length of the config entry */ + fcgi_extension *ext = p->conf.exts->exts[k]; - extension = p->conf.exts->exts[k]; + if (ext->key->used == 0) continue; - if (extension->key->used == 0) continue; - - ct_len = extension->key->used - 1; + ct_len = ext->key->used - 1; /* check _url_ in the form "/fcgi_pattern" */ - if (extension->key->ptr[0] == '/') { + if (ext->key->ptr[0] == '/') { if ((ct_len <= con->uri.path->used -1) && - (strncmp(con->uri.path->ptr, extension->key->ptr, ct_len) == 0)) + (strncmp(con->uri.path->ptr, ext->key->ptr, ct_len) == 0)) { + extension = ext; break; - } else if ((ct_len <= s_len) && (0 == strncmp(fn->ptr + s_len - ct_len, extension->key->ptr, ct_len))) { + } + } else if ((ct_len <= s_len) && (0 == strncmp(fn->ptr + s_len - ct_len, ext->key->ptr, ct_len))) { /* check extension in the form ".fcg" */ + extension = ext; break; } } /* extension doesn't match */ - if (k == p->conf.exts->used) { + if (NULL == extension) { return HANDLER_GO_ON; } } @@ -3535,8 +3511,8 @@ if (!extension->note_is_sent) { extension->note_is_sent = 1; - log_error_write(srv, __FILE__, __LINE__, "sbsbs", - "all handlers for ", con->uri.path, + log_error_write(srv, __FILE__, __LINE__, "sBSbsbs", + "all handlers for", con->uri.path, "?", con->uri.query, "on", extension->key, "are down."); } @@ -3727,107 +3703,12 @@ for (n = 0; n < ex->used; n++) { fcgi_proc *proc; - unsigned long sum_load = 0; fcgi_extension_host *host; host = ex->hosts[n]; fcgi_restart_dead_procs(srv, p, host); - for (proc = host->first; proc; proc = proc->next) { - sum_load += proc->load; - } - - if (host->num_procs && - host->num_procs < host->max_procs && - (sum_load / host->num_procs) > host->max_load_per_proc) { - /* overload, spawn new child */ - if (p->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "s", - "overload detected, spawning a new child"); - } - - for (proc = host->unused_procs; proc && proc->pid != 0; proc = proc->next); - - if (proc) { - if (proc == host->unused_procs) host->unused_procs = proc->next; - - if (proc->next) proc->next->prev = NULL; - - host->max_id++; - } else { - proc = fastcgi_process_init(); - proc->id = host->max_id++; - } - - host->num_procs++; - - if (buffer_is_empty(host->unixsocket)) { - proc->port = host->port + proc->id; - } else { - buffer_copy_string_buffer(proc->unixsocket, host->unixsocket); - buffer_append_string_len(proc->unixsocket, CONST_STR_LEN("-")); - buffer_append_long(proc->unixsocket, proc->id); - } - - if (fcgi_spawn_connection(srv, p, host, proc)) { - log_error_write(srv, __FILE__, __LINE__, "s", - "ERROR: spawning fcgi failed."); - return HANDLER_ERROR; - } - - proc->prev = NULL; - proc->next = host->first; - if (host->first) { - host->first->prev = proc; - } - host->first = proc; - } - - for (proc = host->first; proc; proc = proc->next) { - if (proc->load != 0) break; - if (host->num_procs <= host->min_procs) break; - if (proc->pid == 0) continue; - - if (srv->cur_ts - proc->last_used > host->idle_timeout) { - /* a proc is idling for a long time now, - * terminate it */ - - if (p->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "ssbsd", - "idle-timeout reached; terminating child:", - "socket:", proc->connection_name, - "pid", proc->pid); - } - - - if (proc->next) proc->next->prev = proc->prev; - if (proc->prev) proc->prev->next = proc->next; - - if (proc->prev == NULL) host->first = proc->next; - - proc->prev = NULL; - proc->next = host->unused_procs; - - if (host->unused_procs) host->unused_procs->prev = proc; - host->unused_procs = proc; - - kill(proc->pid, SIGTERM); - - proc->state = PROC_STATE_KILLED; - - log_error_write(srv, __FILE__, __LINE__, "ssbsd", - "killed:", - "socket:", proc->connection_name, - "pid", proc->pid); - - host->num_procs--; - - /* proc is now in unused, let the next second handle the next process */ - break; - } - } - for (proc = host->unused_procs; proc; proc = proc->next) { int status;