lightweight locks.
Marc Munro
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
{
PGShmemHeader *seghdr;
Size size;
+ Size size_b4addins;
int numSemas;
/*
/* 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);
*/
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);
/*
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
* 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"
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.
* (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.
*
* 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.
*/
newFree = newStart + size;
if (newFree <= shmemseghdr->totalsize)
{
- newSpace = (void *) MAKE_PTR(newStart);
+ newSpace = (void *) MAKE_PTRFROM((SHMEM_OFFSET) shmemseghdr, newStart);
shmemseghdr->freeoffset = newFree;
}
else
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
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#include "storage/spin.h"
+static int NumAddinLWLocks(void);
+static void AssignAddinLWLocks(void);
+
+
/* We use the ShmemLock spinlock to protect LWLockAssign */
extern slock_t *ShmemLock;
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;
/* 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;
}
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();
}
* 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 $
*
*-------------------------------------------------------------------------
*/
extern Size LWLockShmemSize(void);
extern void CreateLWLocks(void);
+extern void RegisterAddinLWLock(LWLockId *lock);
+
#endif /* LWLOCK_H */
* 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 $
*
*-------------------------------------------------------------------------
*/
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 */
* 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 $
*
*-------------------------------------------------------------------------
*/
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)))