shmqueue.c 6.3 KB
Newer Older
1 2 3
/*-------------------------------------------------------------------------
 *
 * shmqueue.c--
4
 *	  shared memory linked lists
5 6 7 8 9
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
10
 *	  $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmqueue.c,v 1.7 1998/07/20 16:56:54 momjian Exp $
11 12 13 14
 *
 * NOTES
 *
 * Package for managing doubly-linked lists in shared memory.
15 16
 * The only tricky thing is that SHM_QUEUE will usually be a field
 * in a larger record.	SHMQueueGetFirst has to return a pointer
17 18 19 20 21 22 23 24
 * 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.
 *
 *-------------------------------------------------------------------------
 */
25
#include <stdio.h>				/* for sprintf() */
26
#include "postgres.h"
27
#include "storage/shmem.h"		/* where the declarations go */
28 29 30

/*#define SHMQUEUE_DEBUG*/
#ifdef SHMQUEUE_DEBUG
31 32 33
#define SHMQUEUE_DEBUG_DEL		/* deletions */
#define SHMQUEUE_DEBUG_HD		/* head inserts */
#define SHMQUEUE_DEBUG_TL		/* tail inserts */
34
#define SHMQUEUE_DEBUG_ELOG NOTICE
35
#endif							/* SHMQUEUE_DEBUG */
36 37 38

/*
 * ShmemQueueInit -- make the head of a new queue point
39
 *		to itself
40 41
 */
void
42
SHMQueueInit(SHM_QUEUE *queue)
43
{
44 45
	Assert(SHM_PTR_VALID(queue));
	(queue)->prev = (queue)->next = MAKE_OFFSET(queue);
46 47 48 49
}

/*
 * SHMQueueIsDetached -- TRUE if element is not currently
50
 *		in a queue.
51
 */
52
#ifdef NOT_USED
53
bool
54
SHMQueueIsDetached(SHM_QUEUE *queue)
55
{
56 57
	Assert(SHM_PTR_VALID(queue));
	return ((queue)->prev == INVALID_OFFSET);
58
}
59

60
#endif
61 62 63 64 65

/*
 * SHMQueueElemInit -- clear an element's links
 */
void
66
SHMQueueElemInit(SHM_QUEUE *queue)
67
{
68 69
	Assert(SHM_PTR_VALID(queue));
	(queue)->prev = (queue)->next = INVALID_OFFSET;
70 71 72 73
}

/*
 * SHMQueueDelete -- remove an element from the queue and
74
 *		close the links
75 76
 */
void
77
SHMQueueDelete(SHM_QUEUE *queue)
78
{
79 80
	SHM_QUEUE  *nextElem = (SHM_QUEUE *) MAKE_PTR((queue)->next);
	SHM_QUEUE  *prevElem = (SHM_QUEUE *) MAKE_PTR((queue)->prev);
81 82 83 84 85

	Assert(SHM_PTR_VALID(queue));
	Assert(SHM_PTR_VALID(nextElem));
	Assert(SHM_PTR_VALID(prevElem));

86
#ifdef SHMQUEUE_DEBUG_DEL
87 88 89 90 91 92
	dumpQ(queue, "in SHMQueueDelete: begin");
#endif							/* SHMQUEUE_DEBUG_DEL */

	prevElem->next = (queue)->next;
	nextElem->prev = (queue)->prev;

93
#ifdef SHMQUEUE_DEBUG_DEL
94 95
	dumpQ((SHM_QUEUE *) MAKE_PTR(queue->prev), "in SHMQueueDelete: end");
#endif							/* SHMQUEUE_DEBUG_DEL */
96 97 98 99
}

#ifdef SHMQUEUE_DEBUG
void
100
dumpQ(SHM_QUEUE *q, char *s)
101
{
102
	char		elem[NAMEDATALEN];
103 104 105
	char		buf[1024];
	SHM_QUEUE  *start = q;
	int			count = 0;
106 107 108 109

	sprintf(buf, "q prevs: %x", MAKE_OFFSET(q));
	q = (SHM_QUEUE *) MAKE_PTR(q->prev);
	while (q != start)
110
	{
111 112 113 114 115 116
		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)
117
		{
118 119
			strcat(buf, "BAD PREV QUEUE!!");
			break;
120 121
		}
	}
122 123 124 125 126 127 128 129
	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)
130
	{
131 132 133 134 135 136
		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)
137
		{
138 139
			strcat(buf, "BAD NEXT QUEUE!!");
			break;
140 141
		}
	}
142 143 144
	sprintf(elem, "--->%x", MAKE_OFFSET(q));
	strcat(buf, elem);
	elog(SHMQUEUE_DEBUG_ELOG, "%s: %s", s, buf);
145
}
146 147

#endif							/* SHMQUEUE_DEBUG */
148 149 150

/*
 * SHMQueueInsertHD -- put elem in queue between the queue head
151
 *		and its "prev" element.
152
 */
153
#ifdef NOT_USED
154
void
155
SHMQueueInsertHD(SHM_QUEUE *queue, SHM_QUEUE *elem)
156
{
157 158
	SHM_QUEUE  *prevPtr = (SHM_QUEUE *) MAKE_PTR((queue)->prev);
	SHMEM_OFFSET elemOffset = MAKE_OFFSET(elem);
159 160 161 162

	Assert(SHM_PTR_VALID(queue));
	Assert(SHM_PTR_VALID(elem));

163
#ifdef SHMQUEUE_DEBUG_HD
164 165 166 167 168 169 170 171
	dumpQ(queue, "in SHMQueueInsertHD: begin");
#endif							/* SHMQUEUE_DEBUG_HD */

	(elem)->next = prevPtr->next;
	(elem)->prev = queue->prev;
	(queue)->prev = elemOffset;
	prevPtr->next = elemOffset;

172
#ifdef SHMQUEUE_DEBUG_HD
173 174
	dumpQ(queue, "in SHMQueueInsertHD: end");
#endif							/* SHMQUEUE_DEBUG_HD */
175
}
176

177
#endif
178 179

void
180
SHMQueueInsertTL(SHM_QUEUE *queue, SHM_QUEUE *elem)
181
{
182 183
	SHM_QUEUE  *nextPtr = (SHM_QUEUE *) MAKE_PTR((queue)->next);
	SHMEM_OFFSET elemOffset = MAKE_OFFSET(elem);
184 185 186 187

	Assert(SHM_PTR_VALID(queue));
	Assert(SHM_PTR_VALID(elem));

188
#ifdef SHMQUEUE_DEBUG_TL
189 190 191 192 193 194 195 196
	dumpQ(queue, "in SHMQueueInsertTL: begin");
#endif							/* SHMQUEUE_DEBUG_TL */

	(elem)->prev = nextPtr->prev;
	(elem)->next = queue->next;
	(queue)->next = elemOffset;
	nextPtr->prev = elemOffset;

197
#ifdef SHMQUEUE_DEBUG_TL
198 199
	dumpQ(queue, "in SHMQueueInsertTL: end");
#endif							/* SHMQUEUE_DEBUG_TL */
200 201 202 203 204 205 206 207 208
}

/*
 * 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 {
209 210 211
 *		int				stuff;
 *		SHMQueue		elem;
 * } ELEMType;
212 213 214 215 216 217
 * 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:
 *
218
 *	 &(queueHead),&firstElem,&(firstElem->next)
219 220 221 222 223 224
 *
 * Note that firstElem may well be uninitialized.  if firstElem
 * is initially K, &(firstElem->next) will be K+ the offset to
 * next.
 */
void
225
SHMQueueFirst(SHM_QUEUE *queue, Pointer *nextPtrPtr, SHM_QUEUE *nextQueue)
226
{
227
	SHM_QUEUE  *elemPtr = (SHM_QUEUE *) MAKE_PTR((queue)->next);
228 229 230 231 232 233 234 235 236 237 238 239

	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.
	 */
240 241 242 243 244 245
}

/*
 * SHMQueueEmpty -- TRUE if queue head is only element, FALSE otherwise
 */
bool
246
SHMQueueEmpty(SHM_QUEUE *queue)
247
{
248 249 250
	Assert(SHM_PTR_VALID(queue));

	if (queue->prev == MAKE_OFFSET(queue))
251
	{
252 253
		Assert(queue->next = MAKE_OFFSET(queue));
		return (TRUE);
254
	}
255
	return (FALSE);
256
}