diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c index 0b0bf77eee..a4d36d157b 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 6a65429f0f..3c48173f2f 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 f10de0dca0..16791bf620 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 ce77993243..5c4db52892 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 7a89f31820..47f6709a67 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 96a67b069a..bd55fbdb5c 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)))