/* * SHMQueueInsertBefore -- put elem in queue before the given queue * element. Inserting "before" the queue head puts the elem * at the tail of the queue. */ void SHMQueueInsertBefore(SHM_QUEUE *queue, SHM_QUEUE *elem) { SHM_QUEUE *prevPtr = queue->prev; Assert(ShmemAddrIsValid(queue)); Assert(ShmemAddrIsValid(elem)); elem->next = prevPtr->next; elem->prev = queue->prev; queue->prev = elem; prevPtr->next = elem; }
/* * SHMQueueInsertAfter -- put elem in queue after the given queue * element. Inserting "after" the queue head puts the elem * at the head of the queue. */ void SHMQueueInsertAfter(SHM_QUEUE *queue, SHM_QUEUE *elem) { SHM_QUEUE *nextPtr = queue->next; Assert(ShmemAddrIsValid(queue)); Assert(ShmemAddrIsValid(elem)); elem->prev = nextPtr->prev; elem->next = queue->next; queue->next = elem; nextPtr->prev = elem; }
/* * SHMQueueDelete -- remove an element from the queue and * close the links */ void SHMQueueDelete(SHM_QUEUE *queue) { SHM_QUEUE *nextElem = queue->next; SHM_QUEUE *prevElem = queue->prev; Assert(ShmemAddrIsValid(queue)); Assert(ShmemAddrIsValid(nextElem)); Assert(ShmemAddrIsValid(prevElem)); prevElem->next = queue->next; nextElem->prev = queue->prev; queue->prev = queue->next = NULL; }
/* * SHMQueueEmpty -- TRUE if queue head is only element, FALSE otherwise */ bool SHMQueueEmpty(const SHM_QUEUE *queue) { Assert(ShmemAddrIsValid(queue)); if (queue->prev == queue) { Assert(queue->next == queue); return TRUE; } return FALSE; }
/*-------------------- * SHMQueuePrev -- Get the previous element from a queue * * Same as SHMQueueNext, just starting at tail and moving towards head. * All other comments and usage applies. */ Pointer SHMQueuePrev(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset) { SHM_QUEUE *elemPtr = curElem->prev; Assert(ShmemAddrIsValid(curElem)); if (elemPtr == queue) /* back to the queue head? */ return NULL; return (Pointer) (((char *) elemPtr) - linkOffset); }
/* * SHMQueueElemInit -- clear an element's links */ void SHMQueueElemInit(SHM_QUEUE *queue) { Assert(ShmemAddrIsValid(queue)); queue->prev = queue->next = NULL; }
/* * SHMQueueIsDetached -- TRUE if element is not currently * in a queue. */ bool SHMQueueIsDetached(const SHM_QUEUE *queue) { Assert(ShmemAddrIsValid(queue)); return (queue->prev == NULL); }
/* * ShmemInitStruct -- Create/attach to a structure in shared memory. * * This is called during initialization to find or allocate * a data structure in shared memory. If no other process * has created the structure, this routine allocates space * for it. If it exists already, a pointer to the existing * structure is returned. * * Returns: pointer to the object. *foundPtr is set TRUE if the object was * already in the shmem index (hence, already initialized). * * Note: before Postgres 9.0, this function returned NULL for some failure * cases. Now, it always throws error instead, so callers need not check * for NULL. */ void * ShmemInitStruct(const char *name, Size size, bool *foundPtr) { ShmemIndexEnt *result; void *structPtr; LWLockAcquire(ShmemIndexLock, LW_EXCLUSIVE); if (!ShmemIndex) { PGShmemHeader *shmemseghdr = ShmemSegHdr; /* Must be trying to create/attach to ShmemIndex itself */ Assert(strcmp(name, "ShmemIndex") == 0); if (IsUnderPostmaster) { /* Must be initializing a (non-standalone) backend */ Assert(shmemseghdr->index != NULL); structPtr = shmemseghdr->index; *foundPtr = TRUE; } else { /* * If the shmem index doesn't exist, we are bootstrapping: we must * be trying to init the shmem index itself. * * Notice that the ShmemIndexLock is released before the shmem * index has been initialized. This should be OK because no other * process can be accessing shared memory yet. */ Assert(shmemseghdr->index == NULL); structPtr = ShmemAlloc(size); shmemseghdr->index = structPtr; *foundPtr = FALSE; } LWLockRelease(ShmemIndexLock); return structPtr; } /* look it up in the shmem index */ result = (ShmemIndexEnt *) hash_search(ShmemIndex, name, HASH_ENTER_NULL, foundPtr); if (!result) { LWLockRelease(ShmemIndexLock); ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("could not create ShmemIndex entry for data structure \"%s\"", name))); } if (*foundPtr) { /* * Structure is in the shmem index so someone else has allocated it * already. The size better be the same as the size we are trying to * initialize to, or there is a name conflict (or worse). */ if (result->size != size) { LWLockRelease(ShmemIndexLock); ereport(ERROR, (errmsg("ShmemIndex entry size is wrong for data structure" " \"%s\": expected %zu, actual %zu", name, size, result->size))); } structPtr = result->location; } else { /* It isn't in the table yet. allocate and initialize it */ structPtr = ShmemAllocNoError(size); if (structPtr == NULL) { /* out of memory; remove the failed ShmemIndex entry */ hash_search(ShmemIndex, name, HASH_REMOVE, NULL); LWLockRelease(ShmemIndexLock); ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("not enough shared memory for data structure" " \"%s\" (%zu bytes requested)", name, size))); } result->size = size; result->location = structPtr; } LWLockRelease(ShmemIndexLock); Assert(ShmemAddrIsValid(structPtr)); Assert(structPtr == (void *) CACHELINEALIGN(structPtr)); return structPtr; }
bool ShmemDynAddrIsValid(void *addr) { return ShmemAddrIsValid(addr) && is_allocated(addr); }
/* * ShmemInitStruct -- Create/attach to a structure in shared * memory. * * This is called during initialization to find or allocate * a data structure in shared memory. If no other process * has created the structure, this routine allocates space * for it. If it exists already, a pointer to the existing * table is returned. * * Returns: real pointer to the object. FoundPtr is TRUE if * the object is already in the shmem index (hence, already * initialized). */ void * ShmemInitStruct(const char *name, Size size, bool *foundPtr) { ShmemIndexEnt *result; void *structPtr; LWLockAcquire(ShmemIndexLock, LW_EXCLUSIVE); if (!ShmemIndex) { PGShmemHeader *shmemseghdr = ShmemSegHdr; Assert(strcmp(name, "ShmemIndex") == 0); if (IsUnderPostmaster) { /* Must be initializing a (non-standalone) backend */ Assert(shmemseghdr->index != NULL); structPtr = shmemseghdr->index; *foundPtr = TRUE; } else { /* * If the shmem index doesn't exist, we are bootstrapping: we must * be trying to init the shmem index itself. * * Notice that the ShmemIndexLock is released before the shmem * index has been initialized. This should be OK because no other * process can be accessing shared memory yet. */ Assert(shmemseghdr->index == NULL); structPtr = ShmemAlloc(size); shmemseghdr->index = structPtr; *foundPtr = FALSE; } LWLockRelease(ShmemIndexLock); return structPtr; } /* look it up in the shmem index */ result = (ShmemIndexEnt *) hash_search(ShmemIndex, name, HASH_ENTER_NULL, foundPtr); if (!result) { LWLockRelease(ShmemIndexLock); ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of shared memory"))); } if (*foundPtr) { /* * Structure is in the shmem index so someone else has allocated it * already. The size better be the same as the size we are trying to * initialize to or there is a name conflict (or worse). */ if (result->size != size) { LWLockRelease(ShmemIndexLock); elog(WARNING, "ShmemIndex entry size is wrong"); /* let caller print its message too */ return NULL; } structPtr = result->location; } else { /* It isn't in the table yet. allocate and initialize it */ structPtr = ShmemAlloc(size); if (!structPtr) { /* out of memory */ Assert(ShmemIndex); hash_search(ShmemIndex, name, HASH_REMOVE, NULL); LWLockRelease(ShmemIndexLock); ereport(WARNING, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("could not allocate shared memory segment \"%s\"", name))); *foundPtr = FALSE; return NULL; } result->size = size; result->location = structPtr; } Assert(ShmemAddrIsValid(structPtr)); LWLockRelease(ShmemIndexLock); return structPtr; }