elog(WARNING, "locallock table corrupted");
}
+/*
+ * CanGrantLock -- test for conflicts with already-granted locks, or with
+ * other waiters
+ */
+CanGrantLockResult
+CanGrantLock(LockMethod lockMethodTable, LOCKMODE lockmode, LOCK *lock,
+ PROCLOCK *proclock)
+{
+ int numLockModes = lockMethodTable->numLockModes;
+ LOCKMASK conflictMask;
+ LOCKMASK myLocks;
+ int ngranted = 0;
+ int nawaited = 0;
+ bool group_member_waiting = false;
+
+ /*
+ * If nobody's holding the lock, and nobody's waiting for the lock,
+ * then it's definitely OK to grant the lock.
+ */
+ conflictMask = lockMethodTable->conflictTab[lockmode] & lock->waitMask;
+ if ((conflictMask & (lock->waitMask | lock->grantMask)) == 0)
+ return GRANT_OK;
+
+ /* We can take some shortcuts when no group locking is involved. */
+ if (proclock->groupLeader == NULL)
+ {
+ /*
+ * If no conflicting locks have been granted, there must at least
+ * be someone waiting for a conflicting lock, or the test above would
+ * have returned GRANT_OK. (Note that we can't use this fast-path
+ * when a locking group is in use, because the answer could still be
+ * GRANT_WAITERS_IN_GROUP.)
+ */
+ if ((conflictMask & lock->grantMask) == 0)
+ return GRANT_WAITERS;
+
+ /*
+ * With no lock group, it's only OK to ignore locks held by this
+ * proclock. Any other conflict must be for real.
+ */
+ if (((conflictMask & lock->grantMask) & ~proclock->holdMask) != 0)
+ return GRANT_CONFLICT;
+ }
+
+ /*
+ * There may be conflicting locks present, but they may belong to
+ * this proclock or some other proclock in its locking group. If not,
+ * there will at least be some awaited locks, which may or may not be
+ * in the same locking group. So we must do a more careful analysis.
+ */
+ myLocks = proclock->holdMask;
+ for (i = 1; i <= numLockModes; i++)
+ {
+ /* If this lock type doesn't conflict, we can ignore it. */
+ if ((conflictMask & LOCKBIT_ON(i)) == 0)
+ continue;
+
+ /*
+ * Counted granted and awaited locks, excluding any held by our own
+ * proclock.
+ */
+ ngranted += lock->granted[i] - ((myLocks & LOCKBIT_ON(i)) ? 1 : 0);
+ nawaited += lock->requested[i] - lock->granted[i];
+ }
+
+ /*
+ * If group locking is in use, we must account for locks held by other
+ * members of the locking group - unless of course the only locks held
+ * or awaited in a conflicting mode were held by this PROCLOCK, in
+ * which case we can skip all this.
+ */
+ if (proclock->groupLeader != NULL && (ngranted > 0 || nawaited > 0))
+ {
+ SHM_QUEUE *procLocks = &(lock->procLocks);
+ PROCLOCK *otherproclock;
+
+ otherproclock = (PROCLOCK *)
+ SHMQueueNext(procLocks, procLocks, offsetof(PROCLOCK, lockLink));
+
+ while (otherproclock != NULL)
+ {
+ if (proclock->groupLeader == otherproclock->groupLeader)
+ {
+ LOCKMASK conflicts;
+
+ /* We can get any lock held by our group. */
+ if ((otherproclock->holdMask & LOCKBIT_ON(lockmode)) == 0)
+ return GRANT_OK;
+
+ /* We can disregard any conflicting lock held by our group. */
+ conflicts = otherproclock->holdMask & conflictMask;
+ if (conflicts != 0)
+ {
+ for (i = 1; i <= numLockModes; i++)
+ {
+ if ((conflicts & LOCKBIT_ON(i)) != 0)
+ {
+ Assert(ngranted > 0);
+ ngranted--;
+ }
+ }
+ }
+
+ If p awaits the sought mode, set group_member_waiting = true.
+ If p awaits a conflicting mode, then --w. REALLY????
+ If g == 0 and w == 0, break.
+ }
+ }
+ }
+
+ /* We can now render a final verdict. */
+ if (ngranted > 0)
+ return GRANT_CONFLICT;
+ if (nawaited > 0)
+ return group_member_waiting ? GRANT_WAITERS_IN_GROUP : GRANT_WAITERS;
+ Assert(!group_member_waiting);
+ return GRANT_OK;
+}
+
/*
* LockCheckConflicts -- test whether requested lock conflicts
* with those already granted