mirror of
https://github.com/postgres/postgres.git
synced 2025-05-21 15:54:08 +03:00
191 lines
4.5 KiB
C
191 lines
4.5 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* shmqueue.c
|
|
* shared memory linked lists
|
|
*
|
|
* Portions Copyright (c) 1996-2020, 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;
|
|
}
|