diff options
Diffstat (limited to 'src/backend/storage/ipc/shmem.c')
-rw-r--r-- | src/backend/storage/ipc/shmem.c | 266 |
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) { /* |