diff -dcrpN postgresql/src/backend/postmaster/autovacuum.c postgresql.1/src/backend/postmaster/autovacuum.c *** postgresql/src/backend/postmaster/autovacuum.c 2012-04-16 19:57:22.440915512 +0200 --- postgresql.1/src/backend/postmaster/autovacuum.c 2012-05-07 19:39:07.961976453 +0200 *************** *** 86,94 **** #include "storage/ipc.h" #include "storage/latch.h" #include "storage/pmsignal.h" - #include "storage/proc.h" #include "storage/procsignal.h" #include "storage/sinvaladt.h" #include "tcop/tcopprot.h" #include "utils/fmgroids.h" #include "utils/lsyscache.h" --- 86,94 ---- #include "storage/ipc.h" #include "storage/latch.h" #include "storage/pmsignal.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 */ --- 484,490 ---- /* 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-04-23 08:28:35.641057679 +0200 --- postgresql.1/src/backend/postmaster/postmaster.c 2012-05-07 19:39:07.962976459 +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) *** 3471,3479 **** * Ready to begin client interaction. We will give up and exit(1) after a * time delay, so that a broken client can't hog a connection * 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"); /* --- 3471,3479 ---- * Ready to begin client interaction. We will give up and exit(1) after a * time delay, so that a broken client can't hog a connection * indefinitely. PreAuthDelay and any DNS interactions above don't count ! * against the time limit. Use the deadlock timeout interface. */ ! if (!enable_timeout(DEADLOCK_TIMEOUT, AuthenticationTimeout * 1000)) elog(FATAL, "could not set timer for startup packet timeout"); /* *************** BackendInitialize(Port *port) *** 3511,3517 **** /* * 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); } --- 3511,3517 ---- /* * Disable the timeout, and prevent SIGTERM/SIGQUIT again. */ ! if (!disable_timeout(DEADLOCK_TIMEOUT, false)) elog(FATAL, "could not disable timer for startup packet timeout"); 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-05-07 19:39:07.964976468 +0200 *************** *** 27,33 **** #include "storage/ipc.h" #include "storage/latch.h" #include "storage/pmsignal.h" ! #include "storage/proc.h" #include "utils/guc.h" --- 27,33 ---- #include "storage/ipc.h" #include "storage/latch.h" #include "storage/pmsignal.h" ! #include "storage/timeout.h" #include "utils/guc.h" *************** StartupProcessMain(void) *** 195,202 **** 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); pqsignal(SIGPIPE, SIG_IGN); --- 195,202 ---- 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); pqsignal(SIGPIPE, SIG_IGN); 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-05-02 17:36:48.984503204 +0200 --- postgresql.1/src/backend/storage/ipc/standby.c 2012-05-07 19:39:07.965976473 +0200 *************** *** 23,32 **** #include "miscadmin.h" #include "storage/bufmgr.h" #include "storage/lmgr.h" - #include "storage/proc.h" #include "storage/procarray.h" #include "storage/sinvaladt.h" #include "storage/standby.h" #include "utils/ps_status.h" #include "utils/timestamp.h" --- 23,32 ---- #include "miscadmin.h" #include "storage/bufmgr.h" #include "storage/lmgr.h" #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; --- 394,399 ---- *************** ResolveRecoveryConflictWithBufferPin(voi *** 409,417 **** * 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) --- 408,414 ---- * We're willing to wait forever for conflicts, so set timeout for * deadlock check (only) */ ! if (!enable_timeout(STANDBY_DEADLOCK_TIMEOUT, DeadlockTimeout)) elog(FATAL, "could not set timer for process wakeup"); } 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,447 ---- } 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_timeout(STANDBY_DEADLOCK_TIMEOUT, DeadlockTimeout)) ! elog(FATAL, "could not set timer for process wakeup"); ! ! TimestampDifference(now, ltime, &secs, &usecs); ! msecs = secs * 1000 + usecs / 1000; ! ! if (!enable_timeout(STANDBY_TIMEOUT, msecs)) elog(FATAL, "could not set timer for process wakeup"); } /* Wait to be signaled by UnpinBuffer() */ ProcWaitForSignal(); ! if (!disable_all_timeouts(false)) ! elog(FATAL, "could not disable timer for process wakeup"); } 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-05-07 19:39:07.965976473 +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-05-05 13:22:40.777667148 +0200 --- postgresql.1/src/backend/storage/lmgr/proc.c 2012-05-07 19:39:07.966976479 +0200 *************** *** 48,59 **** #include "storage/procarray.h" #include "storage/procsignal.h" #include "storage/spin.h" #include "utils/timestamp.h" /* GUC variables */ - int DeadlockTimeout = 1000; - int StatementTimeout = 0; bool log_lock_waits = false; /* Pointer to this process's PGPROC struct, if any */ --- 48,58 ---- #include "storage/procarray.h" #include "storage/procsignal.h" #include "storage/spin.h" + #include "storage/timeout.h" #include "utils/timestamp.h" /* GUC variables */ bool log_lock_waits = false; /* Pointer to this process's PGPROC struct, if any */ *************** 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. --- 76,87 ---- /* If we are waiting for a lock, this points to the associated LOCALLOCK */ static LOCALLOCK *lockAwaited = NULL; ! /* Declared in timeout.c */ ! extern 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) *** 654,660 **** 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); --- 638,644 ---- 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 *** 1049,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"); /* --- 1033,1039 ---- * 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_timeout(DEADLOCK_TIMEOUT, DeadlockTimeout)) elog(FATAL, "could not set timer for process wakeup"); /* *************** ProcSleep(LOCALLOCK *locallock, LockMeth *** 1139,1145 **** 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 *** 1201,1207 **** /* * Disable the timer, if it's still running */ ! if (!disable_sig_alarm(false)) elog(FATAL, "could not disable timer for process wakeup"); /* --- 1186,1192 ---- /* * Disable the timer, if it's still running */ ! if (!disable_timeout(DEADLOCK_TIMEOUT, false)) elog(FATAL, "could not disable timer for process wakeup"); /* *************** ProcLockWakeup(LockMethod lockMethodTabl *** 1333,1453 **** } /* - * CheckDeadLock - * - * We only get to this routine if we got SIGALRM after DeadlockTimeout - * while waiting for a lock to be released by some other process. Look - * to see if there's a deadlock; if not, just return and continue waiting. - * (But signal ProcSleep to log a message, if log_lock_waits is true.) - * If we have a real deadlock, remove ourselves from the lock's wait queue - * and signal an error to ProcSleep. - * - * 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; - - /* - * Acquire exclusive lock on the entire shared lock data structures. Must - * grab LWLocks in partition-number order to avoid LWLock deadlock. - * - * Note that the deadlock check interrupt had better not be enabled - * anywhere that this process itself holds lock partition locks, else this - * will wait forever. Also note that LWLockAcquire creates a critical - * section, so that this routine cannot be interrupted by cancel/die - * interrupts. - */ - for (i = 0; i < NUM_LOCK_PARTITIONS; i++) - LWLockAcquire(FirstLockMgrLock + i, LW_EXCLUSIVE); - - /* - * Check to see if we've been awoken by anyone in the interim. - * - * If we have, we can return and resume our transaction -- happy day. - * Before we are awoken the process releasing the lock grants it to us so - * we know that we don't have to wait anymore. - * - * We check by looking to see if we've been unlinked from the wait queue. - * This is quicker than checking our semaphore's state, since no kernel - * call is needed, and it is safe because we hold the lock partition lock. - */ - if (MyProc->links.prev == NULL || - MyProc->links.next == NULL) - goto check_done; - - #ifdef LOCK_DEBUG - if (Debug_deadlocks) - DumpAllLocks(); - #endif - - /* Run the deadlock check, and set deadlock_state for use by ProcSleep */ - deadlock_state = DeadLockCheck(MyProc); - - if (deadlock_state == DS_HARD_DEADLOCK) - { - /* - * Oops. We have a deadlock. - * - * Get this process out of wait state. (Note: we could do this more - * efficiently by relying on lockAwaited, but use this coding to - * preserve the flexibility to kill some other transaction than the - * one detecting the deadlock.) - * - * RemoveFromWaitQueue sets MyProc->waitStatus to STATUS_ERROR, so - * ProcSleep will report an error after we return from the signal - * handler. - */ - Assert(MyProc->waitLock != NULL); - RemoveFromWaitQueue(MyProc, LockTagHashCode(&(MyProc->waitLock->tag))); - - /* - * Unlock my semaphore so that the interrupted ProcSleep() call can - * finish. - */ - PGSemaphoreUnlock(&MyProc->sem); - - /* - * We're done here. Transaction abort caused by the error that - * ProcSleep will raise will cause any other locks we hold to be - * released, thus allowing other processes to wake up; we don't need - * to do that here. NOTE: an exception is that releasing locks we - * hold doesn't consider the possibility of waiters that were blocked - * behind us on the lock we just failed to get, and might now be - * wakable because we're not in front of them anymore. However, - * RemoveFromWaitQueue took care of waking up any such processes. - */ - } - else if (log_lock_waits || deadlock_state == DS_BLOCKED_BY_AUTOVACUUM) - { - /* - * Unlock my semaphore so that the interrupted ProcSleep() call can - * print the log message (we daren't do it here because we are inside - * a signal handler). It will then sleep again until someone releases - * the lock. - * - * If blocked by autovacuum, this wakeup will enable ProcSleep to send - * the canceling signal to the autovacuum worker. - */ - PGSemaphoreUnlock(&MyProc->sem); - } - - /* - * And release locks. We do this in reverse order for two reasons: (1) - * Anyone else who needs more than one of the locks will be trying to lock - * them in increasing order; we don't want to release the other process - * until it can get all the locks it needs. (2) This avoids O(N^2) - * behavior inside LWLockRelease. - */ - check_done: - for (i = NUM_LOCK_PARTITIONS; --i >= 0;) - LWLockRelease(FirstLockMgrLock + i); - } - - - /* * ProcWaitForSignal - wait for a signal from another backend. * * This can share the semaphore normally used for waiting for locks, --- 1318,1323 ---- *************** ProcSendSignal(int pid) *** 1499,1899 **** if (proc != NULL) 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; - } - - /* - * CheckStandbyTimeout() 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) - { - int save_errno = errno; - - if (standby_timeout_active) - (void) CheckStandbyTimeout(); - - errno = save_errno; - } --- 1369,1371 ---- 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-05-07 19:39:07.966976479 +0200 *************** *** 0 **** --- 1,680 ---- + /*------------------------------------------------------------------------- + * + * 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 + * + *------------------------------------------------------------------------- + */ + /* + * Interface: + * enable_timeout(), + * disable_timeout(), disable_all_timeouts() + * get_timeout_indicator(), get_timeout_start() + * and + * handle_sig_alarm() + */ + #include "postgres.h" + + #include + + #include "access/xact.h" + #include "miscadmin.h" + #include "storage/proc.h" + #include "storage/standby.h" + #include "storage/timeout.h" + #include "utils/timestamp.h" + + /* GUC variables */ + int DeadlockTimeout = 1000; + int StatementTimeout = 0; + + /* + * This is used by ProcSleep() in proc.c + * Mark this volatile because it can be changed by the signal handler. + */ + volatile DeadLockState deadlock_state = DS_NOT_YET_CHECKED; + + + /* + * Infrastructure for timeouts + */ + + static void InitDeadLock(TimestampTz start_time, TimestampTz fin_time); + static void DestroyDeadLock(bool keep_indicator); + static bool CheckDeadLock(void); + + static void InitStatementTimeout(TimestampTz start_time, TimestampTz fin_time); + static void DestroyStatementTimeout(bool keep_indicator); + static bool CheckStatementTimeout(void); + + static void InitStandbyDeadLock(TimestampTz start_time, TimestampTz fin_time); + static void DestroyStandbyDeadLock(bool keep_indicator); + static bool CheckStandbyDeadLock(void); + + static void InitStandbyTimeout(TimestampTz start_time, TimestampTz fin_time); + static void DestroyStandbyTimeout(bool keep_indicator); + static bool CheckStandbyTimeout(void); + + typedef void (*timeout_init)(TimestampTz, TimestampTz); + typedef void (*timeout_destroy)(bool); + typedef bool (*timeout_check)(void); + typedef TimestampTz (*timeout_start)(void); + + typedef struct { + TimeoutName index; + bool resched_next; + + /* volatile because it may be changed from the signal handler */ + volatile bool indicator; + + timeout_init timeout_init; + timeout_destroy timeout_destroy; + timeout_check timeout_check; + 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. + */ + static timeout_params base_timeouts[TIMEOUT_MAX] = { + { + DEADLOCK_TIMEOUT, true, false, + InitDeadLock, DestroyDeadLock, + CheckDeadLock, GetCurrentTimestamp, + 0 + }, + + { + STATEMENT_TIMEOUT, false, false, + InitStatementTimeout, DestroyStatementTimeout, + CheckStatementTimeout, GetCurrentStatementStartTimestamp, + 0 + }, + + { + STANDBY_DEADLOCK_TIMEOUT, true, false, + InitStandbyDeadLock, DestroyStandbyDeadLock, + CheckStandbyDeadLock, GetCurrentTimestamp, + 0 + }, + + { + STANDBY_TIMEOUT, false, false, + InitStandbyTimeout, DestroyStandbyTimeout, + CheckStandbyTimeout, GetCurrentTimestamp, + 0 + } + }; + + /* + * 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 && !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) + return; + + 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 bool + schedule_timeout(TimestampTz now) + { + long secs; + int usecs; + struct itimerval timeval; + + /* There is no active timeout, do nothing. */ + if (n_timeouts == 0) + return true; + + 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)) + return false; + return true; + } + + /***************************************************************************** + * Init, Destroy and Check functions for different timeouts. + * + * NB: all Check* functions are run inside a signal handler, so be very wary + * about what is done in them or in called routines. + *****************************************************************************/ + + /* + * 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; + } + + /* + * Functions to manage deadlock + */ + + static void + InitDeadLock(TimestampTz start_time, TimestampTz fin_time) + { + InitTimeout(DEADLOCK_TIMEOUT, start_time, fin_time); + } + + static void + DestroyDeadLock(bool keep_indicator) + { + DestroyTimeout(DEADLOCK_TIMEOUT, keep_indicator); + } + + /* + * CheckDeadLock + * + * Look to see if there's a deadlock; if not, just return. + * (But signal ProcSleep to log a message, if log_lock_waits is true.) + * If we have a real deadlock, remove ourselves from the lock's wait queue + * and signal an error to ProcSleep. + */ + static bool + CheckDeadLock(void) + { + TimestampTz now; + int i; + + now = GetCurrentTimestamp(); + + /* If our time has not come yet, do nothing. */ + if (now < base_timeouts[DEADLOCK_TIMEOUT].fin_time) + return false; + + /* + * Acquire exclusive lock on the entire shared lock data structures. Must + * grab LWLocks in partition-number order to avoid LWLock deadlock. + * + * Note that the deadlock check interrupt had better not be enabled + * anywhere that this process itself holds lock partition locks, else this + * will wait forever. Also note that LWLockAcquire creates a critical + * section, so that this routine cannot be interrupted by cancel/die + * interrupts. + */ + for (i = 0; i < NUM_LOCK_PARTITIONS; i++) + LWLockAcquire(FirstLockMgrLock + i, LW_EXCLUSIVE); + + /* + * Check to see if we've been awoken by anyone in the interim. + * + * If we have, we can return and resume our transaction -- happy day. + * Before we are awoken the process releasing the lock grants it to us so + * we know that we don't have to wait anymore. + * + * We check by looking to see if we've been unlinked from the wait queue. + * This is quicker than checking our semaphore's state, since no kernel + * call is needed, and it is safe because we hold the lock partition lock. + */ + if (MyProc->links.prev == NULL || + MyProc->links.next == NULL) + goto check_done; + + #ifdef LOCK_DEBUG + if (Debug_deadlocks) + DumpAllLocks(); + #endif + + /* Run the deadlock check, and set deadlock_state for use by ProcSleep */ + deadlock_state = DeadLockCheck(MyProc); + + if (deadlock_state == DS_HARD_DEADLOCK) + { + /* + * Oops. We have a deadlock. + * + * Get this process out of wait state. (Note: we could do this more + * efficiently by relying on lockAwaited, but use this coding to + * preserve the flexibility to kill some other transaction than the + * one detecting the deadlock.) + * + * RemoveFromWaitQueue sets MyProc->waitStatus to STATUS_ERROR, so + * ProcSleep will report an error after we return from the signal + * handler. + */ + Assert(MyProc->waitLock != NULL); + RemoveFromWaitQueue(MyProc, LockTagHashCode(&(MyProc->waitLock->tag))); + + /* + * Unlock my semaphore so that the interrupted ProcSleep() call can + * finish. + */ + PGSemaphoreUnlock(&MyProc->sem); + + /* + * We're done here. Transaction abort caused by the error that + * ProcSleep will raise will cause any other locks we hold to be + * released, thus allowing other processes to wake up; we don't need + * to do that here. NOTE: an exception is that releasing locks we + * hold doesn't consider the possibility of waiters that were blocked + * behind us on the lock we just failed to get, and might now be + * wakable because we're not in front of them anymore. However, + * RemoveFromWaitQueue took care of waking up any such processes. + */ + } + else if (log_lock_waits || deadlock_state == DS_BLOCKED_BY_AUTOVACUUM) + { + /* + * Unlock my semaphore so that the interrupted ProcSleep() call can + * print the log message (we daren't do it here because we are inside + * a signal handler). It will then sleep again until someone releases + * the lock. + * + * If blocked by autovacuum, this wakeup will enable ProcSleep to send + * the canceling signal to the autovacuum worker. + */ + PGSemaphoreUnlock(&MyProc->sem); + } + + /* + * And release locks. We do this in reverse order for two reasons: (1) + * Anyone else who needs more than one of the locks will be trying to lock + * them in increasing order; we don't want to release the other process + * until it can get all the locks it needs. (2) This avoids O(N^2) + * behavior inside LWLockRelease. + */ + check_done: + for (i = NUM_LOCK_PARTITIONS; --i >= 0;) + LWLockRelease(FirstLockMgrLock + i); + + base_timeouts[DEADLOCK_TIMEOUT].indicator = true; + + return true; + } + + /* + * Functions to manage statement timeout + */ + + static void + InitStatementTimeout(TimestampTz start_time, TimestampTz fin_time) + { + InitTimeout(STATEMENT_TIMEOUT, start_time, fin_time); + } + + static void + DestroyStatementTimeout(bool keep_indicator) + { + DestroyTimeout(STATEMENT_TIMEOUT, keep_indicator); + } + + static bool + CheckStatementTimeout(void) + { + TimestampTz now; + + now = GetCurrentTimestamp(); + + if (now < base_timeouts[STATEMENT_TIMEOUT].fin_time) + return false; + + base_timeouts[STATEMENT_TIMEOUT].indicator = true; + #ifdef HAVE_SETSID + /* try to signal whole process group */ + kill(-MyProcPid, SIGINT); + #endif + kill(MyProcPid, SIGINT); + + return true; + } + + /* + * Functions to manage standby deadlock functions + */ + + static void + InitStandbyDeadLock(TimestampTz start_time, TimestampTz fin_time) + { + InitTimeout(STANDBY_DEADLOCK_TIMEOUT, start_time, fin_time); + } + + static void + DestroyStandbyDeadLock(bool keep_indicator) + { + DestroyTimeout(STANDBY_DEADLOCK_TIMEOUT, keep_indicator); + } + + static bool + CheckStandbyDeadLock(void) + { + TimestampTz now; + + now = GetCurrentTimestamp(); + + if (now < base_timeouts[STANDBY_DEADLOCK_TIMEOUT].fin_time) + return false; + + base_timeouts[STANDBY_DEADLOCK_TIMEOUT].indicator = true; + SendRecoveryConflictWithBufferPin(PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK); + return true; + } + + /* + * Functions to manage standby timeout + */ + + static void + InitStandbyTimeout(TimestampTz start_time, TimestampTz fin_time) + { + InitTimeout(STANDBY_TIMEOUT, start_time, fin_time); + } + + static void + DestroyStandbyTimeout(bool keep_indicator) + { + DestroyTimeout(STANDBY_TIMEOUT, keep_indicator); + } + + static bool + CheckStandbyTimeout(void) + { + TimestampTz now; + + now = GetCurrentTimestamp(); + + if (now < base_timeouts[STANDBY_TIMEOUT].fin_time) + return false; + + base_timeouts[STANDBY_TIMEOUT].indicator = true; + SendRecoveryConflictWithBufferPin(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN); + return true; + } + + /***************************************************************************** + * Public API + *****************************************************************************/ + + + /* + * 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. + * + * Returns TRUE if okay, FALSE on failure to set the timer. + */ + bool + enable_timeout(TimeoutName tn, int delayms) + { + TimestampTz start_time; + TimestampTz fin_time; + int i; + + Assert(!is_timeout_active(tn)); + + if (delayms <= 0) + return true; + + 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 + */ + base_timeouts[tn].timeout_init(start_time, fin_time); + + insert_timeout(tn, i); + + if (i > 0) + return true; + + /* If we reach here, okay to set the timer interrupt */ + if (!schedule_timeout(start_time)) + return false; + return true; + } + + /* + * Cancel the SIGALRM timer for the specific timeout. + * If a timeout is canceled, any other active timeout remains in force. + * + * Returns TRUE if okay, FALSE on failure to set the timer for + * the next timeout source. + */ + bool + disable_timeout(TimeoutName tn, bool keep_indicator) + { + int i; + + /* + * 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 ->check_timeout(). + */ + if (n_timeouts > 0) + { + struct itimerval timeval; + + MemSet(&timeval, 0, sizeof(struct itimerval)); + if (setitimer(ITIMER_REAL, &timeval, NULL)) + { + n_timeouts = 0; + for (i = 0; i < TIMEOUT_MAX; i++) + base_timeouts[i].timeout_destroy(false); + + return false; + } + } + + /* Find the timeout and remove from the list. */ + i = find_active_timeout(tn); + remove_timeout_index(i); + + /* Do cleanup. */ + base_timeouts[tn].timeout_destroy(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) + if (!schedule_timeout(GetCurrentTimestamp())) + return false; + + return true; + } + + /* + * Disable SIGALRM and remove all timeouts from the list and + * reset the timeout indicators. + */ + bool + disable_all_timeouts(bool keep_indicators) + { + struct itimerval timeval; + int i; + bool ret; + + MemSet(&timeval, 0, sizeof(struct itimerval)); + ret = (setitimer(ITIMER_REAL, &timeval, NULL) == 0); + + n_timeouts = 0; + for (i = 0; i < TIMEOUT_MAX; i++) + base_timeouts[i].timeout_destroy(keep_indicators); + + return ret; + } + + /* + * 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. + * Recovery (the startup process) doesn't have MyProc set so + * it can also use this signal handler. + */ + if (MyProc) + SetLatch(&MyProc->procLatch); + + if (n_timeouts > 0) + { + bool ret; + bool reschedule = true; + + ret = timeouts[0]->timeout_check(); + + /* Shift timeouts if the timeout was triggered */ + if (ret) + { + reschedule = timeouts[0]->resched_next; + /* + * Short circuit disable_timeout(..., true) for the + * timeout source that just triggered. + */ + remove_timeout_index(0); + } + + if (reschedule) + schedule_timeout(GetCurrentTimestamp()); + else + disable_all_timeouts(true); + } + + 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-05-07 19:35:27.203721210 +0200 --- postgresql.1/src/backend/tcop/postgres.c 2012-05-07 19:39:07.968976493 +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 *** 3796,3805 **** /* * 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 */ /* --- 3797,3806 ---- /* * 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-04-16 19:57:22.490916093 +0200 --- postgresql.1/src/backend/utils/init/postinit.c 2012-05-07 19:39:07.968976493 +0200 *************** *** 41,51 **** #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/sinvaladt.h" #include "storage/smgr.h" #include "tcop/tcopprot.h" #include "utils/acl.h" #include "utils/fmgroids.h" --- 41,51 ---- #include "storage/fd.h" #include "storage/ipc.h" #include "storage/lmgr.h" #include "storage/procarray.h" #include "storage/procsignal.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) *** 204,210 **** * 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"); /* --- 204,210 ---- * during authentication. Since we're inside a transaction and might do * database access, we have to use the statement_timeout infrastructure. */ ! if (!enable_timeout(STATEMENT_TIMEOUT, AuthenticationTimeout * 1000)) elog(FATAL, "could not set timer for authorization timeout"); /* *************** PerformAuthentication(Port *port) *** 215,221 **** /* * 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. */ ! if (!disable_timeout(STATEMENT_TIMEOUT, false)) elog(FATAL, "could not disable timer for authorization timeout"); if (Log_connections) diff -dcrpN postgresql/src/backend/utils/misc/guc.c postgresql.1/src/backend/utils/misc/guc.c *** postgresql/src/backend/utils/misc/guc.c 2012-04-30 08:18:06.650737934 +0200 --- postgresql.1/src/backend/utils/misc/guc.c 2012-05-07 19:39:07.970976505 +0200 *************** *** 63,68 **** --- 63,69 ---- #include "storage/standby.h" #include "storage/fd.h" #include "storage/predicate.h" + #include "storage/timeout.h" #include "tcop/tcopprot.h" #include "tsearch/ts_cache.h" #include "utils/builtins.h" diff -dcrpN postgresql/src/include/storage/proc.h postgresql.1/src/include/storage/proc.h *** postgresql/src/include/storage/proc.h 2012-05-02 21:00:13.521347699 +0200 --- postgresql.1/src/include/storage/proc.h 2012-05-07 19:39:07.970976505 +0200 *************** extern PGPROC *PreparedXactProcs; *** 215,227 **** /* configurable options */ - extern int DeadlockTimeout; - extern int StatementTimeout; extern bool log_lock_waits; - extern volatile bool cancel_from_timeout; - - /* * Function Prototypes */ --- 215,222 ---- *************** extern void LockErrorCleanup(void); *** 249,261 **** 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 */ --- 244,247 ---- 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-05-07 19:39:07.971976511 +0200 *************** *** 0 **** --- 1,38 ---- + /*------------------------------------------------------------------------- + * + * 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" + + /* configurable options */ + extern int DeadlockTimeout; + extern int StatementTimeout; + + typedef enum TimeoutName { + DEADLOCK_TIMEOUT, + STATEMENT_TIMEOUT, + STANDBY_DEADLOCK_TIMEOUT, + STANDBY_TIMEOUT, + TIMEOUT_MAX + } TimeoutName; + + extern bool enable_timeout(TimeoutName tn, int delayms); + extern bool disable_timeout(TimeoutName tn, bool keep_indicator); + extern bool 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); + + #endif /* _TIMEOUT_H_ */