PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
deadlock.c File Reference
#include "postgres.h"
#include "miscadmin.h"
#include "pg_trace.h"
#include "pgstat.h"
#include "storage/lmgr.h"
#include "storage/proc.h"
#include "utils/memutils.h"
Include dependency graph for deadlock.c:

Go to the source code of this file.

Data Structures

struct  EDGE
 
struct  WAIT_ORDER
 
struct  DEADLOCK_INFO
 

Functions

static bool DeadLockCheckRecurse (PGPROC *proc)
 
static int TestConfiguration (PGPROC *startProc)
 
static bool FindLockCycle (PGPROC *checkProc, EDGE *softEdges, int *nSoftEdges)
 
static bool FindLockCycleRecurse (PGPROC *checkProc, int depth, EDGE *softEdges, int *nSoftEdges)
 
static bool FindLockCycleRecurseMember (PGPROC *checkProc, PGPROC *checkProcLeader, int depth, EDGE *softEdges, int *nSoftEdges)
 
static bool ExpandConstraints (EDGE *constraints, int nConstraints)
 
static bool TopoSort (LOCK *lock, EDGE *constraints, int nConstraints, PGPROC **ordering)
 
void InitDeadLockChecking (void)
 
DeadLockState DeadLockCheck (PGPROC *proc)
 
PGPROCGetBlockingAutoVacuumPgproc (void)
 
void DeadLockReport (void)
 
void RememberSimpleDeadLock (PGPROC *proc1, LOCKMODE lockmode, LOCK *lock, PGPROC *proc2)
 

Variables

static PGPROC ** visitedProcs
 
static int nVisitedProcs
 
static PGPROC ** topoProcs
 
static int * beforeConstraints
 
static int * afterConstraints
 
static WAIT_ORDERwaitOrders
 
static int nWaitOrders
 
static PGPROC ** waitOrderProcs
 
static EDGEcurConstraints
 
static int nCurConstraints
 
static int maxCurConstraints
 
static EDGEpossibleConstraints
 
static int nPossibleConstraints
 
static int maxPossibleConstraints
 
static DEADLOCK_INFOdeadlockDetails
 
static int nDeadlockDetails
 
static PGPROCblocking_autovacuum_proc = NULL
 

Function Documentation

DeadLockState DeadLockCheck ( PGPROC proc)

Definition at line 217 of file deadlock.c.

References Assert, DeadLockCheckRecurse(), DS_BLOCKED_BY_AUTOVACUUM, DS_HARD_DEADLOCK, DS_NO_DEADLOCK, DS_SOFT_DEADLOCK, elog, FATAL, FindLockCycle(), GetLocksMethodTable(), i, PROC_QUEUE::links, PGPROC::links, WAIT_ORDER::lock, nCurConstraints, nPossibleConstraints, WAIT_ORDER::nProcs, NULL, nWaitOrders, ProcLockWakeup(), ProcQueueInit(), WAIT_ORDER::procs, SHMQueueInsertBefore(), PROC_QUEUE::size, and LOCK::waitProcs.

Referenced by CheckDeadLock().

218 {
219  int i,
220  j;
221 
222  /* Initialize to "no constraints" */
223  nCurConstraints = 0;
225  nWaitOrders = 0;
226 
227  /* Initialize to not blocked by an autovacuum worker */
229 
230  /* Search for deadlocks and possible fixes */
231  if (DeadLockCheckRecurse(proc))
232  {
233  /*
234  * Call FindLockCycle one more time, to record the correct
235  * deadlockDetails[] for the basic state with no rearrangements.
236  */
237  int nSoftEdges;
238 
239  TRACE_POSTGRESQL_DEADLOCK_FOUND();
240 
241  nWaitOrders = 0;
242  if (!FindLockCycle(proc, possibleConstraints, &nSoftEdges))
243  elog(FATAL, "deadlock seems to have disappeared");
244 
245  return DS_HARD_DEADLOCK; /* cannot find a non-deadlocked state */
246  }
247 
248  /* Apply any needed rearrangements of wait queues */
249  for (i = 0; i < nWaitOrders; i++)
250  {
251  LOCK *lock = waitOrders[i].lock;
252  PGPROC **procs = waitOrders[i].procs;
253  int nProcs = waitOrders[i].nProcs;
254  PROC_QUEUE *waitQueue = &(lock->waitProcs);
255 
256  Assert(nProcs == waitQueue->size);
257 
258 #ifdef DEBUG_DEADLOCK
259  PrintLockQueue(lock, "DeadLockCheck:");
260 #endif
261 
262  /* Reset the queue and re-add procs in the desired order */
263  ProcQueueInit(waitQueue);
264  for (j = 0; j < nProcs; j++)
265  {
266  SHMQueueInsertBefore(&(waitQueue->links), &(procs[j]->links));
267  waitQueue->size++;
268  }
269 
270 #ifdef DEBUG_DEADLOCK
271  PrintLockQueue(lock, "rearranged to:");
272 #endif
273 
274  /* See if any waiters for the lock can be woken up now */
275  ProcLockWakeup(GetLocksMethodTable(lock), lock);
276  }
277 
278  /* Return code tells caller if we had to escape a deadlock or not */
279  if (nWaitOrders > 0)
280  return DS_SOFT_DEADLOCK;
281  else if (blocking_autovacuum_proc != NULL)
283  else
284  return DS_NO_DEADLOCK;
285 }
static WAIT_ORDER * waitOrders
Definition: deadlock.c:111
SHM_QUEUE links
Definition: lock.h:32
SHM_QUEUE links
Definition: proc.h:97
static PGPROC * blocking_autovacuum_proc
Definition: deadlock.c:128
void SHMQueueInsertBefore(SHM_QUEUE *queue, SHM_QUEUE *elem)
Definition: shmqueue.c:89
static int nCurConstraints
Definition: deadlock.c:117
static int nPossibleConstraints
Definition: deadlock.c:122
int nProcs
Definition: deadlock.c:60
PROC_QUEUE waitProcs
Definition: lock.h:294
LOCK * lock
Definition: deadlock.c:58
static bool FindLockCycle(PGPROC *checkProc, EDGE *softEdges, int *nSoftEdges)
Definition: deadlock.c:449
PGPROC ** procs
Definition: deadlock.c:59
#define FATAL
Definition: elog.h:52
void ProcQueueInit(PROC_QUEUE *queue)
Definition: proc.c:1004
Definition: lock.h:285
void ProcLockWakeup(LockMethod lockMethodTable, LOCK *lock)
Definition: proc.c:1595
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
static EDGE * possibleConstraints
Definition: deadlock.c:121
static bool DeadLockCheckRecurse(PGPROC *proc)
Definition: deadlock.c:315
int i
int size
Definition: lock.h:33
static int nWaitOrders
Definition: deadlock.c:112
#define elog
Definition: elog.h:219
Definition: proc.h:94
LockMethod GetLocksMethodTable(const LOCK *lock)
Definition: lock.c:460
static bool DeadLockCheckRecurse ( PGPROC proc)
static

Definition at line 315 of file deadlock.c.

References elog, FATAL, i, MaxBackends, maxCurConstraints, maxPossibleConstraints, nCurConstraints, nPossibleConstraints, and TestConfiguration().

Referenced by DeadLockCheck().

316 {
317  int nEdges;
318  int oldPossibleConstraints;
319  bool savedList;
320  int i;
321 
322  nEdges = TestConfiguration(proc);
323  if (nEdges < 0)
324  return true; /* hard deadlock --- no solution */
325  if (nEdges == 0)
326  return false; /* good configuration found */
328  return true; /* out of room for active constraints? */
329  oldPossibleConstraints = nPossibleConstraints;
331  {
332  /* We can save the edge list in possibleConstraints[] */
333  nPossibleConstraints += nEdges;
334  savedList = true;
335  }
336  else
337  {
338  /* Not room; will need to regenerate the edges on-the-fly */
339  savedList = false;
340  }
341 
342  /*
343  * Try each available soft edge as an addition to the configuration.
344  */
345  for (i = 0; i < nEdges; i++)
346  {
347  if (!savedList && i > 0)
348  {
349  /* Regenerate the list of possible added constraints */
350  if (nEdges != TestConfiguration(proc))
351  elog(FATAL, "inconsistent results during deadlock check");
352  }
354  possibleConstraints[oldPossibleConstraints + i];
355  nCurConstraints++;
356  if (!DeadLockCheckRecurse(proc))
357  return false; /* found a valid solution! */
358  /* give up on that added constraint, try again */
359  nCurConstraints--;
360  }
361  nPossibleConstraints = oldPossibleConstraints;
362  return true; /* no solution found */
363 }
static int maxCurConstraints
Definition: deadlock.c:118
static int nCurConstraints
Definition: deadlock.c:117
static int nPossibleConstraints
Definition: deadlock.c:122
#define FATAL
Definition: elog.h:52
int MaxBackends
Definition: globals.c:126
static int TestConfiguration(PGPROC *startProc)
Definition: deadlock.c:381
static EDGE * curConstraints
Definition: deadlock.c:116
static EDGE * possibleConstraints
Definition: deadlock.c:121
static bool DeadLockCheckRecurse(PGPROC *proc)
Definition: deadlock.c:315
int i
#define elog
Definition: elog.h:219
static int maxPossibleConstraints
Definition: deadlock.c:123
void DeadLockReport ( void  )

Definition at line 1077 of file deadlock.c.

References _, appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), StringInfoData::data, DescribeLockTag(), ereport, errcode(), errdetail_internal(), errdetail_log(), errhint(), errmsg(), ERROR, GetLockmodeName(), i, initStringInfo(), DEADLOCK_INFO::lockmode, DEADLOCK_INFO::locktag, LOCKTAG::locktag_lockmethodid, nDeadlockDetails, pgstat_get_backend_current_activity(), pgstat_report_deadlock(), DEADLOCK_INFO::pid, and resetStringInfo().

Referenced by WaitOnLock().

1078 {
1079  StringInfoData clientbuf; /* errdetail for client */
1080  StringInfoData logbuf; /* errdetail for server log */
1081  StringInfoData locktagbuf;
1082  int i;
1083 
1084  initStringInfo(&clientbuf);
1085  initStringInfo(&logbuf);
1086  initStringInfo(&locktagbuf);
1087 
1088  /* Generate the "waits for" lines sent to the client */
1089  for (i = 0; i < nDeadlockDetails; i++)
1090  {
1091  DEADLOCK_INFO *info = &deadlockDetails[i];
1092  int nextpid;
1093 
1094  /* The last proc waits for the first one... */
1095  if (i < nDeadlockDetails - 1)
1096  nextpid = info[1].pid;
1097  else
1098  nextpid = deadlockDetails[0].pid;
1099 
1100  /* reset locktagbuf to hold next object description */
1101  resetStringInfo(&locktagbuf);
1102 
1103  DescribeLockTag(&locktagbuf, &info->locktag);
1104 
1105  if (i > 0)
1106  appendStringInfoChar(&clientbuf, '\n');
1107 
1108  appendStringInfo(&clientbuf,
1109  _("Process %d waits for %s on %s; blocked by process %d."),
1110  info->pid,
1112  info->lockmode),
1113  locktagbuf.data,
1114  nextpid);
1115  }
1116 
1117  /* Duplicate all the above for the server ... */
1118  appendStringInfoString(&logbuf, clientbuf.data);
1119 
1120  /* ... and add info about query strings */
1121  for (i = 0; i < nDeadlockDetails; i++)
1122  {
1123  DEADLOCK_INFO *info = &deadlockDetails[i];
1124 
1125  appendStringInfoChar(&logbuf, '\n');
1126 
1127  appendStringInfo(&logbuf,
1128  _("Process %d: %s"),
1129  info->pid,
1131  }
1132 
1134 
1135  ereport(ERROR,
1136  (errcode(ERRCODE_T_R_DEADLOCK_DETECTED),
1137  errmsg("deadlock detected"),
1138  errdetail_internal("%s", clientbuf.data),
1139  errdetail_log("%s", logbuf.data),
1140  errhint("See server log for query details.")));
1141 }
void pgstat_report_deadlock(void)
Definition: pgstat.c:1470
int errhint(const char *fmt,...)
Definition: elog.c:987
const char * GetLockmodeName(LOCKMETHODID lockmethodid, LOCKMODE mode)
Definition: lock.c:3845
LOCKMODE lockmode
Definition: deadlock.c:74
int errcode(int sqlerrcode)
Definition: elog.c:575
int errdetail_internal(const char *fmt,...)
Definition: elog.c:900
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:110
#define ERROR
Definition: elog.h:43
void DescribeLockTag(StringInfo buf, const LOCKTAG *tag)
Definition: lmgr.c:954
static int nDeadlockDetails
Definition: deadlock.c:125
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:189
void resetStringInfo(StringInfo str)
Definition: stringinfo.c:94
int errdetail_log(const char *fmt,...)
Definition: elog.c:921
#define ereport(elevel, rest)
Definition: elog.h:122
const char * pgstat_get_backend_current_activity(int pid, bool checkUser)
Definition: pgstat.c:3851
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:201
void initStringInfo(StringInfo str)
Definition: stringinfo.c:65
static DEADLOCK_INFO * deadlockDetails
Definition: deadlock.c:124
uint8 locktag_lockmethodid
Definition: lock.h:186
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
LOCKTAG locktag
Definition: deadlock.c:73
#define _(x)
Definition: elog.c:84
static bool ExpandConstraints ( EDGE constraints,
int  nConstraints 
)
static

Definition at line 799 of file deadlock.c.

References Assert, i, EDGE::lock, WAIT_ORDER::lock, MaxBackends, WAIT_ORDER::nProcs, nWaitOrders, WAIT_ORDER::procs, PROC_QUEUE::size, TopoSort(), and LOCK::waitProcs.

Referenced by TestConfiguration().

801 {
802  int nWaitOrderProcs = 0;
803  int i,
804  j;
805 
806  nWaitOrders = 0;
807 
808  /*
809  * Scan constraint list backwards. This is because the last-added
810  * constraint is the only one that could fail, and so we want to test it
811  * for inconsistency first.
812  */
813  for (i = nConstraints; --i >= 0;)
814  {
815  LOCK *lock = constraints[i].lock;
816 
817  /* Did we already make a list for this lock? */
818  for (j = nWaitOrders; --j >= 0;)
819  {
820  if (waitOrders[j].lock == lock)
821  break;
822  }
823  if (j >= 0)
824  continue;
825  /* No, so allocate a new list */
826  waitOrders[nWaitOrders].lock = lock;
827  waitOrders[nWaitOrders].procs = waitOrderProcs + nWaitOrderProcs;
829  nWaitOrderProcs += lock->waitProcs.size;
830  Assert(nWaitOrderProcs <= MaxBackends);
831 
832  /*
833  * Do the topo sort. TopoSort need not examine constraints after this
834  * one, since they must be for different locks.
835  */
836  if (!TopoSort(lock, constraints, i + 1,
837  waitOrders[nWaitOrders].procs))
838  return false;
839  nWaitOrders++;
840  }
841  return true;
842 }
LOCK * lock
Definition: deadlock.c:50
static WAIT_ORDER * waitOrders
Definition: deadlock.c:111
int nProcs
Definition: deadlock.c:60
static PGPROC ** waitOrderProcs
Definition: deadlock.c:113
PROC_QUEUE waitProcs
Definition: lock.h:294
LOCK * lock
Definition: deadlock.c:58
PGPROC ** procs
Definition: deadlock.c:59
int MaxBackends
Definition: globals.c:126
Definition: lock.h:285
static bool TopoSort(LOCK *lock, EDGE *constraints, int nConstraints, PGPROC **ordering)
Definition: deadlock.c:871
#define Assert(condition)
Definition: c.h:675
int i
int size
Definition: lock.h:33
static int nWaitOrders
Definition: deadlock.c:112
static bool FindLockCycle ( PGPROC checkProc,
EDGE softEdges,
int *  nSoftEdges 
)
static

Definition at line 449 of file deadlock.c.

References FindLockCycleRecurse(), nDeadlockDetails, and nVisitedProcs.

Referenced by DeadLockCheck(), and TestConfiguration().

452 {
453  nVisitedProcs = 0;
454  nDeadlockDetails = 0;
455  *nSoftEdges = 0;
456  return FindLockCycleRecurse(checkProc, 0, softEdges, nSoftEdges);
457 }
static int nDeadlockDetails
Definition: deadlock.c:125
static bool FindLockCycleRecurse(PGPROC *checkProc, int depth, EDGE *softEdges, int *nSoftEdges)
Definition: deadlock.c:460
static int nVisitedProcs
Definition: deadlock.c:103
static bool FindLockCycleRecurse ( PGPROC checkProc,
int  depth,
EDGE softEdges,
int *  nSoftEdges 
)
static

Definition at line 460 of file deadlock.c.

References Assert, dlist_iter::cur, dlist_container, dlist_foreach, FindLockCycleRecurseMember(), i, PGPROC::links, PGPROC::lockGroupLeader, PGPROC::lockGroupMembers, MaxBackends, nDeadlockDetails, SHM_QUEUE::next, NULL, nVisitedProcs, and PGPROC::waitLock.

Referenced by FindLockCycle(), and FindLockCycleRecurseMember().

464 {
465  int i;
466  dlist_iter iter;
467 
468  /*
469  * If this process is a lock group member, check the leader instead. (Note
470  * that we might be the leader, in which case this is a no-op.)
471  */
472  if (checkProc->lockGroupLeader != NULL)
473  checkProc = checkProc->lockGroupLeader;
474 
475  /*
476  * Have we already seen this proc?
477  */
478  for (i = 0; i < nVisitedProcs; i++)
479  {
480  if (visitedProcs[i] == checkProc)
481  {
482  /* If we return to starting point, we have a deadlock cycle */
483  if (i == 0)
484  {
485  /*
486  * record total length of cycle --- outer levels will now fill
487  * deadlockDetails[]
488  */
489  Assert(depth <= MaxBackends);
490  nDeadlockDetails = depth;
491 
492  return true;
493  }
494 
495  /*
496  * Otherwise, we have a cycle but it does not include the start
497  * point, so say "no deadlock".
498  */
499  return false;
500  }
501  }
502  /* Mark proc as seen */
503  Assert(nVisitedProcs < MaxBackends);
504  visitedProcs[nVisitedProcs++] = checkProc;
505 
506  /*
507  * If the process is waiting, there is an outgoing waits-for edge to each
508  * process that blocks it.
509  */
510  if (checkProc->links.next != NULL && checkProc->waitLock != NULL &&
511  FindLockCycleRecurseMember(checkProc, checkProc, depth, softEdges,
512  nSoftEdges))
513  return true;
514 
515  /*
516  * If the process is not waiting, there could still be outgoing waits-for
517  * edges if it is part of a lock group, because other members of the lock
518  * group might be waiting even though this process is not. (Given lock
519  * groups {A1, A2} and {B1, B2}, if A1 waits for B1 and B2 waits for A2,
520  * that is a deadlock even neither of B1 and A2 are waiting for anything.)
521  */
522  dlist_foreach(iter, &checkProc->lockGroupMembers)
523  {
524  PGPROC *memberProc;
525 
526  memberProc = dlist_container(PGPROC, lockGroupLink, iter.cur);
527 
528  if (memberProc->links.next != NULL && memberProc->waitLock != NULL &&
529  memberProc != checkProc &&
530  FindLockCycleRecurseMember(memberProc, checkProc, depth, softEdges,
531  nSoftEdges))
532  return true;
533  }
534 
535  return false;
536 }
dlist_head lockGroupMembers
Definition: proc.h:189
SHM_QUEUE links
Definition: proc.h:97
#define dlist_foreach(iter, lhead)
Definition: ilist.h:507
struct SHM_QUEUE * next
Definition: shmem.h:31
#define dlist_container(type, membername, ptr)
Definition: ilist.h:477
int MaxBackends
Definition: globals.c:126
static int nDeadlockDetails
Definition: deadlock.c:125
LOCK * waitLock
Definition: proc.h:135
static bool FindLockCycleRecurseMember(PGPROC *checkProc, PGPROC *checkProcLeader, int depth, EDGE *softEdges, int *nSoftEdges)
Definition: deadlock.c:539
dlist_node * cur
Definition: ilist.h:161
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
static PGPROC ** visitedProcs
Definition: deadlock.c:102
int i
static int nVisitedProcs
Definition: deadlock.c:103
Definition: proc.h:94
PGPROC * lockGroupLeader
Definition: proc.h:188
static bool FindLockCycleRecurseMember ( PGPROC checkProc,
PGPROC checkProcLeader,
int  depth,
EDGE softEdges,
int *  nSoftEdges 
)
static

Definition at line 539 of file deadlock.c.

References PROC_HDR::allPgXact, Assert, EDGE::blocker, LockMethodData::conflictTab, FindLockCycleRecurse(), GetLocksMethodTable(), PROCLOCK::holdMask, i, PROC_QUEUE::links, PGPROC::links, EDGE::lock, LOCKBIT_ON, PGPROC::lockGroupLeader, PROCLOCK::lockLink, DEADLOCK_INFO::lockmode, DEADLOCK_INFO::locktag, MaxBackends, MyProc, PROCLOCKTAG::myProc, SHM_QUEUE::next, WAIT_ORDER::nProcs, NULL, LockMethodData::numLockModes, nWaitOrders, offsetof, PGPROC::pgprocno, DEADLOCK_INFO::pid, PGPROC::pid, PROC_IS_AUTOVACUUM, ProcGlobal, LOCK::procLocks, WAIT_ORDER::procs, SHMQueueNext(), PROC_QUEUE::size, LOCK::tag, PROCLOCK::tag, PGXACT::vacuumFlags, EDGE::waiter, PGPROC::waitLock, PGPROC::waitLockMode, and LOCK::waitProcs.

Referenced by FindLockCycleRecurse().

544 {
545  PGPROC *proc;
546  LOCK *lock = checkProc->waitLock;
547  PGXACT *pgxact;
548  PROCLOCK *proclock;
549  SHM_QUEUE *procLocks;
550  LockMethod lockMethodTable;
551  PROC_QUEUE *waitQueue;
552  int queue_size;
553  int conflictMask;
554  int i;
555  int numLockModes,
556  lm;
557 
558  lockMethodTable = GetLocksMethodTable(lock);
559  numLockModes = lockMethodTable->numLockModes;
560  conflictMask = lockMethodTable->conflictTab[checkProc->waitLockMode];
561 
562  /*
563  * Scan for procs that already hold conflicting locks. These are "hard"
564  * edges in the waits-for graph.
565  */
566  procLocks = &(lock->procLocks);
567 
568  proclock = (PROCLOCK *) SHMQueueNext(procLocks, procLocks,
569  offsetof(PROCLOCK, lockLink));
570 
571  while (proclock)
572  {
573  PGPROC *leader;
574 
575  proc = proclock->tag.myProc;
576  pgxact = &ProcGlobal->allPgXact[proc->pgprocno];
577  leader = proc->lockGroupLeader == NULL ? proc : proc->lockGroupLeader;
578 
579  /* A proc never blocks itself or any other lock group member */
580  if (leader != checkProcLeader)
581  {
582  for (lm = 1; lm <= numLockModes; lm++)
583  {
584  if ((proclock->holdMask & LOCKBIT_ON(lm)) &&
585  (conflictMask & LOCKBIT_ON(lm)))
586  {
587  /* This proc hard-blocks checkProc */
588  if (FindLockCycleRecurse(proc, depth + 1,
589  softEdges, nSoftEdges))
590  {
591  /* fill deadlockDetails[] */
592  DEADLOCK_INFO *info = &deadlockDetails[depth];
593 
594  info->locktag = lock->tag;
595  info->lockmode = checkProc->waitLockMode;
596  info->pid = checkProc->pid;
597 
598  return true;
599  }
600 
601  /*
602  * No deadlock here, but see if this proc is an autovacuum
603  * that is directly hard-blocking our own proc. If so,
604  * report it so that the caller can send a cancel signal
605  * to it, if appropriate. If there's more than one such
606  * proc, it's indeterminate which one will be reported.
607  *
608  * We don't touch autovacuums that are indirectly blocking
609  * us; it's up to the direct blockee to take action. This
610  * rule simplifies understanding the behavior and ensures
611  * that an autovacuum won't be canceled with less than
612  * deadlock_timeout grace period.
613  *
614  * Note we read vacuumFlags without any locking. This is
615  * OK only for checking the PROC_IS_AUTOVACUUM flag,
616  * because that flag is set at process start and never
617  * reset. There is logic elsewhere to avoid canceling an
618  * autovacuum that is working to prevent XID wraparound
619  * problems (which needs to read a different vacuumFlag
620  * bit), but we don't do that here to avoid grabbing
621  * ProcArrayLock.
622  */
623  if (checkProc == MyProc &&
626 
627  /* We're done looking at this proclock */
628  break;
629  }
630  }
631  }
632 
633  proclock = (PROCLOCK *) SHMQueueNext(procLocks, &proclock->lockLink,
634  offsetof(PROCLOCK, lockLink));
635  }
636 
637  /*
638  * Scan for procs that are ahead of this one in the lock's wait queue.
639  * Those that have conflicting requests soft-block this one. This must be
640  * done after the hard-block search, since if another proc both hard- and
641  * soft-blocks this one, we want to call it a hard edge.
642  *
643  * If there is a proposed re-ordering of the lock's wait order, use that
644  * rather than the current wait order.
645  */
646  for (i = 0; i < nWaitOrders; i++)
647  {
648  if (waitOrders[i].lock == lock)
649  break;
650  }
651 
652  if (i < nWaitOrders)
653  {
654  /* Use the given hypothetical wait queue order */
655  PGPROC **procs = waitOrders[i].procs;
656 
657  queue_size = waitOrders[i].nProcs;
658 
659  for (i = 0; i < queue_size; i++)
660  {
661  PGPROC *leader;
662 
663  proc = procs[i];
664  leader = proc->lockGroupLeader == NULL ? proc :
665  proc->lockGroupLeader;
666 
667  /*
668  * TopoSort will always return an ordering with group members
669  * adjacent to each other in the wait queue (see comments
670  * therein). So, as soon as we reach a process in the same lock
671  * group as checkProc, we know we've found all the conflicts that
672  * precede any member of the lock group lead by checkProcLeader.
673  */
674  if (leader == checkProcLeader)
675  break;
676 
677  /* Is there a conflict with this guy's request? */
678  if ((LOCKBIT_ON(proc->waitLockMode) & conflictMask) != 0)
679  {
680  /* This proc soft-blocks checkProc */
681  if (FindLockCycleRecurse(proc, depth + 1,
682  softEdges, nSoftEdges))
683  {
684  /* fill deadlockDetails[] */
685  DEADLOCK_INFO *info = &deadlockDetails[depth];
686 
687  info->locktag = lock->tag;
688  info->lockmode = checkProc->waitLockMode;
689  info->pid = checkProc->pid;
690 
691  /*
692  * Add this edge to the list of soft edges in the cycle
693  */
694  Assert(*nSoftEdges < MaxBackends);
695  softEdges[*nSoftEdges].waiter = checkProcLeader;
696  softEdges[*nSoftEdges].blocker = leader;
697  softEdges[*nSoftEdges].lock = lock;
698  (*nSoftEdges)++;
699  return true;
700  }
701  }
702  }
703  }
704  else
705  {
706  PGPROC *lastGroupMember = NULL;
707 
708  /* Use the true lock wait queue order */
709  waitQueue = &(lock->waitProcs);
710 
711  /*
712  * Find the last member of the lock group that is present in the wait
713  * queue. Anything after this is not a soft lock conflict. If group
714  * locking is not in use, then we know immediately which process we're
715  * looking for, but otherwise we've got to search the wait queue to
716  * find the last process actually present.
717  */
718  if (checkProc->lockGroupLeader == NULL)
719  lastGroupMember = checkProc;
720  else
721  {
722  proc = (PGPROC *) waitQueue->links.next;
723  queue_size = waitQueue->size;
724  while (queue_size-- > 0)
725  {
726  if (proc->lockGroupLeader == checkProcLeader)
727  lastGroupMember = proc;
728  proc = (PGPROC *) proc->links.next;
729  }
730  Assert(lastGroupMember != NULL);
731  }
732 
733  /*
734  * OK, now rescan (or scan) the queue to identify the soft conflicts.
735  */
736  queue_size = waitQueue->size;
737  proc = (PGPROC *) waitQueue->links.next;
738  while (queue_size-- > 0)
739  {
740  PGPROC *leader;
741 
742  leader = proc->lockGroupLeader == NULL ? proc :
743  proc->lockGroupLeader;
744 
745  /* Done when we reach the target proc */
746  if (proc == lastGroupMember)
747  break;
748 
749  /* Is there a conflict with this guy's request? */
750  if ((LOCKBIT_ON(proc->waitLockMode) & conflictMask) != 0 &&
751  leader != checkProcLeader)
752  {
753  /* This proc soft-blocks checkProc */
754  if (FindLockCycleRecurse(proc, depth + 1,
755  softEdges, nSoftEdges))
756  {
757  /* fill deadlockDetails[] */
758  DEADLOCK_INFO *info = &deadlockDetails[depth];
759 
760  info->locktag = lock->tag;
761  info->lockmode = checkProc->waitLockMode;
762  info->pid = checkProc->pid;
763 
764  /*
765  * Add this edge to the list of soft edges in the cycle
766  */
767  Assert(*nSoftEdges < MaxBackends);
768  softEdges[*nSoftEdges].waiter = checkProcLeader;
769  softEdges[*nSoftEdges].blocker = leader;
770  softEdges[*nSoftEdges].lock = lock;
771  (*nSoftEdges)++;
772  return true;
773  }
774  }
775 
776  proc = (PGPROC *) proc->links.next;
777  }
778  }
779 
780  /*
781  * No conflict detected here.
782  */
783  return false;
784 }
PROCLOCKTAG tag
Definition: lock.h:348
LOCK * lock
Definition: deadlock.c:50
LOCKMODE lockmode
Definition: deadlock.c:74
Definition: proc.h:207
static WAIT_ORDER * waitOrders
Definition: deadlock.c:111
SHM_QUEUE links
Definition: lock.h:32
PGXACT * allPgXact
Definition: proc.h:234
PGPROC * MyProc
Definition: proc.c:67
LOCKMASK holdMask
Definition: lock.h:352
SHM_QUEUE links
Definition: proc.h:97
static PGPROC * blocking_autovacuum_proc
Definition: deadlock.c:128
struct SHM_QUEUE * next
Definition: shmem.h:31
PGPROC * waiter
Definition: deadlock.c:48
LOCKMODE waitLockMode
Definition: proc.h:137
LOCKTAG tag
Definition: lock.h:288
const LOCKMASK * conflictTab
Definition: lock.h:115
SHM_QUEUE lockLink
Definition: lock.h:354
PROC_HDR * ProcGlobal
Definition: proc.c:80
int nProcs
Definition: deadlock.c:60
PROC_QUEUE waitProcs
Definition: lock.h:294
uint8 vacuumFlags
Definition: proc.h:218
PGPROC * blocker
Definition: deadlock.c:49
PGPROC ** procs
Definition: deadlock.c:59
int MaxBackends
Definition: globals.c:126
Definition: lock.h:285
LOCK * waitLock
Definition: proc.h:135
SHM_QUEUE procLocks
Definition: lock.h:293
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
static DEADLOCK_INFO * deadlockDetails
Definition: deadlock.c:124
static bool FindLockCycleRecurse(PGPROC *checkProc, int depth, EDGE *softEdges, int *nSoftEdges)
Definition: deadlock.c:460
PGPROC * myProc
Definition: lock.h:342
#define LOCKBIT_ON(lockmode)
Definition: lock.h:88
Definition: lock.h:345
int pgprocno
Definition: proc.h:109
int i
int size
Definition: lock.h:33
static int nWaitOrders
Definition: deadlock.c:112
LOCKTAG locktag
Definition: deadlock.c:73
Definition: proc.h:94
int pid
Definition: proc.h:108
LockMethod GetLocksMethodTable(const LOCK *lock)
Definition: lock.c:460
PGPROC * lockGroupLeader
Definition: proc.h:188
#define PROC_IS_AUTOVACUUM
Definition: proc.h:52
#define offsetof(type, field)
Definition: c.h:555
int numLockModes
Definition: lock.h:114
PGPROC* GetBlockingAutoVacuumPgproc ( void  )

Definition at line 293 of file deadlock.c.

References blocking_autovacuum_proc, and NULL.

Referenced by ProcSleep().

294 {
295  PGPROC *ptr;
296 
299 
300  return ptr;
301 }
static PGPROC * blocking_autovacuum_proc
Definition: deadlock.c:128
#define NULL
Definition: c.h:229
Definition: proc.h:94
void InitDeadLockChecking ( void  )

Definition at line 143 of file deadlock.c.

References afterConstraints, beforeConstraints, MaxBackends, maxCurConstraints, maxPossibleConstraints, MemoryContextSwitchTo(), palloc(), TopMemoryContext, and visitedProcs.

Referenced by InitProcess().

144 {
145  MemoryContext oldcxt;
146 
147  /* Make sure allocations are permanent */
149 
150  /*
151  * FindLockCycle needs at most MaxBackends entries in visitedProcs[] and
152  * deadlockDetails[].
153  */
154  visitedProcs = (PGPROC **) palloc(MaxBackends * sizeof(PGPROC *));
156 
157  /*
158  * TopoSort needs to consider at most MaxBackends wait-queue entries, and
159  * it needn't run concurrently with FindLockCycle.
160  */
161  topoProcs = visitedProcs; /* re-use this space */
162  beforeConstraints = (int *) palloc(MaxBackends * sizeof(int));
163  afterConstraints = (int *) palloc(MaxBackends * sizeof(int));
164 
165  /*
166  * We need to consider rearranging at most MaxBackends/2 wait queues
167  * (since it takes at least two waiters in a queue to create a soft edge),
168  * and the expanded form of the wait queues can't involve more than
169  * MaxBackends total waiters.
170  */
171  waitOrders = (WAIT_ORDER *)
172  palloc((MaxBackends / 2) * sizeof(WAIT_ORDER));
173  waitOrderProcs = (PGPROC **) palloc(MaxBackends * sizeof(PGPROC *));
174 
175  /*
176  * Allow at most MaxBackends distinct constraints in a configuration. (Is
177  * this enough? In practice it seems it should be, but I don't quite see
178  * how to prove it. If we run out, we might fail to find a workable wait
179  * queue rearrangement even though one exists.) NOTE that this number
180  * limits the maximum recursion depth of DeadLockCheckRecurse. Making it
181  * really big might potentially allow a stack-overflow problem.
182  */
185 
186  /*
187  * Allow up to 3*MaxBackends constraints to be saved without having to
188  * re-run TestConfiguration. (This is probably more than enough, but we
189  * can survive if we run low on space by doing excess runs of
190  * TestConfiguration to re-compute constraint lists each time needed.) The
191  * last MaxBackends entries in possibleConstraints[] are reserved as
192  * output workspace for FindLockCycle.
193  */
196  (EDGE *) palloc(maxPossibleConstraints * sizeof(EDGE));
197 
198  MemoryContextSwitchTo(oldcxt);
199 }
static int maxCurConstraints
Definition: deadlock.c:118
static WAIT_ORDER * waitOrders
Definition: deadlock.c:111
Definition: deadlock.c:46
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static PGPROC ** waitOrderProcs
Definition: deadlock.c:113
static PGPROC ** topoProcs
Definition: deadlock.c:106
int MaxBackends
Definition: globals.c:126
static EDGE * curConstraints
Definition: deadlock.c:116
MemoryContext TopMemoryContext
Definition: mcxt.c:43
static int * afterConstraints
Definition: deadlock.c:108
static DEADLOCK_INFO * deadlockDetails
Definition: deadlock.c:124
static PGPROC ** visitedProcs
Definition: deadlock.c:102
static EDGE * possibleConstraints
Definition: deadlock.c:121
void * palloc(Size size)
Definition: mcxt.c:849
static int maxPossibleConstraints
Definition: deadlock.c:123
static int * beforeConstraints
Definition: deadlock.c:107
Definition: proc.h:94
void RememberSimpleDeadLock ( PGPROC proc1,
LOCKMODE  lockmode,
LOCK lock,
PGPROC proc2 
)

Definition at line 1149 of file deadlock.c.

References DEADLOCK_INFO::lockmode, DEADLOCK_INFO::locktag, nDeadlockDetails, DEADLOCK_INFO::pid, PGPROC::pid, LOCK::tag, PGPROC::waitLock, and PGPROC::waitLockMode.

Referenced by ProcSleep().

1153 {
1154  DEADLOCK_INFO *info = &deadlockDetails[0];
1155 
1156  info->locktag = lock->tag;
1157  info->lockmode = lockmode;
1158  info->pid = proc1->pid;
1159  info++;
1160  info->locktag = proc2->waitLock->tag;
1161  info->lockmode = proc2->waitLockMode;
1162  info->pid = proc2->pid;
1163  nDeadlockDetails = 2;
1164 }
LOCKMODE lockmode
Definition: deadlock.c:74
LOCKMODE waitLockMode
Definition: proc.h:137
LOCKTAG tag
Definition: lock.h:288
static int nDeadlockDetails
Definition: deadlock.c:125
LOCK * waitLock
Definition: proc.h:135
static DEADLOCK_INFO * deadlockDetails
Definition: deadlock.c:124
LOCKTAG locktag
Definition: deadlock.c:73
int pid
Definition: proc.h:108
static int TestConfiguration ( PGPROC startProc)
static

Definition at line 381 of file deadlock.c.

References ExpandConstraints(), FindLockCycle(), i, MaxBackends, maxPossibleConstraints, nCurConstraints, and nPossibleConstraints.

Referenced by DeadLockCheckRecurse().

382 {
383  int softFound = 0;
385  int nSoftEdges;
386  int i;
387 
388  /*
389  * Make sure we have room for FindLockCycle's output.
390  */
391  if (nPossibleConstraints + MaxBackends > maxPossibleConstraints)
392  return -1;
393 
394  /*
395  * Expand current constraint set into wait orderings. Fail if the
396  * constraint set is not self-consistent.
397  */
399  return -1;
400 
401  /*
402  * Check for cycles involving startProc or any of the procs mentioned in
403  * constraints. We check startProc last because if it has a soft cycle
404  * still to be dealt with, we want to deal with that first.
405  */
406  for (i = 0; i < nCurConstraints; i++)
407  {
408  if (FindLockCycle(curConstraints[i].waiter, softEdges, &nSoftEdges))
409  {
410  if (nSoftEdges == 0)
411  return -1; /* hard deadlock detected */
412  softFound = nSoftEdges;
413  }
414  if (FindLockCycle(curConstraints[i].blocker, softEdges, &nSoftEdges))
415  {
416  if (nSoftEdges == 0)
417  return -1; /* hard deadlock detected */
418  softFound = nSoftEdges;
419  }
420  }
421  if (FindLockCycle(startProc, softEdges, &nSoftEdges))
422  {
423  if (nSoftEdges == 0)
424  return -1; /* hard deadlock detected */
425  softFound = nSoftEdges;
426  }
427  return softFound;
428 }
Definition: deadlock.c:46
static int nCurConstraints
Definition: deadlock.c:117
static int nPossibleConstraints
Definition: deadlock.c:122
static bool ExpandConstraints(EDGE *constraints, int nConstraints)
Definition: deadlock.c:799
static bool FindLockCycle(PGPROC *checkProc, EDGE *softEdges, int *nSoftEdges)
Definition: deadlock.c:449
int MaxBackends
Definition: globals.c:126
static EDGE * curConstraints
Definition: deadlock.c:116
static EDGE * possibleConstraints
Definition: deadlock.c:121
int i
static int maxPossibleConstraints
Definition: deadlock.c:123
static bool TopoSort ( LOCK lock,
EDGE constraints,
int  nConstraints,
PGPROC **  ordering 
)
static

Definition at line 871 of file deadlock.c.

References afterConstraints, Assert, beforeConstraints, EDGE::blocker, i, EDGE::link, PROC_QUEUE::links, PGPROC::links, PGPROC::lockGroupLeader, MemSet, SHM_QUEUE::next, NULL, EDGE::pred, PROC_QUEUE::size, EDGE::waiter, PGPROC::waitLock, and LOCK::waitProcs.

Referenced by ExpandConstraints().

875 {
876  PROC_QUEUE *waitQueue = &(lock->waitProcs);
877  int queue_size = waitQueue->size;
878  PGPROC *proc;
879  int i,
880  j,
881  jj,
882  k,
883  kk,
884  last;
885 
886  /* First, fill topoProcs[] array with the procs in their current order */
887  proc = (PGPROC *) waitQueue->links.next;
888  for (i = 0; i < queue_size; i++)
889  {
890  topoProcs[i] = proc;
891  proc = (PGPROC *) proc->links.next;
892  }
893 
894  /*
895  * Scan the constraints, and for each proc in the array, generate a count
896  * of the number of constraints that say it must be before something else,
897  * plus a list of the constraints that say it must be after something
898  * else. The count for the j'th proc is stored in beforeConstraints[j],
899  * and the head of its list in afterConstraints[j]. Each constraint
900  * stores its list link in constraints[i].link (note any constraint will
901  * be in just one list). The array index for the before-proc of the i'th
902  * constraint is remembered in constraints[i].pred.
903  *
904  * Note that it's not necessarily the case that every constraint affects
905  * this particular wait queue. Prior to group locking, a process could be
906  * waiting for at most one lock. But a lock group can be waiting for
907  * zero, one, or multiple locks. Since topoProcs[] is an array of the
908  * processes actually waiting, while constraints[] is an array of group
909  * leaders, we've got to scan through topoProcs[] for each constraint,
910  * checking whether both a waiter and a blocker for that group are
911  * present. If so, the constraint is relevant to this wait queue; if not,
912  * it isn't.
913  */
914  MemSet(beforeConstraints, 0, queue_size * sizeof(int));
915  MemSet(afterConstraints, 0, queue_size * sizeof(int));
916  for (i = 0; i < nConstraints; i++)
917  {
918  /*
919  * Find a representative process that is on the lock queue and part of
920  * the waiting lock group. This may or may not be the leader, which
921  * may or may not be waiting at all. If there are any other processes
922  * in the same lock group on the queue, set their number of
923  * beforeConstraints to -1 to indicate that they should be emitted
924  * with their groupmates rather than considered separately.
925  */
926  proc = constraints[i].waiter;
927  Assert(proc != NULL);
928  jj = -1;
929  for (j = queue_size; --j >= 0;)
930  {
931  PGPROC *waiter = topoProcs[j];
932 
933  if (waiter == proc || waiter->lockGroupLeader == proc)
934  {
935  Assert(waiter->waitLock == lock);
936  if (jj == -1)
937  jj = j;
938  else
939  {
940  Assert(beforeConstraints[j] <= 0);
941  beforeConstraints[j] = -1;
942  }
943  break;
944  }
945  }
946 
947  /* If no matching waiter, constraint is not relevant to this lock. */
948  if (jj < 0)
949  continue;
950 
951  /*
952  * Similarly, find a representative process that is on the lock queue
953  * and waiting for the blocking lock group. Again, this could be the
954  * leader but does not need to be.
955  */
956  proc = constraints[i].blocker;
957  Assert(proc != NULL);
958  kk = -1;
959  for (k = queue_size; --k >= 0;)
960  {
961  PGPROC *blocker = topoProcs[k];
962 
963  if (blocker == proc || blocker->lockGroupLeader == proc)
964  {
965  Assert(blocker->waitLock == lock);
966  if (kk == -1)
967  kk = k;
968  else
969  {
970  Assert(beforeConstraints[k] <= 0);
971  beforeConstraints[k] = -1;
972  }
973  }
974  }
975 
976  /* If no matching blocker, constraint is not relevant to this lock. */
977  if (kk < 0)
978  continue;
979 
980  beforeConstraints[jj]++; /* waiter must come before */
981  /* add this constraint to list of after-constraints for blocker */
982  constraints[i].pred = jj;
983  constraints[i].link = afterConstraints[kk];
984  afterConstraints[kk] = i + 1;
985  }
986 
987  /*--------------------
988  * Now scan the topoProcs array backwards. At each step, output the
989  * last proc that has no remaining before-constraints plus any other
990  * members of the same lock group; then decrease the beforeConstraints
991  * count of each of the procs it was constrained against.
992  * i = index of ordering[] entry we want to output this time
993  * j = search index for topoProcs[]
994  * k = temp for scanning constraint list for proc j
995  * last = last non-null index in topoProcs (avoid redundant searches)
996  *--------------------
997  */
998  last = queue_size - 1;
999  for (i = queue_size - 1; i >= 0;)
1000  {
1001  int c;
1002  int nmatches = 0;
1003 
1004  /* Find next candidate to output */
1005  while (topoProcs[last] == NULL)
1006  last--;
1007  for (j = last; j >= 0; j--)
1008  {
1009  if (topoProcs[j] != NULL && beforeConstraints[j] == 0)
1010  break;
1011  }
1012 
1013  /* If no available candidate, topological sort fails */
1014  if (j < 0)
1015  return false;
1016 
1017  /*
1018  * Output everything in the lock group. There's no point in
1019  * outputting an ordering where members of the same lock group are not
1020  * consecutive on the wait queue: if some other waiter is between two
1021  * requests that belong to the same group, then either it conflicts
1022  * with both of them and is certainly not a solution; or it conflicts
1023  * with at most one of them and is thus isomorphic to an ordering
1024  * where the group members are consecutive.
1025  */
1026  proc = topoProcs[j];
1027  if (proc->lockGroupLeader != NULL)
1028  proc = proc->lockGroupLeader;
1029  Assert(proc != NULL);
1030  for (c = 0; c <= last; ++c)
1031  {
1032  if (topoProcs[c] == proc || (topoProcs[c] != NULL &&
1033  topoProcs[c]->lockGroupLeader == proc))
1034  {
1035  ordering[i - nmatches] = topoProcs[c];
1036  topoProcs[c] = NULL;
1037  ++nmatches;
1038  }
1039  }
1040  Assert(nmatches > 0);
1041  i -= nmatches;
1042 
1043  /* Update beforeConstraints counts of its predecessors */
1044  for (k = afterConstraints[j]; k > 0; k = constraints[k - 1].link)
1045  beforeConstraints[constraints[k - 1].pred]--;
1046  }
1047 
1048  /* Done */
1049  return true;
1050 }
int link
Definition: deadlock.c:52
SHM_QUEUE links
Definition: lock.h:32
SHM_QUEUE links
Definition: proc.h:97
struct SHM_QUEUE * next
Definition: shmem.h:31
PGPROC * waiter
Definition: deadlock.c:48
#define MemSet(start, val, len)
Definition: c.h:857
PROC_QUEUE waitProcs
Definition: lock.h:294
int pred
Definition: deadlock.c:51
PGPROC * blocker
Definition: deadlock.c:49
static PGPROC ** topoProcs
Definition: deadlock.c:106
char * c
LOCK * waitLock
Definition: proc.h:135
static int * afterConstraints
Definition: deadlock.c:108
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
int i
int size
Definition: lock.h:33
static int * beforeConstraints
Definition: deadlock.c:107
Definition: proc.h:94
PGPROC * lockGroupLeader
Definition: proc.h:188

Variable Documentation

int* afterConstraints
static

Definition at line 108 of file deadlock.c.

Referenced by InitDeadLockChecking(), and TopoSort().

int* beforeConstraints
static

Definition at line 107 of file deadlock.c.

Referenced by InitDeadLockChecking(), and TopoSort().

PGPROC* blocking_autovacuum_proc = NULL
static

Definition at line 128 of file deadlock.c.

Referenced by GetBlockingAutoVacuumPgproc().

EDGE* curConstraints
static

Definition at line 116 of file deadlock.c.

DEADLOCK_INFO* deadlockDetails
static

Definition at line 124 of file deadlock.c.

int maxCurConstraints
static

Definition at line 118 of file deadlock.c.

Referenced by DeadLockCheckRecurse(), and InitDeadLockChecking().

int maxPossibleConstraints
static

Definition at line 123 of file deadlock.c.

Referenced by DeadLockCheckRecurse(), InitDeadLockChecking(), and TestConfiguration().

int nCurConstraints
static

Definition at line 117 of file deadlock.c.

Referenced by DeadLockCheck(), DeadLockCheckRecurse(), and TestConfiguration().

int nDeadlockDetails
static
int nPossibleConstraints
static

Definition at line 122 of file deadlock.c.

Referenced by DeadLockCheck(), DeadLockCheckRecurse(), and TestConfiguration().

int nVisitedProcs
static

Definition at line 103 of file deadlock.c.

Referenced by FindLockCycle(), and FindLockCycleRecurse().

int nWaitOrders
static

Definition at line 112 of file deadlock.c.

Referenced by DeadLockCheck(), ExpandConstraints(), and FindLockCycleRecurseMember().

EDGE* possibleConstraints
static

Definition at line 121 of file deadlock.c.

PGPROC** topoProcs
static

Definition at line 106 of file deadlock.c.

PGPROC** visitedProcs
static

Definition at line 102 of file deadlock.c.

Referenced by InitDeadLockChecking().

PGPROC** waitOrderProcs
static

Definition at line 113 of file deadlock.c.

WAIT_ORDER* waitOrders
static

Definition at line 111 of file deadlock.c.