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;