/* Initialize the PGPROC entry */
MemSet(proc, 0, sizeof(PGPROC));
proc->pgprocno = gxact->pgprocno;
- SHMQueueElemInit(&(proc->links));
+ dlist_node_init(&proc->links);
proc->waitStatus = PROC_WAIT_STATUS_OK;
if (LocalTransactionIdIsValid(MyProc->lxid))
{
proc->waitProcLock = NULL;
pg_atomic_init_u64(&proc->waitStart, 0);
for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
- SHMQueueInit(&(proc->myProcLocks[i]));
+ dlist_init(&proc->myProcLocks[i]);
/* subxid data must be filled later by GXactLoadSubxactData */
proc->subxidStatus.overflowed = false;
proc->subxidStatus.count = 0;
DeadLockState
DeadLockCheck(PGPROC *proc)
{
- int i,
- j;
-
/* Initialize to "no constraints" */
nCurConstraints = 0;
nPossibleConstraints = 0;
}
/* Apply any needed rearrangements of wait queues */
- for (i = 0; i < nWaitOrders; i++)
+ for (int i = 0; i < nWaitOrders; i++)
{
LOCK *lock = waitOrders[i].lock;
PGPROC **procs = waitOrders[i].procs;
int nProcs = waitOrders[i].nProcs;
- PROC_QUEUE *waitQueue = &(lock->waitProcs);
+ dclist_head *waitQueue = &lock->waitProcs;
- Assert(nProcs == waitQueue->size);
+ Assert(nProcs == dclist_count(waitQueue));
#ifdef DEBUG_DEADLOCK
PrintLockQueue(lock, "DeadLockCheck:");
#endif
/* Reset the queue and re-add procs in the desired order */
- ProcQueueInit(waitQueue);
- for (j = 0; j < nProcs; j++)
- {
- SHMQueueInsertBefore(&(waitQueue->links), &(procs[j]->links));
- waitQueue->size++;
- }
+ dclist_init(waitQueue);
+ for (int j = 0; j < nProcs; j++)
+ dclist_push_tail(waitQueue, &procs[j]->links);
#ifdef DEBUG_DEADLOCK
PrintLockQueue(lock, "rearranged to:");
{
PGPROC *proc;
LOCK *lock = checkProc->waitLock;
- PROCLOCK *proclock;
- SHM_QUEUE *procLocks;
+ dlist_iter proclock_iter;
LockMethod lockMethodTable;
- PROC_QUEUE *waitQueue;
- int queue_size;
int conflictMask;
int i;
int numLockModes,
* Scan for procs that already hold conflicting locks. These are "hard"
* edges in the waits-for graph.
*/
- procLocks = &(lock->procLocks);
-
- proclock = (PROCLOCK *) SHMQueueNext(procLocks, procLocks,
- offsetof(PROCLOCK, lockLink));
-
- while (proclock)
+ dlist_foreach(proclock_iter, &lock->procLocks)
{
+ PROCLOCK *proclock = dlist_container(PROCLOCK, lockLink, proclock_iter.cur);
PGPROC *leader;
proc = proclock->tag.myProc;
}
}
}
-
- proclock = (PROCLOCK *) SHMQueueNext(procLocks, &proclock->lockLink,
- offsetof(PROCLOCK, lockLink));
}
/*
{
/* Use the given hypothetical wait queue order */
PGPROC **procs = waitOrders[i].procs;
-
- queue_size = waitOrders[i].nProcs;
+ int queue_size = waitOrders[i].nProcs;
for (i = 0; i < queue_size; i++)
{
else
{
PGPROC *lastGroupMember = NULL;
+ dlist_iter proc_iter;
+ dclist_head *waitQueue;
/* Use the true lock wait queue order */
- waitQueue = &(lock->waitProcs);
+ waitQueue = &lock->waitProcs;
/*
* Find the last member of the lock group that is present in the wait
lastGroupMember = checkProc;
else
{
- proc = (PGPROC *) waitQueue->links.next;
- queue_size = waitQueue->size;
- while (queue_size-- > 0)
+ dclist_foreach(proc_iter, waitQueue)
{
+ proc = dlist_container(PGPROC, links, proc_iter.cur);
+
if (proc->lockGroupLeader == checkProcLeader)
lastGroupMember = proc;
- proc = (PGPROC *) proc->links.next;
}
Assert(lastGroupMember != NULL);
}
/*
* OK, now rescan (or scan) the queue to identify the soft conflicts.
*/
- queue_size = waitQueue->size;
- proc = (PGPROC *) waitQueue->links.next;
- while (queue_size-- > 0)
+ dclist_foreach(proc_iter, waitQueue)
{
PGPROC *leader;
+ proc = dlist_container(PGPROC, links, proc_iter.cur);
+
leader = proc->lockGroupLeader == NULL ? proc :
proc->lockGroupLeader;
return true;
}
}
-
- proc = (PGPROC *) proc->links.next;
}
}
/* No, so allocate a new list */
waitOrders[nWaitOrders].lock = lock;
waitOrders[nWaitOrders].procs = waitOrderProcs + nWaitOrderProcs;
- waitOrders[nWaitOrders].nProcs = lock->waitProcs.size;
- nWaitOrderProcs += lock->waitProcs.size;
+ waitOrders[nWaitOrders].nProcs = dclist_count(&lock->waitProcs);
+ nWaitOrderProcs += dclist_count(&lock->waitProcs);
Assert(nWaitOrderProcs <= MaxBackends);
/*
int nConstraints,
PGPROC **ordering) /* output argument */
{
- PROC_QUEUE *waitQueue = &(lock->waitProcs);
- int queue_size = waitQueue->size;
+ dclist_head *waitQueue = &lock->waitProcs;
+ int queue_size = dclist_count(waitQueue);
PGPROC *proc;
int i,
j,
k,
kk,
last;
+ dlist_iter proc_iter;
/* First, fill topoProcs[] array with the procs in their current order */
- proc = (PGPROC *) waitQueue->links.next;
- for (i = 0; i < queue_size; i++)
+ i = 0;
+ dclist_foreach(proc_iter, waitQueue)
{
- topoProcs[i] = proc;
- proc = (PGPROC *) proc->links.next;
+ proc = dlist_container(PGPROC, links, proc_iter.cur);
+ topoProcs[i++] = proc;
}
+ Assert(i == queue_size);
/*
* Scan the constraints, and for each proc in the array, generate a count
static void
PrintLockQueue(LOCK *lock, const char *info)
{
- PROC_QUEUE *waitQueue = &(lock->waitProcs);
- int queue_size = waitQueue->size;
- PGPROC *proc;
- int i;
+ dclist_head *waitQueue = &lock->waitProcs;
+ dlist_iter proc_iter;
printf("%s lock %p queue ", info, lock);
- proc = (PGPROC *) waitQueue->links.next;
- for (i = 0; i < queue_size; i++)
+
+ dclist_foreach(proc_iter, waitQueue)
{
+ PGPROC *proc = dlist_container(PGPROC, links, proc_iter.cur);
+
printf(" %d", proc->pid);
- proc = (PGPROC *) proc->links.next;
}
printf("\n");
fflush(stdout);
lock->granted[1], lock->granted[2], lock->granted[3],
lock->granted[4], lock->granted[5], lock->granted[6],
lock->granted[7], lock->nGranted,
- lock->waitProcs.size,
+ dclist_count(&lock->waitProcs),
LockMethods[LOCK_LOCKMETHOD(*lock)]->lockModeNames[type]);
}
uint32 proclock_hashcode;
proclock_hashcode = ProcLockHashCode(&proclock->tag, hashcode);
- SHMQueueDelete(&proclock->lockLink);
- SHMQueueDelete(&proclock->procLink);
+ dlist_delete(&proclock->lockLink);
+ dlist_delete(&proclock->procLink);
if (!hash_search_with_hash_value(LockMethodProcLockHash,
(void *) &(proclock->tag),
proclock_hashcode,
{
lock->grantMask = 0;
lock->waitMask = 0;
- SHMQueueInit(&(lock->procLocks));
- ProcQueueInit(&(lock->waitProcs));
+ dlist_init(&lock->procLocks);
+ dclist_init(&lock->waitProcs);
lock->nRequested = 0;
lock->nGranted = 0;
MemSet(lock->requested, 0, sizeof(int) * MAX_LOCKMODES);
* of shared memory, because there won't be anything to cause
* anyone to release the lock object later.
*/
- Assert(SHMQueueEmpty(&(lock->procLocks)));
+ Assert(dlist_is_empty(&(lock->procLocks)));
if (!hash_search_with_hash_value(LockMethodLockHash,
(void *) &(lock->tag),
hashcode,
proclock->holdMask = 0;
proclock->releaseMask = 0;
/* Add proclock to appropriate lists */
- SHMQueueInsertBefore(&lock->procLocks, &proclock->lockLink);
- SHMQueueInsertBefore(&(proc->myProcLocks[partition]),
- &proclock->procLink);
+ dlist_push_tail(&lock->procLocks, &proclock->lockLink);
+ dlist_push_tail(&proc->myProcLocks[partition], &proclock->procLink);
PROCLOCK_PRINT("LockAcquire: new", proclock);
}
else
int conflictMask = lockMethodTable->conflictTab[lockmode];
int conflictsRemaining[MAX_LOCKMODES];
int totalConflictsRemaining = 0;
+ dlist_iter proclock_iter;
int i;
- SHM_QUEUE *procLocks;
- PROCLOCK *otherproclock;
/*
* first check for global conflicts: If no locks conflict with my request,
* shared memory state more complex (and larger) but it doesn't seem worth
* it.
*/
- procLocks = &(lock->procLocks);
- otherproclock = (PROCLOCK *)
- SHMQueueNext(procLocks, procLocks, offsetof(PROCLOCK, lockLink));
- while (otherproclock != NULL)
+ dlist_foreach(proclock_iter, &lock->procLocks)
{
+ PROCLOCK *otherproclock =
+ dlist_container(PROCLOCK, lockLink, proclock_iter.cur);
+
if (proclock != otherproclock &&
proclock->groupLeader == otherproclock->groupLeader &&
(otherproclock->holdMask & conflictMask) != 0)
return false;
}
}
- otherproclock = (PROCLOCK *)
- SHMQueueNext(procLocks, &otherproclock->lockLink,
- offsetof(PROCLOCK, lockLink));
}
/* Nope, it's a real conflict. */
uint32 proclock_hashcode;
PROCLOCK_PRINT("CleanUpLock: deleting", proclock);
- SHMQueueDelete(&proclock->lockLink);
- SHMQueueDelete(&proclock->procLink);
+ dlist_delete(&proclock->lockLink);
+ dlist_delete(&proclock->procLink);
proclock_hashcode = ProcLockHashCode(&proclock->tag, hashcode);
if (!hash_search_with_hash_value(LockMethodProcLockHash,
(void *) &(proclock->tag),
* object.
*/
LOCK_PRINT("CleanUpLock: deleting", lock, 0);
- Assert(SHMQueueEmpty(&(lock->procLocks)));
+ Assert(dlist_is_empty(&lock->procLocks));
if (!hash_search_with_hash_value(LockMethodLockHash,
(void *) &(lock->tag),
hashcode,
Assert(proc->waitStatus == PROC_WAIT_STATUS_WAITING);
Assert(proc->links.next != NULL);
Assert(waitLock);
- Assert(waitLock->waitProcs.size > 0);
+ Assert(!dclist_is_empty(&waitLock->waitProcs));
Assert(0 < lockmethodid && lockmethodid < lengthof(LockMethods));
/* Remove proc from lock's wait queue */
- SHMQueueDelete(&(proc->links));
- waitLock->waitProcs.size--;
+ dclist_delete_from(&waitLock->waitProcs, &proc->links);
/* Undo increments of request counts by waiting process */
Assert(waitLock->nRequested > 0);
numLockModes;
LOCALLOCK *locallock;
LOCK *lock;
- PROCLOCK *proclock;
int partition;
bool have_fast_path_lwlock = false;
for (partition = 0; partition < NUM_LOCK_PARTITIONS; partition++)
{
LWLock *partitionLock;
- SHM_QUEUE *procLocks = &(MyProc->myProcLocks[partition]);
- PROCLOCK *nextplock;
+ dlist_head *procLocks = &MyProc->myProcLocks[partition];
+ dlist_mutable_iter proclock_iter;
partitionLock = LockHashPartitionLockByIndex(partition);
* locallock situation, we lose that guarantee for fast-path locks.
* This is not ideal.
*/
- if (SHMQueueNext(procLocks, procLocks,
- offsetof(PROCLOCK, procLink)) == NULL)
+ if (dlist_is_empty(procLocks))
continue; /* needn't examine this partition */
LWLockAcquire(partitionLock, LW_EXCLUSIVE);
- for (proclock = (PROCLOCK *) SHMQueueNext(procLocks, procLocks,
- offsetof(PROCLOCK, procLink));
- proclock;
- proclock = nextplock)
+ dlist_foreach_modify(proclock_iter, procLocks)
{
+ PROCLOCK *proclock = dlist_container(PROCLOCK, procLink, proclock_iter.cur);
bool wakeupNeeded = false;
- /* Get link first, since we may unlink/delete this proclock */
- nextplock = (PROCLOCK *)
- SHMQueueNext(procLocks, &proclock->procLink,
- offsetof(PROCLOCK, procLink));
-
Assert(proclock->tag.myProc == MyProc);
lock = proclock->tag.myLock;
LockMethod lockMethodTable;
LOCK *lock;
LOCKMASK conflictMask;
- SHM_QUEUE *procLocks;
+ dlist_iter proclock_iter;
PROCLOCK *proclock;
uint32 hashcode;
LWLock *partitionLock;
/*
* Examine each existing holder (or awaiter) of the lock.
*/
-
- procLocks = &(lock->procLocks);
-
- proclock = (PROCLOCK *) SHMQueueNext(procLocks, procLocks,
- offsetof(PROCLOCK, lockLink));
-
- while (proclock)
+ dlist_foreach(proclock_iter, &lock->procLocks)
{
+ proclock = dlist_container(PROCLOCK, lockLink, proclock_iter.cur);
+
if (conflictMask & proclock->holdMask)
{
PGPROC *proc = proclock->tag.myProc;
/* else, xact already committed or aborted */
}
}
-
- proclock = (PROCLOCK *) SHMQueueNext(procLocks, &proclock->lockLink,
- offsetof(PROCLOCK, lockLink));
}
LWLockRelease(partitionLock);
for (partition = 0; partition < NUM_LOCK_PARTITIONS; partition++)
{
LWLock *partitionLock;
- SHM_QUEUE *procLocks = &(MyProc->myProcLocks[partition]);
- PROCLOCK *nextplock;
+ dlist_head *procLocks = &(MyProc->myProcLocks[partition]);
+ dlist_mutable_iter proclock_iter;
partitionLock = LockHashPartitionLockByIndex(partition);
* another backend is adding something to our lists now. For safety,
* though, we code this the same way as in LockReleaseAll.
*/
- if (SHMQueueNext(procLocks, procLocks,
- offsetof(PROCLOCK, procLink)) == NULL)
+ if (dlist_is_empty(procLocks))
continue; /* needn't examine this partition */
LWLockAcquire(partitionLock, LW_EXCLUSIVE);
- for (proclock = (PROCLOCK *) SHMQueueNext(procLocks, procLocks,
- offsetof(PROCLOCK, procLink));
- proclock;
- proclock = nextplock)
+ dlist_foreach_modify(proclock_iter, procLocks)
{
- /* Get link first, since we may unlink/relink this proclock */
- nextplock = (PROCLOCK *)
- SHMQueueNext(procLocks, &proclock->procLink,
- offsetof(PROCLOCK, procLink));
+ proclock = dlist_container(PROCLOCK, procLink, proclock_iter.cur);
Assert(proclock->tag.myProc == MyProc);
* same hash partition, cf proclock_hash(). So the partition lock
* we already hold is sufficient for this.
*/
- SHMQueueDelete(&proclock->procLink);
+ dlist_delete(&proclock->procLink);
/*
* Create the new hash key for the proclock.
elog(PANIC, "duplicate entry found while reassigning a prepared transaction's locks");
/* Re-link into the new proc's proclock list */
- SHMQueueInsertBefore(&(newproc->myProcLocks[partition]),
- &proclock->procLink);
+ dlist_push_tail(&newproc->myProcLocks[partition], &proclock->procLink);
PROCLOCK_PRINT("PostPrepare_Locks: updated", proclock);
} /* loop over PROCLOCKs within this partition */
{
LOCK *theLock = blocked_proc->waitLock;
BlockedProcData *bproc;
- SHM_QUEUE *procLocks;
- PROCLOCK *proclock;
- PROC_QUEUE *waitQueue;
- PGPROC *queued_proc;
+ dlist_iter proclock_iter;
+ dlist_iter proc_iter;
+ dclist_head *waitQueue;
int queue_size;
- int i;
/* Nothing to do if this proc is not blocked */
if (theLock == NULL)
*/
/* Collect all PROCLOCKs associated with theLock */
- procLocks = &(theLock->procLocks);
- proclock = (PROCLOCK *) SHMQueueNext(procLocks, procLocks,
- offsetof(PROCLOCK, lockLink));
- while (proclock)
+ dlist_foreach(proclock_iter, &theLock->procLocks)
{
+ PROCLOCK *proclock =
+ dlist_container(PROCLOCK, lockLink, proclock_iter.cur);
PGPROC *proc = proclock->tag.myProc;
LOCK *lock = proclock->tag.myLock;
LockInstanceData *instance;
instance->leaderPid = proclock->groupLeader->pid;
instance->fastpath = false;
data->nlocks++;
-
- proclock = (PROCLOCK *) SHMQueueNext(procLocks, &proclock->lockLink,
- offsetof(PROCLOCK, lockLink));
}
/* Enlarge waiter_pids[] if it's too small to hold all wait queue PIDs */
waitQueue = &(theLock->waitProcs);
- queue_size = waitQueue->size;
+ queue_size = dclist_count(waitQueue);
if (queue_size > data->maxpids - data->npids)
{
}
/* Collect PIDs from the lock's wait queue, stopping at blocked_proc */
- queued_proc = (PGPROC *) waitQueue->links.next;
- for (i = 0; i < queue_size; i++)
+ dclist_foreach(proc_iter, waitQueue)
{
+ PGPROC *queued_proc = dlist_container(PGPROC, links, proc_iter.cur);
if (queued_proc == blocked_proc)
break;
data->waiter_pids[data->npids++] = queued_proc->pid;
void
DumpLocks(PGPROC *proc)
{
- SHM_QUEUE *procLocks;
- PROCLOCK *proclock;
- LOCK *lock;
int i;
if (proc == NULL)
for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
{
- procLocks = &(proc->myProcLocks[i]);
+ dlist_head *procLocks = &proc->myProcLocks[i];
+ dlist_iter iter;
- proclock = (PROCLOCK *) SHMQueueNext(procLocks, procLocks,
- offsetof(PROCLOCK, procLink));
-
- while (proclock)
+ dlist_foreach(iter, procLocks)
{
- Assert(proclock->tag.myProc == proc);
-
- lock = proclock->tag.myLock;
+ PROCLOCK *proclock = dlist_container(PROCLOCK, procLink, iter.cur);
+ LOCK *lock = proclock->tag.myLock;
+ Assert(proclock->tag.myProc == proc);
PROCLOCK_PRINT("DumpLocks", proclock);
LOCK_PRINT("DumpLocks", lock, 0);
-
- proclock = (PROCLOCK *)
- SHMQueueNext(procLocks, &proclock->procLink,
- offsetof(PROCLOCK, procLink));
}
}
}
{
lock->grantMask = 0;
lock->waitMask = 0;
- SHMQueueInit(&(lock->procLocks));
- ProcQueueInit(&(lock->waitProcs));
+ dlist_init(&lock->procLocks);
+ dclist_init(&lock->waitProcs);
lock->nRequested = 0;
lock->nGranted = 0;
MemSet(lock->requested, 0, sizeof(int) * MAX_LOCKMODES);
* of shared memory, because there won't be anything to cause
* anyone to release the lock object later.
*/
- Assert(SHMQueueEmpty(&(lock->procLocks)));
+ Assert(dlist_is_empty(&lock->procLocks));
if (!hash_search_with_hash_value(LockMethodLockHash,
(void *) &(lock->tag),
hashcode,
proclock->holdMask = 0;
proclock->releaseMask = 0;
/* Add proclock to appropriate lists */
- SHMQueueInsertBefore(&lock->procLocks, &proclock->lockLink);
- SHMQueueInsertBefore(&(proc->myProcLocks[partition]),
- &proclock->procLink);
+ dlist_push_tail(&lock->procLocks, &proclock->lockLink);
+ dlist_push_tail(&proc->myProcLocks[partition],
+ &proclock->procLink);
PROCLOCK_PRINT("lock_twophase_recover: new", proclock);
}
else
/*
* Interface (a):
* ProcSleep(), ProcWakeup(),
- * ProcQueueAlloc() -- create a shm queue for sleeping processes
- * ProcQueueInit() -- create a queue without allocing memory
*
* Waiting for a lock causes the backend to be put to sleep. Whoever releases
* the lock wakes the process up again (and gives it an error code so it knows
* Initialize the data structures.
*/
ProcGlobal->spins_per_delay = DEFAULT_SPINS_PER_DELAY;
- ProcGlobal->freeProcs = NULL;
- ProcGlobal->autovacFreeProcs = NULL;
- ProcGlobal->bgworkerFreeProcs = NULL;
- ProcGlobal->walsenderFreeProcs = NULL;
+ dlist_init(&ProcGlobal->freeProcs);
+ dlist_init(&ProcGlobal->autovacFreeProcs);
+ dlist_init(&ProcGlobal->bgworkerFreeProcs);
+ dlist_init(&ProcGlobal->walsenderFreeProcs);
ProcGlobal->startupBufferPinWaitBufId = -1;
ProcGlobal->walwriterLatch = NULL;
ProcGlobal->checkpointerLatch = NULL;
for (i = 0; i < TotalProcs; i++)
{
+ PGPROC *proc = &procs[i];
+
/* Common initialization for all PGPROCs, regardless of type. */
/*
*/
if (i < MaxBackends + NUM_AUXILIARY_PROCS)
{
- procs[i].sem = PGSemaphoreCreate();
- InitSharedLatch(&(procs[i].procLatch));
- LWLockInitialize(&(procs[i].fpInfoLock), LWTRANCHE_LOCK_FASTPATH);
+ proc->sem = PGSemaphoreCreate();
+ InitSharedLatch(&(proc->procLatch));
+ LWLockInitialize(&(proc->fpInfoLock), LWTRANCHE_LOCK_FASTPATH);
}
- procs[i].pgprocno = i;
+ proc->pgprocno = i;
/*
* Newly created PGPROCs for normal backends, autovacuum and bgworkers
if (i < MaxConnections)
{
/* PGPROC for normal backend, add to freeProcs list */
- procs[i].links.next = (SHM_QUEUE *) ProcGlobal->freeProcs;
- ProcGlobal->freeProcs = &procs[i];
- procs[i].procgloballist = &ProcGlobal->freeProcs;
+ dlist_push_head(&ProcGlobal->freeProcs, &proc->links);
+ proc->procgloballist = &ProcGlobal->freeProcs;
}
else if (i < MaxConnections + autovacuum_max_workers + 1)
{
/* PGPROC for AV launcher/worker, add to autovacFreeProcs list */
- procs[i].links.next = (SHM_QUEUE *) ProcGlobal->autovacFreeProcs;
- ProcGlobal->autovacFreeProcs = &procs[i];
- procs[i].procgloballist = &ProcGlobal->autovacFreeProcs;
+ dlist_push_head(&ProcGlobal->autovacFreeProcs, &proc->links);
+ proc->procgloballist = &ProcGlobal->autovacFreeProcs;
}
else if (i < MaxConnections + autovacuum_max_workers + 1 + max_worker_processes)
{
/* PGPROC for bgworker, add to bgworkerFreeProcs list */
- procs[i].links.next = (SHM_QUEUE *) ProcGlobal->bgworkerFreeProcs;
- ProcGlobal->bgworkerFreeProcs = &procs[i];
- procs[i].procgloballist = &ProcGlobal->bgworkerFreeProcs;
+ dlist_push_head(&ProcGlobal->bgworkerFreeProcs, &proc->links);
+ proc->procgloballist = &ProcGlobal->bgworkerFreeProcs;
}
else if (i < MaxBackends)
{
/* PGPROC for walsender, add to walsenderFreeProcs list */
- procs[i].links.next = (SHM_QUEUE *) ProcGlobal->walsenderFreeProcs;
- ProcGlobal->walsenderFreeProcs = &procs[i];
- procs[i].procgloballist = &ProcGlobal->walsenderFreeProcs;
+ dlist_push_head(&ProcGlobal->walsenderFreeProcs, &proc->links);
+ proc->procgloballist = &ProcGlobal->walsenderFreeProcs;
}
/* Initialize myProcLocks[] shared memory queues. */
for (j = 0; j < NUM_LOCK_PARTITIONS; j++)
- SHMQueueInit(&(procs[i].myProcLocks[j]));
+ dlist_init(&(proc->myProcLocks[j]));
/* Initialize lockGroupMembers list. */
- dlist_init(&procs[i].lockGroupMembers);
+ dlist_init(&proc->lockGroupMembers);
/*
* Initialize the atomic variables, otherwise, it won't be safe to
* access them for backends that aren't currently in use.
*/
- pg_atomic_init_u32(&(procs[i].procArrayGroupNext), INVALID_PGPROCNO);
- pg_atomic_init_u32(&(procs[i].clogGroupNext), INVALID_PGPROCNO);
- pg_atomic_init_u64(&(procs[i].waitStart), 0);
+ pg_atomic_init_u32(&(proc->procArrayGroupNext), INVALID_PGPROCNO);
+ pg_atomic_init_u32(&(proc->clogGroupNext), INVALID_PGPROCNO);
+ pg_atomic_init_u64(&(proc->waitStart), 0);
}
/*
void
InitProcess(void)
{
- PGPROC *volatile *procgloballist;
+ dlist_head *procgloballist;
/*
* ProcGlobal should be set up already (if we are a backend, we inherit
set_spins_per_delay(ProcGlobal->spins_per_delay);
- MyProc = *procgloballist;
-
- if (MyProc != NULL)
+ if (!dlist_is_empty(procgloballist))
{
- *procgloballist = (PGPROC *) MyProc->links.next;
+ MyProc = (PGPROC*) dlist_pop_head_node(procgloballist);
SpinLockRelease(ProcStructLock);
}
else
* Initialize all fields of MyProc, except for those previously
* initialized by InitProcGlobal.
*/
- SHMQueueElemInit(&(MyProc->links));
+ dlist_node_init(&MyProc->links);
MyProc->waitStatus = PROC_WAIT_STATUS_OK;
MyProc->lxid = InvalidLocalTransactionId;
MyProc->fpVXIDLock = false;
/* Last process should have released all locks. */
for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
- Assert(SHMQueueEmpty(&(MyProc->myProcLocks[i])));
+ Assert(dlist_is_empty(&(MyProc->myProcLocks[i])));
}
#endif
MyProc->recoveryConflictPending = false;
* Initialize all fields of MyProc, except for those previously
* initialized by InitProcGlobal.
*/
- SHMQueueElemInit(&(MyProc->links));
+ dlist_node_init(&MyProc->links);
MyProc->waitStatus = PROC_WAIT_STATUS_OK;
MyProc->lxid = InvalidLocalTransactionId;
MyProc->fpVXIDLock = false;
/* Last process should have released all locks. */
for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
- Assert(SHMQueueEmpty(&(MyProc->myProcLocks[i])));
+ Assert(dlist_is_empty(&(MyProc->myProcLocks[i])));
}
#endif
bool
HaveNFreeProcs(int n)
{
- PGPROC *proc;
+ dlist_iter iter;
SpinLockAcquire(ProcStructLock);
- proc = ProcGlobal->freeProcs;
-
- while (n > 0 && proc != NULL)
+ dlist_foreach(iter, &ProcGlobal->freeProcs)
{
- proc = (PGPROC *) proc->links.next;
n--;
+ if (n == 0)
+ break;
}
SpinLockRelease(ProcStructLock);
partitionLock = LockHashPartitionLock(lockAwaited->hashcode);
LWLockAcquire(partitionLock, LW_EXCLUSIVE);
- if (MyProc->links.next != NULL)
+ if (!dlist_node_is_detached(&MyProc->links))
{
/* We could not have been granted the lock yet */
RemoveFromWaitQueue(MyProc, lockAwaited->hashcode);
ProcKill(int code, Datum arg)
{
PGPROC *proc;
- PGPROC *volatile *procgloballist;
+ dlist_head *procgloballist;
Assert(MyProc != NULL);
/* Last process should have released all locks. */
for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
- Assert(SHMQueueEmpty(&(MyProc->myProcLocks[i])));
+ Assert(dlist_is_empty(&(MyProc->myProcLocks[i])));
}
#endif
/*
* Detach from any lock group of which we are a member. If the leader
- * exist before all other group members, its PGPROC will remain allocated
+ * exits before all other group members, its PGPROC will remain allocated
* until the last group process exits; that process must return the
* leader's PGPROC to the appropriate list.
*/
/* Leader exited first; return its PGPROC. */
SpinLockAcquire(ProcStructLock);
- leader->links.next = (SHM_QUEUE *) *procgloballist;
- *procgloballist = leader;
+ dlist_push_head(procgloballist, &leader->links);
SpinLockRelease(ProcStructLock);
}
}
Assert(dlist_is_empty(&proc->lockGroupMembers));
/* Return PGPROC structure (and semaphore) to appropriate freelist */
- proc->links.next = (SHM_QUEUE *) *procgloballist;
- *procgloballist = proc;
+ dlist_push_tail(procgloballist, &proc->links);
}
/* Update shared estimate of spins_per_delay */
return result;
}
-/*
- * ProcQueue package: routines for putting processes to sleep
- * and waking them up
- */
-
-/*
- * ProcQueueAlloc -- alloc/attach to a shared memory process queue
- *
- * Returns: a pointer to the queue
- * Side Effects: Initializes the queue if it wasn't there before
- */
-#ifdef NOT_USED
-PROC_QUEUE *
-ProcQueueAlloc(const char *name)
-{
- PROC_QUEUE *queue;
- bool found;
-
- queue = (PROC_QUEUE *)
- ShmemInitStruct(name, sizeof(PROC_QUEUE), &found);
-
- if (!found)
- ProcQueueInit(queue);
-
- return queue;
-}
-#endif
-
-/*
- * ProcQueueInit -- initialize a shared memory process queue
- */
-void
-ProcQueueInit(PROC_QUEUE *queue)
-{
- SHMQueueInit(&(queue->links));
- queue->size = 0;
-}
-
/*
* ProcSleep -- put a process to sleep on the specified lock
PROCLOCK *proclock = locallock->proclock;
uint32 hashcode = locallock->hashcode;
LWLock *partitionLock = LockHashPartitionLock(hashcode);
- PROC_QUEUE *waitQueue = &(lock->waitProcs);
- SHM_QUEUE *waitQueuePos;
+ dclist_head *waitQueue = &lock->waitProcs;
+ PGPROC *insert_before = NULL;
LOCKMASK myHeldLocks = MyProc->heldLocks;
TimestampTz standbyWaitStart = 0;
bool early_deadlock = false;
bool logged_recovery_conflict = false;
ProcWaitStatus myWaitStatus;
PGPROC *leader = MyProc->lockGroupLeader;
- int i;
/*
* If group locking is in use, locks held by members of my locking group
*/
if (leader != NULL)
{
- SHM_QUEUE *procLocks = &(lock->procLocks);
- PROCLOCK *otherproclock;
+ dlist_iter iter;
- otherproclock = (PROCLOCK *)
- SHMQueueNext(procLocks, procLocks, offsetof(PROCLOCK, lockLink));
- while (otherproclock != NULL)
+ dlist_foreach(iter, &lock->procLocks)
{
+ PROCLOCK *otherproclock;
+
+ otherproclock = dlist_container(PROCLOCK, lockLink, iter.cur);
+
if (otherproclock->groupLeader == leader)
myHeldLocks |= otherproclock->holdMask;
- otherproclock = (PROCLOCK *)
- SHMQueueNext(procLocks, &otherproclock->lockLink,
- offsetof(PROCLOCK, lockLink));
}
}
* we are only considering the part of the wait queue before my insertion
* point.
*/
- if (myHeldLocks != 0 && waitQueue->size > 0)
+ if (myHeldLocks != 0 && !dclist_is_empty(waitQueue))
{
LOCKMASK aheadRequests = 0;
- SHM_QUEUE *proc_node;
+ dlist_iter iter;
- proc_node = waitQueue->links.next;
- for (i = 0; i < waitQueue->size; i++)
+ dclist_foreach(iter, waitQueue)
{
- PGPROC *proc = (PGPROC *) proc_node;
+ PGPROC *proc = dlist_container(PGPROC, links, iter.cur);
/*
* If we're part of the same locking group as this waiter, its
* aheadRequests.
*/
if (leader != NULL && leader == proc->lockGroupLeader)
- {
- proc_node = proc->links.next;
continue;
- }
+
/* Must he wait for me? */
if (lockMethodTable->conflictTab[proc->waitLockMode] & myHeldLocks)
{
GrantAwaitedLock();
return PROC_WAIT_STATUS_OK;
}
- /* Break out of loop to put myself before him */
+
+ /* Put myself into wait queue before conflicting process */
+ insert_before = proc;
break;
}
/* Nope, so advance to next waiter */
aheadRequests |= LOCKBIT_ON(proc->waitLockMode);
- proc_node = proc->links.next;
}
-
- /*
- * If we iterated through the whole queue, cur points to the waitQueue
- * head, so we will insert at tail of queue as desired.
- */
- waitQueuePos = proc_node;
- }
- else
- {
- /* I hold no locks, so I can't push in front of anyone. */
- waitQueuePos = &waitQueue->links;
}
/*
* Insert self into queue, at the position determined above.
*/
- SHMQueueInsertBefore(waitQueuePos, &MyProc->links);
- waitQueue->size++;
+ if (insert_before)
+ dclist_insert_before(waitQueue, &insert_before->links, &MyProc->links);
+ else
+ dclist_push_tail(waitQueue, &MyProc->links);
lock->waitMask |= LOCKBIT_ON(lockmode);
long secs;
int usecs;
long msecs;
- SHM_QUEUE *procLocks;
+ dlist_iter proc_iter;
PROCLOCK *curproclock;
bool first_holder = true,
first_waiter = true;
LWLockAcquire(partitionLock, LW_SHARED);
- procLocks = &(lock->procLocks);
- curproclock = (PROCLOCK *) SHMQueueNext(procLocks, procLocks,
- offsetof(PROCLOCK, lockLink));
-
- while (curproclock)
+ dlist_foreach(proc_iter, &lock->procLocks)
{
+ curproclock =
+ dlist_container(PROCLOCK, lockLink, proc_iter.cur);
+
/*
* we are a waiter if myProc->waitProcLock == curproclock; we
* are a holder if it is NULL or something different
lockHoldersNum++;
}
-
- curproclock = (PROCLOCK *) SHMQueueNext(procLocks,
- &curproclock->lockLink,
- offsetof(PROCLOCK, lockLink));
}
LWLockRelease(partitionLock);
* ProcWakeup -- wake up a process by setting its latch.
*
* Also remove the process from the wait queue and set its links invalid.
- * RETURN: the next process in the wait queue.
*
* The appropriate lock partition lock must be held by caller.
*
* to twiddle the lock's request counts too --- see RemoveFromWaitQueue.
* Hence, in practice the waitStatus parameter must be PROC_WAIT_STATUS_OK.
*/
-PGPROC *
+void
ProcWakeup(PGPROC *proc, ProcWaitStatus waitStatus)
{
- PGPROC *retProc;
+ if (dlist_node_is_detached(&proc->links))
+ return;
- /* Proc should be sleeping ... */
- if (proc->links.prev == NULL ||
- proc->links.next == NULL)
- return NULL;
Assert(proc->waitStatus == PROC_WAIT_STATUS_WAITING);
- /* Save next process before we zap the list link */
- retProc = (PGPROC *) proc->links.next;
-
/* Remove process from wait queue */
- SHMQueueDelete(&(proc->links));
- (proc->waitLock->waitProcs.size)--;
+ dclist_delete_from_thoroughly(&proc->waitLock->waitProcs, &proc->links);
/* Clean up process' state and pass it the ok/fail signal */
proc->waitLock = NULL;
/* And awaken it */
SetLatch(&proc->procLatch);
-
- return retProc;
}
/*
void
ProcLockWakeup(LockMethod lockMethodTable, LOCK *lock)
{
- PROC_QUEUE *waitQueue = &(lock->waitProcs);
- int queue_size = waitQueue->size;
- PGPROC *proc;
+ dclist_head *waitQueue = &lock->waitProcs;
LOCKMASK aheadRequests = 0;
+ dlist_mutable_iter miter;
- Assert(queue_size >= 0);
-
- if (queue_size == 0)
+ if (dclist_is_empty(waitQueue))
return;
- proc = (PGPROC *) waitQueue->links.next;
-
- while (queue_size-- > 0)
+ dclist_foreach_modify(miter, waitQueue)
{
+ PGPROC *proc = dlist_container(PGPROC, links, miter.cur);
LOCKMODE lockmode = proc->waitLockMode;
/*
{
/* OK to waken */
GrantLock(lock, proc->waitProcLock, lockmode);
- proc = ProcWakeup(proc, PROC_WAIT_STATUS_OK);
-
- /*
- * ProcWakeup removes proc from the lock's waiting process queue
- * and returns the next proc in chain; don't use proc's next-link,
- * because it's been cleared.
- */
+ /* removes proc from the lock's waiting process queue */
+ ProcWakeup(proc, PROC_WAIT_STATUS_OK);
}
else
{
/*
- * Cannot wake this guy. Remember his request for later checks.
+ * Lock conflicts: Don't wake, but remember requested mode for
+ * later checks.
*/
aheadRequests |= LOCKBIT_ON(lockmode);
- proc = (PGPROC *) proc->links.next;
}
}
-
- Assert(waitQueue->size >= 0);
}
/*
#error "lock.h may not be included from frontend code"
#endif
+#include "lib/ilist.h"
#include "storage/backendid.h"
#include "storage/lockdefs.h"
#include "storage/lwlock.h"
/* struct PGPROC is declared in proc.h, but must forward-reference it */
typedef struct PGPROC PGPROC;
-typedef struct PROC_QUEUE
-{
- SHM_QUEUE links; /* head of list of PGPROC objects */
- int size; /* number of entries in list */
-} PROC_QUEUE;
-
/* GUC variables */
extern PGDLLIMPORT int max_locks_per_xact;
/* data */
LOCKMASK grantMask; /* bitmask for lock types already granted */
LOCKMASK waitMask; /* bitmask for lock types awaited */
- SHM_QUEUE procLocks; /* list of PROCLOCK objects assoc. with lock */
- PROC_QUEUE waitProcs; /* list of PGPROC objects waiting on lock */
+ dlist_head procLocks; /* list of PROCLOCK objects assoc. with lock */
+ dclist_head waitProcs; /* list of PGPROC objects waiting on lock */
int requested[MAX_LOCKMODES]; /* counts of requested locks */
int nRequested; /* total of requested[] array */
int granted[MAX_LOCKMODES]; /* counts of granted locks */
PGPROC *groupLeader; /* proc's lock group leader, or proc itself */
LOCKMASK holdMask; /* bitmask for lock types currently held */
LOCKMASK releaseMask; /* bitmask for lock types to be released */
- SHM_QUEUE lockLink; /* list link in LOCK's list of proclocks */
- SHM_QUEUE procLink; /* list link in PGPROC's list of proclocks */
+ dlist_node lockLink; /* list link in LOCK's list of proclocks */
+ dlist_node procLink; /* list link in PGPROC's list of proclocks */
} PROCLOCK;
#define PROCLOCK_LOCKMETHOD(proclock) \
struct PGPROC
{
/* proc->links MUST BE FIRST IN STRUCT (see ProcSleep,ProcWakeup,etc) */
- SHM_QUEUE links; /* list link if process is in a list */
- PGPROC **procgloballist; /* procglobal list that owns this PGPROC */
+ dlist_node links; /* list link if process is in a list */
+ dlist_head *procgloballist; /* procglobal list that owns this PGPROC */
PGSemaphore sem; /* ONE semaphore to sleep on */
ProcWaitStatus waitStatus;
* linked into one of these lists, according to the partition number of
* their lock.
*/
- SHM_QUEUE myProcLocks[NUM_LOCK_PARTITIONS];
+ dlist_head myProcLocks[NUM_LOCK_PARTITIONS];
XidCacheStatus subxidStatus; /* mirrored with
* ProcGlobal->subxidStates[i] */
/* Length of allProcs array */
uint32 allProcCount;
/* Head of list of free PGPROC structures */
- PGPROC *freeProcs;
+ dlist_head freeProcs;
/* Head of list of autovacuum's free PGPROC structures */
- PGPROC *autovacFreeProcs;
+ dlist_head autovacFreeProcs;
/* Head of list of bgworker free PGPROC structures */
- PGPROC *bgworkerFreeProcs;
+ dlist_head bgworkerFreeProcs;
/* Head of list of walsender free PGPROC structures */
- PGPROC *walsenderFreeProcs;
+ dlist_head walsenderFreeProcs;
/* First pgproc waiting for group XID clear */
pg_atomic_uint32 procArrayGroupFirst;
/* First pgproc waiting for group transaction status update */
extern bool HaveNFreeProcs(int n);
extern void ProcReleaseLocks(bool isCommit);
-extern void ProcQueueInit(PROC_QUEUE *queue);
extern ProcWaitStatus ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable);
-extern PGPROC *ProcWakeup(PGPROC *proc, ProcWaitStatus waitStatus);
+extern void ProcWakeup(PGPROC *proc, ProcWaitStatus waitStatus);
extern void ProcLockWakeup(LockMethod lockMethodTable, LOCK *lock);
extern void CheckDeadLockAlert(void);
extern bool IsWaitingForLock(void);
PROCLOCK
PROCLOCKTAG
PROC_HDR
-PROC_QUEUE
PSID
PSID_AND_ATTRIBUTES
PSQL_COMP_CASE