From 239f445b05e1a014e533f51da571d6b2cbdc3279 Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date: Sun, 5 Apr 2026 19:52:48 +0300
Subject: [PATCH v12 06/13] Convert lwlock.c to use the new shmem allocation
 functions

It seems like a good candidate to convert first because it needs to
initialized before any other subsystem, but other than that it's
nothing special.

Reviewed-by: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Reviewed-by: Matthias van de Meent <boekewurm+postgres@gmail.com>
Reviewed-by: Daniel Gustafsson <daniel@yesql.se>
Discussion: https://www.postgresql.org/message-id/CAExHW5vM1bneLYfg0wGeAa=52UiJ3z4vKd3AJ72X8Fw6k3KKrg@mail.gmail.com
---
 src/backend/postmaster/postmaster.c |  16 +++--
 src/backend/storage/ipc/ipci.c      |  13 ----
 src/backend/storage/lmgr/lwlock.c   | 100 +++++++++++++---------------
 src/backend/tcop/postgres.c         |  16 +++--
 src/include/storage/lwlock.h        |   2 -
 src/include/storage/subsystemlist.h |   9 ++-
 6 files changed, 75 insertions(+), 81 deletions(-)

diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index a2de96a9a8e..6f13e8f40a0 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -956,18 +956,22 @@ PostmasterMain(int argc, char *argv[])
 	 */
 	InitializeFastPathLocks();
 
-	/*
-	 * Ask all subsystems, including preloaded libraries, to register their
-	 * shared memory needs.
-	 */
-	ShmemCallRequestCallbacks();
-
 	/*
 	 * Also call any legacy shmem request hooks that might've been installed
 	 * by preloaded libraries.
+	 *
+	 * Note: this must be done before ShmemCallRequestCallbacks(), because the
+	 * hooks may request LWLocks with RequestNamedLWLockTranche(), which in
+	 * turn affects the size of the LWLock array calculated in lwlock.c.
 	 */
 	process_shmem_requests();
 
+	/*
+	 * Ask all subsystems, including preloaded libraries, to register their
+	 * shared memory needs.
+	 */
+	ShmemCallRequestCallbacks();
+
 	/*
 	 * Now that loadable modules have had their chance to request additional
 	 * shared memory, determine the value of any runtime-computed GUCs that
diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c
index e4a6a52f12d..de65a9ef33c 100644
--- a/src/backend/storage/ipc/ipci.c
+++ b/src/backend/storage/ipc/ipci.c
@@ -121,7 +121,6 @@ CalculateShmemSize(void)
 	size = add_size(size, TwoPhaseShmemSize());
 	size = add_size(size, BackgroundWorkerShmemSize());
 	size = add_size(size, MultiXactShmemSize());
-	size = add_size(size, LWLockShmemSize());
 	size = add_size(size, ProcArrayShmemSize());
 	size = add_size(size, BackendStatusShmemSize());
 	size = add_size(size, SharedInvalShmemSize());
@@ -179,11 +178,6 @@ AttachSharedMemoryStructs(void)
 	 */
 	InitializeFastPathLocks();
 
-	/*
-	 * Attach to LWLocks first. They are needed by most other subsystems.
-	 */
-	LWLockShmemInit();
-
 	/* Establish pointers to all shared memory areas in this backend */
 	ShmemAttachRequested();
 	CreateOrAttachShmemStructs();
@@ -230,13 +224,6 @@ CreateSharedMemoryAndSemaphores(void)
 	 */
 	InitShmemAllocator(seghdr);
 
-	/*
-	 * Initialize LWLocks first, in case any of the shmem init function use
-	 * LWLocks.  (Nothing else can be running during startup, so they don't
-	 * need to do any locking yet, but we nevertheless allow it.)
-	 */
-	LWLockShmemInit();
-
 	/* Initialize all shmem areas */
 	ShmemInitRequested();
 
diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c
index 98138cb09d1..b1ad396ba79 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -84,6 +84,7 @@
 #include "storage/proclist.h"
 #include "storage/procnumber.h"
 #include "storage/spin.h"
+#include "storage/subsystems.h"
 #include "utils/memutils.h"
 #include "utils/wait_event.h"
 
@@ -189,9 +190,6 @@ 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;
 
 static LWLockTrancheShmemData *LWLockTranches;
@@ -212,7 +210,18 @@ typedef struct NamedLWLockTrancheRequest
 
 static List *NamedLWLockTrancheRequests = NIL;
 
-static void InitializeLWLocks(int numLocks);
+/* Size of MainLWLockArray.  Only valid in postmaster. */
+static int	num_main_array_locks;
+
+static void LWLockShmemRequest(void *arg);
+static void LWLockShmemInit(void *arg);
+
+const ShmemCallbacks LWLockCallbacks = {
+	.request_fn = LWLockShmemRequest,
+	.init_fn = LWLockShmemInit,
+};
+
+
 static inline void LWLockReportWaitStart(LWLock *lock);
 static inline void LWLockReportWaitEnd(void);
 static const char *GetLWTrancheName(uint16 trancheId);
@@ -401,68 +410,53 @@ NumLWLocksForNamedTranches(void)
 }
 
 /*
- * Compute shmem space needed for user-defined tranches and the main LWLock
- * array.
+ * Request shmem space for user-defined tranches and the main LWLock array.
  */
-Size
-LWLockShmemSize(void)
+static void
+LWLockShmemRequest(void *arg)
 {
-	Size		size;
-	int			numLocks;
+	size_t		size;
 
 	/* Space for user-defined tranches */
-	size = sizeof(LWLockTrancheShmemData);
+	ShmemRequestStruct(.name = "LWLock tranches",
+					   .size = sizeof(LWLockTrancheShmemData),
+					   .ptr = (void **) &LWLockTranches,
+		);
 
 	/* Space for the LWLock array */
-	numLocks = NUM_FIXED_LWLOCKS + NumLWLocksForNamedTranches();
-	size = add_size(size, mul_size(numLocks, sizeof(LWLockPadded)));
-
-	return size;
-}
-
-/*
- * Allocate shmem space for user-defined tranches and the main LWLock array,
- * and initialize it.
- */
-void
-LWLockShmemInit(void)
-{
-	int			numLocks;
-	bool		found;
-
-	LWLockTranches = (LWLockTrancheShmemData *)
-		ShmemInitStruct("LWLock tranches", sizeof(LWLockTrancheShmemData), &found);
-	if (!found)
+	if (!IsUnderPostmaster)
 	{
-		/* 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 */
-		LWLockTranches->num_user_defined = 0;
-
-		SpinLockInit(&LWLockTranches->lock);
+		num_main_array_locks = NUM_FIXED_LWLOCKS + NumLWLocksForNamedTranches();
+		size = num_main_array_locks * sizeof(LWLockPadded);
 	}
+	else
+		size = SHMEM_ATTACH_UNKNOWN_SIZE;
 
-	/* 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);
-	}
+	ShmemRequestStruct(.name = "Main LWLock array",
+					   .size = size,
+					   .ptr = (void **) &MainLWLockArray,
+		);
 }
 
 /*
- * Initialize LWLocks for built-in tranches and those requested with
- * RequestNamedLWLockTranche().
+ * Initialize shmem space for user-defined tranches and the main LWLock array.
  */
 static void
-InitializeLWLocks(int numLocks)
+LWLockShmemInit(void *arg)
 {
-	int			pos = 0;
+	int			pos;
+
+	/* Initialize the dynamic-allocation counter for tranches */
+	LWLockTranches->num_user_defined = 0;
+
+	SpinLockInit(&LWLockTranches->lock);
+
+	/*
+	 * Allocate and initialize all LWLocks in the main array.  It includes all
+	 * LWLocks for built-in tranches and those requested with
+	 * RequestNamedLWLockTranche().
+	 */
+	pos = 0;
 
 	/* Initialize all individual LWLocks in main array */
 	for (int id = 0; id < NUM_INDIVIDUAL_LWLOCKS; id++)
@@ -501,8 +495,8 @@ InitializeLWLocks(int numLocks)
 			LWLockInitialize(&MainLWLockArray[pos++].lock, LWTRANCHE_FIRST_USER_DEFINED + idx);
 	}
 
-	/* Cross-check that we agree on the total size with the caller */
-	Assert(pos == numLocks);
+	/* Cross-check that we agree on the total size with LWLockShmemRequest() */
+	Assert(pos == num_main_array_locks);
 }
 
 /*
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 6a9ff3ad225..95496654714 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -4158,18 +4158,22 @@ PostgresSingleUserMain(int argc, char *argv[],
 	/* Initialize size of fast-path lock cache. */
 	InitializeFastPathLocks();
 
-	/*
-	 * Before computing the total size needed, give all subsystems, including
-	 * add-ins, a chance to chance to adjust their requested shmem sizes.
-	 */
-	ShmemCallRequestCallbacks();
-
 	/*
 	 * Also call any legacy shmem request hooks that might'be been installed
 	 * by preloaded libraries.
+	 *
+	 * Note: this must be done before ShmemCallRequestCallbacks(), because the
+	 * hooks may request LWLocks with RequestNamedLWLockTranche(), which in
+	 * turn affects the size of the LWLock array calculated in lwlock.c.
 	 */
 	process_shmem_requests();
 
+	/*
+	 * Before computing the total size needed, give all subsystems, including
+	 * add-ins, a chance to chance to adjust their requested shmem sizes.
+	 */
+	ShmemCallRequestCallbacks();
+
 	/*
 	 * Now that loadable modules have had their chance to request additional
 	 * shared memory, determine the value of any runtime-computed GUCs that
diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h
index 61f0dbe749a..efa5b427e9f 100644
--- a/src/include/storage/lwlock.h
+++ b/src/include/storage/lwlock.h
@@ -126,8 +126,6 @@ extern bool LWLockHeldByMeInMode(LWLock *lock, LWLockMode mode);
 extern bool LWLockWaitForVar(LWLock *lock, pg_atomic_uint64 *valptr, uint64 oldval, uint64 *newval);
 extern void LWLockUpdateVar(LWLock *lock, pg_atomic_uint64 *valptr, uint64 val);
 
-extern Size LWLockShmemSize(void);
-extern void LWLockShmemInit(void);
 extern void InitLWLockAccess(void);
 
 extern const char *GetLWLockIdentifier(uint32 classId, uint16 eventId);
diff --git a/src/include/storage/subsystemlist.h b/src/include/storage/subsystemlist.h
index ed43c90bcc3..f0cf01f5a85 100644
--- a/src/include/storage/subsystemlist.h
+++ b/src/include/storage/subsystemlist.h
@@ -20,4 +20,11 @@
  * of these matter.
  */
 
-/* TODO: empty for now */
+/*
+ * LWLocks first, in case any of the other shmem init functions use LWLocks.
+ * (Nothing else can be running during startup, so they don't need to do any
+ * locking yet, but we nevertheless allow it.)
+ */
+PG_SHMEM_SUBSYSTEM(LWLockCallbacks)
+
+/* TODO: nothing else for now */
-- 
2.47.3

