1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-19 13:42:17 +03:00

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.
This commit is contained in:
Tom Lane
2000-11-28 23:27:57 +00:00
parent 914822713c
commit c715fdea26
27 changed files with 1172 additions and 1755 deletions

View File

@@ -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; /* primary index hashtable for shmem */
static HTAB *ShmemIndex = NULL;
static bool ShmemBootstrap = false; /* bootstrapping shmem index? */
/* ---------------------
* 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;
}
/*
* 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.
* InitShmemAllocation() --- set up shared-memory allocation and index table.
*/
static IpcMemoryId ShmemId;
void
ShmemCreate(unsigned int key, unsigned int size)
InitShmemAllocation(PGShmemHeader *seghdr)
{
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.
*
*/
int
InitShmem(unsigned int key, unsigned int size)
{
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));
/* Set up basic pointers to shared memory */
ShmemSegHdr = seghdr;
ShmemBase = (SHMEM_OFFSET) seghdr;
ShmemEnd = ShmemBase + seghdr->totalsize;
/*
* bootstrap initialize spin locks so we can start to use the
* allocator and shmem index.
* 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.
*/
InitSpinLocks();
ShmemIndex = (HTAB *) NULL;
ShmemBootstrap = true;
/*
* We have just allocated additional space for two spinlocks. Now
* setup the global free space count
*/
if (ShmemBootstrap)
{
*ShmemFreeStart = currFreeSpace;
memset(ShmemVariableCache, 0, sizeof(*ShmemVariableCache));
}
/* if ShmemFreeStart is NULL, then the allocator won't work */
Assert(*ShmemFreeStart);
/* 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;
}
elog(FATAL, "InitShmemAllocation: corrupted shmem index");
if (!found)
{
Assert(ShmemBootstrap && !found);
/*
* bootstrapping shmem: we have to initialize the shmem index now.
*/
result->location = MAKE_OFFSET(ShmemIndex->hctl);
result->size = SHMEM_INDEX_SIZE;
Assert(ShmemBootstrap);
result->location = MAKE_OFFSET(ShmemIndex->hctl);
*ShmemIndexOffset = result->location;
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)
{
/*