Hi All,

PFA two patches for $subject.

0001: Adds assertions to InitShmemAccess() and InitShmemAllocation
which indicate the conditions, EXEC_BACKEND and IsUnderPostmaster,
these functions are expected to be called. I found these annotations
to be useful when modifying these functions to handle multiple Shmem
segments required by buffer pool resizing project [1].

0002: We use two different methods to pass ShmemIndex and ShmemLock
respectively to new backends even though both the structures are
allocated before creating named structures in the shared memory. This
patch consistently uses the same method - passing via PGShmemHeader.
Further the patch gets rid of InitShmemAllocation and moves that code
inside InitShmemAccess() itself. Maybe that's overkill but at least we
would be able to call InitShmemAllocation() from InitShmemAccess() and
declare first as static within shmem.c. That way we avoid a minor risk
of InitShmemAllocation() being called twice.

We may achieve consistency by passing ShmemIndex through
BackendParameter, but I haven't tried that.

[1] 
https://www.postgresql.org/message-id/cnthxg2eekacrejyeonuhiaezc7vd7o2uowlsbenxqfkjwgvwj%40qgzu6eoqrglb

-- 
Best Wishes,
Ashutosh Bapat
From e5866917ec0236d6a74710c8762fecf54dbee52c Mon Sep 17 00:00:00 2001
From: Ashutosh Bapat <[email protected]>
Date: Thu, 29 Jan 2026 11:16:45 +0530
Subject: [PATCH v20260129 1/2] Clarify Shmem access by Postmaster and
 standalone backends

InitShmemAccess is called by a standbalone backend or the Postmaster. It is also
called by other backends in EXEC_BACKEND case. InitShmemAllocation() is called
only by the Postmaster. Add Asserts to document this fact.

The code which creates ShmemIndex is already called only for the Postmaster or a
standalone backend and is adequately documented. Rest of the code may be called
by any backend.

Author: Ashutosh Bapat <[email protected]>
---
 src/backend/storage/ipc/shmem.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c
index 1b536363152..b997a043145 100644
--- a/src/backend/storage/ipc/shmem.c
+++ b/src/backend/storage/ipc/shmem.c
@@ -99,10 +99,19 @@ Datum		pg_numa_available(PG_FUNCTION_ARGS);
 
 /*
  *	InitShmemAccess() --- set up basic pointers to shared memory.
+ *
+ * In EXEC_BACKEND case, this function is called by the Postmaster as well as
+ * every backend to setup the shared memory access. In non-EXEC_BACKEND case, it
+ * is called only by a standalone backend or the Postmaster, who passes the
+ * setup to the child backends via fork().
  */
 void
 InitShmemAccess(PGShmemHeader *seghdr)
 {
+#ifndef EXEC_BACKEND
+	Assert(!IsUnderPostmaster);
+#endif
+
 	ShmemSegHdr = seghdr;
 	ShmemBase = seghdr;
 	ShmemEnd = (char *) ShmemBase + seghdr->totalsize;
@@ -119,6 +128,7 @@ InitShmemAllocation(void)
 	PGShmemHeader *shmhdr = ShmemSegHdr;
 	char	   *aligned;
 
+	Assert(!IsUnderPostmaster);
 	Assert(shmhdr != NULL);
 
 	/*

base-commit: 20a8f783e15c503125c2ed0ae890510879f62801
-- 
2.34.1

From c9d9d267d40234f92b821a48bd43aaab4ad0ca2d Mon Sep 17 00:00:00 2001
From: Ashutosh Bapat <[email protected]>
Date: Thu, 29 Jan 2026 13:58:38 +0530
Subject: [PATCH v20260129 2/2] Move shmem allocation lock into shared memory
 header

The pointer to the shared memory index table is in the shared memory header. In
EXEC_BACKEND case, the backends retrieve it from there during shmem access
initialization. Shared memory lock is allocated even before that but is passed
to the backends via BackendParameters. There is no explanation as to why this
asymmetry exists. This commit makes the handling of shmem index and shmem lock
consistent by moving the shmem allocation lock pointer into the shared memory
header, so that backends can retrieve it from there.

Author: Ashutosh Bapat <[email protected]>
---
 src/backend/postmaster/launch_backend.c |  5 --
 src/backend/storage/ipc/ipci.c          |  5 --
 src/backend/storage/ipc/shmem.c         | 67 ++++++++++++++-----------
 src/include/storage/pg_shmem.h          |  2 +
 4 files changed, 39 insertions(+), 40 deletions(-)

diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index cea229ad6a4..6d857c30659 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -96,7 +96,6 @@ typedef struct
 	HANDLE		UsedShmemSegID;
 #endif
 	void	   *UsedShmemSegAddr;
-	slock_t    *ShmemLock;
 #ifdef USE_INJECTION_POINTS
 	struct InjectionPointsCtl *ActiveInjectionPoints;
 #endif
@@ -724,8 +723,6 @@ save_backend_variables(BackendParameters *param,
 	param->UsedShmemSegID = UsedShmemSegID;
 	param->UsedShmemSegAddr = UsedShmemSegAddr;
 
-	param->ShmemLock = ShmemLock;
-
 #ifdef USE_INJECTION_POINTS
 	param->ActiveInjectionPoints = ActiveInjectionPoints;
 #endif
@@ -986,8 +983,6 @@ restore_backend_variables(BackendParameters *param)
 	UsedShmemSegID = param->UsedShmemSegID;
 	UsedShmemSegAddr = param->UsedShmemSegAddr;
 
-	ShmemLock = param->ShmemLock;
-
 #ifdef USE_INJECTION_POINTS
 	ActiveInjectionPoints = param->ActiveInjectionPoints;
 #endif
diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c
index 2a3dfedf7e9..a2ed8742c91 100644
--- a/src/backend/storage/ipc/ipci.c
+++ b/src/backend/storage/ipc/ipci.c
@@ -214,11 +214,6 @@ CreateSharedMemoryAndSemaphores(void)
 
 	InitShmemAccess(seghdr);
 
-	/*
-	 * Set up shared memory allocation mechanism
-	 */
-	InitShmemAllocation();
-
 	/* Initialize subsystems */
 	CreateOrAttachShmemStructs();
 
diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c
index b997a043145..37a2555577b 100644
--- a/src/backend/storage/ipc/shmem.c
+++ b/src/backend/storage/ipc/shmem.c
@@ -104,6 +104,10 @@ Datum		pg_numa_available(PG_FUNCTION_ARGS);
  * every backend to setup the shared memory access. In non-EXEC_BACKEND case, it
  * is called only by a standalone backend or the Postmaster, who passes the
  * setup to the child backends via fork().
+ *
+ * Postmaster creates the lock used for shared memory allocations and saves it
+ * in the shared memory header, from where backends retrieve it in EXEC_BACKEND
+ * build.
  */
 void
 InitShmemAccess(PGShmemHeader *seghdr)
@@ -115,42 +119,45 @@ InitShmemAccess(PGShmemHeader *seghdr)
 	ShmemSegHdr = seghdr;
 	ShmemBase = seghdr;
 	ShmemEnd = (char *) ShmemBase + seghdr->totalsize;
-}
-
-/*
- *	InitShmemAllocation() --- set up shared-memory space allocation.
- *
- * This should be called only in the postmaster or a standalone backend.
- */
-void
-InitShmemAllocation(void)
-{
-	PGShmemHeader *shmhdr = ShmemSegHdr;
-	char	   *aligned;
-
-	Assert(!IsUnderPostmaster);
-	Assert(shmhdr != NULL);
 
 	/*
-	 * Initialize the spinlock used by ShmemAlloc.  We must use
-	 * ShmemAllocUnlocked, since obviously ShmemAlloc can't be called yet.
+	 * Postmaster create the shared memory lock after setting up access to the
+	 * shared memory but backends setup shmem lock from the shared memory
+	 * header
 	 */
-	ShmemLock = (slock_t *) ShmemAllocUnlocked(sizeof(slock_t));
+	if (IsUnderPostmaster)
+	{
+		Assert(seghdr->shmem_lock);
+		ShmemLock = seghdr->shmem_lock;
 
-	SpinLockInit(ShmemLock);
+		/* ShmemIndex will be setup later. */
+	}
+	else
+	{
+		char	   *aligned;
 
-	/*
-	 * Allocations after this point should go through ShmemAlloc, which
-	 * expects to allocate everything on cache line boundaries.  Make sure the
-	 * first allocation begins on a cache line boundary.
-	 */
-	aligned = (char *)
-		(CACHELINEALIGN((((char *) shmhdr) + shmhdr->freeoffset)));
-	shmhdr->freeoffset = aligned - (char *) shmhdr;
+		/*
+		 * Initialize the spinlock used by ShmemAlloc.  We must use
+		 * ShmemAllocUnlocked, since obviously ShmemAlloc can't be called yet.
+		 */
+		ShmemLock = (slock_t *) ShmemAllocUnlocked(sizeof(slock_t));
+		seghdr->shmem_lock = ShmemLock;
 
-	/* ShmemIndex can't be set up yet (need LWLocks first) */
-	shmhdr->index = NULL;
-	ShmemIndex = (HTAB *) NULL;
+		SpinLockInit(ShmemLock);
+
+		/*
+		 * Allocations after this point should go through ShmemAlloc, which
+		 * expects to allocate everything on cache line boundaries.  Make sure
+		 * the first allocation begins on a cache line boundary.
+		 */
+		aligned = (char *)
+			(CACHELINEALIGN((((char *) seghdr) + seghdr->freeoffset)));
+		seghdr->freeoffset = aligned - (char *) seghdr;
+
+		/* ShmemIndex can't be set up yet (need LWLocks first) */
+		seghdr->index = NULL;
+		ShmemIndex = (HTAB *) NULL;
+	}
 }
 
 /*
diff --git a/src/include/storage/pg_shmem.h b/src/include/storage/pg_shmem.h
index 3aeada554b2..ec1818b9aec 100644
--- a/src/include/storage/pg_shmem.h
+++ b/src/include/storage/pg_shmem.h
@@ -25,6 +25,7 @@
 #define PG_SHMEM_H
 
 #include "storage/dsm_impl.h"
+#include "storage/s_lock.h"
 
 typedef struct PGShmemHeader	/* standard header for all Postgres shmem */
 {
@@ -35,6 +36,7 @@ typedef struct PGShmemHeader	/* standard header for all Postgres shmem */
 	Size		freeoffset;		/* offset to first free space */
 	dsm_handle	dsm_control;	/* ID of dynamic shared memory control seg */
 	void	   *index;			/* pointer to ShmemIndex table */
+	slock_t    *shmem_lock;		/* spinlock for shmem allocation */
 #ifndef WIN32					/* Windows doesn't have useful inode#s */
 	dev_t		device;			/* device data directory is on */
 	ino_t		inode;			/* inode number of data directory */
-- 
2.34.1

Reply via email to