*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/ipc/ipci.c,v 1.88 2006/10/04 00:29:57 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/ipc/ipci.c,v 1.89 2006/10/15 22:04:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "storage/spin.h"
+static Size total_addin_request = 0;
+static bool addin_request_allowed = true;
+
+
+/*
+ * RequestAddinShmemSpace
+ * Request that extra shmem space be allocated for use by
+ * a loadable module.
+ *
+ * This is only useful if called from the _PG_init hook of a library that
+ * is loaded into the postmaster via shared_preload_libraries. Once
+ * shared memory has been allocated, calls will be ignored. (We could
+ * raise an error, but it seems better to make it a no-op, so that
+ * libraries containing such calls can be reloaded if needed.)
+ */
+void
+RequestAddinShmemSpace(Size size)
+{
+ if (IsUnderPostmaster || !addin_request_allowed)
+ return; /* too late */
+ total_addin_request = add_size(total_addin_request, size);
+}
+
+
/*
* CreateSharedMemoryAndSemaphores
* Creates and initializes shared memory and semaphores.
{
PGShmemHeader *seghdr;
Size size;
- Size size_b4addins;
int numSemas;
/*
size = add_size(size, ShmemBackendArraySize());
#endif
- /* might as well round it off to a multiple of a typical page size */
- size = add_size(size, 8192 - (size % 8192));
+ /* freeze the addin request size and include it */
+ addin_request_allowed = false;
+ size = add_size(size, total_addin_request);
- /*
- * 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 */
+ /* might as well round it off to a multiple of a typical page size */
size = add_size(size, 8192 - (size % 8192));
elog(DEBUG3, "invoking IpcMemoryCreate(size=%lu)",
*/
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.97 2006/10/04 00:29:57 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/ipc/shmem.c,v 1.98 2006/10/15 22:04:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* postmaster. However, this does not work in the EXEC_BACKEND case.
* In ports using EXEC_BACKEND, new backends have to set up their local
* pointers using the method described in (b) above.
-
+ *
* (d) memory allocation model: shared memory can never be
* freed, once allocated. Each hash table has its own free list,
* so hash buckets can be reused when an item is deleted. However,
* 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.
}
/*
- * 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
+ * ShmemAlloc -- allocate max-aligned chunk from shared memory
*
* Assumes ShmemLock and ShmemSegHdr are initialized.
*
* to be compatible with malloc().
*/
void *
-ShmemAllocFromContext(Size size, const char *context_name)
+ShmemAlloc(Size size)
{
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_PTRFROM((SHMEM_OFFSET) shmemseghdr, newStart);
+ newSpace = (void *) MAKE_PTR(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.46 2006/10/04 00:29:57 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/lmgr/lwlock.c,v 1.47 2006/10/15 22:04:07 tgl 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 num_held_lwlocks = 0;
static LWLockId held_lwlocks[MAX_SIMUL_LWLOCKS];
+static int lock_addin_request = 0;
+static bool lock_addin_request_allowed = true;
+
#ifdef LWLOCK_STATS
static int counts_for_pid = 0;
static int *sh_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.
- */
-static int
-NumAddinLWLocks()
-{
- return num_addin_locks;
-}
-
-/*
- * AssignAddinLWLocks() --- Assign LWLocks previously requested by add-ins.
- */
-static void
-AssignAddinLWLocks()
-{
- LWLockNode *node = addin_locks;
-
- while (node)
- {
- *(node->lock) = LWLockAssign();
- node = node->next;
- }
-}
-
-
-
-
#ifdef LOCK_DEBUG
bool Trace_lwlocks = false;
/* multixact.c needs two SLRU areas */
numLocks += NUM_MXACTOFFSET_BUFFERS + NUM_MXACTMEMBER_BUFFERS;
- /* 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();
+ /*
+ * Add any requested by loadable modules; for backwards-compatibility
+ * reasons, allocate at least NUM_USER_DEFINED_LWLOCKS of them even
+ * if there are no explicit requests.
+ */
+ lock_addin_request_allowed = false;
+ numLocks += Max(lock_addin_request, NUM_USER_DEFINED_LWLOCKS);
return numLocks;
}
+/*
+ * RequestAddinLWLocks
+ * Request that extra LWLocks be allocated for use by
+ * a loadable module.
+ *
+ * This is only useful if called from the _PG_init hook of a library that
+ * is loaded into the postmaster via shared_preload_libraries. Once
+ * shared memory has been allocated, calls will be ignored. (We could
+ * raise an error, but it seems better to make it a no-op, so that
+ * libraries containing such calls can be reloaded if needed.)
+ */
+void
+RequestAddinLWLocks(int n)
+{
+ if (IsUnderPostmaster || !lock_addin_request_allowed)
+ return; /* too late */
+ lock_addin_request += n;
+}
+
+
/*
* Compute shmem space needed for LWLocks.
*/
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.31 2006/08/01 19:03:11 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/storage/lwlock.h,v 1.32 2006/10/15 22:04:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
TwoPhaseStateLock,
TablespaceCreateLock,
BtreeVacuumLock,
+ AddinShmemInitLock,
FirstBufMappingLock,
FirstLockMgrLock = FirstBufMappingLock + NUM_BUFFER_PARTITIONS,
extern Size LWLockShmemSize(void);
extern void CreateLWLocks(void);
-extern void RegisterAddinLWLock(LWLockId *lock);
+extern void RequestAddinLWLocks(int n);
#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.20 2006/10/04 00:30:10 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/storage/pg_shmem.h,v 1.21 2006/10/15 22:04:07 tgl 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.48 2006/08/01 19:03:11 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/storage/shmem.h,v 1.49 2006/10/15 22:04:08 tgl 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)))
extern Size add_size(Size s1, Size s2);
extern Size mul_size(Size s1, Size s2);
+/* ipci.c */
+extern void RequestAddinShmemSpace(Size size);
+
/* size constants for the shmem index table */
/* max size of data structure string name */
#define SHMEM_INDEX_KEYSIZE (48)