Index: src/backend/postmaster/pgarch.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/postmaster/pgarch.c,v
retrieving revision 1.37
diff -c -r1.37 pgarch.c
*** src/backend/postmaster/pgarch.c	1 Jan 2008 19:45:51 -0000	1.37
--- src/backend/postmaster/pgarch.c	10 Jan 2008 01:03:50 -0000
***************
*** 77,87 ****
--- 77,89 ----
   * ----------
   */
  static time_t last_pgarch_start_time;
+ static time_t last_sigterm_time = 0;
  
  /*
   * Flags set by interrupt handlers for later service in the main loop.
   */
  static volatile sig_atomic_t got_SIGHUP = false;
+ static volatile sig_atomic_t got_SIGTERM = false;
  static volatile sig_atomic_t wakened = false;
  
  /* ----------
***************
*** 95,100 ****
--- 97,103 ----
  NON_EXEC_STATIC void PgArchiverMain(int argc, char *argv[]);
  static void pgarch_exit(SIGNAL_ARGS);
  static void ArchSigHupHandler(SIGNAL_ARGS);
+ static void ArchSigTermHandler(SIGNAL_ARGS);
  static void pgarch_waken(SIGNAL_ARGS);
  static void pgarch_MainLoop(void);
  static void pgarch_ArchiverCopyLoop(void);
***************
*** 236,246 ****
  
  	/*
  	 * Ignore all signals usually bound to some action in the postmaster,
! 	 * except for SIGHUP, SIGUSR1 and SIGQUIT.
  	 */
  	pqsignal(SIGHUP, ArchSigHupHandler);
  	pqsignal(SIGINT, SIG_IGN);
! 	pqsignal(SIGTERM, SIG_IGN);
  	pqsignal(SIGQUIT, pgarch_exit);
  	pqsignal(SIGALRM, SIG_IGN);
  	pqsignal(SIGPIPE, SIG_IGN);
--- 239,249 ----
  
  	/*
  	 * Ignore all signals usually bound to some action in the postmaster,
! 	 * except for SIGHUP, SIGTERM, SIGUSR1 and SIGQUIT.
  	 */
  	pqsignal(SIGHUP, ArchSigHupHandler);
  	pqsignal(SIGINT, SIG_IGN);
! 	pqsignal(SIGTERM, ArchSigTermHandler);
  	pqsignal(SIGQUIT, pgarch_exit);
  	pqsignal(SIGALRM, SIG_IGN);
  	pqsignal(SIGPIPE, SIG_IGN);
***************
*** 267,291 ****
  static void
  pgarch_exit(SIGNAL_ARGS)
  {
! 	/*
! 	 * For now, we just nail the doors shut and get out of town.  It might
! 	 * seem cleaner to finish up any pending archive copies, but there's a
! 	 * nontrivial risk that init will kill us partway through.
! 	 */
! 	exit(0);
  }
  
! /* SIGHUP: set flag to re-read config file at next convenient time */
  static void
  ArchSigHupHandler(SIGNAL_ARGS)
  {
  	got_SIGHUP = true;
  }
  
  /* SIGUSR1 signal handler for archiver process */
  static void
  pgarch_waken(SIGNAL_ARGS)
  {
  	wakened = true;
  }
  
--- 270,305 ----
  static void
  pgarch_exit(SIGNAL_ARGS)
  {
! 	/* SIGQUIT means curl up and die ... */
! 	exit(1);
  }
  
! /* SIGHUP signal handler for archiver process */
  static void
  ArchSigHupHandler(SIGNAL_ARGS)
  {
+ 	/* set flag to re-read config file at next convenient time */
  	got_SIGHUP = true;
  }
  
+ /* SIGTERM signal handler for archiver process */
+ static void
+ ArchSigTermHandler(SIGNAL_ARGS)
+ {
+ 	/*
+ 	 * The postmaster never sends us SIGTERM, so we assume that this means
+ 	 * that init is trying to shut down the whole system.  If we hang around
+ 	 * too long we'll get SIGKILL'd.  Set flag to prevent starting any more
+ 	 * archive commands.
+ 	 */
+ 	got_SIGTERM = true;
+ }
+ 
  /* SIGUSR1 signal handler for archiver process */
  static void
  pgarch_waken(SIGNAL_ARGS)
  {
+ 	/* set flag that there is work to be done */
  	wakened = true;
  }
  
***************
*** 298,303 ****
--- 312,318 ----
  pgarch_MainLoop(void)
  {
  	time_t		last_copy_time = 0;
+ 	bool		postmaster_alive;
  
  	/*
  	 * We run the copy loop immediately upon entry, in case there are
***************
*** 309,314 ****
--- 324,332 ----
  
  	do
  	{
+ 		/* When the postmaster dies, we do one more archive cycle, then exit */
+ 		postmaster_alive = PostmasterIsAlive(true);
+ 
  		/* Check for config update */
  		if (got_SIGHUP)
  		{
***************
*** 316,321 ****
--- 334,357 ----
  			ProcessConfigFile(PGC_SIGHUP);
  		}
  
+ 		/*
+ 		 * If we've gotten SIGTERM, we normally just sit and do nothing until
+ 		 * the postmaster dies.  However, that means a random SIGTERM would
+ 		 * disable archiving indefinitely, which doesn't seem like a good
+ 		 * idea.  If more than 60 seconds pass since SIGTERM, exit anyway,
+ 		 * so that the postmaster can start a new archiver if needed.
+ 		 */
+ 		if (got_SIGTERM)
+ 		{
+ 			time_t		curtime = time(NULL);
+ 
+ 			if (last_sigterm_time == 0)
+ 				last_sigterm_time = curtime;
+ 			else if ((unsigned int) (curtime - last_sigterm_time) >=
+ 					 (unsigned int) 60)
+ 				break;
+ 		}
+ 
  		/* Do what we're here for */
  		if (wakened)
  		{
***************
*** 334,340 ****
  		 * sleep into 1-second increments, and check for interrupts after each
  		 * nap.
  		 */
! 		while (!(wakened || got_SIGHUP))
  		{
  			time_t		curtime;
  
--- 370,376 ----
  		 * sleep into 1-second increments, and check for interrupts after each
  		 * nap.
  		 */
! 		while (!(wakened || got_SIGHUP || !PostmasterIsAlive(true)))
  		{
  			time_t		curtime;
  
***************
*** 344,350 ****
  				(unsigned int) PGARCH_AUTOWAKE_INTERVAL)
  				wakened = true;
  		}
! 	} while (PostmasterIsAlive(true));
  }
  
  /*
--- 380,386 ----
  				(unsigned int) PGARCH_AUTOWAKE_INTERVAL)
  				wakened = true;
  		}
! 	} while (postmaster_alive);
  }
  
  /*
***************
*** 377,384 ****
  
  		for (;;)
  		{
! 			/* Abandon processing if we notice our postmaster has died */
! 			if (!PostmasterIsAlive(true))
  				return;
  
  			if (pgarch_archiveXlog(xlog))
--- 413,420 ----
  
  		for (;;)
  		{
! 			/* Abandon processing if we've gotten SIGTERM */
! 			if (got_SIGTERM)
  				return;
  
  			if (pgarch_archiveXlog(xlog))
Index: src/backend/postmaster/postmaster.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v
retrieving revision 1.550
diff -c -r1.550 postmaster.c
*** src/backend/postmaster/postmaster.c	1 Jan 2008 19:45:51 -0000	1.550
--- src/backend/postmaster/postmaster.c	10 Jan 2008 01:03:51 -0000
***************
*** 1312,1323 ****
  				start_autovac_launcher = false; /* signal processed */
  		}
  
! 		/*
! 		 * If we have lost the archiver, try to start a new one. We do this
! 		 * even if we are shutting down, to allow archiver to take care of any
! 		 * remaining WAL files.
! 		 */
! 		if (XLogArchivingActive() && PgArchPID == 0 && pmState >= PM_RUN)
  			PgArchPID = pgarch_start();
  
  		/* If we have lost the stats collector, try to start a new one */
--- 1312,1319 ----
  				start_autovac_launcher = false; /* signal processed */
  		}
  
! 		/* If we have lost the archiver, try to start a new one */
! 		if (XLogArchivingActive() && PgArchPID == 0 && pmState == PM_RUN)
  			PgArchPID = pgarch_start();
  
  		/* If we have lost the stats collector, try to start a new one */
***************
*** 2175,2186 ****
  				 * checkpoint.	(If for some reason it didn't, recovery will
  				 * occur on next postmaster start.)
  				 *
! 				 * At this point we should have no normal children left (else
! 				 * we'd not be in PM_SHUTDOWN state) but we might have
! 				 * dead_end children.
  				 */
  				Assert(Shutdown > NoShutdown);
  				pmState = PM_WAIT_DEAD_END;
  			}
  			else
  			{
--- 2171,2193 ----
  				 * checkpoint.	(If for some reason it didn't, recovery will
  				 * occur on next postmaster start.)
  				 *
! 				 * At this point we should have no normal backend children
! 				 * left (else we'd not be in PM_SHUTDOWN state) but we might
! 				 * have dead_end children to wait for.
! 				 *
! 				 * We can also tell the archiver and stats collector processes
! 				 * to shut down (in the archiver's case, after doing a last
! 				 * round of archiving).
  				 */
  				Assert(Shutdown > NoShutdown);
  				pmState = PM_WAIT_DEAD_END;
+ 
+ 				/* Waken archiver for the last time */
+ 				if (PgArchPID != 0)
+ 					signal_child(PgArchPID, SIGUSR1);
+ 				/* Tell pgstat to shut down; nothing left for it to do */
+ 				if (PgStatPID != 0)
+ 					signal_child(PgStatPID, SIGQUIT);
  			}
  			else
  			{
***************
*** 2235,2241 ****
  			if (!EXIT_STATUS_0(exitstatus))
  				LogChildExit(LOG, _("archiver process"),
  							 pid, exitstatus);
! 			if (XLogArchivingActive() && pmState >= PM_RUN)
  				PgArchPID = pgarch_start();
  			continue;
  		}
--- 2242,2248 ----
  			if (!EXIT_STATUS_0(exitstatus))
  				LogChildExit(LOG, _("archiver process"),
  							 pid, exitstatus);
! 			if (XLogArchivingActive() && pmState == PM_RUN)
  				PgArchPID = pgarch_start();
  			continue;
  		}
***************
*** 2563,2568 ****
--- 2570,2580 ----
  				 * change causes ServerLoop to stop creating new ones.
  				 */
  				pmState = PM_WAIT_DEAD_END;
+ 
+ 				/*
+ 				 * We already SIGQUIT'd the archiver and stats processes,
+ 				 * if any, when we entered FatalError state.
+ 				 */
  			}
  			else
  			{
***************
*** 2591,2603 ****
  					 */
  					FatalError = true;
  					pmState = PM_WAIT_DEAD_END;
  				}
- 				/* Tell pgarch to shut down too; nothing left for it to do */
- 				if (PgArchPID != 0)
- 					signal_child(PgArchPID, SIGQUIT);
- 				/* Tell pgstat to shut down too; nothing left for it to do */
- 				if (PgStatPID != 0)
- 					signal_child(PgStatPID, SIGQUIT);
  			}
  		}
  	}
--- 2603,2615 ----
  					 */
  					FatalError = true;
  					pmState = PM_WAIT_DEAD_END;
+ 
+ 					/* Kill the archiver and stats collector too */
+ 					if (PgArchPID != 0)
+ 						signal_child(PgArchPID, SIGQUIT);
+ 					if (PgStatPID != 0)
+ 						signal_child(PgStatPID, SIGQUIT);
  				}
  			}
  		}
  	}
***************
*** 2629,2641 ****
  	 * before init decides to SIGKILL us.)
  	 *
  	 * Note: we do not wait around for exit of the archiver or stats
! 	 * processes.  They've been sent SIGQUIT by this point (either when we
! 	 * entered PM_SHUTDOWN state, or when we set FatalError, and at least one
! 	 * of those must have happened by now).  In any case they contain logic to
! 	 * commit hara-kiri if they notice the postmaster is gone.	Since they
! 	 * aren't connected to shared memory, they pose no problem for shutdown.
! 	 * The syslogger is not considered either, since it's intended to survive
! 	 * till the postmaster exits.
  	 */
  	if (Shutdown > NoShutdown && pmState == PM_NO_CHILDREN)
  	{
--- 2641,2653 ----
  	 * before init decides to SIGKILL us.)
  	 *
  	 * Note: we do not wait around for exit of the archiver or stats
! 	 * processes.  They've been sent appropriate signals by this point (either
! 	 * when we entered PM_WAIT_DEAD_END state, or when we set FatalError, and
! 	 * at least one of those must have happened by now).  In any case they
! 	 * contain logic to commit hara-kiri if they notice the postmaster is
! 	 * gone.  Since they aren't connected to shared memory, they pose no
! 	 * problem for shutdown.  The syslogger is not considered either, since
! 	 * it's intended to survive till the postmaster exits.
  	 */
  	if (Shutdown > NoShutdown && pmState == PM_NO_CHILDREN)
  	{
***************
*** 3782,3788 ****
  	}
  
  	if (CheckPostmasterSignal(PMSIGNAL_WAKEN_ARCHIVER) &&
! 		PgArchPID != 0 && Shutdown <= SmartShutdown)
  	{
  		/*
  		 * Send SIGUSR1 to archiver process, to wake it up and begin archiving
--- 3794,3800 ----
  	}
  
  	if (CheckPostmasterSignal(PMSIGNAL_WAKEN_ARCHIVER) &&
! 		PgArchPID != 0)
  	{
  		/*
  		 * Send SIGUSR1 to archiver process, to wake it up and begin archiving
