*
* shmqueue.cpp
* shared memory linked lists
*
* Portions Copyright (c) 2020 Huawei Technologies Co.,Ltd.
* Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* src/gausskernel/storage/ipc/shmqueue.cpp
*
* 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 "knl/knl_variable.h"
#include "storage/shmem.h"
void SHMQueueInit(SHM_QUEUE* queue)
{
queue->prev = queue->next = queue;
}
bool SHMQueueIsDetached(const SHM_QUEUE* queue)
{
return (queue->prev == NULL);
}
void SHMQueueElemInit(SHM_QUEUE* queue)
{
queue->prev = NULL;
queue->next = NULL;
}
void SHMQueueDelete(SHM_QUEUE* queue)
{
SHM_QUEUE* nextElem = queue->next;
SHM_QUEUE* prevElem = queue->prev;
prevElem->next = queue->next;
nextElem->prev = queue->prev;
queue->prev = queue->next = NULL;
}
* 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;
elem->next = prevPtr->next;
elem->prev = queue->prev;
queue->prev = elem;
prevPtr->next = elem;
}
* 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;
elem->prev = nextPtr->prev;
elem->next = queue->next;
queue->next = elem;
nextPtr->prev = elem;
}
* 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 these parameters: &(queueHead), &(curElem->elem), offsetof(ELEMType, elem)
*/
Pointer SHMQueueNext(const SHM_QUEUE* queue, const SHM_QUEUE* curElem, Size linkOffset)
{
SHM_QUEUE* elemPtr = curElem->next;
if (elemPtr == queue) {
return NULL;
}
return (Pointer)(((char*)elemPtr) - linkOffset);
}
* 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;
if (elemPtr == queue) {
return NULL;
}
return (Pointer)(((char*)elemPtr) - linkOffset);
}
bool SHMQueueEmpty(const SHM_QUEUE* queue)
{
if (queue->prev == queue) {
Assert(queue->next == queue);
return TRUE;
}
return FALSE;
}