From 46651ce6fe013220ed397add242004d764fc0153 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 4 May 2024 14:15:05 +0200 Subject: Adding upstream version 14.5. Signed-off-by: Daniel Baumann --- src/backend/storage/ipc/shmqueue.c | 190 +++++++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 src/backend/storage/ipc/shmqueue.c (limited to 'src/backend/storage/ipc/shmqueue.c') diff --git a/src/backend/storage/ipc/shmqueue.c b/src/backend/storage/ipc/shmqueue.c new file mode 100644 index 0000000..dc3238c --- /dev/null +++ b/src/backend/storage/ipc/shmqueue.c @@ -0,0 +1,190 @@ +/*------------------------------------------------------------------------- + * + * shmqueue.c + * shared memory linked lists + * + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/storage/ipc/shmqueue.c + * + * NOTES + * + * Package for managing doubly-linked lists in shared memory. + * The only tricky thing is that SHM_QUEUE will usually be a field + * in a larger record. SHMQueueNext has to return a pointer + * to the record itself instead of a pointer to the SHMQueue field + * of the record. It takes an extra parameter and does some extra + * pointer arithmetic to do this correctly. + * + * NOTE: These are set up so they can be turned into macros some day. + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "storage/shmem.h" + + +/* + * ShmemQueueInit -- make the head of a new queue point + * to itself + */ +void +SHMQueueInit(SHM_QUEUE *queue) +{ + Assert(ShmemAddrIsValid(queue)); + queue->prev = queue->next = queue; +} + +/* + * SHMQueueIsDetached -- true if element is not currently + * in a queue. + */ +bool +SHMQueueIsDetached(const SHM_QUEUE *queue) +{ + Assert(ShmemAddrIsValid(queue)); + return (queue->prev == NULL); +} + +/* + * SHMQueueElemInit -- clear an element's links + */ +void +SHMQueueElemInit(SHM_QUEUE *queue) +{ + Assert(ShmemAddrIsValid(queue)); + queue->prev = queue->next = NULL; +} + +/* + * 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; +} + +/* + * 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; +} + +/*-------------------- + * SHMQueueNext -- Get the next element from a queue + * + * To start the iteration, pass the queue head as both queue and curElem. + * Returns NULL if no more elements. + * + * Next element is at curElem->next. If SHMQueue is part of + * a larger structure, we want to return a pointer to the + * whole structure rather than a pointer to its SHMQueue field. + * For example, + * struct { + * int stuff; + * SHMQueue elem; + * } ELEMType; + * When this element is in a queue, prevElem->next points at struct.elem. + * We subtract linkOffset to get the correct start address of the structure. + * + * calls to SHMQueueNext should take these parameters: + * &(queueHead), &(queueHead), offsetof(ELEMType, elem) + * or + * &(queueHead), &(curElem->elem), offsetof(ELEMType, elem) + *-------------------- + */ +Pointer +SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset) +{ + SHM_QUEUE *elemPtr = curElem->next; + + Assert(ShmemAddrIsValid(curElem)); + + if (elemPtr == queue) /* back to the queue head? */ + return NULL; + + return (Pointer) (((char *) elemPtr) - linkOffset); +} + +/*-------------------- + * 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); +} + +/* + * 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; +} -- cgit v1.2.3