1-timeout-framework-v13.patch
text/x-patch
Filename: 1-timeout-framework-v13.patch
Type: text/x-patch
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: context
Series: patch v13
| File | + | − |
|---|---|---|
| src/backend/postmaster/autovacuum.c | 2 | 1 |
| src/backend/postmaster/postmaster.c | 11 | 5 |
| src/backend/postmaster/startup.c | 14 | 1 |
| src/backend/storage/ipc/standby.c | 13 | 14 |
| src/backend/storage/lmgr/Makefile | 1 | 1 |
| src/backend/storage/lmgr/proc.c | 22 | 399 |
| src/backend/storage/lmgr/timeout.c | 448 | 0 |
| src/backend/tcop/postgres.c | 18 | 6 |
| src/backend/utils/init/postinit.c | 3 | 5 |
| src/include/storage/proc.h | 5 | 11 |
| src/include/storage/timeout.h | 46 | 0 |
diff -dcrpN postgresql/src/backend/postmaster/autovacuum.c postgresql.1/src/backend/postmaster/autovacuum.c
*** postgresql/src/backend/postmaster/autovacuum.c 2012-06-26 09:10:21.275759379 +0200
--- postgresql.1/src/backend/postmaster/autovacuum.c 2012-06-27 08:34:13.982510939 +0200
***************
*** 89,94 ****
--- 89,95 ----
#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"
*************** AutoVacLauncherMain(int argc, char *argv
*** 484,490 ****
/* Forget any pending QueryCancel request */
QueryCancelPending = false;
! disable_sig_alarm(true);
QueryCancelPending = false; /* again in case timeout occurred */
/* Report the error to the server log */
--- 485,491 ----
/* Forget any pending QueryCancel request */
QueryCancelPending = false;
! disable_all_timeouts(false);
QueryCancelPending = false; /* again in case timeout occurred */
/* Report the error to the server log */
diff -dcrpN postgresql/src/backend/postmaster/postmaster.c postgresql.1/src/backend/postmaster/postmaster.c
*** postgresql/src/backend/postmaster/postmaster.c 2012-06-26 09:10:21.277759395 +0200
--- postgresql.1/src/backend/postmaster/postmaster.c 2012-06-27 08:34:13.985510958 +0200
***************
*** 112,118 ****
#include "storage/ipc.h"
#include "storage/pg_shmem.h"
#include "storage/pmsignal.h"
! #include "storage/proc.h"
#include "tcop/tcopprot.h"
#include "utils/builtins.h"
#include "utils/datetime.h"
--- 112,118 ----
#include "storage/ipc.h"
#include "storage/pg_shmem.h"
#include "storage/pmsignal.h"
! #include "storage/timeout.h"
#include "tcop/tcopprot.h"
#include "utils/builtins.h"
#include "utils/datetime.h"
*************** BackendInitialize(Port *port)
*** 3437,3442 ****
--- 3437,3450 ----
PG_SETMASK(&StartupBlockSig);
/*
+ * Initialize timeout sources and register authentication timeout early.
+ */
+ init_timeouts();
+ register_timeout(AUTHENTICATION_TIMEOUT, false,
+ DummyTimeoutFunction,
+ GetCurrentTimestamp);
+
+ /*
* Get the remote host name and port for logging and status display.
*/
remote_host[0] = '\0';
*************** BackendInitialize(Port *port)
*** 3488,3495 ****
* 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");
/*
* Receive the startup packet (which might turn out to be a cancel request
--- 3496,3502 ----
* indefinitely. PreAuthDelay and any DNS interactions above don't count
* against the time limit.
*/
! enable_timeout(AUTHENTICATION_TIMEOUT, AuthenticationTimeout * 1000);
/*
* Receive the startup packet (which might turn out to be a cancel request
*************** BackendInitialize(Port *port)
*** 3526,3533 ****
/*
* Disable the timeout, and prevent SIGTERM/SIGQUIT again.
*/
! if (!disable_sig_alarm(false))
! elog(FATAL, "could not disable timer for startup packet timeout");
PG_SETMASK(&BlockSig);
}
--- 3533,3539 ----
/*
* Disable the timeout, and prevent SIGTERM/SIGQUIT again.
*/
! disable_timeout(AUTHENTICATION_TIMEOUT, false);
PG_SETMASK(&BlockSig);
}
diff -dcrpN postgresql/src/backend/postmaster/startup.c postgresql.1/src/backend/postmaster/startup.c
*** postgresql/src/backend/postmaster/startup.c 2012-04-16 19:57:22.442915536 +0200
--- postgresql.1/src/backend/postmaster/startup.c 2012-06-27 10:22:43.730344717 +0200
***************
*** 28,34 ****
--- 28,36 ----
#include "storage/latch.h"
#include "storage/pmsignal.h"
#include "storage/proc.h"
+ #include "storage/timeout.h"
#include "utils/guc.h"
+ #include "utils/timestamp.h"
/*
*************** StartupProcessMain(void)
*** 195,201 ****
pqsignal(SIGTERM, StartupProcShutdownHandler); /* request shutdown */
pqsignal(SIGQUIT, startupproc_quickdie); /* hard crash time */
if (EnableHotStandby)
! pqsignal(SIGALRM, handle_standby_sig_alarm); /* ignored unless
* InHotStandby */
else
pqsignal(SIGALRM, SIG_IGN);
--- 197,203 ----
pqsignal(SIGTERM, StartupProcShutdownHandler); /* request shutdown */
pqsignal(SIGQUIT, startupproc_quickdie); /* hard crash time */
if (EnableHotStandby)
! pqsignal(SIGALRM, handle_sig_alarm); /* ignored unless
* InHotStandby */
else
pqsignal(SIGALRM, SIG_IGN);
*************** StartupProcessMain(void)
*** 204,209 ****
--- 206,222 ----
pqsignal(SIGUSR2, StartupProcTriggerHandler);
/*
+ * Initialize timeouts and register timeouts needed for standby.
+ */
+ init_timeouts();
+ register_timeout(STANDBY_DEADLOCK_TIMEOUT, true,
+ StandbyDeadLockFunction,
+ GetCurrentTimestamp);
+ register_timeout(STANDBY_TIMEOUT, false,
+ StandbyTimeoutFunction,
+ GetCurrentTimestamp);
+
+ /*
* Reset some signals that are accepted by postmaster but not here
*/
pqsignal(SIGCHLD, SIG_DFL);
diff -dcrpN postgresql/src/backend/storage/ipc/standby.c postgresql.1/src/backend/storage/ipc/standby.c
*** postgresql/src/backend/storage/ipc/standby.c 2012-06-26 09:10:21.280759421 +0200
--- postgresql.1/src/backend/storage/ipc/standby.c 2012-06-27 08:34:13.986510964 +0200
***************
*** 27,32 ****
--- 27,33 ----
#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"
*************** ResolveRecoveryConflictWithLock(Oid dbOi
*** 394,400 ****
void
ResolveRecoveryConflictWithBufferPin(void)
{
- bool sig_alarm_enabled = false;
TimestampTz ltime;
TimestampTz now;
--- 395,400 ----
*************** ResolveRecoveryConflictWithBufferPin(voi
*** 409,418 ****
* 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");
}
else if (now >= ltime)
{
--- 409,415 ----
* We're willing to wait forever for conflicts, so set timeout for
* deadlock check (only)
*/
! enable_timeout(STANDBY_DEADLOCK_TIMEOUT, DeadlockTimeout);
}
else if (now >= ltime)
{
*************** ResolveRecoveryConflictWithBufferPin(voi
*** 423,446 ****
}
else
{
/*
* 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");
}
/* 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");
! }
}
void
--- 420,445 ----
}
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
*/
! 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();
! disable_all_timeouts(false);
}
void
diff -dcrpN postgresql/src/backend/storage/lmgr/Makefile postgresql.1/src/backend/storage/lmgr/Makefile
*** postgresql/src/backend/storage/lmgr/Makefile 2012-04-16 19:57:22.458915722 +0200
--- postgresql.1/src/backend/storage/lmgr/Makefile 2012-06-27 08:34:13.987510970 +0200
*************** subdir = src/backend/storage/lmgr
*** 12,18 ****
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
include $(top_srcdir)/src/backend/common.mk
--- 12,18 ----
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 timeout.o
include $(top_srcdir)/src/backend/common.mk
diff -dcrpN postgresql/src/backend/storage/lmgr/proc.c postgresql.1/src/backend/storage/lmgr/proc.c
*** postgresql/src/backend/storage/lmgr/proc.c 2012-06-26 09:10:21.282759438 +0200
--- postgresql.1/src/backend/storage/lmgr/proc.c 2012-06-27 09:21:15.411010772 +0200
***************
*** 48,53 ****
--- 48,54 ----
#include "storage/procarray.h"
#include "storage/procsignal.h"
#include "storage/spin.h"
+ #include "storage/timeout.h"
#include "utils/timestamp.h"
*************** PGPROC *PreparedXactProcs = NULL;
*** 77,103 ****
/* 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 */
!
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.
--- 78,89 ----
/* If we are waiting for a lock, this points to the associated LOCALLOCK */
static LOCALLOCK *lockAwaited = NULL;
! /* 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);
/*
* Report shared-memory space needed by InitProcGlobal.
*************** LockErrorCleanup(void)
*** 653,659 ****
return;
/* Turn off the deadlock timer, if it's still running (see ProcSleep) */
! disable_sig_alarm(false);
/* Unlink myself from the wait queue, if on it (might not be anymore!) */
partitionLock = LockHashPartitionLock(lockAwaited->hashcode);
--- 639,645 ----
return;
/* Turn off the deadlock timer, if it's still running (see ProcSleep) */
! disable_timeout(DEADLOCK_TIMEOUT, false);
/* Unlink myself from the wait queue, if on it (might not be anymore!) */
partitionLock = LockHashPartitionLock(lockAwaited->hashcode);
*************** ProcSleep(LOCALLOCK *locallock, LockMeth
*** 1048,1055 ****
* 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");
/*
* If someone wakes us between LWLockRelease and PGSemaphoreLock,
--- 1034,1040 ----
* 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(DEADLOCK_TIMEOUT, DeadlockTimeout);
/*
* If someone wakes us between LWLockRelease and PGSemaphoreLock,
*************** ProcSleep(LOCALLOCK *locallock, LockMeth
*** 1138,1144 ****
DescribeLockTag(&buf, &locallock->tag.lock);
modename = GetLockmodeName(locallock->tag.lock.locktag_lockmethodid,
lockmode);
! TimestampDifference(timeout_start_time, GetCurrentTimestamp(),
&secs, &usecs);
msecs = secs * 1000 + usecs / 1000;
usecs = usecs % 1000;
--- 1123,1130 ----
DescribeLockTag(&buf, &locallock->tag.lock);
modename = GetLockmodeName(locallock->tag.lock.locktag_lockmethodid,
lockmode);
! TimestampDifference(get_timeout_start(DEADLOCK_TIMEOUT),
! GetCurrentTimestamp(),
&secs, &usecs);
msecs = secs * 1000 + usecs / 1000;
usecs = usecs % 1000;
*************** ProcSleep(LOCALLOCK *locallock, LockMeth
*** 1200,1207 ****
/*
* Disable the timer, if it's still running
*/
! if (!disable_sig_alarm(false))
! elog(FATAL, "could not disable timer for process wakeup");
/*
* Re-acquire the lock table's partition lock. We have to do this to hold
--- 1186,1192 ----
/*
* Disable the timer, if it's still running
*/
! disable_timeout(DEADLOCK_TIMEOUT, false);
/*
* Re-acquire the lock table's partition lock. We have to do this to hold
*************** ProcLockWakeup(LockMethod lockMethodTabl
*** 1344,1350 ****
* NB: this is run inside a signal handler, so be very wary about what is done
* here or in called routines.
*/
! static void
CheckDeadLock(void)
{
int i;
--- 1329,1335 ----
* NB: this is run inside a signal handler, so be very wary about what is done
* here or in called routines.
*/
! void
CheckDeadLock(void)
{
int i;
*************** ProcSendSignal(int pid)
*** 1499,1816 ****
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.
*/
! static bool
! CheckStatementTimeout(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);
#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;
}
-
/*
! * 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.
*/
void
! handle_sig_alarm(SIGNAL_ARGS)
! {
! 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;
}
/*
--- 1484,1512 ----
PGSemaphoreUnlock(&proc->sem);
}
/*
* Check for statement timeout. If the timeout time has come,
! * trigger a query-cancel interrupt.
*/
! void
! StatementTimeoutFunction(void)
{
#ifdef HAVE_SETSID
! /* try to signal whole process group */
! kill(-MyProcPid, SIGINT);
#endif
! kill(MyProcPid, SIGINT);
}
/*
! * CheckStandbyDeadLock() will trigger if the deadlock timeout
! * happens earlier than StandbyTimeout. If it triggers,
! * StandbyTimeout will still be rescheduled.
*/
void
! StandbyDeadLockFunction(void)
{
! SendRecoveryConflictWithBufferPin(PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK);
}
/*
*************** disable_standby_sig_alarm(void)
*** 1818,1898 ****
* 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)
{
! int save_errno = errno;
!
! if (standby_timeout_active)
! (void) CheckStandbyTimeout();
!
! errno = save_errno;
}
--- 1514,1521 ----
* SIGALRM handler. Timers will only be set when InHotStandby.
* We simply ignore any signals unless the timer has been set.
*/
void
! StandbyTimeoutFunction(void)
{
! SendRecoveryConflictWithBufferPin(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN);
}
diff -dcrpN postgresql/src/backend/storage/lmgr/timeout.c postgresql.1/src/backend/storage/lmgr/timeout.c
*** postgresql/src/backend/storage/lmgr/timeout.c 1970-01-01 01:00:00.000000000 +0100
--- postgresql.1/src/backend/storage/lmgr/timeout.c 2012-06-27 09:55:21.784879822 +0200
***************
*** 0 ****
--- 1,448 ----
+ /*-------------------------------------------------------------------------
+ *
+ * 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 "access/xact.h"
+ #include "storage/proc.h"
+ #include "storage/timeout.h"
+ #include "utils/timestamp.h"
+
+ /*
+ * Infrastructure for timeouts
+ */
+
+ static void InitTimeout(TimeoutName tn, TimestampTz start_time,
+ TimestampTz fin_time);
+ static void DestroyTimeout(TimeoutName tn, bool keep_indicator);
+
+ typedef void (*timeout_func)(void);
+ typedef TimestampTz (*timeout_start)(void);
+
+ 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 n_timeouts = 0;
+ static timeout_params *timeouts[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 < n_timeouts; i++)
+ {
+ if (timeouts[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 > n_timeouts)
+ elog(FATAL, "timeout index %d out of range 0..%d", index, n_timeouts);
+
+ if (index > 0 && !timeouts[index - 1]->resched_next)
+ return;
+
+ for (i = n_timeouts - 1; i >= index; i--)
+ timeouts[i + 1] = timeouts[i];
+
+ timeouts[index] = &base_timeouts[tn];
+ n_timeouts++;
+ }
+
+ /*
+ * Remove the index'th element from the timeout list.
+ */
+ static void
+ remove_timeout_index(int index)
+ {
+ int i;
+
+ if (index < 0 || index > n_timeouts)
+ elog(FATAL, "timeout index %d out of range 0..%d", index, n_timeouts);
+
+ for (i = index + 1; i < n_timeouts; i++)
+ timeouts[i - 1] = timeouts[i];
+
+ if (n_timeouts > 0 && index < n_timeouts)
+ n_timeouts--;
+ }
+
+ /*
+ * (Re)schedule the next active timeout
+ */
+ static void
+ schedule_timeout(TimestampTz now)
+ {
+ long secs;
+ int usecs;
+ struct itimerval timeval;
+
+ /* There is no active timeout, do nothing. */
+ if (n_timeouts == 0)
+ return;
+
+ TimestampDifference(now, timeouts[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, Destroy and callback functions for different timeouts.
+ *****************************************************************************/
+
+ /*
+ * Common 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;
+ }
+
+ /*
+ * CheckDummyTimeout
+ *
+ * Do nothing. Usable for timeout sources that don't need
+ * extra processing, like authentication_timeout.
+ * The timeout indicator is set by the signal handler.
+ */
+ void
+ DummyTimeoutFunction(void)
+ {
+ return;
+ }
+
+ /*****************************************************************************
+ * Public API
+ *****************************************************************************/
+
+ /*
+ * Initialize
+ */
+ void
+ init_timeouts(void)
+ {
+ int i;
+
+ if (base_timeouts_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
+ */
+ int
+ register_timeout(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 == 0)
+ break;
+ if (tn == TIMEOUT_MAX)
+ elog(FATAL, "Cannot add more timeout source");
+ }
+
+ 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 < n_timeouts; i++)
+ {
+ /*
+ * The new timeout triggers earlier than a previously added one:
+ * insert here.
+ */
+ if (fin_time < timeouts[i]->fin_time)
+ break;
+ /*
+ * The new timeout triggers at the same time as the previously added
+ * one but has greater priority.
+ */
+ if (fin_time == timeouts[i]->fin_time && tn < timeouts[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_timeout(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 (n_timeouts > 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)
+ return;
+ remove_timeout_index(i);
+
+ /* Do cleanup. */
+ DestroyTimeout(tn, keep_indicator);
+
+ /*
+ * If the first timeout was removed from the list and there is
+ * at least one active left, reschedule it.
+ */
+ if (i == 0 && n_timeouts > 0)
+ schedule_timeout(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");
+
+ n_timeouts = 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 (n_timeouts > 0)
+ {
+ TimestampTz now;
+ bool reschedule;
+
+ now = GetCurrentTimestamp();
+
+ /* If our time has not come yet, do nothing. */
+ if (now < timeouts[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.
+ */
+ timeouts[0]->indicator = true;
+
+ /* Call the timeout checker. */
+ timeouts[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 = timeouts[0]->resched_next;
+ remove_timeout_index(0);
+
+ if (reschedule)
+ schedule_timeout(now);
+ else
+ disable_all_timeouts(true);
+ }
+
+ out:
+ errno = save_errno;
+ }
diff -dcrpN postgresql/src/backend/tcop/postgres.c postgresql.1/src/backend/tcop/postgres.c
*** postgresql/src/backend/tcop/postgres.c 2012-06-26 09:10:21.283759446 +0200
--- postgresql.1/src/backend/tcop/postgres.c 2012-06-27 10:01:22.219982497 +0200
***************
*** 64,69 ****
--- 64,70 ----
#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"
*************** start_xact_command(void)
*** 2396,2404 ****
/* 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);
else
! cancel_from_timeout = false;
xact_started = true;
}
--- 2397,2405 ----
/* Set statement timeout running, if any */
/* NB: this mustn't be enabled until we are within an xact */
if (StatementTimeout > 0)
! enable_timeout(STATEMENT_TIMEOUT, StatementTimeout);
else
! disable_timeout(STATEMENT_TIMEOUT, false);
xact_started = true;
}
*************** finish_xact_command(void)
*** 2410,2416 ****
if (xact_started)
{
/* Cancel any active statement timeout before committing */
! disable_sig_alarm(true);
/* Now commit the command */
ereport(DEBUG3,
--- 2411,2417 ----
if (xact_started)
{
/* Cancel any active statement timeout before committing */
! disable_all_timeouts(false);
/* Now commit the command */
ereport(DEBUG3,
*************** ProcessInterrupts(void)
*** 2891,2897 ****
(errcode(ERRCODE_QUERY_CANCELED),
errmsg("canceling authentication due to timeout")));
}
! if (cancel_from_timeout)
{
ImmediateInterruptOK = false; /* not idle anymore */
DisableNotifyInterrupt();
--- 2892,2898 ----
(errcode(ERRCODE_QUERY_CANCELED),
errmsg("canceling authentication due to timeout")));
}
! if (get_timeout_indicator(STATEMENT_TIMEOUT))
{
ImmediateInterruptOK = false; /* not idle anymore */
DisableNotifyInterrupt();
*************** PostgresMain(int argc, char *argv[], con
*** 3617,3622 ****
--- 3618,3634 ----
pqsignal(SIGALRM, handle_sig_alarm); /* timeout conditions */
/*
+ * Register timeout sources needed by backend operation.
+ */
+ init_timeouts();
+ register_timeout(DEADLOCK_TIMEOUT, true,
+ CheckDeadLock,
+ GetCurrentTimestamp);
+ register_timeout(STATEMENT_TIMEOUT, false,
+ StatementTimeoutFunction,
+ GetCurrentStatementStartTimestamp);
+
+ /*
* Ignore failure to write to frontend. Note: if frontend closes
* connection, we will notice it and exit cleanly when control next
* returns to outer loop. This seems safer than forcing exit in the
*************** PostgresMain(int argc, char *argv[], con
*** 3802,3811 ****
/*
* Forget any pending QueryCancel request, since we're returning to
! * the idle loop anyway, and cancel the statement timer if running.
*/
QueryCancelPending = false;
! disable_sig_alarm(true);
QueryCancelPending = false; /* again in case timeout occurred */
/*
--- 3814,3823 ----
/*
* Forget any pending QueryCancel request, since we're returning to
! * the idle loop anyway, and cancel the timer if running.
*/
QueryCancelPending = false;
! disable_all_timeouts(false);
QueryCancelPending = false; /* again in case timeout occurred */
/*
diff -dcrpN postgresql/src/backend/utils/init/postinit.c postgresql.1/src/backend/utils/init/postinit.c
*** postgresql/src/backend/utils/init/postinit.c 2012-06-26 09:10:21.287759479 +0200
--- postgresql.1/src/backend/utils/init/postinit.c 2012-06-27 08:34:13.992511002 +0200
***************
*** 41,52 ****
#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 "tcop/tcopprot.h"
#include "utils/acl.h"
#include "utils/fmgroids.h"
--- 41,52 ----
#include "storage/fd.h"
#include "storage/ipc.h"
#include "storage/lmgr.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"
*************** PerformAuthentication(Port *port)
*** 205,212 ****
* 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");
/*
* Now perform authentication exchange.
--- 205,211 ----
* during authentication. Since we're inside a transaction and might do
* database access, we have to use the statement_timeout infrastructure.
*/
! enable_timeout(STATEMENT_TIMEOUT, AuthenticationTimeout * 1000);
/*
* Now perform authentication exchange.
*************** PerformAuthentication(Port *port)
*** 216,223 ****
/*
* Done with authentication. Disable the timeout, and log if needed.
*/
! if (!disable_sig_alarm(true))
! elog(FATAL, "could not disable timer for authorization timeout");
if (Log_connections)
{
--- 215,221 ----
/*
* Done with authentication. Disable the timeout, and log if needed.
*/
! disable_timeout(STATEMENT_TIMEOUT, false);
if (Log_connections)
{
diff -dcrpN postgresql/src/include/storage/proc.h postgresql.1/src/include/storage/proc.h
*** postgresql/src/include/storage/proc.h 2012-06-26 09:10:21.316759721 +0200
--- postgresql.1/src/include/storage/proc.h 2012-06-27 09:21:57.139257370 +0200
*************** extern int DeadlockTimeout;
*** 222,230 ****
extern int StatementTimeout;
extern bool log_lock_waits;
- extern volatile bool cancel_from_timeout;
-
-
/*
* Function Prototypes
*/
--- 222,227 ----
*************** extern void LockErrorCleanup(void);
*** 252,264 ****
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);
#endif /* PROC_H */
--- 249,258 ----
extern void ProcWaitForSignal(void);
extern void ProcSendSignal(int pid);
! /* Timeout functions exported for register_timeout() */
! extern void CheckDeadLock(void);
! extern void StatementTimeoutFunction(void);
! extern void StandbyDeadLockFunction(void);
! extern void StandbyTimeoutFunction(void);
#endif /* PROC_H */
diff -dcrpN postgresql/src/include/storage/timeout.h postgresql.1/src/include/storage/timeout.h
*** postgresql/src/include/storage/timeout.h 1970-01-01 01:00:00.000000000 +0100
--- postgresql.1/src/include/storage/timeout.h 2012-06-27 09:49:16.789761575 +0200
***************
*** 0 ****
--- 1,46 ----
+ /*-------------------------------------------------------------------------
+ *
+ * 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;
+
+ typedef void (*timeout_func)(void);
+ typedef TimestampTz (*timeout_start)(void);
+
+ extern void init_timeouts(void);
+ extern int register_timeout(TimeoutName tn, bool resched_next,
+ timeout_func func, timeout_start start);
+ 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);
+ extern bool get_timeout_indicator(TimeoutName tn);
+ extern TimestampTz get_timeout_start(TimeoutName tn);
+ extern void handle_sig_alarm(SIGNAL_ARGS);
+
+ extern void DummyTimeoutFunction(void);
+
+ #endif /* _TIMEOUT_H_ */