aboutsummaryrefslogtreecommitdiff
path: root/src/backend/storage/ipc/shmem.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2000-11-28 23:27:57 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2000-11-28 23:27:57 +0000
commitc715fdea267843fd7fae4253aee0ae91e941393c (patch)
treeb19e41edd57afe461ebc3dae271c8a5d17eba710 /src/backend/storage/ipc/shmem.c
parent914822713c9a8ce452860fb895ef79ecfd583746 (diff)
downloadpostgresql-c715fdea267843fd7fae4253aee0ae91e941393c.tar.gz
postgresql-c715fdea267843fd7fae4253aee0ae91e941393c.zip
Significant cleanups in SysV IPC handling (shared mem and semaphores).
IPC key assignment will now work correctly even when multiple postmasters are using same logical port number (which is possible given -k switch). There is only one shared-mem segment per postmaster now, not 3. Rip out broken code for non-TAS case in bufmgr and xlog, substitute a complete S_LOCK emulation using semaphores in spin.c. TAS and non-TAS logic is now exactly the same. When deadlock is detected, "Deadlock detected" is now the elog(ERROR) message, rather than a NOTICE that comes out before an unhelpful ERROR.
Diffstat (limited to 'src/backend/storage/ipc/shmem.c')
-rw-r--r--src/backend/storage/ipc/shmem.c266
1 files changed, 65 insertions, 201 deletions
diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c
index c5048a389b1..15922947087 100644
--- a/src/backend/storage/ipc/shmem.c
+++ b/src/backend/storage/ipc/shmem.c
@@ -8,14 +8,14 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.54 2000/11/21 21:16:01 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.55 2000/11/28 23:27:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* POSTGRES processes share one or more regions of shared memory.
* The shared memory is created by a postmaster and is inherited
- * by each backends via fork(). The routines in this file are used for
+ * by each backend via fork(). The routines in this file are used for
* allocating and binding to shared memory data structures.
*
* NOTES:
@@ -56,153 +56,57 @@
*
* See InitSem() in sem.c for an example of how to use the
* shmem index.
- *
*/
#include "postgres.h"
+
#include "access/transam.h"
#include "utils/tqual.h"
/* shared memory global variables */
-unsigned long ShmemBase = 0; /* start and end address of shared memory */
-static unsigned long ShmemEnd = 0;
-static unsigned long ShmemSize = 0; /* current size (and default) */
+static PGShmemHeader *ShmemSegHdr; /* shared mem segment header */
+
+SHMEM_OFFSET ShmemBase; /* start address of shared memory */
+
+static SHMEM_OFFSET ShmemEnd; /* end+1 address of shared memory */
SPINLOCK ShmemLock; /* lock for shared memory allocation */
SPINLOCK ShmemIndexLock; /* lock for shmem index access */
-static unsigned long *ShmemFreeStart = NULL; /* pointer to the OFFSET
- * of first free shared
- * memory */
-static unsigned long *ShmemIndexOffset = NULL; /* start of the shmem
- * index table (for
- * bootstrap) */
-static int ShmemBootstrap = FALSE; /* flag becomes true when shared
- * mem is created by POSTMASTER */
-
-static HTAB *ShmemIndex = NULL;
-
-/* ---------------------
- * ShmemIndexReset() - Resets the shmem index to NULL....
- * useful when the postmaster destroys existing shared memory
- * and creates all new segments after a backend crash.
- * ----------------------
- */
-void
-ShmemIndexReset(void)
-{
- ShmemIndex = (HTAB *) NULL;
-}
+static HTAB *ShmemIndex = NULL; /* primary index hashtable for shmem */
-/*
- * CreateSharedRegion()
- *
- * This routine is called once by the postmaster to
- * initialize the shared buffer pool. Assume there is
- * only one postmaster so no synchronization is necessary
- * until after this routine completes successfully.
- *
- * key is a unique identifier for the shmem region.
- * size is the size of the region.
- */
-static IpcMemoryId ShmemId;
+static bool ShmemBootstrap = false; /* bootstrapping shmem index? */
-void
-ShmemCreate(unsigned int key, unsigned int size)
-{
- if (size)
- ShmemSize = size;
- /* create shared mem region */
- if ((ShmemId = IpcMemoryCreate(key, ShmemSize, IPCProtection))
- == IpcMemCreationFailed)
- {
- elog(FATAL, "ShmemCreate: cannot create region");
- exit(1);
- }
-
- /*
- * ShmemBootstrap is true if shared memory has been created, but not
- * yet initialized. Only the postmaster/creator-of-all-things should
- * have this flag set.
- */
- ShmemBootstrap = TRUE;
-}
/*
- * InitShmem() -- map region into process address space
- * and initialize shared data structures.
- *
+ * InitShmemAllocation() --- set up shared-memory allocation and index table.
*/
-int
-InitShmem(unsigned int key, unsigned int size)
+void
+InitShmemAllocation(PGShmemHeader *seghdr)
{
- Pointer sharedRegion;
- unsigned long currFreeSpace;
-
HASHCTL info;
int hash_flags;
ShmemIndexEnt *result,
item;
bool found;
- IpcMemoryId shmid;
-
- /* if zero key, use default memory size */
- if (size)
- ShmemSize = size;
-
- /* default key is 0 */
-
- /* attach to shared memory region (SysV or BSD OS specific) */
- if (ShmemBootstrap && key == PrivateIPCKey)
- /* if we are running backend alone */
- shmid = ShmemId;
- else
- shmid = IpcMemoryIdGet(IPCKeyGetBufferMemoryKey(key), ShmemSize);
- sharedRegion = IpcMemoryAttach(shmid);
- if (sharedRegion == NULL)
- {
- elog(FATAL, "AttachSharedRegion: couldn't attach to shmem\n");
- return FALSE;
- }
-
- /* get pointers to the dimensions of shared memory */
- ShmemBase = (unsigned long) sharedRegion;
- ShmemEnd = (unsigned long) sharedRegion + ShmemSize;
-
- /* First long in shared memory is the available-space pointer */
- ShmemFreeStart = (unsigned long *) ShmemBase;
- /* next is a shmem pointer to the shmem index */
- ShmemIndexOffset = ShmemFreeStart + 1;
- /* next is ShmemVariableCache */
- ShmemVariableCache = (VariableCache) (ShmemIndexOffset + 1);
-
- /* here is where to start dynamic allocation */
- currFreeSpace = MAXALIGN(sizeof(*ShmemFreeStart) +
- sizeof(*ShmemIndexOffset) +
- sizeof(*ShmemVariableCache));
- /*
- * bootstrap initialize spin locks so we can start to use the
- * allocator and shmem index.
- */
- InitSpinLocks();
+ /* Set up basic pointers to shared memory */
+ ShmemSegHdr = seghdr;
+ ShmemBase = (SHMEM_OFFSET) seghdr;
+ ShmemEnd = ShmemBase + seghdr->totalsize;
/*
- * We have just allocated additional space for two spinlocks. Now
- * setup the global free space count
+ * Since ShmemInitHash calls ShmemInitStruct, which expects the
+ * ShmemIndex hashtable to exist already, we have a bit of a circularity
+ * problem in initializing the ShmemIndex itself. We set ShmemBootstrap
+ * to tell ShmemInitStruct to fake it.
*/
- if (ShmemBootstrap)
- {
- *ShmemFreeStart = currFreeSpace;
- memset(ShmemVariableCache, 0, sizeof(*ShmemVariableCache));
- }
-
- /* if ShmemFreeStart is NULL, then the allocator won't work */
- Assert(*ShmemFreeStart);
+ ShmemIndex = (HTAB *) NULL;
+ ShmemBootstrap = true;
- /* create OR attach to the shared memory shmem index */
+ /* create the shared memory shmem index */
info.keysize = SHMEM_INDEX_KEYSIZE;
info.datasize = SHMEM_INDEX_DATASIZE;
hash_flags = HASH_ELEM;
@@ -211,60 +115,43 @@ InitShmem(unsigned int key, unsigned int size)
ShmemIndex = ShmemInitHash("ShmemIndex",
SHMEM_INDEX_SIZE, SHMEM_INDEX_SIZE,
&info, hash_flags);
-
if (!ShmemIndex)
- {
- elog(FATAL, "InitShmem: couldn't initialize Shmem Index");
- return FALSE;
- }
+ elog(FATAL, "InitShmemAllocation: couldn't initialize Shmem Index");
/*
- * Now, check the shmem index for an entry to the shmem index. If
- * there is an entry there, someone else created the table. Otherwise,
- * we did and we have to initialize it.
+ * Now, create an entry in the hashtable for the index itself.
*/
MemSet(item.key, 0, SHMEM_INDEX_KEYSIZE);
strncpy(item.key, "ShmemIndex", SHMEM_INDEX_KEYSIZE);
result = (ShmemIndexEnt *)
hash_search(ShmemIndex, (char *) &item, HASH_ENTER, &found);
-
-
if (!result)
- {
- elog(FATAL, "InitShmem: corrupted shmem index");
- return FALSE;
- }
-
- if (!found)
- {
+ elog(FATAL, "InitShmemAllocation: corrupted shmem index");
- /*
- * bootstrapping shmem: we have to initialize the shmem index now.
- */
+ Assert(ShmemBootstrap && !found);
- Assert(ShmemBootstrap);
- result->location = MAKE_OFFSET(ShmemIndex->hctl);
- *ShmemIndexOffset = result->location;
- result->size = SHMEM_INDEX_SIZE;
+ result->location = MAKE_OFFSET(ShmemIndex->hctl);
+ result->size = SHMEM_INDEX_SIZE;
- ShmemBootstrap = FALSE;
+ ShmemBootstrap = false;
- }
- else
- Assert(!ShmemBootstrap);
- /* now release the lock acquired in ShmemHashInit */
+ /* now release the lock acquired in ShmemInitStruct */
SpinRelease(ShmemIndexLock);
- Assert(result->location == MAKE_OFFSET(ShmemIndex->hctl));
-
- return TRUE;
+ /*
+ * Initialize ShmemVariableCache for transaction manager.
+ */
+ ShmemVariableCache = (VariableCache)
+ ShmemAlloc(sizeof(*ShmemVariableCache));
+ memset(ShmemVariableCache, 0, sizeof(*ShmemVariableCache));
}
/*
- * ShmemAlloc -- allocate max-aligned byte string from shared memory
+ * ShmemAlloc -- allocate max-aligned chunk from shared memory
+ *
+ * Assumes ShmemLock and ShmemSegHdr are initialized.
*
- * Assumes ShmemLock and ShmemFreeStart 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().
@@ -272,7 +159,7 @@ InitShmem(unsigned int key, unsigned int size)
void *
ShmemAlloc(Size size)
{
- unsigned long tmpFree;
+ uint32 newFree;
void *newSpace;
/*
@@ -280,15 +167,15 @@ ShmemAlloc(Size size)
*/
size = MAXALIGN(size);
- Assert(*ShmemFreeStart);
+ Assert(ShmemSegHdr);
SpinAcquire(ShmemLock);
- tmpFree = *ShmemFreeStart + size;
- if (tmpFree <= ShmemSize)
+ newFree = ShmemSegHdr->freeoffset + size;
+ if (newFree <= ShmemSegHdr->totalsize)
{
- newSpace = (void *) MAKE_PTR(*ShmemFreeStart);
- *ShmemFreeStart += size;
+ newSpace = (void *) MAKE_PTR(ShmemSegHdr->freeoffset);
+ ShmemSegHdr->freeoffset = newFree;
}
else
newSpace = NULL;
@@ -306,7 +193,7 @@ ShmemAlloc(Size size)
*
* Returns TRUE if the pointer is valid.
*/
-int
+bool
ShmemIsValid(unsigned long addr)
{
return (addr < ShmemEnd) && (addr >= ShmemBase);
@@ -394,16 +281,15 @@ ShmemPIDLookup(int pid, SHMEM_OFFSET *locationPtr)
sprintf(item.key, "PID %d", pid);
SpinAcquire(ShmemIndexLock);
+
result = (ShmemIndexEnt *)
hash_search(ShmemIndex, (char *) &item, HASH_ENTER, &found);
if (!result)
{
-
SpinRelease(ShmemIndexLock);
elog(ERROR, "ShmemInitPID: ShmemIndex corrupted");
return FALSE;
-
}
if (found)
@@ -438,19 +324,19 @@ ShmemPIDDestroy(int pid)
sprintf(item.key, "PID %d", pid);
SpinAcquire(ShmemIndexLock);
+
result = (ShmemIndexEnt *)
hash_search(ShmemIndex, (char *) &item, HASH_REMOVE, &found);
if (found)
location = result->location;
+
SpinRelease(ShmemIndexLock);
if (!result)
{
-
elog(ERROR, "ShmemPIDDestroy: PID table corrupted");
return INVALID_OFFSET;
-
}
if (found)
@@ -487,53 +373,31 @@ ShmemInitStruct(char *name, Size size, bool *foundPtr)
if (!ShmemIndex)
{
-#ifdef USE_ASSERT_CHECKING
- char *strname = "ShmemIndex";
-
-#endif
-
/*
- * If the shmem index doesn't exist, we fake it.
+ * If the shmem index doesn't exist, we are bootstrapping: we must
+ * be trying to init the shmem index itself.
*
- * If we are creating the first shmem index, then let shmemalloc()
- * allocate the space for a new HTAB. Otherwise, find the old one
- * and return that. Notice that the ShmemIndexLock is held until
- * the shmem index has been completely initialized.
+ * Notice that the ShmemIndexLock is held until the shmem index has
+ * been completely initialized.
*/
- Assert(strcmp(name, strname) == 0);
- if (ShmemBootstrap)
- {
- /* in POSTMASTER/Single process */
-
- *foundPtr = FALSE;
- return ShmemAlloc(size);
- }
- else
- {
- Assert(*ShmemIndexOffset);
-
- *foundPtr = TRUE;
- return (void *) MAKE_PTR(*ShmemIndexOffset);
- }
-
-
- }
- else
- {
- /* look it up in the shmem index */
- result = (ShmemIndexEnt *)
- hash_search(ShmemIndex, (char *) &item, HASH_ENTER, foundPtr);
+ Assert(strcmp(name, "ShmemIndex") == 0);
+ Assert(ShmemBootstrap);
+ *foundPtr = FALSE;
+ return ShmemAlloc(size);
}
+ /* look it up in the shmem index */
+ result = (ShmemIndexEnt *)
+ hash_search(ShmemIndex, (char *) &item, HASH_ENTER, foundPtr);
+
if (!result)
{
SpinRelease(ShmemIndexLock);
-
elog(ERROR, "ShmemInitStruct: Shmem Index corrupted");
return NULL;
-
}
- else if (*foundPtr)
+
+ if (*foundPtr)
{
/*