diff src/backend/access/transam/xlog.c
index 8d0aabf..e5adfab
*** a/src/backend/access/transam/xlog.c
--- b/src/backend/access/transam/xlog.c
*************** typedef struct XLogCtlData
*** 434,444 ****
  	Latch		recoveryWakeupLatch;

  	/*
- 	 * WALWriterLatch is used to wake up the WALWriter to write some WAL.
- 	 */
- 	Latch		WALWriterLatch;
-
- 	/*
  	 * During recovery, we keep a copy of the latest checkpoint record here.
  	 * Used by the background writer when it wants to create a restartpoint.
  	 *
--- 434,439 ----
*************** begin:;
*** 1213,1218 ****
--- 1208,1220 ----

  	END_CRIT_SECTION();

+ 	/*
+ 	 * Now that we've gone through with inserting WAL, nudge the WALWriter,
+ 	 * provoking a set number of iterations.
+ 	 */
+ 	if (ProcGlobal->walwriterLatch)
+ 		SetLatch(ProcGlobal->walwriterLatch);
+
  	return RecPtr;
  }

*************** XLogSetAsyncXactLSN(XLogRecPtr asyncXact
*** 1935,1941 ****
  	/*
  	 * Nudge the WALWriter if we have a full page of WAL to write.
  	 */
! 	SetLatch(&XLogCtl->WALWriterLatch);
  }

  /*
--- 1937,1944 ----
  	/*
  	 * Nudge the WALWriter if we have a full page of WAL to write.
  	 */
! 	if (ProcGlobal->walwriterLatch)
! 		SetLatch(ProcGlobal->walwriterLatch);
  }

  /*
*************** XLogFlush(XLogRecPtr record)
*** 2173,2188 ****
   * case for async commits.)
   *
   * This routine is invoked periodically by the background walwriter process.
   */
! void
  XLogBackgroundFlush(void)
  {
  	XLogRecPtr	WriteRqstPtr;
  	bool		flexible = true;

  	/* XLOG doesn't need flushing during recovery */
  	if (RecoveryInProgress())
! 		return;

  	/* read LogwrtResult and update local state */
  	{
--- 2176,2194 ----
   * case for async commits.)
   *
   * This routine is invoked periodically by the background walwriter process.
+  *
+  * Returns a value indicating if useful work was performed.
   */
! bool
  XLogBackgroundFlush(void)
  {
  	XLogRecPtr	WriteRqstPtr;
  	bool		flexible = true;
+ 	bool		worked = false;

  	/* XLOG doesn't need flushing during recovery */
  	if (RecoveryInProgress())
! 		return false;

  	/* read LogwrtResult and update local state */
  	{
*************** XLogBackgroundFlush(void)
*** 2224,2230 ****
  				XLogFileClose();
  			}
  		}
! 		return;
  	}

  #ifdef WAL_DEBUG
--- 2230,2236 ----
  				XLogFileClose();
  			}
  		}
! 		return false;
  	}

  #ifdef WAL_DEBUG
*************** XLogBackgroundFlush(void)
*** 2247,2256 ****
--- 2253,2265 ----
  		WriteRqst.Write = WriteRqstPtr;
  		WriteRqst.Flush = WriteRqstPtr;
  		XLogWrite(WriteRqst, flexible, false);
+ 		worked = true;
  	}
  	LWLockRelease(WALWriteLock);

  	END_CRIT_SECTION();
+
+ 	return worked;
  }

  /*
*************** XLOGShmemInit(void)
*** 5101,5107 ****
  	XLogCtl->Insert.currpage = (XLogPageHeader) (XLogCtl->pages);
  	SpinLockInit(&XLogCtl->info_lck);
  	InitSharedLatch(&XLogCtl->recoveryWakeupLatch);
- 	InitSharedLatch(&XLogCtl->WALWriterLatch);

  	/*
  	 * If we are not in bootstrap mode, pg_control should already exist. Read
--- 5110,5115 ----
*************** WakeupRecovery(void)
*** 10479,10490 ****
  {
  	SetLatch(&XLogCtl->recoveryWakeupLatch);
  }
-
- /*
-  * Manage the WALWriterLatch
-  */
- Latch *
- WALWriterLatch(void)
- {
- 	return &XLogCtl->WALWriterLatch;
- }
--- 10487,10489 ----
diff src/backend/postmaster/walwriter.c
index 08ef946..eb09359
*** a/src/backend/postmaster/walwriter.c
--- b/src/backend/postmaster/walwriter.c
***************
*** 54,59 ****
--- 54,60 ----
  #include "storage/ipc.h"
  #include "storage/lwlock.h"
  #include "storage/pmsignal.h"
+ #include "storage/proc.h"
  #include "storage/smgr.h"
  #include "utils/guc.h"
  #include "utils/hsearch.h"
***************
*** 67,81 ****
--- 68,93 ----
  int			WalWriterDelay = 200;

  /*
+  * Number of loops before each nap is extended to a hibernation, and time to
+  * sleep between walwriter rounds when hibernating.
+  */
+ #define LOOPS_UNTIL_HIBERNATE		100
+ #define HIBERNATE_MS				10000
+
+ /*
   * 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 shutdown_requested = false;

+ /* Prototypes for private functions */
+ static bool WalWriterNap(bool hibernating);
+
  /* Signal handlers */
  static void wal_quickdie(SIGNAL_ARGS);
  static void WalSigHupHandler(SIGNAL_ARGS);
  static void WalShutdownHandler(SIGNAL_ARGS);
+ static void walwriter_sigusr1_handler(SIGNAL_ARGS);

  /*
   * Main entry point for walwriter process
*************** WalWriterMain(void)
*** 88,95 ****
  {
  	sigjmp_buf	local_sigjmp_buf;
  	MemoryContext walwriter_context;
!
! 	InitLatch(WALWriterLatch()); /* initialize latch used in main loop */

  	/*
  	 * If possible, make this process a group leader, so that the postmaster
--- 100,107 ----
  {
  	sigjmp_buf	local_sigjmp_buf;
  	MemoryContext walwriter_context;
! 	int			left_till_hibernate = LOOPS_UNTIL_HIBERNATE;
! 	bool		hibernating;

  	/*
  	 * If possible, make this process a group leader, so that the postmaster
*************** WalWriterMain(void)
*** 114,120 ****
  	pqsignal(SIGQUIT, wal_quickdie);	/* hard crash time */
  	pqsignal(SIGALRM, SIG_IGN);
  	pqsignal(SIGPIPE, SIG_IGN);
! 	pqsignal(SIGUSR1, SIG_IGN); /* reserve for ProcSignal */
  	pqsignal(SIGUSR2, SIG_IGN); /* not used */

  	/*
--- 126,132 ----
  	pqsignal(SIGQUIT, wal_quickdie);	/* hard crash time */
  	pqsignal(SIGALRM, SIG_IGN);
  	pqsignal(SIGPIPE, SIG_IGN);
! 	pqsignal(SIGUSR1, walwriter_sigusr1_handler);
  	pqsignal(SIGUSR2, SIG_IGN); /* not used */

  	/*
*************** WalWriterMain(void)
*** 218,229 ****
  	PG_SETMASK(&UnBlockSig);

  	/*
  	 * Loop forever
  	 */
  	for (;;)
  	{
- 		ResetLatch(WALWriterLatch());
-
  		/*
  		 * Emergency bailout if postmaster has died.  This is to avoid the
  		 * necessity for manual cleanup of all postmaster children.
--- 230,246 ----
  	PG_SETMASK(&UnBlockSig);

  	/*
+ 	 * Advertise our latch that backends can use to wake us up while we're
+ 	 * sleeping.
+ 	 */
+ 	ProcGlobal->walwriterLatch = &MyProc->procLatch;
+
+ 	/*
  	 * Loop forever
  	 */
+ 	hibernating = false;
  	for (;;)
  	{
  		/*
  		 * Emergency bailout if postmaster has died.  This is to avoid the
  		 * necessity for manual cleanup of all postmaster children.
*************** WalWriterMain(void)
*** 248,261 ****
  		/*
  		 * Do what we're here for...
  		 */
! 		XLogBackgroundFlush();

! 		(void) WaitLatch(WALWriterLatch(),
! 							   WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
! 							   WalWriterDelay /* ms */);
  	}
  }


  /* --------------------------------
   *		signal handler routines
--- 265,394 ----
  		/*
  		 * Do what we're here for...
  		 */
! 		if (hibernating)
! 			ResetLatch(&MyProc->procLatch);

! 		/*
! 		 * If XLogBackgroundFlush() found useful work to do, reset iterations
! 		 * left until hibernation.
! 		 */
! 		if (XLogBackgroundFlush())
! 			left_till_hibernate = LOOPS_UNTIL_HIBERNATE;
! 		else if (left_till_hibernate > 0)
! 			left_till_hibernate--;
!
! 		if (left_till_hibernate == 0 && !hibernating)
! 		{
! 			/*
! 			 * XLogBackgroundFlush did nothing for a sufficient number of
! 			 * iterations. Since there doesn't seem to be any work for the
! 			 * walwriter to do, go into slower-paced "hibernation" mode, where
! 			 * we sleep for much longer times than bgwriter_delay says. Fewer
! 			 * wakeups saves electricity.  If a backend inserts WAL, it will
! 			 * wake us up by setting our latch.
! 			 *
! 			 * The latch is kept set during productive cycles where WAL is
! 			 * written and/or synced, and only reset before going into a longer
! 			 * sleep.  That ensures that when there's a constant trickle of
! 			 * activity, the SetLatch() calls that backends have to do will see
! 			 * the latch as already set, and are not slowed down by having to
! 			 * actually set the latch and signal us.
! 			 */
! 			hibernating = true;
!
! 			/*
! 			 * Take one more short nap and perform one more walwriter cycle -
! 			 * control in another process might have reached XLogInsert() just
! 			 * after we finished the previous walwriter cycle, while the latch
! 			 * was still set.  If we still find nothing to do after this cycle,
! 			 * the next sleep will be longer.
! 			 */
! 			WalWriterNap(false);
! 			continue;
! 		}
! 		else if (left_till_hibernate > 0 && hibernating)
! 		{
! 			/*
! 			 * Woke up from hibernation, and may have found work to do. Set the
! 			 * latch just in case it's not set yet (usually we wake up from
! 			 * hibernation because a backend already set the latch, but not
! 			 * necessarily).
! 			 */
! 			SetLatch(&MyProc->procLatch);
! 			hibernating = false;
! 		}
!
! 		/*
! 		 * If the latch is set, don't immediately go back to hibernation if no
! 		 * work is performed in the first iteration.
! 		 */
! 		if (WalWriterNap(hibernating))
! 			left_till_hibernate = LOOPS_UNTIL_HIBERNATE;
  	}
  }
+ /*
+  * WalWriterNap -- Nap for the configured time or until a signal is received.
+  *
+  * If 'hibernating' is false, sleeps for wal_writer_delay milliseconds.
+  * Otherwise sleeps longer, but also wakes up if the process latch is set.
+  *
+  * Returns a value indicating if return was due to latch being set.
+  */
+ static bool
+ WalWriterNap(bool hibernating)
+ {
+ 	long		udelay;
+ 	bool		latch_set = false;
+
+ 	/*
+ 	 * Nap for the configured time, or sleep for 10 seconds if there is no
+ 	 * walwriter activity required.
+ 	 *
+ 	 * If there was no work to do in the previous LOOPS_UNTIL_HIBERNATE cycles,
+ 	 * take a longer nap.
+ 	 */
+ 	if (hibernating)
+ 	{
+ 		int res = WaitLatch(&MyProc->procLatch,
+ 							   WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ 							   HIBERNATE_MS);
+
+ 		/*
+ 		 * Only do a quick return if timeout was reached (or postmaster died)
+ 		 * to ensure that no less than WalWriterDelay ms has passed between
+ 		 * XLogBackgroundFlush calls - WaitLatch() might have returned
+ 		 * instantaneously.
+ 		 */
+ 		if (res & (WL_TIMEOUT | WL_POSTMASTER_DEATH))
+ 			return false;
+
+ 		/* WL_LATCH_SET is documented as reliable */
+ 		latch_set = (res & WL_LATCH_SET) != 0;
+ 	}
+
+ 	/*
+ 	 * Nap for the configured time.
+ 	 *
+ 	 * On some platforms, signals won't interrupt the sleep.  To ensure we
+ 	 * respond reasonably promptly when someone signals us, break down the
+ 	 * sleep into 1-second increments, and check for interrupts after each
+ 	 * nap.
+ 	 */
+ 	udelay = WalWriterDelay * 1000L;
+
+ 	while (udelay > 999999L)
+ 	{
+ 		if (got_SIGHUP || shutdown_requested)
+ 			break;
+ 		pg_usleep(1000000L);
+ 		udelay -= 1000000L;
+ 	}

+ 	if (!(got_SIGHUP || shutdown_requested))
+ 		pg_usleep(udelay);
+
+ 	return latch_set;
+ }

  /* --------------------------------
   *		signal handler routines
*************** wal_quickdie(SIGNAL_ARGS)
*** 298,311 ****
  static void
  WalSigHupHandler(SIGNAL_ARGS)
  {
  	got_SIGHUP = true;
! 	SetLatch(WALWriterLatch());
  }

  /* SIGTERM: set flag to exit normally */
  static void
  WalShutdownHandler(SIGNAL_ARGS)
  {
  	shutdown_requested = true;
! 	SetLatch(WALWriterLatch());
  }
--- 431,465 ----
  static void
  WalSigHupHandler(SIGNAL_ARGS)
  {
+ 	int			save_errno = errno;
+
  	got_SIGHUP = true;
! 	if (MyProc)
! 		SetLatch(&MyProc->procLatch);
!
! 	errno = save_errno;
  }

  /* SIGTERM: set flag to exit normally */
  static void
  WalShutdownHandler(SIGNAL_ARGS)
  {
+ 	int			save_errno = errno;
+
  	shutdown_requested = true;
! 	if (MyProc)
! 		SetLatch(&MyProc->procLatch);
!
! 	errno = save_errno;
! }
!
! /* SIGUSR1: used for latch wakeups */
! static void
! walwriter_sigusr1_handler(SIGNAL_ARGS)
! {
! 	int			save_errno = errno;
!
! 	latch_sigusr1_handler();
!
! 	errno = save_errno;
  }
diff src/backend/storage/lmgr/proc.c
index d1bf264..43c4846
*** a/src/backend/storage/lmgr/proc.c
--- b/src/backend/storage/lmgr/proc.c
*************** InitProcGlobal(void)
*** 187,192 ****
--- 187,193 ----
  	ProcGlobal->startupProcPid = 0;
  	ProcGlobal->startupBufferPinWaitBufId = -1;
  	ProcGlobal->bgwriterLatch = NULL;
+ 	ProcGlobal->walwriterLatch = NULL;

  	/*
  	 * Create and initialize all the PGPROC structures we'll need (except for
diff src/include/access/xlog.h
index f8aecef..3c1a509
*** a/src/include/access/xlog.h
--- b/src/include/access/xlog.h
*************** extern CheckpointStatsData CheckpointSta
*** 266,272 ****

  extern XLogRecPtr XLogInsert(RmgrId rmid, uint8 info, XLogRecData *rdata);
  extern void XLogFlush(XLogRecPtr RecPtr);
! extern void XLogBackgroundFlush(void);
  extern bool XLogNeedsFlush(XLogRecPtr RecPtr);
  extern int XLogFileInit(uint32 log, uint32 seg,
  			 bool *use_existent, bool use_lock);
--- 266,272 ----

  extern XLogRecPtr XLogInsert(RmgrId rmid, uint8 info, XLogRecData *rdata);
  extern void XLogFlush(XLogRecPtr RecPtr);
! extern bool XLogBackgroundFlush(void);
  extern bool XLogNeedsFlush(XLogRecPtr RecPtr);
  extern int XLogFileInit(uint32 log, uint32 seg,
  			 bool *use_existent, bool use_lock);
*************** extern TimeLineID GetRecoveryTargetTLI(v
*** 317,323 ****

  extern bool CheckPromoteSignal(void);
  extern void WakeupRecovery(void);
- extern Latch *WALWriterLatch(void);

  /*
   * Starting/stopping a base backup
--- 317,322 ----
diff src/include/storage/latch.h
index f97fedf..12f500a
*** a/src/include/storage/latch.h
--- b/src/include/storage/latch.h
***************
*** 25,31 ****
   * and must be initialized at postmaster startup by InitSharedLatch. Before
   * a shared latch can be waited on, it must be associated with a process
   * with OwnLatch. Only the process owning the latch can wait on it, but any
!  * process can set it.
   *
   * There are three basic operations on a latch:
   *
--- 25,37 ----
   * and must be initialized at postmaster startup by InitSharedLatch. Before
   * a shared latch can be waited on, it must be associated with a process
   * with OwnLatch. Only the process owning the latch can wait on it, but any
!  * process can set it. Note that the use of the process latch (a field in
!  * PGPROC) is generally preferred over an ad-hoc latch for auxiliary processes.
!  * This is because generic signal handlers will call SetLatch on the process
!  * latch only. Signals have the potential to invalidate the latch timeout on
!  * certain platforms, resulting in a denial-of-service, so even if the process
!  * latch cannot be used it is important to verify that all signal handlers
!  * within the process call SetLatch().
   *
   * There are three basic operations on a latch:
   *
diff src/include/storage/proc.h
index a66c484..478577f
*** a/src/include/storage/proc.h
--- b/src/include/storage/proc.h
*************** typedef struct PROC_HDR
*** 190,195 ****
--- 190,197 ----
  	PGPROC	   *autovacFreeProcs;
  	/* BGWriter process latch */
  	Latch	   *bgwriterLatch;
+ 	/* WALWriter process latch */
+ 	Latch	   *walwriterLatch;
  	/* Current shared estimate of appropriate spins_per_delay value */
  	int			spins_per_delay;
  	/* The proc of the Startup process, since not in ProcArray */
