mirror of
https://github.com/postgres/postgres.git
synced 2026-04-22 22:59:54 -04:00
cleanup: Deadlock checker is no longer called from signal handler
Clean up a few leftovers from when the deadlock checker was called
from signal handler. We stopped doing that in commit 6753333f55, in
year 2015.
- CheckDeadLock can return a return value directly to the caller,
there's no need to use a global variable for that.
- Remove outdated comments that claimed that CheckDeadLock "signals
ProcSleep".
- It should be OK to ereport() from DeadLockCheck now. I considered
getting rid of InitDeadLockChecking() and moving the workspace
allocations into DeadLockCheck, but it's still good to avoid doing
the allocations while we're holding all the partition locks. So just
update the comment to give that as the reason we do the allocations
up front.
This commit is contained in:
parent
cbef472558
commit
73d60ac385
2 changed files with 20 additions and 18 deletions
|
|
@ -135,10 +135,9 @@ static PGPROC *blocking_autovacuum_proc = NULL;
|
|||
* This does per-backend initialization of the deadlock checker; primarily,
|
||||
* allocation of working memory for DeadLockCheck. We do this per-backend
|
||||
* since there's no percentage in making the kernel do copy-on-write
|
||||
* inheritance of workspace from the postmaster. We want to allocate the
|
||||
* space at startup because (a) the deadlock checker might be invoked when
|
||||
* there's no free memory left, and (b) the checker is normally run inside a
|
||||
* signal handler, which is a very dangerous place to invoke palloc from.
|
||||
* inheritance of workspace from the postmaster. We allocate the space at
|
||||
* startup because the deadlock checker is run with all the partitions of the
|
||||
* lock table locked, and we want to keep that section as short as possible.
|
||||
*/
|
||||
void
|
||||
InitDeadLockChecking(void)
|
||||
|
|
@ -213,8 +212,7 @@ InitDeadLockChecking(void)
|
|||
*
|
||||
* On failure, deadlock details are recorded in deadlockDetails[] for
|
||||
* subsequent printing by DeadLockReport(). That activity is separate
|
||||
* because (a) we don't want to do it while holding all those LWLocks,
|
||||
* and (b) we are typically invoked inside a signal handler.
|
||||
* because we don't want to do it while holding all those LWLocks.
|
||||
*/
|
||||
DeadLockState
|
||||
DeadLockCheck(PGPROC *proc)
|
||||
|
|
|
|||
|
|
@ -80,15 +80,13 @@ PROC_HDR *ProcGlobal = NULL;
|
|||
NON_EXEC_STATIC PGPROC *AuxiliaryProcs = NULL;
|
||||
PGPROC *PreparedXactProcs = NULL;
|
||||
|
||||
static DeadLockState deadlock_state = DS_NOT_YET_CHECKED;
|
||||
|
||||
/* Is a deadlock check pending? */
|
||||
static volatile sig_atomic_t got_deadlock_timeout;
|
||||
|
||||
static void RemoveProcFromArray(int code, Datum arg);
|
||||
static void ProcKill(int code, Datum arg);
|
||||
static void AuxiliaryProcKill(int code, Datum arg);
|
||||
static void CheckDeadLock(void);
|
||||
static DeadLockState CheckDeadLock(void);
|
||||
|
||||
|
||||
/*
|
||||
|
|
@ -1321,6 +1319,7 @@ ProcSleep(LOCALLOCK *locallock)
|
|||
bool allow_autovacuum_cancel = true;
|
||||
bool logged_recovery_conflict = false;
|
||||
ProcWaitStatus myWaitStatus;
|
||||
DeadLockState deadlock_state;
|
||||
|
||||
/* The caller must've armed the on-error cleanup mechanism */
|
||||
Assert(GetAwaitedLock() == locallock);
|
||||
|
|
@ -1461,7 +1460,7 @@ ProcSleep(LOCALLOCK *locallock)
|
|||
/* check for deadlocks first, as that's probably log-worthy */
|
||||
if (got_deadlock_timeout)
|
||||
{
|
||||
CheckDeadLock();
|
||||
deadlock_state = CheckDeadLock();
|
||||
got_deadlock_timeout = false;
|
||||
}
|
||||
CHECK_FOR_INTERRUPTS();
|
||||
|
|
@ -1784,14 +1783,14 @@ ProcLockWakeup(LockMethod lockMethodTable, LOCK *lock)
|
|||
*
|
||||
* We only get to this routine, if DEADLOCK_TIMEOUT fired while waiting for a
|
||||
* lock to be released by some other process. Check 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.
|
||||
* not, just return. If we have a real deadlock, remove ourselves from the
|
||||
* lock's wait queue.
|
||||
*/
|
||||
static void
|
||||
static DeadLockState
|
||||
CheckDeadLock(void)
|
||||
{
|
||||
int i;
|
||||
DeadLockState result;
|
||||
|
||||
/*
|
||||
* Acquire exclusive lock on the entire shared lock data structures. Must
|
||||
|
|
@ -1818,17 +1817,20 @@ CheckDeadLock(void)
|
|||
*/
|
||||
if (MyProc->links.prev == NULL ||
|
||||
MyProc->links.next == NULL)
|
||||
{
|
||||
result = DS_NO_DEADLOCK;
|
||||
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);
|
||||
/* Run the deadlock check */
|
||||
result = DeadLockCheck(MyProc);
|
||||
|
||||
if (deadlock_state == DS_HARD_DEADLOCK)
|
||||
if (result == DS_HARD_DEADLOCK)
|
||||
{
|
||||
/*
|
||||
* Oops. We have a deadlock.
|
||||
|
|
@ -1840,7 +1842,7 @@ CheckDeadLock(void)
|
|||
*
|
||||
* RemoveFromWaitQueue sets MyProc->waitStatus to
|
||||
* PROC_WAIT_STATUS_ERROR, so ProcSleep will report an error after we
|
||||
* return from the signal handler.
|
||||
* return.
|
||||
*/
|
||||
Assert(MyProc->waitLock != NULL);
|
||||
RemoveFromWaitQueue(MyProc, LockTagHashCode(&(MyProc->waitLock->tag)));
|
||||
|
|
@ -1867,6 +1869,8 @@ CheckDeadLock(void)
|
|||
check_done:
|
||||
for (i = NUM_LOCK_PARTITIONS; --i >= 0;)
|
||||
LWLockRelease(LockHashPartitionLockByIndex(i));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
Loading…
Reference in a new issue