diff -durpN postgresql/doc/src/sgml/config.sgml postgresql.1/doc/src/sgml/config.sgml
--- postgresql/doc/src/sgml/config.sgml	2012-09-18 01:53:52.102316070 +0200
+++ postgresql.1/doc/src/sgml/config.sgml	2012-09-24 21:15:32.306956142 +0200
@@ -4974,7 +4974,10 @@ COPY postgres_log FROM '/full/path/to/lo
         milliseconds, starting from the time the command arrives at the server
         from the client.  If <varname>log_min_error_statement</> is set to
         <literal>ERROR</> or lower, the statement that timed out will also be
-        logged.  A value of zero (the default) turns this off.
+        logged.  The timeout may happen any time, i.e. while waiting for locks
+        on database objects or in case of a large result set, during data
+        retrieval from the server after all locks were successfully acquired.
+        A value of zero (the default) turns this off.
        </para>
 
        <para>
@@ -4985,6 +4988,59 @@ COPY postgres_log FROM '/full/path/to/lo
       </listitem>
      </varlistentry>
 
+     <varlistentry id="guc-lock-timeout" xreflabel="lock_timeout">
+      <term><varname>lock_timeout</varname> (<type>integer</type>)</term>
+      <indexterm>
+       <primary><varname>lock_timeout</> configuration parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+        Abort any statement that tries to acquire a heavy-weight lock on rows,
+        pages, tables, indices or other objects and the lock(s) has to wait
+        more than the specified number of milliseconds. As opposed to
+        <varname>statement_timeout</>, this timeout (and the error) may only
+        occur while waiting for locks. If <varname>log_min_error_statement</>
+        is set to <literal>ERROR</> or lower, the statement that timed out will
+        also be logged. A value of zero (the default) turns this off.
+       </para>
+
+       <para>
+        Setting <varname>lock_timeout</> in
+        <filename>postgresql.conf</> is not recommended because it
+        affects all sessions.
+       </para>      
+      </listitem>   
+     </varlistentry>
+
+     <varlistentry id="guc-lock-timeout-option" xreflabel="lock_timeout_option">
+      <term><varname>lock_timeout_option</varname> (<type>enum</type>)</term>
+      <indexterm>
+       <primary><varname>lock_timeout_option</> configuration parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+        Control the behaviour of <varname>lock_timeout</>. Possible values are
+        'per_lock' and 'per_statement'.
+       </para>
+
+       <para>
+        With 'per_lock' in effect and if the statement involves more than one
+        lock, the timeout applies to every one of them individually, starting
+        from the time the server attempts to lock an object. This makes the
+        statement possibly wait for almost N * <varname>lock_timeout</> time in
+        the worst case where N is the number of locks attempted. This is the
+        default.
+       </para>
+
+       <para>
+        With 'per_statement' in effect, the time spent in waiting for locks is
+        accurately accumulated and if this exceeds the specified
+        <varname>lock_timeout</> value in milliseconds, the statement is aborted.
+       </para>
+
+      </listitem>   
+     </varlistentry>
+
      <varlistentry id="guc-vacuum-freeze-table-age" xreflabel="vacuum_freeze_table_age">
       <term><varname>vacuum_freeze_table_age</varname> (<type>integer</type>)</term>
       <indexterm>
diff -durpN postgresql/doc/src/sgml/ref/lock.sgml postgresql.1/doc/src/sgml/ref/lock.sgml
--- postgresql/doc/src/sgml/ref/lock.sgml	2012-09-18 01:53:52.106316094 +0200
+++ postgresql.1/doc/src/sgml/ref/lock.sgml	2012-09-24 15:52:18.270493958 +0200
@@ -39,8 +39,11 @@ LOCK [ TABLE ] [ ONLY ] <replaceable cla
    <literal>NOWAIT</literal> is specified, <command>LOCK
    TABLE</command> does not wait to acquire the desired lock: if it
    cannot be acquired immediately, the command is aborted and an
-   error is emitted.  Once obtained, the lock is held for the
-   remainder of the current transaction.  (There is no <command>UNLOCK
+   error is emitted. If <varname>lock_timeout</varname> is set to a value
+   higher than 0, and the lock cannot be acquired under the specified
+   timeout value in milliseconds, the command is aborted and an error
+   is emitted. Once obtained, the lock is held for the remainder of  
+   the current transaction.  (There is no <command>UNLOCK
    TABLE</command> command; locks are always released at transaction
    end.)
   </para>
diff -durpN postgresql/doc/src/sgml/ref/select.sgml postgresql.1/doc/src/sgml/ref/select.sgml
--- postgresql/doc/src/sgml/ref/select.sgml	2012-09-18 01:53:52.106316094 +0200
+++ postgresql.1/doc/src/sgml/ref/select.sgml	2012-09-24 15:52:18.271493965 +0200
@@ -1243,6 +1243,14 @@ FOR SHARE [ OF <replaceable class="param
    </para>
 
    <para>
+    If <literal>NOWAIT</> option is not specified and <varname>lock_timeout</varname>
+    is set to a value higher than 0, and the lock or statement (depending on
+    <varname>lock_timeout_option</varname>) needs to wait more than
+    the specified value in milliseconds, the command reports an error after
+    timing out, rather than waiting indefinitely.
+   </para>
+
+   <para>
     If specific tables are named in <literal>FOR UPDATE</literal>
     or <literal>FOR SHARE</literal>,
     then only rows coming from those tables are locked; any other
diff -durpN postgresql/src/backend/port/posix_sema.c postgresql.1/src/backend/port/posix_sema.c
--- postgresql/src/backend/port/posix_sema.c	2012-04-16 19:57:22.438915489 +0200
+++ postgresql.1/src/backend/port/posix_sema.c	2012-09-24 12:05:20.938923996 +0200
@@ -313,3 +313,41 @@ PGSemaphoreTryLock(PGSemaphore sema)
 
 	return true;
 }
+
+/*
+ * PGSemaphoreTimedLock
+ *
+ * Lock a semaphore (decrement count), blocking if count would be < 0
+ * until a timeout triggers. Returns true if 
+ */
+bool
+PGSemaphoreTimedLock(PGSemaphore sema, bool interruptOK,
+					TimeoutCondition condition)
+{
+	int			errStatus;
+	int			saved_errno;
+	bool			timeout;
+
+	/*
+	 * See notes in sysv_sema.c's implementation of PGSemaphoreLock. Just as
+	 * that code does for semop(), we handle both the case where sem_wait()
+	 * returns errno == EINTR after a signal, and the case where it just keeps
+	 * waiting.
+	 */
+	do
+	{
+		ImmediateInterruptOK = interruptOK;
+		CHECK_FOR_INTERRUPTS();
+		errStatus = sem_wait(PG_SEM_REF(sema));
+		saved_errno = errno;
+		ImmediateInterruptOK = false;
+		timeout = condition();
+		errno = saved_errno;
+	} while (errStatus < 0 && errno == EINTR && !timeout);
+
+	if (timeout)
+		return false;
+	if (errStatus < 0)
+		elog(FATAL, "sem_wait failed: %m");
+	return true;
+}
diff -durpN postgresql/src/backend/port/sysv_sema.c postgresql.1/src/backend/port/sysv_sema.c
--- postgresql/src/backend/port/sysv_sema.c	2012-05-14 08:20:56.284830580 +0200
+++ postgresql.1/src/backend/port/sysv_sema.c	2012-09-24 12:05:02.633797277 +0200
@@ -492,3 +492,43 @@ PGSemaphoreTryLock(PGSemaphore sema)
 
 	return true;
 }
+
+/*
+ * PGSemaphoreTimedLock
+ *
+ * Lock a semaphore (decrement count), blocking if count would be < 0
+ * until a timeout triggers.
+ */
+bool
+PGSemaphoreTimedLock(PGSemaphore sema, bool interruptOK,
+					TimeoutCondition condition)
+{
+	int			errStatus;
+	int			saved_errno;
+	bool			timeout;
+	struct sembuf sops;
+
+	sops.sem_op = -1;			/* decrement */
+	sops.sem_flg = 0;
+	sops.sem_num = sema->semNum;
+
+	/*
+	 * See notes in PGSemaphoreLock.
+	 */
+	do
+	{
+		ImmediateInterruptOK = interruptOK;
+		CHECK_FOR_INTERRUPTS();
+		errStatus = semop(sema->semId, &sops, 1);
+		saved_errno = errno;
+		ImmediateInterruptOK = false;
+		timeout = condition();
+		errno = saved_errno;
+	} while (errStatus < 0 && errno == EINTR && !timeout);
+
+	if (timeout)
+		return false;
+	if (errStatus < 0)
+		elog(FATAL, "semop(id=%d) failed: %m", sema->semId);
+	return true;
+}
diff -durpN postgresql/src/backend/port/win32_sema.c postgresql.1/src/backend/port/win32_sema.c
--- postgresql/src/backend/port/win32_sema.c	2012-06-11 06:22:48.137921483 +0200
+++ postgresql.1/src/backend/port/win32_sema.c	2012-09-24 12:06:03.523218749 +0200
@@ -209,3 +209,68 @@ PGSemaphoreTryLock(PGSemaphore sema)
 	/* keep compiler quiet */
 	return false;
 }
+
+/*
+ * PGSemaphoreTimedLock
+ *
+ * Lock a semaphore (decrement count), blocking if count would be < 0
+ * until a timeout triggers. Serve the interrupt if interruptOK is true.
+ */
+bool
+PGSemaphoreTimedLock(PGSemaphore sema, bool interruptOK,
+					TimeoutCondition condition)
+{
+	DWORD		ret;
+	HANDLE		wh[2];
+	int		saved_errno;
+	bool		timeout;
+
+	/*
+	 * Note: pgwin32_signal_event should be first to ensure that it will be
+	 * reported when multiple events are set.  We want to guarantee that
+	 * pending signals are serviced.
+	 */
+	wh[0] = pgwin32_signal_event;
+	wh[1] = *sema;
+
+	/*
+	 * As in other implementations of PGSemaphoreLock, we need to check for
+	 * cancel/die interrupts each time through the loop.  But here, there is
+	 * no hidden magic about whether the syscall will internally service a
+	 * signal --- we do that ourselves.
+	 */
+	do
+	{
+		ImmediateInterruptOK = interruptOK;
+		CHECK_FOR_INTERRUPTS();
+
+		ret = WaitForMultipleObjectsEx(2, wh, FALSE, INFINITE, TRUE);
+
+		if (ret == WAIT_OBJECT_0)
+		{
+			/* Signal event is set - we have a signal to deliver */
+			pgwin32_dispatch_queued_signals();
+			errno = EINTR;
+		}
+		else if (ret == WAIT_OBJECT_0 + 1)
+		{
+			/* We got it! */
+			errno = 0;
+		}
+		else
+			/* Otherwise we are in trouble */
+			errno = EIDRM;
+
+		saved_errno = errno;
+		ImmediateInterruptOK = false;
+		timeout = condition();
+		errno = saved_errno;
+	} while (errno == EINTR && !timeout);
+
+	if (timeout)
+		return false;
+	if (errno != 0)
+		ereport(FATAL,
+		(errmsg("could not lock semaphore: error code %lu", GetLastError())));
+	return true;
+}
diff -durpN postgresql/src/backend/postmaster/postmaster.c postgresql.1/src/backend/postmaster/postmaster.c
--- postgresql/src/backend/postmaster/postmaster.c	2012-09-22 10:28:31.103805205 +0200
+++ postgresql.1/src/backend/postmaster/postmaster.c	2012-09-24 20:51:44.769456087 +0200
@@ -3555,7 +3555,8 @@ BackendInitialize(Port *port)
 	 * since we never use it again after this function.
 	 */
 	RegisterTimeout(STARTUP_PACKET_TIMEOUT, StartupPacketTimeoutHandler);
-	enable_timeout_after(STARTUP_PACKET_TIMEOUT, AuthenticationTimeout * 1000);
+	timeout_reset_base_time(0);
+	enable_timeout_after(STARTUP_PACKET_TIMEOUT, AuthenticationTimeout * 1000, 0);
 
 	/*
 	 * Receive the startup packet (which might turn out to be a cancel request
diff -durpN postgresql/src/backend/storage/ipc/standby.c postgresql.1/src/backend/storage/ipc/standby.c
--- postgresql/src/backend/storage/ipc/standby.c	2012-07-22 16:48:48.519857712 +0200
+++ postgresql.1/src/backend/storage/ipc/standby.c	2012-09-24 22:09:13.390912893 +0200
@@ -46,6 +46,12 @@ static void LogCurrentRunningXacts(Runni
 static void LogAccessExclusiveLocks(int nlocks, xl_standby_lock *locks);
 
 
+static TimeoutMulti	timeout_multi[2] = {
+	{ STANDBY_DEADLOCK_TIMEOUT, TMPARAM_AFTER, &DeadlockTimeout, 0, false },
+	{ STANDBY_TIMEOUT, TMPARAM_AT, NULL, 0, false }
+};
+
+
 /*
  * InitRecoveryTransactionEnvironment
  *		Initialize tracking of in-progress transactions in master
@@ -404,13 +410,15 @@ ResolveRecoveryConflictWithBufferPin(voi
 
 	ltime = GetStandbyLimitTime();
 
+	timeout_reset_base_time(0);
+
 	if (ltime == 0)
 	{
 		/*
 		 * We're willing to wait forever for conflicts, so set timeout for
 		 * deadlock check only
 		 */
-		enable_timeout_after(STANDBY_DEADLOCK_TIMEOUT, DeadlockTimeout);
+		enable_timeout_after(STANDBY_DEADLOCK_TIMEOUT, DeadlockTimeout, 0);
 	}
 	else if (GetCurrentTimestamp() >= ltime)
 	{
@@ -425,8 +433,8 @@ ResolveRecoveryConflictWithBufferPin(voi
 		 * Wake up at ltime, and check for deadlocks as well if we will be
 		 * waiting longer than deadlock_timeout
 		 */
-		enable_timeout_after(STANDBY_DEADLOCK_TIMEOUT, DeadlockTimeout);
-		enable_timeout_at(STANDBY_TIMEOUT, ltime);
+		timeout_multi[1].fin_time = ltime;
+		enable_multiple_timeouts(timeout_multi, 2);
 	}
 
 	/* Wait to be signaled by UnpinBuffer() */
diff -durpN postgresql/src/backend/storage/lmgr/lock.c postgresql.1/src/backend/storage/lmgr/lock.c
--- postgresql/src/backend/storage/lmgr/lock.c	2012-08-29 09:38:57.673436501 +0200
+++ postgresql.1/src/backend/storage/lmgr/lock.c	2012-09-24 22:57:47.634131060 +0200
@@ -1458,6 +1458,7 @@ WaitOnLock(LOCALLOCK *locallock, Resourc
 	LOCKMETHODID lockmethodid = LOCALLOCK_LOCKMETHOD(*locallock);
 	LockMethod	lockMethodTable = LockMethods[lockmethodid];
 	char	   *volatile new_status = NULL;
+	int		wait_status;
 
 	LOCK_PRINT("WaitOnLock: sleeping on lock",
 			   locallock->lock, locallock->tag.mode);
@@ -1483,12 +1484,13 @@ WaitOnLock(LOCALLOCK *locallock, Resourc
 	/*
 	 * NOTE: Think not to put any shared-state cleanup after the call to
 	 * ProcSleep, in either the normal or failure path.  The lock state must
-	 * be fully set by the lock grantor, or by CheckDeadLock if we give up
-	 * waiting for the lock.  This is necessary because of the possibility
-	 * that a cancel/die interrupt will interrupt ProcSleep after someone else
-	 * grants us the lock, but before we've noticed it. Hence, after granting,
-	 * the locktable state must fully reflect the fact that we own the lock;
-	 * we can't do additional work on return.
+	 * be fully set by the lock grantor, or by CheckDeadLock or by ProcSleep
+	 * itself in case a timeout is detected or if we give up waiting for the lock.
+	 * This is necessary because of the possibility that a cancel/die interrupt
+	 * will interrupt ProcSleep after someone else grants us the lock, but
+	 * before we've noticed it. Hence, after granting, the locktable state must
+	 * fully reflect the fact that we own the lock; we can't do additional work
+	 * on return.
 	 *
 	 * We can and do use a PG_TRY block to try to clean up after failure, but
 	 * this still has a major limitation: elog(FATAL) can occur while waiting
@@ -1499,8 +1501,10 @@ WaitOnLock(LOCALLOCK *locallock, Resourc
 	 */
 	PG_TRY();
 	{
-		if (ProcSleep(locallock, lockMethodTable) != STATUS_OK)
+		wait_status = ProcSleep(locallock, lockMethodTable);
+		switch (wait_status)
 		{
+		case STATUS_ERROR:
 			/*
 			 * We failed as a result of a deadlock, see CheckDeadLock(). Quit
 			 * now.
@@ -1516,6 +1520,20 @@ WaitOnLock(LOCALLOCK *locallock, Resourc
 			 */
 			DeadLockReport();
 			/* not reached */
+			break;
+
+		case STATUS_WAITING:
+			/*
+			 * We failed because of a timeout, see ProcSleep(). Quit now.
+			 */
+			ereport(ERROR,
+							(errcode(ERRCODE_QUERY_CANCELED),
+							 errmsg("canceling statement due to lock timeout")));
+			/* not reached */
+			break;
+
+		default:
+			break;
 		}
 	}
 	PG_CATCH();
@@ -1545,7 +1563,11 @@ WaitOnLock(LOCALLOCK *locallock, Resourc
 		pfree(new_status);
 	}
 
-	LOCK_PRINT("WaitOnLock: wakeup on lock",
+	if (wait_status == STATUS_OK)
+		LOCK_PRINT("WaitOnLock: wakeup on lock",
+			   locallock->lock, locallock->tag.mode);
+	else if (wait_status == STATUS_WAITING)
+		LOCK_PRINT("WaitOnLock: timeout on lock",
 			   locallock->lock, locallock->tag.mode);
 }
 
diff -durpN postgresql/src/backend/storage/lmgr/proc.c postgresql.1/src/backend/storage/lmgr/proc.c
--- postgresql/src/backend/storage/lmgr/proc.c	2012-08-30 19:45:28.889000142 +0200
+++ postgresql.1/src/backend/storage/lmgr/proc.c	2012-09-24 22:30:23.918894626 +0200
@@ -55,8 +55,15 @@
 /* GUC variables */
 int			DeadlockTimeout = 1000;
 int			StatementTimeout = 0;
+int			LockTimeout = 0;
+int			LockTimeoutOption = LOCK_TIMEOUT_PER_LOCK;
 bool		log_lock_waits = false;
 
+static TimeoutMulti	timeout_multi[2] = {
+	{ DEADLOCK_TIMEOUT, TMPARAM_AFTER, &DeadlockTimeout, 0, false },
+	{ LOCK_TIMEOUT, TMPARAM_AFTER, &LockTimeout, 0, false }
+};
+
 /* Pointer to this process's PGPROC and PGXACT structs, if any */
 PGPROC	   *MyProc = NULL;
 PGXACT	   *MyPgXact = NULL;
@@ -640,8 +647,11 @@ LockErrorCleanup(void)
 	if (lockAwaited == NULL)
 		return;
 
-	/* Turn off the deadlock timer, if it's still running (see ProcSleep) */
-	disable_timeout(DEADLOCK_TIMEOUT, false);
+	/*
+	 * Turn off the deadlock and lock timeout timers,
+	 * if they are still running (see ProcSleep).
+	 */
+	disable_multiple_timeouts(timeout_multi, 2);
 
 	/* Unlink myself from the wait queue, if on it (might not be anymore!) */
 	partitionLock = LockHashPartitionLock(lockAwaited->hashcode);
@@ -869,6 +879,16 @@ ProcQueueInit(PROC_QUEUE *queue)
 
 
 /*
+ * LockTimeoutIndicator -- passed to PGSemaphoreTimedLock()
+ */
+static bool
+LockTimeoutIndicator(void)
+{
+	return get_timeout_indicator(LOCK_TIMEOUT);
+}
+
+
+/*
  * ProcSleep -- put a process to sleep on the specified lock
  *
  * Caller must have set MyProc->heldLocks to reflect locks already held
@@ -877,7 +897,10 @@ ProcQueueInit(PROC_QUEUE *queue)
  * The lock table's partition lock must be held at entry, and will be held
  * at exit.
  *
- * Result: STATUS_OK if we acquired the lock, STATUS_ERROR if not (deadlock).
+ * Result:
+ *	STATUS_OK if we acquired the lock
+ *	STATUS_WAITING if not because of a timeout
+ *	STATUS_ERROR if not (deadlock).
  *
  * ASSUME: that no one will fiddle with the queue until after
  *		we release the partition lock.
@@ -899,6 +922,7 @@ ProcSleep(LOCALLOCK *locallock, LockMeth
 	LOCKMASK	myHeldLocks = MyProc->heldLocks;
 	bool		early_deadlock = false;
 	bool		allow_autovacuum_cancel = true;
+	bool		timeout_detected = false;
 	int			myWaitStatus;
 	PGPROC	   *proc;
 	int			i;
@@ -1027,20 +1051,52 @@ ProcSleep(LOCALLOCK *locallock, LockMeth
 	/* Reset deadlock_state before enabling the timeout handler */
 	deadlock_state = DS_NOT_YET_CHECKED;
 
+	/* Set the "now" base time for the timeouts below. */
+	timeout_reset_base_time(0);
+
 	/*
-	 * Set timer so we can wake up after awhile and check for a deadlock. If a
-	 * deadlock is detected, the handler releases the process's semaphore and
-	 * sets MyProc->waitStatus = STATUS_ERROR, allowing us to know that we
-	 * must report failure rather than success.
+	 * Set timer so:
+	 * a) we can wake up after awhile and check for a deadlock. If a
+	 *    deadlock is detected, the handler releases the process's semaphore and
+	 *    sets MyProc->waitStatus = STATUS_ERROR, allowing us to know that we
+	 *    must report failure rather than success.
+	 * b) detect lock timeout.
 	 *
-	 * By delaying the check until we've waited for a bit, we can avoid
-	 * running the rather expensive deadlock-check code in most cases.
+	 * Regarding the deadlock check, by delaying the check until we've waited
+	 * for a bit, we can avoid running the rather expensive deadlock-check code
+	 * in most cases.
 	 */
-	enable_timeout_after(DEADLOCK_TIMEOUT, DeadlockTimeout);
+	if (LockTimeout > 0)
+	{
+		if (LockTimeoutOption == LOCK_TIMEOUT_PER_LOCK)
+			timeout_multi[1].flags = TMPARAM_AFTER;
+		else
+			timeout_multi[1].flags = TMPARAM_AFTER | TMPARAM_ACCUM;
+
+		if (enable_multiple_timeouts(timeout_multi, 2))
+		{
+			/* Re-acquire the partition lock */
+			LWLockAcquire(partitionLock, LW_EXCLUSIVE);
+
+			RemoveFromWaitQueue(MyProc, hashcode);
+
+			return (get_timeout_indicator(LOCK_TIMEOUT) ?
+						STATUS_WAITING : STATUS_ERROR);
+		}
+	}
+	else if (enable_timeout_after(DEADLOCK_TIMEOUT, DeadlockTimeout, 0))
+	{
+		/* Re-acquire the partition lock */
+		LWLockAcquire(partitionLock, LW_EXCLUSIVE);
+
+		RemoveFromWaitQueue(MyProc, hashcode);
+
+		return STATUS_ERROR;
+	}
 
 	/*
-	 * If someone wakes us between LWLockRelease and PGSemaphoreLock,
-	 * PGSemaphoreLock will not block.	The wakeup is "saved" by the semaphore
+	 * If someone wakes us between LWLockRelease and PGSemaphoreTimedLock,
+	 * PGSemaphoreTimedLock will not block.	The wakeup is "saved" by the semaphore
 	 * implementation.	While this is normally good, there are cases where a
 	 * saved wakeup might be leftover from a previous operation (for example,
 	 * we aborted ProcWaitForSignal just before someone did ProcSendSignal).
@@ -1057,7 +1113,13 @@ ProcSleep(LOCALLOCK *locallock, LockMeth
 	 */
 	do
 	{
-		PGSemaphoreLock(&MyProc->sem, true);
+		timeout_detected = !PGSemaphoreTimedLock(&MyProc->sem, true,
+								LockTimeoutIndicator);
+
+		if (timeout_detected)
+			break;
+		else
+			timeout_add_accum_time(LOCK_TIMEOUT, GetCurrentTimestamp());
 
 		/*
 		 * waitStatus could change from STATUS_WAITING to something else
@@ -1203,9 +1265,9 @@ ProcSleep(LOCALLOCK *locallock, LockMeth
 	} while (myWaitStatus == STATUS_WAITING);
 
 	/*
-	 * Disable the timer, if it's still running
+	 * Disable the timers, if they are still running
 	 */
-	disable_timeout(DEADLOCK_TIMEOUT, false);
+	disable_multiple_timeouts(timeout_multi, 2);
 
 	/*
 	 * Re-acquire the lock table's partition lock.  We have to do this to hold
@@ -1215,6 +1277,15 @@ ProcSleep(LOCALLOCK *locallock, LockMeth
 	LWLockAcquire(partitionLock, LW_EXCLUSIVE);
 
 	/*
+	 * If we're in timeout, so:
+	 *	1. we're not waiting anymore and
+	 *	2. we're not the one that the lock will be granted to,
+	 * remove ourselves from the wait queue.
+	 */
+	if (timeout_detected)
+		RemoveFromWaitQueue(MyProc, hashcode);
+
+	/*
 	 * We no longer want LockErrorCleanup to do anything.
 	 */
 	lockAwaited = NULL;
@@ -1228,8 +1299,10 @@ ProcSleep(LOCALLOCK *locallock, LockMeth
 	/*
 	 * We don't have to do anything else, because the awaker did all the
 	 * necessary update of the lock table and MyProc.
+	 * RemoveFromWaitQueue() have set MyProc->waitStatus = STATUS_ERROR,
+	 * we need to distinguish this case.
 	 */
-	return MyProc->waitStatus;
+	return (timeout_detected ? STATUS_WAITING : MyProc->waitStatus);
 }
 
 
diff -durpN postgresql/src/backend/tcop/postgres.c postgresql.1/src/backend/tcop/postgres.c
--- postgresql/src/backend/tcop/postgres.c	2012-08-12 19:05:58.732948324 +0200
+++ postgresql.1/src/backend/tcop/postgres.c	2012-09-24 20:58:13.355136706 +0200
@@ -2396,8 +2396,9 @@ start_xact_command(void)
 
 		/* Set statement timeout running, if any */
 		/* NB: this mustn't be enabled until we are within an xact */
+		timeout_reset_base_time(TMPARAM_ACCUM);
 		if (StatementTimeout > 0)
-			enable_timeout_after(STATEMENT_TIMEOUT, StatementTimeout);
+			enable_timeout_after(STATEMENT_TIMEOUT, StatementTimeout, 0);
 		else
 			disable_timeout(STATEMENT_TIMEOUT, false);
 
diff -durpN postgresql/src/backend/utils/init/postinit.c postgresql.1/src/backend/utils/init/postinit.c
--- postgresql/src/backend/utils/init/postinit.c	2012-09-22 10:28:31.108805246 +0200
+++ postgresql.1/src/backend/utils/init/postinit.c	2012-09-24 22:35:46.104893799 +0200
@@ -66,6 +66,7 @@ static void PerformAuthentication(Port *
 static void CheckMyDatabase(const char *name, bool am_superuser);
 static void InitCommunication(void);
 static void ShutdownPostgres(int code, Datum arg);
+static void LockTimeoutHandler(void);
 static void StatementTimeoutHandler(void);
 static bool ThereIsAtLeastOneRole(void);
 static void process_startup_options(Port *port, bool am_superuser);
@@ -214,7 +215,8 @@ PerformAuthentication(Port *port)
 	 * during authentication.  Since we're inside a transaction and might do
 	 * database access, we have to use the statement_timeout infrastructure.
 	 */
-	enable_timeout_after(STATEMENT_TIMEOUT, AuthenticationTimeout * 1000);
+	timeout_reset_base_time(0);
+	enable_timeout_after(STATEMENT_TIMEOUT, AuthenticationTimeout * 1000, 0);
 
 	/*
 	 * Now perform authentication exchange.
@@ -509,6 +511,7 @@ InitPostgres(const char *in_dbname, Oid
 	if (!bootstrap)
 	{
 		RegisterTimeout(DEADLOCK_TIMEOUT, CheckDeadLock);
+		RegisterTimeout(LOCK_TIMEOUT, LockTimeoutHandler);
 		RegisterTimeout(STATEMENT_TIMEOUT, StatementTimeoutHandler);
 	}
 
@@ -1000,6 +1003,16 @@ ShutdownPostgres(int code, Datum arg)
 }
 
 
+/*
+ * LOCK_TIMEOUT handler: nothing to do
+ */
+static void
+LockTimeoutHandler(void)
+{
+	return;
+}
+
+
 /*
  * STATEMENT_TIMEOUT handler: trigger a query-cancel interrupt.
  */
diff -durpN postgresql/src/backend/utils/misc/guc.c postgresql.1/src/backend/utils/misc/guc.c
--- postgresql/src/backend/utils/misc/guc.c	2012-08-16 10:42:50.226582077 +0200
+++ postgresql.1/src/backend/utils/misc/guc.c	2012-09-24 15:00:05.883099276 +0200
@@ -389,6 +389,17 @@ static const struct config_enum_entry sy
 };
 
 /*
+ * Control behaviour of lock_timeout:
+ * - timeout applied per lock from the time the lock is attempted to be taken
+ * - timeout applied per statement from the time the statements has started
+ */
+static const struct config_enum_entry lock_timeout_options[] = {
+	{"per_lock", LOCK_TIMEOUT_PER_LOCK, false},
+	{"per_statement", LOCK_TIMEOUT_PER_STMT, false},
+	{NULL, 0, false}
+};
+
+/*
  * Options for enum values stored in other modules
  */
 extern const struct config_enum_entry wal_level_options[];
@@ -1861,6 +1872,17 @@ static struct config_int ConfigureNamesI
 	},
 
 	{
+		{"lock_timeout", PGC_USERSET, CLIENT_CONN_STATEMENT,
+			gettext_noop("Sets the maximum allowed timeout for any lock taken by a statement."),
+			gettext_noop("A value of 0 turns off the timeout."),
+			GUC_UNIT_MS
+		},
+		&LockTimeout,
+		0, 0, INT_MAX,
+		NULL, NULL, NULL
+	},
+
+	{
 		{"vacuum_freeze_min_age", PGC_USERSET, CLIENT_CONN_STATEMENT,
 			gettext_noop("Minimum age at which VACUUM should freeze a table row."),
 			NULL
@@ -3146,6 +3168,16 @@ static struct config_enum ConfigureNames
 		NULL, NULL, NULL
 	},
 
+	{
+		{"lock_timeout_option", PGC_USERSET, CLIENT_CONN_STATEMENT,
+			gettext_noop("Sets the lock_timeout behaviour."),
+			NULL
+		},
+		&LockTimeoutOption,
+		LOCK_TIMEOUT_PER_LOCK, lock_timeout_options,
+		NULL, NULL, NULL
+	},
+
 	{
 		{"log_error_verbosity", PGC_SUSET, LOGGING_WHAT,
 			gettext_noop("Sets the verbosity of logged messages."),
diff -durpN postgresql/src/backend/utils/misc/postgresql.conf.sample postgresql.1/src/backend/utils/misc/postgresql.conf.sample
--- postgresql/src/backend/utils/misc/postgresql.conf.sample	2012-08-16 10:42:50.227582083 +0200
+++ postgresql.1/src/backend/utils/misc/postgresql.conf.sample	2012-09-24 15:00:56.090427660 +0200
@@ -529,6 +529,11 @@
 #------------------------------------------------------------------------------
 
 #deadlock_timeout = 1s
+#lock_timeout = 0			# timeout value for heavy-weight locks
+					# taken by statements. 0 disables timeout
+					# unit in milliseconds, default is 0
+#lock_timeout_option = 'per_lock'	# behaviour of lock_timeout. possible
+					# values are: 'per_lock' or 'per_statement'
 #max_locks_per_transaction = 64		# min 10
 					# (change requires restart)
 # Note:  Each lock table slot uses ~270 bytes of shared memory, and there are
diff -durpN postgresql/src/backend/utils/misc/timeout.c postgresql.1/src/backend/utils/misc/timeout.c
--- postgresql/src/backend/utils/misc/timeout.c	2012-07-22 16:48:48.535857816 +0200
+++ postgresql.1/src/backend/utils/misc/timeout.c	2012-09-24 22:55:45.185365037 +0200
@@ -35,6 +35,8 @@ typedef struct timeout_params
 
 	TimestampTz start_time;		/* time that timeout was last activated */
 	TimestampTz fin_time;		/* if active, time it is due to fire */
+	long		accum_secs;	/* accumulated time over several lock waits */
+	int		accum_usecs;
 } timeout_params;
 
 /*
@@ -50,6 +52,10 @@ static bool all_timeouts_initialized = f
 static volatile int num_active_timeouts = 0;
 static timeout_params *volatile active_timeouts[MAX_TIMEOUTS];
 
+/*
+ * Base time value for a lock wait
+ */
+static TimestampTz	timeout_start;
 
 /*****************************************************************************
  * Internal helper functions
@@ -153,6 +159,30 @@ schedule_alarm(TimestampTz now)
 	}
 }
 
+/*
+ * Disable alarm
+ *
+ * If num_active_timeouts is zero, we don't have to call setitimer.  There
+ * should not be any pending interrupt, and even if there is, the worst
+ * possible case is that the signal handler fires during schedule_alarm.
+ * (If it fires at any point before insert_timeout has incremented
+ * num_active_timeouts, it will do nothing.)  In that case we could end up
+ * scheduling a useless interrupt ... but when the interrupt does happen,
+ * the signal handler will do nothing, so it's all good.
+ */
+static void
+disable_alarm(void)
+{
+	struct itimerval timeval;
+
+	if (num_active_timeouts > 0)
+	{
+		MemSet(&timeval, 0, sizeof(struct itimerval));
+		if (setitimer(ITIMER_REAL, &timeval, NULL) != 0)
+			elog(FATAL, "could not disable SIGALRM timer: %m");
+	}
+}
+
 
 /*****************************************************************************
  * Signal handler
@@ -243,6 +273,8 @@ InitializeTimeouts(void)
 		all_timeouts[i].timeout_handler = NULL;
 		all_timeouts[i].start_time = 0;
 		all_timeouts[i].fin_time = 0;
+		all_timeouts[i].accum_secs = 0;
+		all_timeouts[i].accum_usecs = 0;
 	}
 
 	all_timeouts_initialized = true;
@@ -284,12 +316,52 @@ RegisterTimeout(TimeoutId id, timeout_ha
 }
 
 /*
+ * Set timeout base time and optionally reset the accumulated time
+ * for timeouts.
+ */
+void
+timeout_reset_base_time(int flags)
+{
+	timeout_start = GetCurrentTimestamp();
+
+	if (flags & TMPARAM_ACCUM)
+	{
+		int	i;
+
+		for (i = 0; i < MAX_TIMEOUTS; i++)
+		{
+			all_timeouts[i].accum_secs = 0;
+			all_timeouts[i].accum_usecs = 0;
+		}
+	}
+}
+
+
+/*
+ * Accumulate time spent in waiting for the specified timeout.
+ */
+void timeout_add_accum_time(TimeoutId id, TimestampTz now)
+{
+	long	secs;
+	int	usecs;
+
+	TimestampDifference(all_timeouts[id].start_time, now, &secs, &usecs);
+	all_timeouts[id].accum_secs += secs;
+	all_timeouts[id].accum_usecs = usecs;
+	while (all_timeouts[id].accum_usecs > 1000000)
+	{
+		all_timeouts[id].accum_usecs -= 1000000;
+		all_timeouts[id].accum_secs++;
+	}
+}
+
+
+/*
  * Enable the specified timeout reason
  */
 static void
 enable_timeout(TimeoutId id, TimestampTz now, TimestampTz fin_time)
 {
-	struct itimerval timeval;
 	int			i;
 
 	/* Assert request is sane */
@@ -297,26 +369,6 @@ enable_timeout(TimeoutId id, TimestampTz
 	Assert(all_timeouts[id].timeout_handler != NULL);
 
 	/*
-	 * Disable the timer if it is active; this avoids getting interrupted by
-	 * the signal handler and thereby possibly getting confused.  We will
-	 * re-enable the interrupt below.
-	 *
-	 * If num_active_timeouts is zero, we don't have to call setitimer.  There
-	 * should not be any pending interrupt, and even if there is, the worst
-	 * possible case is that the signal handler fires during schedule_alarm.
-	 * (If it fires at any point before insert_timeout has incremented
-	 * num_active_timeouts, it will do nothing.)  In that case we could end up
-	 * scheduling a useless interrupt ... but when the interrupt does happen,
-	 * the signal handler will do nothing, so it's all good.
-	 */
-	if (num_active_timeouts > 0)
-	{
-		MemSet(&timeval, 0, sizeof(struct itimerval));
-		if (setitimer(ITIMER_REAL, &timeval, NULL) != 0)
-			elog(FATAL, "could not disable SIGALRM timer: %m");
-	}
-
-	/*
 	 * If this timeout was already active, momentarily disable it.	We
 	 * interpret the call as a directive to reschedule the timeout.
 	 */
@@ -345,41 +397,153 @@ enable_timeout(TimeoutId id, TimestampTz
 	all_timeouts[id].start_time = now;
 	all_timeouts[id].fin_time = fin_time;
 	insert_timeout(id, i);
-
-	/*
-	 * Set the timer.
-	 */
-	schedule_alarm(now);
 }
 
 /*
- * Enable the specified timeout to fire after the specified delay.
+ * Enable the specified timeout to fire after the specified delay
+ * from the given base time. Subtract the accumulated time if the
+ * TMPARAM_ACCUM flag is given. Requires the "now" base times to be
+ * recently set. 
  *
  * Delay is given in milliseconds.
+ *
+ * Returns true if the timeout is to trigger in the past and indicate
+ * that the timeout has triggered. Leave previously set timeouts scheduled.
  */
-void
-enable_timeout_after(TimeoutId id, int delay_ms)
+bool
+enable_timeout_after(TimeoutId id, int delay_ms, int flags)
 {
-	TimestampTz now;
 	TimestampTz fin_time;
 
-	now = GetCurrentTimestamp();
-	fin_time = TimestampTzPlusMilliseconds(now, delay_ms);
+	fin_time = TimestampTzPlusMilliseconds(timeout_start, delay_ms);
 
-	enable_timeout(id, now, fin_time);
+	if (flags & TMPARAM_ACCUM)
+		fin_time = TimestampTzPlusMicroseconds(fin_time,
+				-(all_timeouts[id].accum_secs * 1000000 + all_timeouts[id].accum_usecs));
+
+	if (fin_time < timeout_start)
+	{
+		all_timeouts[id].indicator = true;
+		return true;
+	}
+
+	/*
+	 * Disable the timer if it is active; this avoids getting interrupted by
+	 * the signal handler and thereby possibly getting confused.  We will
+	 * re-enable the interrupt below.
+	 */
+	disable_alarm();
+
+	enable_timeout(id, timeout_start, fin_time);
+
+	/*
+	 * Set the timer.
+	 */
+	schedule_alarm(timeout_start);
+
+	return false;
 }
 
 /*
  * Enable the specified timeout to fire at the specified time.
+ * Return true if the specified time is in the past and indicate
+ * the timeout has triggered. Requires the base "now" time to be
+ * recently set. Leave previously set timeouts scheduled.
  *
  * This is provided to support cases where there's a reason to calculate
  * the timeout by reference to some point other than "now".  If there isn't,
  * use enable_timeout_after(), to avoid calling GetCurrentTimestamp() twice.
  */
-void
+bool
 enable_timeout_at(TimeoutId id, TimestampTz fin_time)
 {
-	enable_timeout(id, GetCurrentTimestamp(), fin_time);
+	if (fin_time < timeout_start)
+	{
+		all_timeouts[id].indicator = true;
+		return true;
+	}
+
+	/*
+	 * Disable the timer if it is active; this avoids getting interrupted by
+	 * the signal handler and thereby possibly getting confused.  We will
+	 * re-enable the interrupt below.
+	 */
+	disable_alarm();
+
+	enable_timeout(id, timeout_start, fin_time);
+
+	/*
+	 * Set the timer.
+	 */
+	schedule_alarm(timeout_start);
+
+	return false;
+}
+
+/*
+ * Enable multiple timeouts at once. Requires the "now" base
+ * time to be recently set. The TimeoutMulti.flags field
+ * may contain the following combinations:
+ *	TMPARAM_AFTER
+ *	TMPARAM_AFTER | TMPARAM_ACCUM
+ *	TMPARAM_AT
+ * These work like calling enable_timeout_after() w/ or w/o TMPARAM_ACCUM
+ * or enable_timeout_at() separately. This is provided to minimize the number
+ * of setitimer() calls.
+ *
+ * The *param array contains parameters for n timeouts.
+ */
+bool
+enable_multiple_timeouts(TimeoutMulti *timeouts, int n)
+{
+	int	i;
+
+	/*
+	 * Disable the timer if it is active; this avoids getting interrupted by
+	 * the signal handler and thereby possibly getting confused.  We will
+	 * re-enable the interrupt below.
+	 */
+	disable_alarm();
+
+	for (i = 0; i < n; i++)
+	{
+		TimeoutId	id = timeouts[i].id;
+
+		if (timeouts[i].flags & TMPARAM_AFTER)
+		{
+			timeouts[i].fin_time = TimestampTzPlusMilliseconds(timeout_start, *timeouts[i].delay_ms);
+
+			if (timeouts[i].flags & TMPARAM_ACCUM)
+				timeouts[i].fin_time = TimestampTzPlusMicroseconds(timeouts[i].fin_time,
+								-(all_timeouts[id].accum_secs * 1000000 + all_timeouts[id].accum_usecs));
+
+			if (timeouts[i].fin_time < timeout_start)
+			{
+				all_timeouts[id].indicator = true;
+				schedule_alarm(timeout_start);
+				return true;
+			}
+		}
+		else /* TMPARAM_AT */
+		{
+			if (timeouts[i].fin_time < timeout_start)
+			{
+				all_timeouts[id].indicator = true;
+				schedule_alarm(timeout_start);
+				return true;
+			}
+		}
+	}
+
+	for (i = 0; i < n; i++)
+		enable_timeout(timeouts[i].id, timeout_start, timeouts[i].fin_time);
+
+	/*
+	 * Set the timer.
+	 */
+	schedule_alarm(timeout_start);
+
+	return false;
 }
 
 /*
@@ -394,29 +558,13 @@ enable_timeout_at(TimeoutId id, Timestam
 void
 disable_timeout(TimeoutId id, bool keep_indicator)
 {
-	struct itimerval timeval;
 	int			i;
 
 	/* Assert request is sane */
 	Assert(all_timeouts_initialized);
 	Assert(all_timeouts[id].timeout_handler != NULL);
 
-	/*
-	 * Disable the timer if it is active; this avoids getting interrupted by
-	 * the signal handler and thereby possibly getting confused.  We will
-	 * re-enable the interrupt if necessary below.
-	 *
-	 * If num_active_timeouts is zero, we don't have to call setitimer.  There
-	 * should not be any pending interrupt, and even if there is, the signal
-	 * handler will not do anything.  In this situation the only thing we
-	 * really have to do is reset the timeout's indicator.
-	 */
-	if (num_active_timeouts > 0)
-	{
-		MemSet(&timeval, 0, sizeof(struct itimerval));
-		if (setitimer(ITIMER_REAL, &timeval, NULL) != 0)
-			elog(FATAL, "could not disable SIGALRM timer: %m");
-	}
+	disable_alarm();
 
 	/* Find the timeout and remove it from the active list. */
 	i = find_active_timeout(id);
@@ -429,6 +577,48 @@ disable_timeout(TimeoutId id, bool keep_
 
 	/* Now re-enable the timer, if necessary. */
 	if (num_active_timeouts > 0)
+		schedule_alarm(GetCurrentTimestamp());
+}
+
+/*
+ * Cancel the specified timeouts at once.
+ *
+ * The timeouts' I've-been-fired indicator are reset,
+ * unless ->keep_indicator is true.
+ *
+ * After cancelling the specified timeouts, any other active timeout
+ * remains in force. It's not an error to disable a timeout that is
+ * not enabled.
+ */
+void
+disable_multiple_timeouts(TimeoutMulti *timeouts, int n)
+{
+	int			i, idx;
+
+	/* Assert request is sane */
+	Assert(all_timeouts_initialized);
+	for (i = 0; i < n; i++)
+	{
+		Assert(all_timeouts[timeouts[i].id].timeout_handler != NULL);
+	}
+
+	disable_alarm();
+
+	for (i = 0; i < n; i++)
+	{
+		TimeoutId	id = timeouts[i].id;
+		/* Find the timeout and remove it from the active list. */
+		idx = find_active_timeout(id);
+		if (idx >= 0)
+			remove_timeout_index(idx);
+
+		/* Mark it inactive, whether it was active or not. */
+		if (!timeouts[i].keep_indicator)
+			all_timeouts[id].indicator = false;
+	}
+
+	/* Now re-enable the timer, if necessary. */
+	if (num_active_timeouts > 0)
 		schedule_alarm(GetCurrentTimestamp());
 }
 
diff -durpN postgresql/src/include/storage/pg_sema.h postgresql.1/src/include/storage/pg_sema.h
--- postgresql/src/include/storage/pg_sema.h	2012-04-16 19:57:22.672918205 +0200
+++ postgresql.1/src/include/storage/pg_sema.h	2012-09-24 14:33:35.158742314 +0200
@@ -61,6 +61,7 @@ typedef HANDLE PGSemaphoreData;
 
 typedef PGSemaphoreData *PGSemaphore;
 
+typedef bool (*TimeoutCondition)(void);
 
 /* Module initialization (called during postmaster start or shmem reinit) */
 extern void PGReserveSemaphores(int maxSemas, int port);
@@ -80,4 +81,8 @@ extern void PGSemaphoreUnlock(PGSemaphor
 /* Lock a semaphore only if able to do so without blocking */
 extern bool PGSemaphoreTryLock(PGSemaphore sema);
 
+/* Lock a semaphore (decrement count), blocking if count would be < 0 with timeout */
+extern bool PGSemaphoreTimedLock(PGSemaphore sema, bool interruptOK,
+						TimeoutCondition condition);
+
 #endif   /* PG_SEMA_H */
diff -durpN postgresql/src/include/storage/proc.h postgresql.1/src/include/storage/proc.h
--- postgresql/src/include/storage/proc.h	2012-07-22 16:48:48.548857900 +0200
+++ postgresql.1/src/include/storage/proc.h	2012-09-24 14:29:49.775238328 +0200
@@ -219,8 +219,15 @@ extern PGPROC *PreparedXactProcs;
 /* configurable options */
 extern int	DeadlockTimeout;
 extern int	StatementTimeout;
+extern int	LockTimeout;
+extern int	LockTimeoutOption;
 extern bool log_lock_waits;
 
+typedef enum LockTimeoutOptions {
+	LOCK_TIMEOUT_PER_LOCK,
+	LOCK_TIMEOUT_PER_STMT
+} LockTimeoutOptions;
+
 
 /*
  * Function Prototypes
diff -durpN postgresql/src/include/utils/timeout.h postgresql.1/src/include/utils/timeout.h
--- postgresql/src/include/utils/timeout.h	2012-07-22 16:48:48.549857907 +0200
+++ postgresql.1/src/include/utils/timeout.h	2012-09-24 22:22:50.028052456 +0200
@@ -25,6 +25,7 @@ typedef enum TimeoutId
 	/* Predefined timeout reasons */
 	STARTUP_PACKET_TIMEOUT,
 	DEADLOCK_TIMEOUT,
+	LOCK_TIMEOUT,
 	STATEMENT_TIMEOUT,
 	STANDBY_DEADLOCK_TIMEOUT,
 	STANDBY_TIMEOUT,
@@ -34,6 +35,38 @@ typedef enum TimeoutId
 	MAX_TIMEOUTS = 16
 } TimeoutId;
 
+/*
+ * Flags for timeout_reset_base_time(), enable_timeout_after() and
+ * (in TimeoutMulti.flags) enable_multiple_timeouts()
+ *
+ * Meaningful combinations:
+ * - for timeout_reset_base_time:
+ *                 0 - set only the base time
+ *     TMPARAM_ACCUM - set the base time and reset all accumulated time
+ * - for enable_timeout_after:
+ *                 0 - use base time
+ *     TMPARAM_ACCUM - use base time minus accumulated time
+ * - for enable_multiple_timeouts in TimeoutMulti.flags:
+ *     TMPARAM_AFTER - use the delay_ms and base time as is
+ *     (TMPARAM_AFTER|TMPARAM_ACCUM)
+ *                   - use the delay_ms and base time minus accumulated time
+ *     TMPARAM_AT    - use fin_time as is
+ */
+#define TMPARAM_AFTER		(1)
+#define TMPARAM_AT		(2)
+#define TMPARAM_ACCUM		(4)
+
+/*
+ * Structure for setting multiple timeouts at once
+ */
+typedef struct {
+	TimeoutId	id;
+	int		flags;
+	int		*delay_ms;
+	TimestampTz	fin_time;
+	bool		keep_indicator;
+} TimeoutMulti;
+
 /* callback function signature */
 typedef void (*timeout_handler) (void);
 
@@ -42,9 +75,13 @@ extern void InitializeTimeouts(void);
 extern TimeoutId RegisterTimeout(TimeoutId id, timeout_handler handler);
 
 /* timeout operation */
-extern void enable_timeout_after(TimeoutId id, int delay_ms);
-extern void enable_timeout_at(TimeoutId id, TimestampTz fin_time);
+extern void timeout_reset_base_time(int flags);
+extern void timeout_add_accum_time(TimeoutId id, TimestampTz now);
+extern bool enable_timeout_after(TimeoutId id, int delay_ms, int flags);
+extern bool enable_timeout_at(TimeoutId id, TimestampTz fin_time);
+extern bool enable_multiple_timeouts(TimeoutMulti *timeouts, int n);
 extern void disable_timeout(TimeoutId id, bool keep_indicator);
+extern void disable_multiple_timeouts(TimeoutMulti *timeouts, int n);
 extern void disable_all_timeouts(bool keep_indicators);
 
 /* accessors */
diff -durpN postgresql/src/include/utils/timestamp.h postgresql.1/src/include/utils/timestamp.h
--- postgresql/src/include/utils/timestamp.h	2012-09-04 11:02:05.973828607 +0200
+++ postgresql.1/src/include/utils/timestamp.h	2012-09-24 20:18:11.713597403 +0200
@@ -76,8 +76,10 @@
 
 #ifdef HAVE_INT64_TIMESTAMP
 #define TimestampTzPlusMilliseconds(tz,ms) ((tz) + ((ms) * (int64) 1000))
+#define TimestampTzPlusMicroseconds(tz,us) ((tz) + (us))
 #else
 #define TimestampTzPlusMilliseconds(tz,ms) ((tz) + ((ms) / 1000.0))
+#define TimestampTzPlusMicroseconds(tz,us) ((tz) + ((us) / 1000000.0))
 #endif
 
 
diff -durpN postgresql/src/test/regress/expected/prepared_xacts.out postgresql.1/src/test/regress/expected/prepared_xacts.out
--- postgresql/src/test/regress/expected/prepared_xacts.out	2012-04-16 19:57:22.776919413 +0200
+++ postgresql.1/src/test/regress/expected/prepared_xacts.out	2012-09-24 21:35:56.464996194 +0200
@@ -198,6 +198,22 @@ set statement_timeout to 2000;
 SELECT * FROM pxtest3;
 ERROR:  canceling statement due to statement timeout
 reset statement_timeout;
+-- pxtest3 should be locked because of the pending DROP
+set lock_timeout to 2000;
+SELECT * FROM pxtest3;
+ERROR:  canceling statement due to lock timeout
+reset lock_timeout;
+-- Test lock_timeout_option = 'per_statement' and see that
+-- statement_timeout triggers before lock_timeout if both are set.
+-- pxtest3 should be locked because of the pending DROP
+set statement_timeout to 2000;
+set lock_timeout to 2000;
+set lock_timeout_option to 'per_statement';
+SELECT * FROM pxtest3;
+ERROR:  canceling statement due to statement timeout
+reset lock_timeout;
+reset statement_timeout;
+reset lock_timeout_option;
 -- Disconnect, we will continue testing in a different backend
 \c -
 -- There should still be two prepared transactions
@@ -213,6 +229,11 @@ set statement_timeout to 2000;
 SELECT * FROM pxtest3;
 ERROR:  canceling statement due to statement timeout
 reset statement_timeout;
+-- pxtest3 should be locked because of the pending DROP
+set lock_timeout to 2000;
+SELECT * FROM pxtest3;
+ERROR:  canceling statement due to lock timeout
+reset lock_timeout;
 -- Commit table creation
 COMMIT PREPARED 'regress-one';
 \d pxtest2
diff -durpN postgresql/src/test/regress/sql/prepared_xacts.sql postgresql.1/src/test/regress/sql/prepared_xacts.sql
--- postgresql/src/test/regress/sql/prepared_xacts.sql	2012-04-16 19:57:22.796919644 +0200
+++ postgresql.1/src/test/regress/sql/prepared_xacts.sql	2012-09-24 21:04:38.420668529 +0200
@@ -126,6 +126,22 @@ set statement_timeout to 2000;
 SELECT * FROM pxtest3;
 reset statement_timeout;
 
+-- pxtest3 should be locked because of the pending DROP
+set lock_timeout to 2000;
+SELECT * FROM pxtest3;
+reset lock_timeout;
+
+-- Test lock_timeout_option = 'per_statement' and see that
+-- statement_timeout triggers before lock_timeout if both are set.
+-- pxtest3 should be locked because of the pending DROP
+set statement_timeout to 2000;
+set lock_timeout to 2000;
+set lock_timeout_option to 'per_statement';
+SELECT * FROM pxtest3;
+reset lock_timeout;
+reset statement_timeout;
+reset lock_timeout_option;
+
 -- Disconnect, we will continue testing in a different backend
 \c -
 
@@ -137,6 +153,11 @@ set statement_timeout to 2000;
 SELECT * FROM pxtest3;
 reset statement_timeout;
 
+-- pxtest3 should be locked because of the pending DROP
+set lock_timeout to 2000;
+SELECT * FROM pxtest3;
+reset lock_timeout;
+
 -- Commit table creation
 COMMIT PREPARED 'regress-one';
 \d pxtest2
