From: Heikki Linnakangas Date: Wed, 11 Feb 2026 14:48:45 +0000 (+0200) Subject: Move ProcStructLock to the ProcGlobal struct X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7984ce7a1d21819865e473f17cb6b928cf58a10d;p=thirdparty%2Fpostgresql.git Move ProcStructLock to the ProcGlobal struct It protects the freeProcs and some other fields in ProcGlobal, so let's move it there. It's good for cache locality to have it next to the thing it protects, and just makes more sense anyway. I believe it was allocated as a separate shared memory area just for historical reasons. Reviewed-by: Chao Li Reviewed-by: Ashutosh Bapat Discussion: https://www.postgresql.org/message-id/b78719db-0c54-409f-b185-b0d59261143f@iki.fi --- diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 05b1feef3cf..e9134b9751b 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -104,7 +104,6 @@ typedef struct char **LWLockTrancheNames; int *LWLockCounter; LWLockPadded *MainLWLockArray; - slock_t *ProcStructLock; PROC_HDR *ProcGlobal; PGPROC *AuxiliaryProcs; PGPROC *PreparedXactProcs; @@ -735,7 +734,6 @@ save_backend_variables(BackendParameters *param, param->LWLockTrancheNames = LWLockTrancheNames; param->LWLockCounter = LWLockCounter; param->MainLWLockArray = MainLWLockArray; - param->ProcStructLock = ProcStructLock; param->ProcGlobal = ProcGlobal; param->AuxiliaryProcs = AuxiliaryProcs; param->PreparedXactProcs = PreparedXactProcs; @@ -995,7 +993,6 @@ restore_backend_variables(BackendParameters *param) LWLockTrancheNames = param->LWLockTrancheNames; LWLockCounter = param->LWLockCounter; MainLWLockArray = param->MainLWLockArray; - ProcStructLock = param->ProcStructLock; ProcGlobal = param->ProcGlobal; AuxiliaryProcs = param->AuxiliaryProcs; PreparedXactProcs = param->PreparedXactProcs; diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index 31ccdb1ef89..fd8318bdf3d 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -66,15 +66,6 @@ bool log_lock_waits = true; /* Pointer to this process's PGPROC struct, if any */ PGPROC *MyProc = NULL; -/* - * This spinlock protects the freelist of recycled PGPROC structures. - * We cannot use an LWLock because the LWLock manager depends on already - * having a PGPROC and a wait semaphore! But these structures are touched - * relatively infrequently (only at backend startup or shutdown) and not for - * very long, so a spinlock is okay. - */ -NON_EXEC_STATIC slock_t *ProcStructLock = NULL; - /* Pointers to shared-memory structures */ PROC_HDR *ProcGlobal = NULL; NON_EXEC_STATIC PGPROC *AuxiliaryProcs = NULL; @@ -214,6 +205,7 @@ InitProcGlobal(void) * Initialize the data structures. */ ProcGlobal->spins_per_delay = DEFAULT_SPINS_PER_DELAY; + SpinLockInit(&ProcGlobal->freeProcsLock); dlist_init(&ProcGlobal->freeProcs); dlist_init(&ProcGlobal->autovacFreeProcs); dlist_init(&ProcGlobal->bgworkerFreeProcs); @@ -378,12 +370,6 @@ InitProcGlobal(void) */ AuxiliaryProcs = &procs[MaxBackends]; PreparedXactProcs = &procs[MaxBackends + NUM_AUXILIARY_PROCS]; - - /* Create ProcStructLock spinlock, too */ - ProcStructLock = (slock_t *) ShmemInitStruct("ProcStructLock spinlock", - sizeof(slock_t), - &found); - SpinLockInit(ProcStructLock); } /* @@ -429,17 +415,17 @@ InitProcess(void) * Try to get a proc struct from the appropriate free list. If this * fails, we must be out of PGPROC structures (not to mention semaphores). * - * While we are holding the ProcStructLock, also copy the current shared + * While we are holding the spinlock, also copy the current shared * estimate of spins_per_delay to local storage. */ - SpinLockAcquire(ProcStructLock); + SpinLockAcquire(&ProcGlobal->freeProcsLock); set_spins_per_delay(ProcGlobal->spins_per_delay); if (!dlist_is_empty(procgloballist)) { MyProc = dlist_container(PGPROC, links, dlist_pop_head_node(procgloballist)); - SpinLockRelease(ProcStructLock); + SpinLockRelease(&ProcGlobal->freeProcsLock); } else { @@ -449,7 +435,7 @@ InitProcess(void) * error message. XXX do we need to give a different failure message * in the autovacuum case? */ - SpinLockRelease(ProcStructLock); + SpinLockRelease(&ProcGlobal->freeProcsLock); if (AmWalSenderProcess()) ereport(FATAL, (errcode(ERRCODE_TOO_MANY_CONNECTIONS), @@ -634,13 +620,13 @@ InitAuxiliaryProcess(void) RegisterPostmasterChildActive(); /* - * We use the ProcStructLock to protect assignment and releasing of + * We use the freeProcsLock to protect assignment and releasing of * AuxiliaryProcs entries. * - * While we are holding the ProcStructLock, also copy the current shared + * While we are holding the spinlock, also copy the current shared * estimate of spins_per_delay to local storage. */ - SpinLockAcquire(ProcStructLock); + SpinLockAcquire(&ProcGlobal->freeProcsLock); set_spins_per_delay(ProcGlobal->spins_per_delay); @@ -655,7 +641,7 @@ InitAuxiliaryProcess(void) } if (proctype >= NUM_AUXILIARY_PROCS) { - SpinLockRelease(ProcStructLock); + SpinLockRelease(&ProcGlobal->freeProcsLock); elog(FATAL, "all AuxiliaryProcs are in use"); } @@ -663,7 +649,7 @@ InitAuxiliaryProcess(void) /* use volatile pointer to prevent code rearrangement */ ((volatile PGPROC *) auxproc)->pid = MyProcPid; - SpinLockRelease(ProcStructLock); + SpinLockRelease(&ProcGlobal->freeProcsLock); MyProc = auxproc; MyProcNumber = GetNumberFromPGProc(MyProc); @@ -789,7 +775,7 @@ HaveNFreeProcs(int n, int *nfree) Assert(n > 0); Assert(nfree); - SpinLockAcquire(ProcStructLock); + SpinLockAcquire(&ProcGlobal->freeProcsLock); *nfree = 0; dlist_foreach(iter, &ProcGlobal->freeProcs) @@ -799,7 +785,7 @@ HaveNFreeProcs(int n, int *nfree) break; } - SpinLockRelease(ProcStructLock); + SpinLockRelease(&ProcGlobal->freeProcsLock); return (*nfree == n); } @@ -980,9 +966,9 @@ ProcKill(int code, Datum arg) procgloballist = leader->procgloballist; /* Leader exited first; return its PGPROC. */ - SpinLockAcquire(ProcStructLock); + SpinLockAcquire(&ProcGlobal->freeProcsLock); dlist_push_head(procgloballist, &leader->links); - SpinLockRelease(ProcStructLock); + SpinLockRelease(&ProcGlobal->freeProcsLock); } } else if (leader != MyProc) @@ -1013,7 +999,7 @@ ProcKill(int code, Datum arg) proc->vxid.lxid = InvalidTransactionId; procgloballist = proc->procgloballist; - SpinLockAcquire(ProcStructLock); + SpinLockAcquire(&ProcGlobal->freeProcsLock); /* * If we're still a member of a locking group, that means we're a leader @@ -1032,7 +1018,7 @@ ProcKill(int code, Datum arg) /* Update shared estimate of spins_per_delay */ ProcGlobal->spins_per_delay = update_spins_per_delay(ProcGlobal->spins_per_delay); - SpinLockRelease(ProcStructLock); + SpinLockRelease(&ProcGlobal->freeProcsLock); } /* @@ -1072,7 +1058,7 @@ AuxiliaryProcKill(int code, Datum arg) MyProcNumber = INVALID_PROC_NUMBER; DisownLatch(&proc->procLatch); - SpinLockAcquire(ProcStructLock); + SpinLockAcquire(&ProcGlobal->freeProcsLock); /* Mark auxiliary proc no longer in use */ proc->pid = 0; @@ -1082,7 +1068,7 @@ AuxiliaryProcKill(int code, Datum arg) /* Update shared estimate of spins_per_delay */ ProcGlobal->spins_per_delay = update_spins_per_delay(ProcGlobal->spins_per_delay); - SpinLockRelease(ProcStructLock); + SpinLockRelease(&ProcGlobal->freeProcsLock); } /* diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index ac0df4aeaaa..23e5cd98161 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -420,6 +420,16 @@ typedef struct PROC_HDR /* Length of allProcs array */ uint32 allProcCount; + + /* + * This spinlock protects the below freelists of PGPROC structures. We + * cannot use an LWLock because the LWLock manager depends on already + * having a PGPROC and a wait semaphore! But these structures are touched + * relatively infrequently (only at backend startup or shutdown) and not + * for very long, so a spinlock is okay. + */ + slock_t freeProcsLock; + /* Head of list of free PGPROC structures */ dlist_head freeProcs; /* Head of list of autovacuum & special worker free PGPROC structures */ @@ -428,6 +438,7 @@ typedef struct PROC_HDR dlist_head bgworkerFreeProcs; /* Head of list of walsender free PGPROC structures */ dlist_head walsenderFreeProcs; + /* First pgproc waiting for group XID clear */ pg_atomic_uint32 procArrayGroupFirst; /* First pgproc waiting for group transaction status update */ @@ -489,7 +500,6 @@ extern PGDLLIMPORT int IdleSessionTimeout; extern PGDLLIMPORT bool log_lock_waits; #ifdef EXEC_BACKEND -extern PGDLLIMPORT slock_t *ProcStructLock; extern PGDLLIMPORT PGPROC *AuxiliaryProcs; #endif