1 /*-------------------------------------------------------------------------
4 * shared memory linked lists
6 * Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmqueue.c,v 1.2 1996/11/03 05:06:58 scrappy Exp $
14 * Package for managing doubly-linked lists in shared memory.
15 * The only tricky thing is that SHM_QUEUE will usually be a field
16 * in a larger record. SHMQueueGetFirst has to return a pointer
17 * to the record itself instead of a pointer to the SHMQueue field
18 * of the record. It takes an extra pointer and does some extra
19 * pointer arithmetic to do this correctly.
21 * NOTE: These are set up so they can be turned into macros some day.
23 *-------------------------------------------------------------------------
25 #include <stdio.h> /* for sprintf() */
27 #include "storage/shmem.h" /* where the declarations go */
29 /*#define SHMQUEUE_DEBUG*/
31 #define SHMQUEUE_DEBUG_DEL /* deletions */
32 #define SHMQUEUE_DEBUG_HD /* head inserts */
33 #define SHMQUEUE_DEBUG_TL /* tail inserts */
34 #define SHMQUEUE_DEBUG_ELOG NOTICE
35 #endif /* SHMQUEUE_DEBUG */
38 * ShmemQueueInit -- make the head of a new queue point
42 SHMQueueInit(SHM_QUEUE *queue)
44 Assert(SHM_PTR_VALID(queue));
45 (queue)->prev = (queue)->next = MAKE_OFFSET(queue);
49 * SHMQueueIsDetached -- TRUE if element is not currently
53 SHMQueueIsDetached(SHM_QUEUE *queue)
55 Assert(SHM_PTR_VALID(queue));
56 return ((queue)->prev == INVALID_OFFSET);
60 * SHMQueueElemInit -- clear an element's links
63 SHMQueueElemInit(SHM_QUEUE *queue)
65 Assert(SHM_PTR_VALID(queue));
66 (queue)->prev = (queue)->next = INVALID_OFFSET;
70 * SHMQueueDelete -- remove an element from the queue and
74 SHMQueueDelete(SHM_QUEUE *queue)
76 SHM_QUEUE *nextElem = (SHM_QUEUE *) MAKE_PTR((queue)->next);
77 SHM_QUEUE *prevElem = (SHM_QUEUE *) MAKE_PTR((queue)->prev);
79 Assert(SHM_PTR_VALID(queue));
80 Assert(SHM_PTR_VALID(nextElem));
81 Assert(SHM_PTR_VALID(prevElem));
83 #ifdef SHMQUEUE_DEBUG_DEL
84 dumpQ(queue, "in SHMQueueDelete: begin");
85 #endif /* SHMQUEUE_DEBUG_DEL */
87 prevElem->next = (queue)->next;
88 nextElem->prev = (queue)->prev;
90 #ifdef SHMQUEUE_DEBUG_DEL
91 dumpQ((SHM_QUEUE *)MAKE_PTR(queue->prev), "in SHMQueueDelete: end");
92 #endif /* SHMQUEUE_DEBUG_DEL */
97 dumpQ(SHM_QUEUE *q, char *s)
101 SHM_QUEUE *start = q;
104 sprintf(buf, "q prevs: %x", MAKE_OFFSET(q));
105 q = (SHM_QUEUE *)MAKE_PTR(q->prev);
108 sprintf(elem, "--->%x", MAKE_OFFSET(q));
110 q = (SHM_QUEUE *)MAKE_PTR(q->prev);
111 if (q->prev == MAKE_OFFSET(q))
115 strcat(buf, "BAD PREV QUEUE!!");
119 sprintf(elem, "--->%x", MAKE_OFFSET(q));
121 elog(SHMQUEUE_DEBUG_ELOG, "%s: %s", s, buf);
123 sprintf(buf, "q nexts: %x", MAKE_OFFSET(q));
125 q = (SHM_QUEUE *)MAKE_PTR(q->next);
128 sprintf(elem, "--->%x", MAKE_OFFSET(q));
130 q = (SHM_QUEUE *)MAKE_PTR(q->next);
131 if (q->next == MAKE_OFFSET(q))
135 strcat(buf, "BAD NEXT QUEUE!!");
139 sprintf(elem, "--->%x", MAKE_OFFSET(q));
141 elog(SHMQUEUE_DEBUG_ELOG, "%s: %s", s, buf);
143 #endif /* SHMQUEUE_DEBUG */
146 * SHMQueueInsertHD -- put elem in queue between the queue head
147 * and its "prev" element.
150 SHMQueueInsertHD(SHM_QUEUE *queue, SHM_QUEUE *elem)
152 SHM_QUEUE *prevPtr = (SHM_QUEUE *) MAKE_PTR((queue)->prev);
153 SHMEM_OFFSET elemOffset = MAKE_OFFSET(elem);
155 Assert(SHM_PTR_VALID(queue));
156 Assert(SHM_PTR_VALID(elem));
158 #ifdef SHMQUEUE_DEBUG_HD
159 dumpQ(queue, "in SHMQueueInsertHD: begin");
160 #endif /* SHMQUEUE_DEBUG_HD */
162 (elem)->next = prevPtr->next;
163 (elem)->prev = queue->prev;
164 (queue)->prev = elemOffset;
165 prevPtr->next = elemOffset;
167 #ifdef SHMQUEUE_DEBUG_HD
168 dumpQ(queue, "in SHMQueueInsertHD: end");
169 #endif /* SHMQUEUE_DEBUG_HD */
173 SHMQueueInsertTL(SHM_QUEUE *queue, SHM_QUEUE *elem)
175 SHM_QUEUE *nextPtr = (SHM_QUEUE *) MAKE_PTR((queue)->next);
176 SHMEM_OFFSET elemOffset = MAKE_OFFSET(elem);
178 Assert(SHM_PTR_VALID(queue));
179 Assert(SHM_PTR_VALID(elem));
181 #ifdef SHMQUEUE_DEBUG_TL
182 dumpQ(queue, "in SHMQueueInsertTL: begin");
183 #endif /* SHMQUEUE_DEBUG_TL */
185 (elem)->prev = nextPtr->prev;
186 (elem)->next = queue->next;
187 (queue)->next = elemOffset;
188 nextPtr->prev = elemOffset;
190 #ifdef SHMQUEUE_DEBUG_TL
191 dumpQ(queue, "in SHMQueueInsertTL: end");
192 #endif /* SHMQUEUE_DEBUG_TL */
196 * SHMQueueFirst -- Get the first element from a queue
198 * First element is queue->next. If SHMQueue is part of
199 * a larger structure, we want to return a pointer to the
200 * whole structure rather than a pointer to its SHMQueue field.
205 * when this element is in a queue (queue->next) is struct.elem.
206 * nextQueue allows us to calculate the offset of the SHMQueue
207 * field in the structure.
209 * call to SHMQueueFirst should take these parameters:
211 * &(queueHead),&firstElem,&(firstElem->next)
213 * Note that firstElem may well be uninitialized. if firstElem
214 * is initially K, &(firstElem->next) will be K+ the offset to
218 SHMQueueFirst(SHM_QUEUE *queue, Pointer *nextPtrPtr, SHM_QUEUE *nextQueue)
220 SHM_QUEUE *elemPtr = (SHM_QUEUE *) MAKE_PTR((queue)->next);
222 Assert(SHM_PTR_VALID(queue));
223 *nextPtrPtr = (Pointer) (((unsigned long) *nextPtrPtr) +
224 ((unsigned long) elemPtr) - ((unsigned long) nextQueue));
227 nextPtrPtr a ptr to a structure linked in the queue
228 nextQueue is the SHMQueue field of the structure
229 *nextPtrPtr - nextQueue is 0 minus the offset of the queue
231 elemPtr + (*nextPtrPtr - nexQueue) is the start of the
232 structure containing elemPtr.
237 * SHMQueueEmpty -- TRUE if queue head is only element, FALSE otherwise
240 SHMQueueEmpty(SHM_QUEUE *queue)
242 Assert(SHM_PTR_VALID(queue));
244 if (queue->prev == MAKE_OFFSET(queue))
246 Assert(queue->next = MAKE_OFFSET(queue));