From 2c6d96cef6c9d9a1a8bf80c5f6a761d29f7a2a47 Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
Date: Tue, 1 Aug 2006 19:03:11 +0000
Subject: [PATCH] Add support for loadable modules to allocated shared memory
 and lightweight locks.

Marc Munro
---
 src/backend/storage/ipc/ipci.c    |  22 +++-
 src/backend/storage/ipc/shmem.c   | 161 ++++++++++++++++++++++++++++--
 src/backend/storage/lmgr/lwlock.c |  71 ++++++++++++-
 src/include/storage/lwlock.h      |   4 +-
 src/include/storage/pg_shmem.h    |   9 +-
 src/include/storage/shmem.h       |   7 +-
 6 files changed, 261 insertions(+), 13 deletions(-)

diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c
index 0b0bf77eee6..a4d36d157be 100644
--- a/src/backend/storage/ipc/ipci.c
+++ b/src/backend/storage/ipc/ipci.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/storage/ipc/ipci.c,v 1.86 2006/07/15 15:47:17 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/storage/ipc/ipci.c,v 1.87 2006/08/01 19:03:11 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -57,6 +57,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
 	{
 		PGShmemHeader *seghdr;
 		Size		size;
+		Size		size_b4addins;
 		int			numSemas;
 
 		/*
@@ -93,6 +94,15 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
 		/* might as well round it off to a multiple of a typical page size */
 		size = add_size(size, 8192 - (size % 8192));
 
+		/*
+		 * The shared memory for add-ins is treated as a separate
+		 * segment, but in reality it is not.
+		 */
+		size_b4addins = size;
+		size = add_size(size, AddinShmemSize());
+		/* round it off again */
+		size = add_size(size, 8192 - (size % 8192));
+
 		elog(DEBUG3, "invoking IpcMemoryCreate(size=%lu)",
 			 (unsigned long) size);
 
@@ -101,6 +111,16 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
 		 */
 		seghdr = PGSharedMemoryCreate(size, makePrivate, port);
 
+		/*
+		 * Modify hdr to show segment size before add-ins
+		 */
+		seghdr->totalsize = size_b4addins;
+		
+		/* 
+		 * Set up segment header sections in each Addin context
+		 */
+		InitAddinContexts((void *) ((char *) seghdr + size_b4addins));
+
 		InitShmemAccess(seghdr);
 
 		/*
diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c
index 6a65429f0fc..3c48173f2f6 100644
--- a/src/backend/storage/ipc/shmem.c
+++ b/src/backend/storage/ipc/shmem.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/storage/ipc/shmem.c,v 1.94 2006/07/22 23:04:39 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/storage/ipc/shmem.c,v 1.95 2006/08/01 19:03:11 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -61,6 +61,15 @@
  *	cannot be redistributed to other tables.  We could build a simple
  *	hash bucket garbage collector if need be.  Right now, it seems
  *	unnecessary.
+ *
+ *      (e) Add-ins can request their own logical shared memory segments
+ *  by calling RegisterAddinContext() from the preload-libraries hook.
+ *  Each call establishes a uniquely named add-in shared memopry
+ *  context which will be set up as part of postgres intialisation.
+ *  Memory can be allocated from these contexts using
+ *  ShmemAllocFromContext(), and can be reset to its initial condition
+ *  using ShmemResetContext().  Also, RegisterAddinLWLock(LWLockid *lock_ptr)
+ *  can be used to request that a LWLock be allocated, placed into *lock_ptr.
  */
 
 #include "postgres.h"
@@ -86,6 +95,19 @@ slock_t    *ShmemLock;			/* spinlock for shared memory and LWLock
 
 static HTAB *ShmemIndex = NULL; /* primary index hashtable for shmem */
 
+/* Structures and globals for managing add-in shared memory contexts */
+typedef struct context
+{
+	char           *name;
+	Size            size;
+	PGShmemHeader  *seg_hdr;
+	struct context *next;
+} ContextNode;
+
+static ContextNode *addin_contexts = NULL;
+static Size addin_contexts_size = 0;
+
+
 
 /*
  *	InitShmemAccess() --- set up basic pointers to shared memory.
@@ -135,12 +157,104 @@ InitShmemAllocation(void)
 	 * (This doesn't really belong here, but not worth moving.)
 	 */
 	ShmemVariableCache = (VariableCache)
-		ShmemAlloc(sizeof(*ShmemVariableCache));
+	ShmemAlloc(sizeof(*ShmemVariableCache));
 	memset(ShmemVariableCache, 0, sizeof(*ShmemVariableCache));
 }
 
 /*
- * ShmemAlloc -- allocate max-aligned chunk from shared memory
+ * RegisterAddinContext -- Register the requirement for a named shared
+ *                         memory context.
+ */
+void
+RegisterAddinContext(const char *name, Size size)
+{
+	char *newstr = malloc(strlen(name) + 1);
+	ContextNode *node = malloc(sizeof(ContextNode));
+
+	strcpy(newstr, name);
+	node->name = newstr;
+
+	/* Round up to typical page size */
+	node->size = add_size(size, 8192 - (size % 8192));
+	node->next = addin_contexts;
+
+	addin_contexts = node;
+	addin_contexts_size = add_size(addin_contexts_size, node->size);
+}
+
+
+/*
+ * ContextFromName -- Return the ContextNode for the given named
+ *                    context, or NULL if not found.
+ */
+static ContextNode *
+ContextFromName(const char *name)
+{
+	ContextNode *context = addin_contexts;
+
+	while (context)
+	{
+		if (strcmp(name, context->name) == 0)
+			return context;
+		context = context->next;
+	}
+	return NULL;
+}
+
+/*
+ * InitAddinContexts -- Initialise the registered addin shared memory
+ *                      contexts. 
+ */
+void
+InitAddinContexts(void *start)
+{
+	PGShmemHeader *next_segment = (PGShmemHeader *) start;
+	ContextNode *context = addin_contexts;
+
+	while (context)
+	{
+		context->seg_hdr = next_segment;
+
+		next_segment->totalsize = context->size;
+		next_segment->freeoffset = MAXALIGN(sizeof(PGShmemHeader));
+
+		next_segment = (PGShmemHeader *) 
+			((char *) next_segment + context->size);
+		context = context->next;
+	}
+}
+
+/*
+ * ShmemResetContext -- Re-initialise the named addin shared memory context.
+ */
+void
+ShmemResetContext(const char *name)
+{
+	PGShmemHeader *segment;
+	ContextNode *context = ContextFromName(name);
+
+	if (!context)
+		ereport(ERROR,
+				(errcode(ERRCODE_INTERNAL_ERROR),
+				 errmsg("cannot reset unknown shared memory context %s",
+						name)));
+
+	segment = context->seg_hdr;
+	segment->freeoffset = MAXALIGN(sizeof(PGShmemHeader));
+}
+
+/*
+ * AddinShmemSize -- Report how much shared memory has been registered
+ *  for add-ins.
+ */
+Size
+AddinShmemSize(void)
+{
+	return addin_contexts_size;
+}
+
+/*
+ * ShmemAllocFromContext -- allocate max-aligned chunk from shared memory
  *
  * Assumes ShmemLock and ShmemSegHdr are initialized.
  *
@@ -149,15 +263,30 @@ InitShmemAllocation(void)
  *		to be compatible with malloc().
  */
 void *
-ShmemAlloc(Size size)
+ShmemAllocFromContext(Size size, const char *context_name)
 {
-	Size		newStart;
-	Size		newFree;
-	void	   *newSpace;
+	Size		  newStart;
+	Size	 	  newFree;
+	void	     *newSpace;
+	ContextNode  *context;
 
 	/* use volatile pointer to prevent code rearrangement */
 	volatile PGShmemHeader *shmemseghdr = ShmemSegHdr;
 
+	/* 
+	 * if context_name is provided, allocate from the named context
+	 */
+	if (context_name)
+	{
+		context = ContextFromName(context_name);
+		if (!context)
+			ereport(ERROR,
+					(errcode(ERRCODE_INTERNAL_ERROR),
+					 errmsg("cannot reset unknown shared memory context %s",
+							context_name)));
+		shmemseghdr = context->seg_hdr;
+	}
+
 	/*
 	 * ensure all space is adequately aligned.
 	 */
@@ -176,7 +305,7 @@ ShmemAlloc(Size size)
 	newFree = newStart + size;
 	if (newFree <= shmemseghdr->totalsize)
 	{
-		newSpace = (void *) MAKE_PTR(newStart);
+		newSpace = (void *) MAKE_PTRFROM((SHMEM_OFFSET) shmemseghdr, newStart);
 		shmemseghdr->freeoffset = newFree;
 	}
 	else
@@ -192,6 +321,22 @@ ShmemAlloc(Size size)
 	return newSpace;
 }
 
+/*
+ * ShmemAlloc -- allocate max-aligned chunk from shared memory
+ *
+ * Assumes ShmemLock and ShmemSegHdr are initialized.
+ *
+ * Returns: real pointer to memory or NULL if we are out
+ *		of space.  Has to return a real pointer in order
+ *		to be compatible with malloc().
+ */
+
+void *
+ShmemAlloc(Size size)
+{
+	return ShmemAllocFromContext(size, NULL);
+}
+
 /*
  * ShmemIsValid -- test if an offset refers to valid shared memory
  *
diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c
index f10de0dca0e..16791bf620d 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/storage/lmgr/lwlock.c,v 1.42 2006/07/24 16:32:45 petere Exp $
+ *	  $PostgreSQL: pgsql/src/backend/storage/lmgr/lwlock.c,v 1.43 2006/08/01 19:03:11 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -29,6 +29,10 @@
 #include "storage/spin.h"
 
 
+static int NumAddinLWLocks(void);
+static void AssignAddinLWLocks(void);
+
+
 /* We use the ShmemLock spinlock to protect LWLockAssign */
 extern slock_t *ShmemLock;
 
@@ -90,6 +94,62 @@ static int *ex_acquire_counts;
 static int *block_counts;
 #endif
 
+/* 
+ * Structures and globals to allow add-ins to register for their own
+ * lwlocks from the preload-libraries hook.
+ */
+typedef struct LWLockNode
+{
+	LWLockId *lock;
+	struct LWLockNode *next;
+} LWLockNode;
+
+static LWLockNode *addin_locks = NULL;
+static int num_addin_locks = 0;
+
+
+/*
+ *	RegisterAddinLWLock() --- Allow an andd-in to request a LWLock
+ *	                          from the preload-libraries hook.
+ */
+void
+RegisterAddinLWLock(LWLockId *lock)
+{
+	LWLockNode *locknode = malloc(sizeof(LWLockNode));
+
+	locknode->next = addin_locks;
+	locknode->lock = lock;
+
+	addin_locks = locknode;
+	num_addin_locks++;
+}
+
+/*
+ *	NumAddinLWLocks() --- Return the number of LWLocks requested by add-ins.
+ */
+int
+NumAddinLWLocks()
+{
+	return num_addin_locks;
+}
+
+/*
+ *	AssignAddinLWLocks() --- Assign LWLocks previously requested by add-ins.
+ */
+void
+AssignAddinLWLocks()
+{
+	LWLockNode *node = addin_locks;
+
+	while (node)
+	{
+		*(node->lock) = LWLockAssign();
+		node = node->next;
+	}
+}
+
+
+
 
 #ifdef LOCK_DEBUG
 bool		Trace_lwlocks = false;
@@ -174,6 +234,9 @@ NumLWLocks(void)
 	/* Leave a few extra for use by user-defined modules. */
 	numLocks += NUM_USER_DEFINED_LWLOCKS;
 
+	/* Add the number that have been explicitly requested by add-ins. */
+	numLocks += NumAddinLWLocks();
+
 	return numLocks;
 }
 
@@ -241,6 +304,12 @@ CreateLWLocks(void)
 	LWLockCounter = (int *) ((char *) LWLockArray - 2 * sizeof(int));
 	LWLockCounter[0] = (int) NumFixedLWLocks;
 	LWLockCounter[1] = numLocks;
+
+	/* 
+	 * Allocate LWLocks for those add-ins that have explicitly requested
+	 * them.
+	 */
+	AssignAddinLWLocks();
 }
 
 
diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h
index ce779932430..5c4db528920 100644
--- a/src/include/storage/lwlock.h
+++ b/src/include/storage/lwlock.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/storage/lwlock.h,v 1.30 2006/07/23 23:08:46 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/storage/lwlock.h,v 1.31 2006/08/01 19:03:11 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -92,4 +92,6 @@ extern int	NumLWLocks(void);
 extern Size LWLockShmemSize(void);
 extern void CreateLWLocks(void);
 
+extern void RegisterAddinLWLock(LWLockId *lock);
+
 #endif   /* LWLOCK_H */
diff --git a/src/include/storage/pg_shmem.h b/src/include/storage/pg_shmem.h
index 7a89f318206..47f6709a674 100644
--- a/src/include/storage/pg_shmem.h
+++ b/src/include/storage/pg_shmem.h
@@ -17,7 +17,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/storage/pg_shmem.h,v 1.18 2006/03/05 15:58:59 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/storage/pg_shmem.h,v 1.19 2006/08/01 19:03:11 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -51,4 +51,11 @@ extern PGShmemHeader *PGSharedMemoryCreate(Size size, bool makePrivate,
 extern bool PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2);
 extern void PGSharedMemoryDetach(void);
 
+
+extern void RegisterAddinContext(const char *name, Size size);
+extern Size AddinShmemSize(void);
+extern void InitAddinContexts(void * start);
+extern void *ShmemAllocFromContext(Size size, const char *name);
+extern void ShmemResetContext(const char *name);
+
 #endif   /* PG_SHMEM_H */
diff --git a/src/include/storage/shmem.h b/src/include/storage/shmem.h
index 96a67b069a9..bd55fbdb5c8 100644
--- a/src/include/storage/shmem.h
+++ b/src/include/storage/shmem.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/storage/shmem.h,v 1.47 2006/03/05 15:59:00 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/storage/shmem.h,v 1.48 2006/08/01 19:03:11 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -38,6 +38,11 @@ typedef unsigned long SHMEM_OFFSET;
 extern DLLIMPORT SHMEM_OFFSET ShmemBase;
 
 
+/* coerce an offset into a pointer in a specified address space.  This
+ * macro (only) is not confined to the primary shared memory region */
+#define MAKE_PTRFROM(base,xx_offs)\
+  (base+((unsigned long)(xx_offs)))
+
 /* coerce an offset into a pointer in this process's address space */
 #define MAKE_PTR(xx_offs)\
   (ShmemBase+((unsigned long)(xx_offs)))
-- 
GitLab