From d5362cffef3de02259841ce4b049b7bd8898bef9 Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date: Thu, 26 Mar 2026 13:26:59 +0200
Subject: [PATCH v1 4/5] Use ShmemInitStruct to allocate lwlock.c's shared
 memory

It's nice to have them show up in pg_shmem_allocations like all other
shmem areas. ShmemInitStruct() depends on ShmemIndexLock, but only
after postmaster startup.
---
 src/backend/postmaster/launch_backend.c |  3 --
 src/backend/storage/ipc/ipci.c          |  6 ++--
 src/backend/storage/ipc/shmem.c         | 15 ++++++----
 src/backend/storage/lmgr/lwlock.c       | 39 ++++++++++++++++---------
 src/include/storage/lwlock.h            |  7 +----
 5 files changed, 39 insertions(+), 31 deletions(-)

diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 8c134eaca88..8aaf427df48 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -99,7 +99,6 @@ typedef struct
 #ifdef USE_INJECTION_POINTS
 	struct InjectionPointsCtl *ActiveInjectionPoints;
 #endif
-	LWLockTrancheShmemData *LWLockTranches;
 	LWLockPadded *MainLWLockArray;
 	PROC_HDR   *ProcGlobal;
 	PGPROC	   *AuxiliaryProcs;
@@ -726,7 +725,6 @@ save_backend_variables(BackendParameters *param,
 	param->ActiveInjectionPoints = ActiveInjectionPoints;
 #endif
 
-	param->LWLockTranches = LWLockTranches;
 	param->MainLWLockArray = MainLWLockArray;
 	param->ProcGlobal = ProcGlobal;
 	param->AuxiliaryProcs = AuxiliaryProcs;
@@ -982,7 +980,6 @@ restore_backend_variables(BackendParameters *param)
 	ActiveInjectionPoints = param->ActiveInjectionPoints;
 #endif
 
-	LWLockTranches = param->LWLockTranches;
 	MainLWLockArray = param->MainLWLockArray;
 	ProcGlobal = param->ProcGlobal;
 	AuxiliaryProcs = param->AuxiliaryProcs;
diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c
index 3d3f153809b..036db3fa514 100644
--- a/src/backend/storage/ipc/ipci.c
+++ b/src/backend/storage/ipc/ipci.c
@@ -249,10 +249,8 @@ CreateSharedMemoryAndSemaphores(void)
 static void
 CreateOrAttachShmemStructs(void)
 {
-	/*
-	 * Now initialize LWLocks, which do shared memory allocation.
-	 */
-	CreateLWLocks();
+	/* Start with initializing LWLock tranches */
+	LWLockShmemInit();
 
 	dsm_shmem_init();
 	DSMRegistryShmemInit();
diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c
index f392faa534f..339fbba3404 100644
--- a/src/backend/storage/ipc/shmem.c
+++ b/src/backend/storage/ipc/shmem.c
@@ -379,7 +379,8 @@ ShmemInitStruct(const char *name, Size size, bool *foundPtr)
 
 	Assert(ShmemIndex != NULL);
 
-	LWLockAcquire(ShmemIndexLock, LW_EXCLUSIVE);
+	if (IsUnderPostmaster)
+		LWLockAcquire(ShmemIndexLock, LW_EXCLUSIVE);
 
 	/* look it up in the shmem index */
 	result = (ShmemIndexEnt *)
@@ -387,7 +388,8 @@ ShmemInitStruct(const char *name, Size size, bool *foundPtr)
 
 	if (!result)
 	{
-		LWLockRelease(ShmemIndexLock);
+		if (IsUnderPostmaster)
+			LWLockRelease(ShmemIndexLock);
 		ereport(ERROR,
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("could not create ShmemIndex entry for data structure \"%s\"",
@@ -403,7 +405,8 @@ ShmemInitStruct(const char *name, Size size, bool *foundPtr)
 		 */
 		if (result->size != size)
 		{
-			LWLockRelease(ShmemIndexLock);
+			if (IsUnderPostmaster)
+				LWLockRelease(ShmemIndexLock);
 			ereport(ERROR,
 					(errmsg("ShmemIndex entry size is wrong for data structure"
 							" \"%s\": expected %zu, actual %zu",
@@ -421,7 +424,8 @@ ShmemInitStruct(const char *name, Size size, bool *foundPtr)
 		{
 			/* out of memory; remove the failed ShmemIndex entry */
 			hash_search(ShmemIndex, name, HASH_REMOVE, NULL);
-			LWLockRelease(ShmemIndexLock);
+			if (IsUnderPostmaster)
+				LWLockRelease(ShmemIndexLock);
 			ereport(ERROR,
 					(errcode(ERRCODE_OUT_OF_MEMORY),
 					 errmsg("not enough shared memory for data structure"
@@ -433,7 +437,8 @@ ShmemInitStruct(const char *name, Size size, bool *foundPtr)
 		result->location = structPtr;
 	}
 
-	LWLockRelease(ShmemIndexLock);
+	if (IsUnderPostmaster)
+		LWLockRelease(ShmemIndexLock);
 
 	Assert(ShmemAddrIsValid(structPtr));
 
diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c
index 4c01afce2f7..7bb005a5833 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -193,9 +193,12 @@ typedef struct LWLockTrancheShmemData
 	int			num_user_defined;	/* 'user_defined' entries in use */
 
 	slock_t		lock;			/* protects the above */
+
+	/* Size of MainLWLockArray */
+	int			num_main_array_locks;
 } LWLockTrancheShmemData;
 
-LWLockTrancheShmemData *LWLockTranches;
+static LWLockTrancheShmemData *LWLockTranches;
 
 /* backend-local copy of NamedLWLockTranches->num_user_defined */
 static int	LocalNumUserDefinedTranches;
@@ -405,7 +408,8 @@ NumLWLocksForNamedTranches(void)
 }
 
 /*
- * Compute shmem space needed for LWLocks and named tranches.
+ * Compute shmem space needed for user-defined tranches and the main LWLock
+ * array.
  */
 Size
 LWLockShmemSize(void)
@@ -424,27 +428,36 @@ LWLockShmemSize(void)
 }
 
 /*
- * Allocate shmem space for the main LWLock array and all tranches and
- * initialize it.
+ * Allocate and initialize shmem for user-defined LWLock tranches and the main
+ * LWLock array.
  */
 void
-CreateLWLocks(void)
+LWLockShmemInit(void)
 {
 	int			numLocks;
+	bool		found;
 
-	if (!IsUnderPostmaster)
+	LWLockTranches = (LWLockTrancheShmemData *)
+		ShmemInitStruct("LWLock tranches", sizeof(LWLockTrancheShmemData), &found);
+	if (!found)
 	{
-		/* Allocate space for LWLockTranches */
-		LWLockTranches = (LWLockTrancheShmemData *)
-			ShmemAlloc(sizeof(LWLockTrancheShmemData));
+		/* Calculate total number of locks needed in the main array */
+		LWLockTranches->num_main_array_locks =
+			NUM_FIXED_LWLOCKS + NumLWLocksForNamedTranches();
 
 		/* Initialize the dynamic-allocation counter for tranches */
-		SpinLockInit(&LWLockTranches->lock);
 		LWLockTranches->num_user_defined = 0;
 
-		/* Allocate and initialize the main array */
-		numLocks = NUM_FIXED_LWLOCKS + NumLWLocksForNamedTranches();
-		MainLWLockArray = (LWLockPadded *) ShmemAlloc(numLocks * sizeof(LWLockPadded));
+		SpinLockInit(&LWLockTranches->lock);
+	}
+
+	/* Allocate and initialize the main array */
+	numLocks = LWLockTranches->num_main_array_locks;
+	MainLWLockArray = (LWLockPadded *)
+		ShmemInitStruct("Main LWLock array", numLocks * sizeof(LWLockPadded), &found);
+	if (!found)
+	{
+		/* Initialize all LWLocks */
 		InitializeLWLocks(numLocks);
 	}
 }
diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h
index 30557631eb8..61f0dbe749a 100644
--- a/src/include/storage/lwlock.h
+++ b/src/include/storage/lwlock.h
@@ -73,11 +73,6 @@ typedef union LWLockPadded
 
 extern PGDLLIMPORT LWLockPadded *MainLWLockArray;
 
-/* forward declaration of private type for use only by lwlock.c */
-typedef struct LWLockTrancheShmemData LWLockTrancheShmemData;
-
-extern PGDLLIMPORT LWLockTrancheShmemData *LWLockTranches;
-
 /*
  * It's a bit odd to declare NUM_BUFFER_PARTITIONS and NUM_LOCK_PARTITIONS
  * here, but we need them to figure out offsets within MainLWLockArray, and
@@ -132,7 +127,7 @@ extern bool LWLockWaitForVar(LWLock *lock, pg_atomic_uint64 *valptr, uint64 oldv
 extern void LWLockUpdateVar(LWLock *lock, pg_atomic_uint64 *valptr, uint64 val);
 
 extern Size LWLockShmemSize(void);
-extern void CreateLWLocks(void);
+extern void LWLockShmemInit(void);
 extern void InitLWLockAccess(void);
 
 extern const char *GetLWLockIdentifier(uint32 classId, uint16 eventId);
-- 
2.47.3

