257 lines
6.3 KiB
C
257 lines
6.3 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* shmqueue.c--
|
|
* shared memory linked lists
|
|
*
|
|
* Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
*
|
|
* IDENTIFICATION
|
|
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmqueue.c,v 1.7 1998/07/20 16:56:54 momjian Exp $
|
|
*
|
|
* 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. SHMQueueGetFirst has to return a pointer
|
|
* to the record itself instead of a pointer to the SHMQueue field
|
|
* of the record. It takes an extra pointer 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 <stdio.h> /* for sprintf() */
|
|
#include "postgres.h"
|
|
#include "storage/shmem.h" /* where the declarations go */
|
|
|
|
/*#define SHMQUEUE_DEBUG*/
|
|
#ifdef SHMQUEUE_DEBUG
|
|
#define SHMQUEUE_DEBUG_DEL /* deletions */
|
|
#define SHMQUEUE_DEBUG_HD /* head inserts */
|
|
#define SHMQUEUE_DEBUG_TL /* tail inserts */
|
|
#define SHMQUEUE_DEBUG_ELOG NOTICE
|
|
#endif /* SHMQUEUE_DEBUG */
|
|
|
|
/*
|
|
* ShmemQueueInit -- make the head of a new queue point
|
|
* to itself
|
|
*/
|
|
void
|
|
SHMQueueInit(SHM_QUEUE *queue)
|
|
{
|
|
Assert(SHM_PTR_VALID(queue));
|
|
(queue)->prev = (queue)->next = MAKE_OFFSET(queue);
|
|
}
|
|
|
|
/*
|
|
* SHMQueueIsDetached -- TRUE if element is not currently
|
|
* in a queue.
|
|
*/
|
|
#ifdef NOT_USED
|
|
bool
|
|
SHMQueueIsDetached(SHM_QUEUE *queue)
|
|
{
|
|
Assert(SHM_PTR_VALID(queue));
|
|
return ((queue)->prev == INVALID_OFFSET);
|
|
}
|
|
|
|
#endif
|
|
|
|
/*
|
|
* SHMQueueElemInit -- clear an element's links
|
|
*/
|
|
void
|
|
SHMQueueElemInit(SHM_QUEUE *queue)
|
|
{
|
|
Assert(SHM_PTR_VALID(queue));
|
|
(queue)->prev = (queue)->next = INVALID_OFFSET;
|
|
}
|
|
|
|
/*
|
|
* SHMQueueDelete -- remove an element from the queue and
|
|
* close the links
|
|
*/
|
|
void
|
|
SHMQueueDelete(SHM_QUEUE *queue)
|
|
{
|
|
SHM_QUEUE *nextElem = (SHM_QUEUE *) MAKE_PTR((queue)->next);
|
|
SHM_QUEUE *prevElem = (SHM_QUEUE *) MAKE_PTR((queue)->prev);
|
|
|
|
Assert(SHM_PTR_VALID(queue));
|
|
Assert(SHM_PTR_VALID(nextElem));
|
|
Assert(SHM_PTR_VALID(prevElem));
|
|
|
|
#ifdef SHMQUEUE_DEBUG_DEL
|
|
dumpQ(queue, "in SHMQueueDelete: begin");
|
|
#endif /* SHMQUEUE_DEBUG_DEL */
|
|
|
|
prevElem->next = (queue)->next;
|
|
nextElem->prev = (queue)->prev;
|
|
|
|
#ifdef SHMQUEUE_DEBUG_DEL
|
|
dumpQ((SHM_QUEUE *) MAKE_PTR(queue->prev), "in SHMQueueDelete: end");
|
|
#endif /* SHMQUEUE_DEBUG_DEL */
|
|
}
|
|
|
|
#ifdef SHMQUEUE_DEBUG
|
|
void
|
|
dumpQ(SHM_QUEUE *q, char *s)
|
|
{
|
|
char elem[NAMEDATALEN];
|
|
char buf[1024];
|
|
SHM_QUEUE *start = q;
|
|
int count = 0;
|
|
|
|
sprintf(buf, "q prevs: %x", MAKE_OFFSET(q));
|
|
q = (SHM_QUEUE *) MAKE_PTR(q->prev);
|
|
while (q != start)
|
|
{
|
|
sprintf(elem, "--->%x", MAKE_OFFSET(q));
|
|
strcat(buf, elem);
|
|
q = (SHM_QUEUE *) MAKE_PTR(q->prev);
|
|
if (q->prev == MAKE_OFFSET(q))
|
|
break;
|
|
if (count++ > 40)
|
|
{
|
|
strcat(buf, "BAD PREV QUEUE!!");
|
|
break;
|
|
}
|
|
}
|
|
sprintf(elem, "--->%x", MAKE_OFFSET(q));
|
|
strcat(buf, elem);
|
|
elog(SHMQUEUE_DEBUG_ELOG, "%s: %s", s, buf);
|
|
|
|
sprintf(buf, "q nexts: %x", MAKE_OFFSET(q));
|
|
count = 0;
|
|
q = (SHM_QUEUE *) MAKE_PTR(q->next);
|
|
while (q != start)
|
|
{
|
|
sprintf(elem, "--->%x", MAKE_OFFSET(q));
|
|
strcat(buf, elem);
|
|
q = (SHM_QUEUE *) MAKE_PTR(q->next);
|
|
if (q->next == MAKE_OFFSET(q))
|
|
break;
|
|
if (count++ > 10)
|
|
{
|
|
strcat(buf, "BAD NEXT QUEUE!!");
|
|
break;
|
|
}
|
|
}
|
|
sprintf(elem, "--->%x", MAKE_OFFSET(q));
|
|
strcat(buf, elem);
|
|
elog(SHMQUEUE_DEBUG_ELOG, "%s: %s", s, buf);
|
|
}
|
|
|
|
#endif /* SHMQUEUE_DEBUG */
|
|
|
|
/*
|
|
* SHMQueueInsertHD -- put elem in queue between the queue head
|
|
* and its "prev" element.
|
|
*/
|
|
#ifdef NOT_USED
|
|
void
|
|
SHMQueueInsertHD(SHM_QUEUE *queue, SHM_QUEUE *elem)
|
|
{
|
|
SHM_QUEUE *prevPtr = (SHM_QUEUE *) MAKE_PTR((queue)->prev);
|
|
SHMEM_OFFSET elemOffset = MAKE_OFFSET(elem);
|
|
|
|
Assert(SHM_PTR_VALID(queue));
|
|
Assert(SHM_PTR_VALID(elem));
|
|
|
|
#ifdef SHMQUEUE_DEBUG_HD
|
|
dumpQ(queue, "in SHMQueueInsertHD: begin");
|
|
#endif /* SHMQUEUE_DEBUG_HD */
|
|
|
|
(elem)->next = prevPtr->next;
|
|
(elem)->prev = queue->prev;
|
|
(queue)->prev = elemOffset;
|
|
prevPtr->next = elemOffset;
|
|
|
|
#ifdef SHMQUEUE_DEBUG_HD
|
|
dumpQ(queue, "in SHMQueueInsertHD: end");
|
|
#endif /* SHMQUEUE_DEBUG_HD */
|
|
}
|
|
|
|
#endif
|
|
|
|
void
|
|
SHMQueueInsertTL(SHM_QUEUE *queue, SHM_QUEUE *elem)
|
|
{
|
|
SHM_QUEUE *nextPtr = (SHM_QUEUE *) MAKE_PTR((queue)->next);
|
|
SHMEM_OFFSET elemOffset = MAKE_OFFSET(elem);
|
|
|
|
Assert(SHM_PTR_VALID(queue));
|
|
Assert(SHM_PTR_VALID(elem));
|
|
|
|
#ifdef SHMQUEUE_DEBUG_TL
|
|
dumpQ(queue, "in SHMQueueInsertTL: begin");
|
|
#endif /* SHMQUEUE_DEBUG_TL */
|
|
|
|
(elem)->prev = nextPtr->prev;
|
|
(elem)->next = queue->next;
|
|
(queue)->next = elemOffset;
|
|
nextPtr->prev = elemOffset;
|
|
|
|
#ifdef SHMQUEUE_DEBUG_TL
|
|
dumpQ(queue, "in SHMQueueInsertTL: end");
|
|
#endif /* SHMQUEUE_DEBUG_TL */
|
|
}
|
|
|
|
/*
|
|
* SHMQueueFirst -- Get the first element from a queue
|
|
*
|
|
* First element is queue->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.
|
|
* I.E. struct {
|
|
* int stuff;
|
|
* SHMQueue elem;
|
|
* } ELEMType;
|
|
* when this element is in a queue (queue->next) is struct.elem.
|
|
* nextQueue allows us to calculate the offset of the SHMQueue
|
|
* field in the structure.
|
|
*
|
|
* call to SHMQueueFirst should take these parameters:
|
|
*
|
|
* &(queueHead),&firstElem,&(firstElem->next)
|
|
*
|
|
* Note that firstElem may well be uninitialized. if firstElem
|
|
* is initially K, &(firstElem->next) will be K+ the offset to
|
|
* next.
|
|
*/
|
|
void
|
|
SHMQueueFirst(SHM_QUEUE *queue, Pointer *nextPtrPtr, SHM_QUEUE *nextQueue)
|
|
{
|
|
SHM_QUEUE *elemPtr = (SHM_QUEUE *) MAKE_PTR((queue)->next);
|
|
|
|
Assert(SHM_PTR_VALID(queue));
|
|
*nextPtrPtr = (Pointer) (((unsigned long) *nextPtrPtr) +
|
|
((unsigned long) elemPtr) - ((unsigned long) nextQueue));
|
|
|
|
/*
|
|
* nextPtrPtr a ptr to a structure linked in the queue nextQueue is
|
|
* the SHMQueue field of the structure nextPtrPtr - nextQueue is 0
|
|
* minus the offset of the queue field n the record elemPtr +
|
|
* (*nextPtrPtr - nexQueue) is the start of the structure containing
|
|
* elemPtr.
|
|
*/
|
|
}
|
|
|
|
/*
|
|
* SHMQueueEmpty -- TRUE if queue head is only element, FALSE otherwise
|
|
*/
|
|
bool
|
|
SHMQueueEmpty(SHM_QUEUE *queue)
|
|
{
|
|
Assert(SHM_PTR_VALID(queue));
|
|
|
|
if (queue->prev == MAKE_OFFSET(queue))
|
|
{
|
|
Assert(queue->next = MAKE_OFFSET(queue));
|
|
return (TRUE);
|
|
}
|
|
return (FALSE);
|
|
}
|