diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index dade5cc..bfa6f49 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -89,6 +89,7 @@
 #include "storage/proc.h"
 #include "storage/procsignal.h"
 #include "storage/sinvaladt.h"
+#include "storage/timeout.h"
 #include "tcop/tcopprot.h"
 #include "utils/fmgroids.h"
 #include "utils/lsyscache.h"
@@ -484,7 +485,7 @@ AutoVacLauncherMain(int argc, char *argv[])
 
 		/* Forget any pending QueryCancel request */
 		QueryCancelPending = false;
-		disable_sig_alarm(true);
+		disable_all_timeouts(false);
 		QueryCancelPending = false;		/* again in case timeout occurred */
 
 		/* Report the error to the server log */
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 913734f..a501d0d 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -112,7 +112,7 @@
 #include "storage/ipc.h"
 #include "storage/pg_shmem.h"
 #include "storage/pmsignal.h"
-#include "storage/proc.h"
+#include "storage/timeout.h"
 #include "tcop/tcopprot.h"
 #include "utils/builtins.h"
 #include "utils/datetime.h"
@@ -3365,6 +3365,17 @@ report_fork_failure_to_client(Port *port, int errnum)
 	} while (rc < 0 && errno == EINTR);
 }
 
+/*
+ * DummyTimeoutFunction
+ *
+ * Do nothing -- just to break out of a sleeping system call.
+ * The timeout indicator is set by the signal handler.
+ */
+static void
+DummyTimeoutFunction(void)
+{
+	return;
+}
 
 /*
  * BackendInitialize -- initialize an interactive (postmaster-child)
@@ -3437,6 +3448,13 @@ BackendInitialize(Port *port)
 	PG_SETMASK(&StartupBlockSig);
 
 	/*
+	 * Initialize timeout sources and register authentication timeout early.
+	 */
+	InitializeTimeouts();
+	RegisterTimeout(AUTHENTICATION_TIMEOUT, false,
+			   		DummyTimeoutFunction, GetCurrentTimestamp);
+
+	/*
 	 * Get the remote host name and port for logging and status display.
 	 */
 	remote_host[0] = '\0';
@@ -3488,8 +3506,7 @@ BackendInitialize(Port *port)
 	 * indefinitely.  PreAuthDelay and any DNS interactions above don't count
 	 * against the time limit.
 	 */
-	if (!enable_sig_alarm(AuthenticationTimeout * 1000, false))
-		elog(FATAL, "could not set timer for startup packet timeout");
+	enable_timeout(AUTHENTICATION_TIMEOUT, AuthenticationTimeout * 1000);
 
 	/*
 	 * Receive the startup packet (which might turn out to be a cancel request
@@ -3526,8 +3543,7 @@ BackendInitialize(Port *port)
 	/*
 	 * Disable the timeout, and prevent SIGTERM/SIGQUIT again.
 	 */
-	if (!disable_sig_alarm(false))
-		elog(FATAL, "could not disable timer for startup packet timeout");
+	disable_timeout(AUTHENTICATION_TIMEOUT, false);
 	PG_SETMASK(&BlockSig);
 }
 
diff --git a/src/backend/postmaster/startup.c b/src/backend/postmaster/startup.c
index ed75d09..ffeb0e0 100644
--- a/src/backend/postmaster/startup.c
+++ b/src/backend/postmaster/startup.c
@@ -28,7 +28,9 @@
 #include "storage/latch.h"
 #include "storage/pmsignal.h"
 #include "storage/proc.h"
+#include "storage/timeout.h"
 #include "utils/guc.h"
+#include "utils/timestamp.h"
 
 
 /*
@@ -184,19 +186,23 @@ StartupProcessMain(void)
 #endif
 
 	/*
+	 * Initialize timeouts and register timeouts needed for standby.
+	 */
+	InitializeTimeouts();
+	RegisterTimeout(STANDBY_DEADLOCK_TIMEOUT, true,
+					StandbyDeadLockHandler, GetCurrentTimestamp);
+	RegisterTimeout(STANDBY_TIMEOUT, false,
+					StandbyTimeoutHandler, GetCurrentTimestamp);
+
+	/*
 	 * Properly accept or ignore signals the postmaster might send us.
-	 *
-	 * Note: ideally we'd not enable handle_standby_sig_alarm unless actually
-	 * doing hot standby, but we don't know that yet.  Rely on it to not do
-	 * anything if it shouldn't.
 	 */
 	pqsignal(SIGHUP, StartupProcSigHupHandler); /* reload config file */
 	pqsignal(SIGINT, SIG_IGN);	/* ignore query cancel */
 	pqsignal(SIGTERM, StartupProcShutdownHandler);		/* request shutdown */
 	pqsignal(SIGQUIT, startupproc_quickdie);	/* hard crash time */
 	if (EnableHotStandby)
-		pqsignal(SIGALRM, handle_standby_sig_alarm);	/* ignored unless
-														 * InHotStandby */
+		pqsignal(SIGALRM, handle_sig_alarm);
 	else
 		pqsignal(SIGALRM, SIG_IGN);
 	pqsignal(SIGPIPE, SIG_IGN);
diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c
index 995b68a..6b8233f 100644
--- a/src/backend/storage/ipc/standby.c
+++ b/src/backend/storage/ipc/standby.c
@@ -27,6 +27,7 @@
 #include "storage/procarray.h"
 #include "storage/sinvaladt.h"
 #include "storage/standby.h"
+#include "storage/timeout.h"
 #include "utils/ps_status.h"
 #include "utils/timestamp.h"
 
@@ -394,7 +395,6 @@ ResolveRecoveryConflictWithLock(Oid dbOid, Oid relOid)
 void
 ResolveRecoveryConflictWithBufferPin(void)
 {
-	bool		sig_alarm_enabled = false;
 	TimestampTz ltime;
 	TimestampTz now;
 
@@ -409,10 +409,7 @@ ResolveRecoveryConflictWithBufferPin(void)
 		 * We're willing to wait forever for conflicts, so set timeout for
 		 * deadlock check (only)
 		 */
-		if (enable_standby_sig_alarm(now, now, true))
-			sig_alarm_enabled = true;
-		else
-			elog(FATAL, "could not set timer for process wakeup");
+		enable_timeout(STANDBY_DEADLOCK_TIMEOUT, DeadlockTimeout);
 	}
 	else if (now >= ltime)
 	{
@@ -423,24 +420,26 @@ ResolveRecoveryConflictWithBufferPin(void)
 	}
 	else
 	{
+		long		secs,
+					msecs;
+		int			usecs;
+
 		/*
 		 * Wake up at ltime, and check for deadlocks as well if we will be
 		 * waiting longer than deadlock_timeout
 		 */
-		if (enable_standby_sig_alarm(now, ltime, false))
-			sig_alarm_enabled = true;
-		else
-			elog(FATAL, "could not set timer for process wakeup");
+		enable_timeout(STANDBY_DEADLOCK_TIMEOUT, DeadlockTimeout);
+
+		TimestampDifference(now, ltime, &secs, &usecs);
+		msecs = secs * 1000 + usecs / 1000;
+
+		enable_timeout(STANDBY_TIMEOUT, msecs);
 	}
 
 	/* Wait to be signaled by UnpinBuffer() */
 	ProcWaitForSignal();
 
-	if (sig_alarm_enabled)
-	{
-		if (!disable_standby_sig_alarm())
-			elog(FATAL, "could not disable timer for process wakeup");
-	}
+	disable_all_timeouts(false);
 }
 
 void
diff --git a/src/backend/storage/lmgr/Makefile b/src/backend/storage/lmgr/Makefile
index e12a854..f0f7814 100644
--- a/src/backend/storage/lmgr/Makefile
+++ b/src/backend/storage/lmgr/Makefile
@@ -12,7 +12,7 @@ subdir = src/backend/storage/lmgr
 top_builddir = ../../../..
 include $(top_builddir)/src/Makefile.global
 
-OBJS = lmgr.o lock.o proc.o deadlock.o lwlock.o spin.o s_lock.o predicate.o
+OBJS = lmgr.o lock.o proc.o deadlock.o lwlock.o spin.o s_lock.o predicate.o timeout.o
 
 include $(top_srcdir)/src/backend/common.mk
 
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 21598d3..4b5b8d0 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -48,6 +48,7 @@
 #include "storage/procarray.h"
 #include "storage/procsignal.h"
 #include "storage/spin.h"
+#include "storage/timeout.h"
 #include "utils/timestamp.h"
 
 
@@ -77,27 +78,12 @@ PGPROC	   *PreparedXactProcs = NULL;
 /* If we are waiting for a lock, this points to the associated LOCALLOCK */
 static LOCALLOCK *lockAwaited = NULL;
 
-/* Mark these volatile because they can be changed by signal handler */
-static volatile bool standby_timeout_active = false;
-static volatile bool statement_timeout_active = false;
-static volatile bool deadlock_timeout_active = false;
-static volatile DeadLockState deadlock_state = DS_NOT_YET_CHECKED;
-volatile bool cancel_from_timeout = false;
-
-/* timeout_start_time is set when log_lock_waits is true */
-static TimestampTz timeout_start_time;
-
-/* statement_fin_time is valid only if statement_timeout_active is true */
-static TimestampTz statement_fin_time;
-static TimestampTz statement_fin_time2; /* valid only in recovery */
-
+/* Mark this volatile because it can be changed by signal handler */
+static volatile DeadLockState deadlock_state;
 
 static void RemoveProcFromArray(int code, Datum arg);
 static void ProcKill(int code, Datum arg);
 static void AuxiliaryProcKill(int code, Datum arg);
-static bool CheckStatementTimeout(void);
-static bool CheckStandbyTimeout(void);
-
 
 /*
  * Report shared-memory space needed by InitProcGlobal.
@@ -653,7 +639,7 @@ LockErrorCleanup(void)
 		return;
 
 	/* Turn off the deadlock timer, if it's still running (see ProcSleep) */
-	disable_sig_alarm(false);
+	disable_timeout(DEADLOCK_TIMEOUT, false);
 
 	/* Unlink myself from the wait queue, if on it (might not be anymore!) */
 	partitionLock = LockHashPartitionLock(lockAwaited->hashcode);
@@ -1048,8 +1034,7 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
 	 * By delaying the check until we've waited for a bit, we can avoid
 	 * running the rather expensive deadlock-check code in most cases.
 	 */
-	if (!enable_sig_alarm(DeadlockTimeout, false))
-		elog(FATAL, "could not set timer for process wakeup");
+	enable_timeout(DEADLOCK_TIMEOUT, DeadlockTimeout);
 
 	/*
 	 * If someone wakes us between LWLockRelease and PGSemaphoreLock,
@@ -1138,7 +1123,8 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
 			DescribeLockTag(&buf, &locallock->tag.lock);
 			modename = GetLockmodeName(locallock->tag.lock.locktag_lockmethodid,
 									   lockmode);
-			TimestampDifference(timeout_start_time, GetCurrentTimestamp(),
+			TimestampDifference(get_timeout_start(DEADLOCK_TIMEOUT),
+								GetCurrentTimestamp(),
 								&secs, &usecs);
 			msecs = secs * 1000 + usecs / 1000;
 			usecs = usecs % 1000;
@@ -1200,8 +1186,7 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
 	/*
 	 * Disable the timer, if it's still running
 	 */
-	if (!disable_sig_alarm(false))
-		elog(FATAL, "could not disable timer for process wakeup");
+	disable_timeout(DEADLOCK_TIMEOUT, false);
 
 	/*
 	 * Re-acquire the lock table's partition lock.  We have to do this to hold
@@ -1344,7 +1329,7 @@ ProcLockWakeup(LockMethod lockMethodTable, LOCK *lock)
  * NB: this is run inside a signal handler, so be very wary about what is done
  * here or in called routines.
  */
-static void
+void
 CheckDeadLock(void)
 {
 	int			i;
@@ -1499,400 +1484,38 @@ ProcSendSignal(int pid)
 		PGSemaphoreUnlock(&proc->sem);
 }
 
-
-/*****************************************************************************
- * SIGALRM interrupt support
- *
- * Maybe these should be in pqsignal.c?
- *****************************************************************************/
-
-/*
- * Enable the SIGALRM interrupt to fire after the specified delay
- *
- * Delay is given in milliseconds.	Caller should be sure a SIGALRM
- * signal handler is installed before this is called.
- *
- * This code properly handles nesting of deadlock timeout alarms within
- * statement timeout alarms.
- *
- * Returns TRUE if okay, FALSE on failure.
- */
-bool
-enable_sig_alarm(int delayms, bool is_statement_timeout)
-{
-	TimestampTz fin_time;
-	struct itimerval timeval;
-
-	if (is_statement_timeout)
-	{
-		/*
-		 * Begin statement-level timeout
-		 *
-		 * Note that we compute statement_fin_time with reference to the
-		 * statement_timestamp, but apply the specified delay without any
-		 * correction; that is, we ignore whatever time has elapsed since
-		 * statement_timestamp was set.  In the normal case only a small
-		 * interval will have elapsed and so this doesn't matter, but there
-		 * are corner cases (involving multi-statement query strings with
-		 * embedded COMMIT or ROLLBACK) where we might re-initialize the
-		 * statement timeout long after initial receipt of the message. In
-		 * such cases the enforcement of the statement timeout will be a bit
-		 * inconsistent.  This annoyance is judged not worth the cost of
-		 * performing an additional gettimeofday() here.
-		 */
-		Assert(!deadlock_timeout_active);
-		fin_time = GetCurrentStatementStartTimestamp();
-		fin_time = TimestampTzPlusMilliseconds(fin_time, delayms);
-		statement_fin_time = fin_time;
-		cancel_from_timeout = false;
-		statement_timeout_active = true;
-	}
-	else if (statement_timeout_active)
-	{
-		/*
-		 * Begin deadlock timeout with statement-level timeout active
-		 *
-		 * Here, we want to interrupt at the closer of the two timeout times.
-		 * If fin_time >= statement_fin_time then we need not touch the
-		 * existing timer setting; else set up to interrupt at the deadlock
-		 * timeout time.
-		 *
-		 * NOTE: in this case it is possible that this routine will be
-		 * interrupted by the previously-set timer alarm.  This is okay
-		 * because the signal handler will do only what it should do according
-		 * to the state variables.	The deadlock checker may get run earlier
-		 * than normal, but that does no harm.
-		 */
-		timeout_start_time = GetCurrentTimestamp();
-		fin_time = TimestampTzPlusMilliseconds(timeout_start_time, delayms);
-		deadlock_timeout_active = true;
-		if (fin_time >= statement_fin_time)
-			return true;
-	}
-	else
-	{
-		/* Begin deadlock timeout with no statement-level timeout */
-		deadlock_timeout_active = true;
-		/* GetCurrentTimestamp can be expensive, so only do it if we must */
-		if (log_lock_waits)
-			timeout_start_time = GetCurrentTimestamp();
-	}
-
-	/* If we reach here, okay to set the timer interrupt */
-	MemSet(&timeval, 0, sizeof(struct itimerval));
-	timeval.it_value.tv_sec = delayms / 1000;
-	timeval.it_value.tv_usec = (delayms % 1000) * 1000;
-	if (setitimer(ITIMER_REAL, &timeval, NULL))
-		return false;
-	return true;
-}
-
-/*
- * Cancel the SIGALRM timer, either for a deadlock timeout or a statement
- * timeout.  If a deadlock timeout is canceled, any active statement timeout
- * remains in force.
- *
- * Returns TRUE if okay, FALSE on failure.
- */
-bool
-disable_sig_alarm(bool is_statement_timeout)
-{
-	/*
-	 * Always disable the interrupt if it is active; this avoids being
-	 * interrupted by the signal handler and thereby possibly getting
-	 * confused.
-	 *
-	 * We will re-enable the interrupt if necessary in CheckStatementTimeout.
-	 */
-	if (statement_timeout_active || deadlock_timeout_active)
-	{
-		struct itimerval timeval;
-
-		MemSet(&timeval, 0, sizeof(struct itimerval));
-		if (setitimer(ITIMER_REAL, &timeval, NULL))
-		{
-			statement_timeout_active = false;
-			cancel_from_timeout = false;
-			deadlock_timeout_active = false;
-			return false;
-		}
-	}
-
-	/* Always cancel deadlock timeout, in case this is error cleanup */
-	deadlock_timeout_active = false;
-
-	/* Cancel or reschedule statement timeout */
-	if (is_statement_timeout)
-	{
-		statement_timeout_active = false;
-		cancel_from_timeout = false;
-	}
-	else if (statement_timeout_active)
-	{
-		if (!CheckStatementTimeout())
-			return false;
-	}
-	return true;
-}
-
-
 /*
  * Check for statement timeout.  If the timeout time has come,
- * trigger a query-cancel interrupt; if not, reschedule the SIGALRM
- * interrupt to occur at the right time.
- *
- * Returns true if okay, false if failed to set the interrupt.
+ * trigger a query-cancel interrupt.
  */
-static bool
-CheckStatementTimeout(void)
+void
+StatementTimeoutHandler(void)
 {
-	TimestampTz now;
-
-	if (!statement_timeout_active)
-		return true;			/* do nothing if not active */
-
-	now = GetCurrentTimestamp();
-
-	if (now >= statement_fin_time)
-	{
-		/* Time to die */
-		statement_timeout_active = false;
-		cancel_from_timeout = true;
 #ifdef HAVE_SETSID
-		/* try to signal whole process group */
-		kill(-MyProcPid, SIGINT);
+	/* try to signal whole process group */
+	kill(-MyProcPid, SIGINT);
 #endif
-		kill(MyProcPid, SIGINT);
-	}
-	else
-	{
-		/* Not time yet, so (re)schedule the interrupt */
-		long		secs;
-		int			usecs;
-		struct itimerval timeval;
-
-		TimestampDifference(now, statement_fin_time,
-							&secs, &usecs);
-
-		/*
-		 * It's possible that the difference is less than a microsecond;
-		 * ensure we don't cancel, rather than set, the interrupt.
-		 */
-		if (secs == 0 && usecs == 0)
-			usecs = 1;
-		MemSet(&timeval, 0, sizeof(struct itimerval));
-		timeval.it_value.tv_sec = secs;
-		timeval.it_value.tv_usec = usecs;
-		if (setitimer(ITIMER_REAL, &timeval, NULL))
-			return false;
-	}
-
-	return true;
+	kill(MyProcPid, SIGINT);
 }
 
-
 /*
- * Signal handler for SIGALRM for normal user backends
- *
- * Process deadlock check and/or statement timeout check, as needed.
- * To avoid various edge cases, we must be careful to do nothing
- * when there is nothing to be done.  We also need to be able to
- * reschedule the timer interrupt if called before end of statement.
+ * StandbyDeadLockHandler() will trigger if the deadlock timeout
+ * happens earlier than StandbyTimeout. If it triggers,
+ * StandbyTimeout will still be rescheduled.
  */
 void
-handle_sig_alarm(SIGNAL_ARGS)
+StandbyDeadLockHandler(void)
 {
-	int			save_errno = errno;
-
-	/* SIGALRM is cause for waking anything waiting on the process latch */
-	if (MyProc)
-		SetLatch(&MyProc->procLatch);
-
-	if (deadlock_timeout_active)
-	{
-		deadlock_timeout_active = false;
-		CheckDeadLock();
-	}
-
-	if (statement_timeout_active)
-		(void) CheckStatementTimeout();
-
-	errno = save_errno;
-}
-
-/*
- * Signal handler for SIGALRM in Startup process
- *
- * To avoid various edge cases, we must be careful to do nothing
- * when there is nothing to be done.  We also need to be able to
- * reschedule the timer interrupt if called before end of statement.
- *
- * We set either deadlock_timeout_active or statement_timeout_active
- * or both. Interrupts are enabled if standby_timeout_active.
- */
-bool
-enable_standby_sig_alarm(TimestampTz now, TimestampTz fin_time, bool deadlock_only)
-{
-	TimestampTz deadlock_time = TimestampTzPlusMilliseconds(now,
-															DeadlockTimeout);
-
-	if (deadlock_only)
-	{
-		/*
-		 * Wake up at deadlock_time only, then wait forever
-		 */
-		statement_fin_time = deadlock_time;
-		deadlock_timeout_active = true;
-		statement_timeout_active = false;
-	}
-	else if (fin_time > deadlock_time)
-	{
-		/*
-		 * Wake up at deadlock_time, then again at fin_time
-		 */
-		statement_fin_time = deadlock_time;
-		statement_fin_time2 = fin_time;
-		deadlock_timeout_active = true;
-		statement_timeout_active = true;
-	}
-	else
-	{
-		/*
-		 * Wake only at fin_time because its fairly soon
-		 */
-		statement_fin_time = fin_time;
-		deadlock_timeout_active = false;
-		statement_timeout_active = true;
-	}
-
-	if (deadlock_timeout_active || statement_timeout_active)
-	{
-		long		secs;
-		int			usecs;
-		struct itimerval timeval;
-
-		TimestampDifference(now, statement_fin_time,
-							&secs, &usecs);
-		if (secs == 0 && usecs == 0)
-			usecs = 1;
-		MemSet(&timeval, 0, sizeof(struct itimerval));
-		timeval.it_value.tv_sec = secs;
-		timeval.it_value.tv_usec = usecs;
-		if (setitimer(ITIMER_REAL, &timeval, NULL))
-			return false;
-		standby_timeout_active = true;
-	}
-
-	return true;
-}
-
-bool
-disable_standby_sig_alarm(void)
-{
-	/*
-	 * Always disable the interrupt if it is active; this avoids being
-	 * interrupted by the signal handler and thereby possibly getting
-	 * confused.
-	 *
-	 * We will re-enable the interrupt if necessary in CheckStandbyTimeout.
-	 */
-	if (standby_timeout_active)
-	{
-		struct itimerval timeval;
-
-		MemSet(&timeval, 0, sizeof(struct itimerval));
-		if (setitimer(ITIMER_REAL, &timeval, NULL))
-		{
-			standby_timeout_active = false;
-			return false;
-		}
-	}
-
-	standby_timeout_active = false;
-
-	return true;
+	SendRecoveryConflictWithBufferPin(PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK);
 }
 
 /*
- * CheckStandbyTimeout() runs unconditionally in the Startup process
+ * StandbyTimeoutHandler() runs unconditionally in the Startup process
  * SIGALRM handler. Timers will only be set when InHotStandby.
  * We simply ignore any signals unless the timer has been set.
  */
-static bool
-CheckStandbyTimeout(void)
-{
-	TimestampTz now;
-	bool		reschedule = false;
-
-	standby_timeout_active = false;
-
-	now = GetCurrentTimestamp();
-
-	/*
-	 * Reschedule the timer if its not time to wake yet, or if we have both
-	 * timers set and the first one has just been reached.
-	 */
-	if (now >= statement_fin_time)
-	{
-		if (deadlock_timeout_active)
-		{
-			/*
-			 * We're still waiting when we reach deadlock timeout, so send out
-			 * a request to have other backends check themselves for deadlock.
-			 * Then continue waiting until statement_fin_time, if that's set.
-			 */
-			SendRecoveryConflictWithBufferPin(PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK);
-			deadlock_timeout_active = false;
-
-			/*
-			 * Begin second waiting period if required.
-			 */
-			if (statement_timeout_active)
-			{
-				reschedule = true;
-				statement_fin_time = statement_fin_time2;
-			}
-		}
-		else
-		{
-			/*
-			 * We've now reached statement_fin_time, so ask all conflicts to
-			 * leave, so we can press ahead with applying changes in recovery.
-			 */
-			SendRecoveryConflictWithBufferPin(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN);
-		}
-	}
-	else
-		reschedule = true;
-
-	if (reschedule)
-	{
-		long		secs;
-		int			usecs;
-		struct itimerval timeval;
-
-		TimestampDifference(now, statement_fin_time,
-							&secs, &usecs);
-		if (secs == 0 && usecs == 0)
-			usecs = 1;
-		MemSet(&timeval, 0, sizeof(struct itimerval));
-		timeval.it_value.tv_sec = secs;
-		timeval.it_value.tv_usec = usecs;
-		if (setitimer(ITIMER_REAL, &timeval, NULL))
-			return false;
-		standby_timeout_active = true;
-	}
-
-	return true;
-}
-
 void
-handle_standby_sig_alarm(SIGNAL_ARGS)
+StandbyTimeoutHandler(void)
 {
-	int			save_errno = errno;
-
-	if (standby_timeout_active)
-		(void) CheckStandbyTimeout();
-
-	errno = save_errno;
+	SendRecoveryConflictWithBufferPin(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN);
 }
diff --git a/src/backend/storage/lmgr/timeout.c b/src/backend/storage/lmgr/timeout.c
new file mode 100644
index 0000000..de1bb09
--- /dev/null
+++ b/src/backend/storage/lmgr/timeout.c
@@ -0,0 +1,432 @@
+/*-------------------------------------------------------------------------
+ *
+ * timeout.c
+ *	  routines to manage timeout sources handled by SIGALRM
+ *
+ * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/backend/storage/lmgr/timeout.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include <sys/time.h>
+
+#include "storage/proc.h"
+#include "storage/timeout.h"
+#include "utils/timestamp.h"
+
+
+static void InitTimeout(TimeoutName tn, TimestampTz start_time,
+			TimestampTz fin_time);
+static void DestroyTimeout(TimeoutName tn, bool keep_indicator);
+
+typedef struct timeout_params
+{
+	TimeoutName		index;
+	bool			resched_next;
+
+	/* volatile because it may be changed from the signal handler */
+	volatile bool	indicator;
+
+	timeout_func	timeout_func;
+	timeout_start	timeout_start;
+
+	TimestampTz		start_time;
+	TimestampTz		fin_time;
+} timeout_params;
+
+/*
+ * List of possible timeout reasons in the order of enum TimeoutName.
+ * The priority of timeouts (in case two of them would trigger at the
+ * same time) is determined by this order: the earlier one in the list
+ * has higher priority. InitializeBackend() and PostgresMain() initialize
+ * this array and register timeout sources.
+ */
+static bool base_timeouts_initialized = false;
+static timeout_params base_timeouts[TIMEOUT_MAX];
+
+/*
+ * List of active timeouts ordered by their fin_time and priority.
+ */
+static int		NumActiveTimeouts = 0;
+static timeout_params *ActiveTimeouts[TIMEOUT_MAX];
+
+/*****************************************************************************
+ * Internal helper functions
+ *****************************************************************************/
+
+/*
+ * Find the index of a given timeout type in the active array
+ */
+static int
+find_active_timeout(TimeoutName tn)
+{
+	int		i;
+
+	for (i = 0; i < NumActiveTimeouts; i++)
+	{
+		if (ActiveTimeouts[i]->index == tn)
+			return i;
+	}
+
+	return -1;
+}
+
+#define is_timeout_active(tn)	(find_active_timeout(tn) >= 0)
+
+/*
+ * Insert tn'th timeout into the list of timeouts at the given index
+ * if the previous timeout allows rescheduling the next one in the list.
+ */
+static void
+insert_timeout(TimeoutName tn, int index)
+{
+	int	i;
+
+	if (index < 0 || index > NumActiveTimeouts)
+		elog(FATAL, "timeout index %d out of range 0..%d", index,
+			 NumActiveTimeouts);
+
+	if (index > 0 && !ActiveTimeouts[index - 1]->resched_next)
+		return;
+
+	for (i = NumActiveTimeouts - 1; i >= index; i--)
+		ActiveTimeouts[i + 1] = ActiveTimeouts[i];
+
+	ActiveTimeouts[index] = &base_timeouts[tn];
+	NumActiveTimeouts++;
+}
+
+/*
+ * Remove the index'th element from the timeout list.
+ */
+static void
+remove_timeout_index(int index)
+{
+	int		i;
+
+	if (index < 0 || index > NumActiveTimeouts)
+		elog(FATAL, "timeout index %d out of range 0..%d", index,
+			 NumActiveTimeouts);
+
+	for (i = index + 1; i < NumActiveTimeouts; i++)
+		ActiveTimeouts[i - 1] = ActiveTimeouts[i];
+
+	if (NumActiveTimeouts > 0 && index < NumActiveTimeouts)
+		NumActiveTimeouts--;
+}
+
+/*
+ * (Re)schedule alarm for the next active timeout
+ */
+static void
+schedule_alarm(TimestampTz now)
+{
+	long		secs;
+	int			usecs;
+	struct itimerval timeval;
+
+	/* There is no active timeout, do nothing. */
+	if (NumActiveTimeouts == 0)
+		return;
+
+	TimestampDifference(now, ActiveTimeouts[0]->fin_time,
+						&secs, &usecs);
+
+	/*
+	 * It's possible that the difference is less than a microsecond;
+	 * ensure we don't cancel, rather than set, the interrupt.
+	 */
+	if (secs == 0 && usecs == 0)
+		usecs = 1;
+
+	MemSet(&timeval, 0, sizeof(struct itimerval));
+	timeval.it_value.tv_sec = secs;
+	timeval.it_value.tv_usec = usecs;
+	if (setitimer(ITIMER_REAL, &timeval, NULL) != 0)
+		elog(FATAL, "could not enable timer");
+}
+
+/*****************************************************************************
+ * Init and Destroy functions
+ *****************************************************************************/
+
+static void
+InitTimeout(TimeoutName tn, TimestampTz start_time, TimestampTz fin_time)
+{
+	base_timeouts[tn].indicator = false;
+	base_timeouts[tn].start_time = start_time;
+	base_timeouts[tn].fin_time = fin_time;
+}
+
+static void
+DestroyTimeout(TimeoutName tn, bool keep_indicator)
+{
+	if (!keep_indicator)
+		base_timeouts[tn].indicator = false;
+	base_timeouts[tn].start_time = 0;
+	base_timeouts[tn].fin_time = 0;
+}
+
+/*****************************************************************************
+ * Public API
+ *****************************************************************************/
+
+/*
+ * Initialize timeout module.
+ *
+ * This must be called on every process that wants to use timeouts.
+ */
+void
+InitializeTimeouts(void)
+{
+	int	i;
+
+	if (base_timeouts_initialized)
+	{
+		elog(PANIC, "timeouts already initialized");
+		return;
+	}
+
+	for (i = 0; i < TIMEOUT_MAX; i++)
+	{
+		base_timeouts[i].index = i;
+		base_timeouts[i].resched_next = false;
+		base_timeouts[i].indicator = false;
+		base_timeouts[i].timeout_func = NULL;
+		base_timeouts[i].timeout_start = NULL;
+		base_timeouts[i].start_time = 0;
+		base_timeouts[i].fin_time = 0;
+	}
+
+	base_timeouts_initialized = true;
+}
+
+/*
+ * Register a timeout source
+ */
+TimeoutName
+RegisterTimeout(TimeoutName tn, bool resched_next,
+	   			timeout_func func, timeout_start start)
+{
+	Assert(base_timeouts_initialized);
+	Assert(base_timeouts[tn].timeout_func == NULL);
+
+	if (tn < 0)
+	{
+		for (tn = USER_TIMEOUT; tn < TIMEOUT_MAX; tn++)
+			if (base_timeouts[tn].timeout_func == NULL)
+				break;
+		if (tn >= TIMEOUT_MAX)
+			ereport(FATAL,
+					(errcode(ERRCODE_CONFIGURATION_LIMIT_EXCEEDED),
+					 errmsg("cannot add more timeout sources")));
+	}
+
+	base_timeouts[tn].resched_next = resched_next;
+	base_timeouts[tn].timeout_func = func;
+	base_timeouts[tn].timeout_start = start;
+
+	return tn;
+}
+
+/*
+ * Enable the SIGALRM interrupt to fire after the specified delay
+ *
+ * Delay is given in milliseconds. Caller should be sure a SIGALRM
+ * signal handler is installed before this is called.
+ *
+ * This code properly handles nesting of different timeout alarms.
+ */
+void
+enable_timeout(TimeoutName tn, int delayms)
+{
+	TimestampTz start_time;
+	TimestampTz fin_time;
+	int		i;
+
+	Assert(base_timeouts_initialized);
+	Assert(base_timeouts[tn].timeout_func != NULL);
+	Assert(!is_timeout_active(tn));
+
+	if (delayms <= 0)
+		return;
+
+	start_time = base_timeouts[tn].timeout_start();
+	fin_time = TimestampTzPlusMilliseconds(start_time, delayms);
+
+	/* Find out the index where to insert the new timeout. */
+	for (i = 0; i < NumActiveTimeouts; i++)
+	{
+		/*
+		 * The new timeout triggers earlier than a previously added one:
+		 * insert here.
+		 */
+		if (fin_time < ActiveTimeouts[i]->fin_time)
+			break;
+		/*
+		 * The new timeout triggers at the same time as the previously added
+		 * one but has greater priority.
+		 */
+		if (fin_time == ActiveTimeouts[i]->fin_time &&
+			tn < ActiveTimeouts[i]->index)
+			break;
+	}
+
+	/*
+	 * Initialize the timeout parameters
+	 */
+	InitTimeout(tn, start_time, fin_time);
+
+	insert_timeout(tn, i);
+
+	/*
+	 * If the timeout was inserted in the first position, set the timer.
+	 */
+	if (i == 0)
+		schedule_alarm(start_time);
+}
+
+/*
+ * Cancel the SIGALRM timer for the specific timeout.
+ * If a timeout is canceled, any other active timeout remains in force.
+ *
+ * It's not an error to disable a timeout that is not enabled.
+ */
+void
+disable_timeout(TimeoutName tn, bool keep_indicator)
+{
+	int		i;
+
+	/*
+	 * Always disable the timer if it is active; this avoids being
+	 * interrupted by the signal handler and thereby possibly getting
+	 * confused.
+	 *
+	 * We will re-enable the interrupt if necessary later in this function.
+	 */
+	if (NumActiveTimeouts > 0)
+	{
+		struct itimerval timeval;
+
+		MemSet(&timeval, 0, sizeof(struct itimerval));
+		if (setitimer(ITIMER_REAL, &timeval, NULL) != 0)
+			elog(FATAL, "could not disable timer");
+	}
+
+	/* Find the timeout and remove from the list. */
+	i = find_active_timeout(tn);
+	if (i >= 0)
+	{
+		remove_timeout_index(i);
+		DestroyTimeout(tn, keep_indicator);
+	}
+
+	/*
+	 * Now re-enable the timer, if necessary.
+	 */
+	if (NumActiveTimeouts > 0)
+		schedule_alarm(GetCurrentTimestamp());
+}
+
+/*
+ * Disable SIGALRM and remove all timeouts from the list and
+ * reset the timeout indicators.
+ */
+void
+disable_all_timeouts(bool keep_indicators)
+{
+	struct itimerval timeval;
+	int		i;
+
+	MemSet(&timeval, 0, sizeof(struct itimerval));
+	if (setitimer(ITIMER_REAL, &timeval, NULL) != 0)
+		elog(FATAL, "could not disable timer");
+
+	NumActiveTimeouts = 0;
+	for (i = 0; i < TIMEOUT_MAX; i++)
+		DestroyTimeout(i, keep_indicators);
+}
+
+/*
+ * Return the timeout indicator
+ */
+bool
+get_timeout_indicator(TimeoutName tn)
+{
+	return base_timeouts[tn].indicator;
+}
+
+/*
+ * Return the start of the timer for this timeout
+ */
+TimestampTz
+get_timeout_start(TimeoutName tn)
+{
+	return base_timeouts[tn].start_time;
+}
+
+/*
+ * Signal handler for SIGALRM
+ *
+ * Process the check for the currently active timeout source and
+ * reschedule the next as needed. To avoid various edge cases,
+ * we must be careful to do nothing when there is nothing to be done.
+ */
+void
+handle_sig_alarm(SIGNAL_ARGS)
+{
+	int			save_errno = errno;
+
+	/*
+	 * SIGALRM is cause for waking anything waiting on the process latch.
+	 * Cope with MyProc not being there, as the startup process also uses
+	 * this signal handler.
+	 */
+	if (MyProc)
+		SetLatch(&MyProc->procLatch);
+
+	if (NumActiveTimeouts > 0)
+	{
+		TimestampTz	now;
+		bool		reschedule;
+
+		now = GetCurrentTimestamp();
+
+		/* If this timeout's time has not come yet, do nothing. */
+		if (now < ActiveTimeouts[0]->fin_time)
+			goto out;
+
+		/*
+		 * Set the trigger indicator before calling the checker function.
+		 * Setting if after may have side effects that lead to detecting
+		 * a different event, like "user pressed Ctrl-C" is detected instead
+		 * of the statement timeout having triggered.
+		 */
+		ActiveTimeouts[0]->indicator = true;
+
+		/* Call the timeout checker. */
+		ActiveTimeouts[0]->timeout_func();
+
+		/*
+		 * Remove the current timeout source and reschedule
+		 * the next if needed. Short circuit disable_timeout(..., true)
+		 * for the timeout source that just triggered.
+		 */
+		reschedule = ActiveTimeouts[0]->resched_next;
+		remove_timeout_index(0);
+
+		if (reschedule)
+			schedule_alarm(now);
+		else
+			disable_all_timeouts(true);
+	}
+
+out:
+	errno = save_errno;
+}
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 9a5438f..fde536a 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -64,6 +64,7 @@
 #include "storage/proc.h"
 #include "storage/procsignal.h"
 #include "storage/sinval.h"
+#include "storage/timeout.h"
 #include "tcop/fastpath.h"
 #include "tcop/pquery.h"
 #include "tcop/tcopprot.h"
@@ -2396,9 +2397,9 @@ start_xact_command(void)
 		/* Set statement timeout running, if any */
 		/* NB: this mustn't be enabled until we are within an xact */
 		if (StatementTimeout > 0)
-			enable_sig_alarm(StatementTimeout, true);
+			enable_timeout(STATEMENT_TIMEOUT, StatementTimeout);
 		else
-			cancel_from_timeout = false;
+			disable_timeout(STATEMENT_TIMEOUT, false);
 
 		xact_started = true;
 	}
@@ -2410,7 +2411,7 @@ finish_xact_command(void)
 	if (xact_started)
 	{
 		/* Cancel any active statement timeout before committing */
-		disable_sig_alarm(true);
+		disable_all_timeouts(false);
 
 		/* Now commit the command */
 		ereport(DEBUG3,
@@ -2891,7 +2892,7 @@ ProcessInterrupts(void)
 					(errcode(ERRCODE_QUERY_CANCELED),
 					 errmsg("canceling authentication due to timeout")));
 		}
-		if (cancel_from_timeout)
+		if (get_timeout_indicator(STATEMENT_TIMEOUT))
 		{
 			ImmediateInterruptOK = false;		/* not idle anymore */
 			DisableNotifyInterrupt();
@@ -3600,6 +3601,16 @@ PostgresMain(int argc, char *argv[], const char *username)
 		WalSndSignals();
 	else
 	{
+		/*
+		 * Register timeout sources needed by backend operation.  Note
+		 * that InitializeTimeout was already called by BackendInitialize.
+		 */
+		RegisterTimeout(DEADLOCK_TIMEOUT, true,
+						CheckDeadLock, GetCurrentTimestamp);
+		RegisterTimeout(STATEMENT_TIMEOUT, false,
+						StatementTimeoutHandler,
+						GetCurrentStatementStartTimestamp);
+
 		pqsignal(SIGHUP, SigHupHandler);		/* set flag to read config
 												 * file */
 		pqsignal(SIGINT, StatementCancelHandler);		/* cancel current query */
@@ -3802,10 +3813,10 @@ PostgresMain(int argc, char *argv[], const char *username)
 
 		/*
 		 * Forget any pending QueryCancel request, since we're returning to
-		 * the idle loop anyway, and cancel the statement timer if running.
+		 * the idle loop anyway, and cancel the timer if running.
 		 */
 		QueryCancelPending = false;
-		disable_sig_alarm(true);
+		disable_all_timeouts(false);
 		QueryCancelPending = false;		/* again in case timeout occurred */
 
 		/*
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 4d4a895..36e61cd 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -41,12 +41,12 @@
 #include "storage/fd.h"
 #include "storage/ipc.h"
 #include "storage/lmgr.h"
-#include "storage/proc.h"
 #include "storage/procarray.h"
 #include "storage/procsignal.h"
 #include "storage/proc.h"
 #include "storage/sinvaladt.h"
 #include "storage/smgr.h"
+#include "storage/timeout.h"
 #include "tcop/tcopprot.h"
 #include "utils/acl.h"
 #include "utils/fmgroids.h"
@@ -205,8 +205,7 @@ PerformAuthentication(Port *port)
 	 * during authentication.  Since we're inside a transaction and might do
 	 * database access, we have to use the statement_timeout infrastructure.
 	 */
-	if (!enable_sig_alarm(AuthenticationTimeout * 1000, true))
-		elog(FATAL, "could not set timer for authorization timeout");
+	enable_timeout(STATEMENT_TIMEOUT, AuthenticationTimeout * 1000);
 
 	/*
 	 * Now perform authentication exchange.
@@ -216,8 +215,7 @@ PerformAuthentication(Port *port)
 	/*
 	 * Done with authentication.  Disable the timeout, and log if needed.
 	 */
-	if (!disable_sig_alarm(true))
-		elog(FATAL, "could not disable timer for authorization timeout");
+	disable_timeout(STATEMENT_TIMEOUT, false);
 
 	if (Log_connections)
 	{
diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h
index 31f7099..4db90b8 100644
--- a/src/include/storage/proc.h
+++ b/src/include/storage/proc.h
@@ -222,9 +222,6 @@ extern int	DeadlockTimeout;
 extern int	StatementTimeout;
 extern bool log_lock_waits;
 
-extern volatile bool cancel_from_timeout;
-
-
 /*
  * Function Prototypes
  */
@@ -252,13 +249,10 @@ extern void LockErrorCleanup(void);
 extern void ProcWaitForSignal(void);
 extern void ProcSendSignal(int pid);
 
-extern bool enable_sig_alarm(int delayms, bool is_statement_timeout);
-extern bool disable_sig_alarm(bool is_statement_timeout);
-extern void handle_sig_alarm(SIGNAL_ARGS);
-
-extern bool enable_standby_sig_alarm(TimestampTz now,
-						 TimestampTz fin_time, bool deadlock_only);
-extern bool disable_standby_sig_alarm(void);
-extern void handle_standby_sig_alarm(SIGNAL_ARGS);
+/* Timeout handlers */
+extern void CheckDeadLock(void);
+extern void StatementTimeoutHandler(void);
+extern void StandbyDeadLockHandler(void);
+extern void StandbyTimeoutHandler(void);
 
 #endif   /* PROC_H */
diff --git a/src/include/storage/timeout.h b/src/include/storage/timeout.h
new file mode 100644
index 0000000..d430e20
--- /dev/null
+++ b/src/include/storage/timeout.h
@@ -0,0 +1,50 @@
+/*-------------------------------------------------------------------------
+ *
+ * timeout.h
+ *	  SIGALRM timeout API
+ *
+ *
+ * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/storage/timeout.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef TIMEOUT_H
+#define TIMEOUT_H
+
+#include "datatype/timestamp.h"
+
+typedef enum TimeoutName
+{
+	AUTHENTICATION_TIMEOUT,
+	DEADLOCK_TIMEOUT,
+	STATEMENT_TIMEOUT,
+	STANDBY_DEADLOCK_TIMEOUT,
+	STANDBY_TIMEOUT,
+	/* First user timeout source */
+	USER_TIMEOUT,
+	/* Maximum number of timeout sources */
+	TIMEOUT_MAX = 16
+} TimeoutName;
+
+/* timeout setup */
+typedef void (*timeout_func)(void);
+typedef TimestampTz (*timeout_start)(void);
+
+extern void InitializeTimeouts(void);
+extern TimeoutName RegisterTimeout(TimeoutName tn, bool resched_next,
+				timeout_func func, timeout_start start);
+
+/* timeout operation */
+extern void enable_timeout(TimeoutName tn, int delayms);
+extern void disable_timeout(TimeoutName tn, bool keep_indicator);
+extern void disable_all_timeouts(bool keep_indicators);
+
+/* accessors */
+extern bool get_timeout_indicator(TimeoutName tn);
+extern TimestampTz get_timeout_start(TimeoutName tn);
+extern void handle_sig_alarm(SIGNAL_ARGS);
+
+#endif /* TIMEOUT_H */
