834f916c452907f534c927bfdf4d0a28600a0e4e galt Sun Jan 13 12:16:54 2013 -0800 calling exit(1) after receiving SIGTERM allows atexit cleanup when apache kills timed-out cgi diff --git src/lib/cheapcgi.c src/lib/cheapcgi.c index d376689..763812f 100644 --- src/lib/cheapcgi.c +++ src/lib/cheapcgi.c @@ -633,65 +633,81 @@ boolean ok = TRUE; int status = setjmp(cgiParseRecover); if (status == 0) /* Always true except after long jump. */ { pushAbortHandler(cgiParseAbort); cgiParseInputAbort(input, retHash, retList); } else /* They long jumped here because of an error. */ { ok = FALSE; } popAbortHandler(); return ok; } - static boolean dumpStackOnSignal = FALSE; // should a stack dump be generated? static void catchSignal(int sigNum) /* handler for various terminal signals for logging purposes */ { char *sig = NULL; switch (sigNum) { + case SIGTERM: // after timing out for not producing any stdout or stderr output for too long, + // apache gives you 3 seconds to clean up and exit or it then sends SIGKILL. + sig = "SIGTERM"; + break; + case SIGHUP: // apache sends this when it is doing a graceful restart or a log rotate. + sig = "SIGHUP"; + break; case SIGABRT: sig = "SIGABRT"; break; case SIGSEGV: sig = "SIGSEGV"; break; case SIGFPE: sig = "SIGFPE"; break; case SIGBUS: sig = "SIGBUS"; break; } logCgiToStderr(); + + // apache closes STDERR on the CGI before it sends the SIGTERM and SIGKILL signals + // which means that stderr output after that point will not be visible in error_log. fprintf(stderr, "Received signal %s\n", sig); if (dumpStackOnSignal) dumpStack("Stack for signal %s\n", sig); + +if (sigNum == SIGTERM || sigNum == SIGHUP) + exit(1); // so that atexit cleanup get called + raise(SIGKILL); } void initSigHandlers(boolean dumpStack) /* set handler for various terminal signals for logging purposes. * if dumpStack is TRUE, attempt to dump the stack. */ { if (cgiIsOnWeb()) { + // SIGKILL is not trappable or ignorable + signal(SIGTERM, catchSignal); + signal(SIGHUP, catchSignal); signal(SIGABRT, catchSignal); signal(SIGSEGV, catchSignal); signal(SIGFPE, catchSignal); signal(SIGBUS, catchSignal); dumpStackOnSignal = dumpStack; } } static void initCgiInput() /* Initialize CGI input stuff. After this CGI vars are * stored in an internal hash/list regardless of how they * were passed to the program. */ { char* s;