ipc.c 19.0 KB
Newer Older
B
Bruce Momjian 已提交
1
 /*-------------------------------------------------------------------------
2 3
 *
 * ipc.c--
4
 *	  POSTGRES inter-process communication definitions.
5 6 7 8 9
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
M
 
Marc G. Fournier 已提交
10
 *	  $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipc.c,v 1.31 1998/08/25 21:34:01 scrappy Exp $
11 12 13
 *
 * NOTES
 *
14 15 16 17 18 19 20 21 22 23
 *	  Currently, semaphores are used (my understanding anyway) in two
 *	  different ways:
 *		1. as mutexes on machines that don't have test-and-set (eg.
 *		   mips R3000).
 *		2. for putting processes to sleep when waiting on a lock
 *		   and waking them up when the lock is free.
 *	  The number of semaphores in (1) is fixed and those are shared
 *	  among all backends. In (2), there is 1 semaphore per process and those
 *	  are not shared with anyone else.
 *														  -ay 4/95
24 25 26 27 28 29
 *
 *-------------------------------------------------------------------------
 */
#include <sys/types.h>
#include <sys/file.h>
#include <stdio.h>
B
Bruce Momjian 已提交
30
#include <string.h>
31 32 33
#include <errno.h>


M
Marc G. Fournier 已提交
34
#include "postgres.h"
35
#include "storage/ipc.h"
36
#include "storage/s_lock.h"
37 38 39
/* In Ultrix, sem.h and shm.h must be included AFTER ipc.h */
#include <sys/sem.h>
#include <sys/shm.h>
40
#include "utils/memutils.h"
41
#include "libpq/libpq.h"
M
 
Marc G. Fournier 已提交
42
#include "utils/trace.h"
43

B
Bruce Momjian 已提交
44
#if defined(solaris_sparc)
45 46 47 48
#include <string.h>
#include <sys/ipc.h>
#endif

B
Bruce Momjian 已提交
49
static int			UsePrivateMemory = 0;
50

51
static void IpcMemoryDetach(int status, char *shmaddr);
52

53
/* ----------------------------------------------------------------
54
 *						exit() handling stuff
55 56 57 58 59
 * ----------------------------------------------------------------
 */

#define MAX_ON_EXITS 20

60 61
static struct ONEXIT
{
62 63
	void		(*function) ();
	caddr_t		arg;
64
}	on_proc_exit_list[MAX_ON_EXITS], on_shmem_exit_list[MAX_ON_EXITS];
65

66
static int	on_proc_exit_index, on_shmem_exit_index;
67
static void IpcConfigTip(void);
68

69 70
typedef struct _PrivateMemStruct
{
71 72
	int			id;
	char	   *memptr;
73
} PrivateMem;
74

75
PrivateMem	IpcPrivateMem[16];
76 77 78

static int
PrivateMemoryCreate(IpcMemoryKey memKey,
79
					uint32 size)
80
{
81
	static int	memid = 0;
82 83 84 85 86 87

	UsePrivateMemory = 1;

	IpcPrivateMem[memid].id = memid;
	IpcPrivateMem[memid].memptr = malloc(size);
	if (IpcPrivateMem[memid].memptr == NULL)
88
		elog(ERROR, "PrivateMemoryCreate: not enough memory to malloc");
B
Bruce Momjian 已提交
89
	MemSet(IpcPrivateMem[memid].memptr, 0, size);		/* XXX PURIFY */
90 91

	return (memid++);
92 93
}

94
static char *
95 96
PrivateMemoryAttach(IpcMemoryId memid)
{
97
	return (IpcPrivateMem[memid].memptr);
98 99 100 101
}


/* ----------------------------------------------------------------
102
 *		proc_exit
103
 *
104 105 106 107
 *		this function calls all the callbacks registered
 *		for it (to free resources) and then calls exit.
 *		This should be the only function to call exit().
 *		-cim 2/6/90
108 109
 * ----------------------------------------------------------------
 */
110
static int	proc_exit_inprogress = 0;
111 112

void
113
proc_exit(int code)
114
{
115
	int			i;
116

M
 
Marc G. Fournier 已提交
117 118 119 120 121 122 123 124 125 126 127
	TPRINTF(TRACE_VERBOSE, "proc_exit(%d) [#%d]", code, proc_exit_inprogress);

    /*
	 * If proc_exit is called too many times something bad is
	 * happenig, so exit immediately.
	 */
	if (proc_exit_inprogress > 9) {
		elog(ERROR, "infinite recursion in proc_exit");
		goto exit;
	}

128
	/* ----------------
129
	 *	if proc_exit_inprocess is true, then it means that we
130 131 132 133
	 *	are being invoked from within an on_exit() handler
	 *	and so we return immediately to avoid recursion.
	 * ----------------
	 */
M
 
Marc G. Fournier 已提交
134
	if (proc_exit_inprogress++)
135 136
		return;

137 138 139
	/* do our shared memory exits first */
	shmem_exit(code);
	
140 141 142 143
	/* ----------------
	 *	call all the callbacks registered before calling exit().
	 * ----------------
	 */
144 145
	for (i = on_proc_exit_index - 1; i >= 0; --i)
		(*on_proc_exit_list[i].function) (code, on_proc_exit_list[i].arg);
146

M
 
Marc G. Fournier 已提交
147 148
exit:
	TPRINTF(TRACE_VERBOSE, "exit(%d)", code);
149
	exit(code);
150 151 152
}

/* ------------------
153
 * Run all of the on_shmem_exit routines but don't exit in the end.
154 155 156 157
 * This is used by the postmaster to re-initialize shared memory and
 * semaphores after a backend dies horribly
 * ------------------
 */
158 159
static int	shmem_exit_inprogress = 0;

160
void
161
shmem_exit(int code)
162
{
163
	int			i;
164

M
 
Marc G. Fournier 已提交
165 166 167 168 169 170 171 172 173 174 175 176
	TPRINTF(TRACE_VERBOSE, "shmem_exit(%d) [#%d]",
			code, shmem_exit_inprogress);

	/*
	 * If shmem_exit is called too many times something bad is
	 * happenig, so exit immediately.
	 */
	if (shmem_exit_inprogress > 9) {
		elog(ERROR, "infinite recursion in shmem_exit");
		exit(-1);
	}

177
	/* ----------------
178
	 *	if shmem_exit_inprocess is true, then it means that we
179 180 181 182
	 *	are being invoked from within an on_exit() handler
	 *	and so we return immediately to avoid recursion.
	 * ----------------
	 */
M
 
Marc G. Fournier 已提交
183
	if (shmem_exit_inprogress++)
184 185 186 187 188 189
		return;

	/* ----------------
	 *	call all the callbacks registered before calling exit().
	 * ----------------
	 */
190 191 192 193 194 195
	for (i = on_shmem_exit_index - 1; i >= 0; --i)
		(*on_shmem_exit_list[i].function) (code, on_shmem_exit_list[i].arg);

	on_shmem_exit_index = 0;
	shmem_exit_inprogress = 0;
}
196

197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
/* ----------------------------------------------------------------
 *		on_proc_exit
 *
 *		this function adds a callback function to the list of
 *		functions invoked by proc_exit().	-cim 2/6/90
 * ----------------------------------------------------------------
 */
int
on_proc_exit(void (*function) (), caddr_t arg)
{
	if (on_proc_exit_index >= MAX_ON_EXITS)
		return (-1);

	on_proc_exit_list[on_proc_exit_index].function = function;
	on_proc_exit_list[on_proc_exit_index].arg = arg;

	++on_proc_exit_index;

	return (0);
216 217 218
}

/* ----------------------------------------------------------------
219
 *		on_shmem_exit
220
 *
221
 *		this function adds a callback function to the list of
222
 *		functions invoked by shmem_exit().	-cim 2/6/90
223 224 225
 * ----------------------------------------------------------------
 */
int
226
on_shmem_exit(void (*function) (), caddr_t arg)
227
{
228
	if (on_shmem_exit_index >= MAX_ON_EXITS)
229 230
		return (-1);

231 232
	on_shmem_exit_list[on_shmem_exit_index].function = function;
	on_shmem_exit_list[on_shmem_exit_index].arg = arg;
233

234
	++on_shmem_exit_index;
235 236

	return (0);
237 238
}

239
/* ----------------------------------------------------------------
240
 *		on_exit_reset
241
 *
242
 *		this function clears all proc_exit() registered functions.
243 244 245
 * ----------------------------------------------------------------
 */
void
246
on_exit_reset(void)
247
{
248
	on_shmem_exit_index = 0;
249
	on_proc_exit_index = 0;
250 251
}

252
/****************************************************************************/
253 254
/*	 IPCPrivateSemaphoreKill(status, semId)									*/
/*																			*/
255 256 257
/****************************************************************************/
static void
IPCPrivateSemaphoreKill(int status,
258
						int semId)		/* caddr_t */
259
{
260
	union semun semun;
261 262

	semctl(semId, 0, IPC_RMID, semun);
263 264 265 266
}


/****************************************************************************/
267 268
/*	 IPCPrivateMemoryKill(status, shmId)									*/
/*																			*/
269 270 271
/****************************************************************************/
static void
IPCPrivateMemoryKill(int status,
272
					 int shmId) /* caddr_t */
273
{
274 275 276 277 278 279 280 281 282 283 284
	if (UsePrivateMemory)
	{
		/* free ( IpcPrivateMem[shmId].memptr ); */
	}
	else
	{
		if (shmctl(shmId, IPC_RMID, (struct shmid_ds *) NULL) < 0)
		{
			elog(NOTICE, "IPCPrivateMemoryKill: shmctl(%d, %d, 0) failed: %m",
				 shmId, IPC_RMID);
		}
285 286 287 288 289
	}
}


/****************************************************************************/
290 291 292 293
/*	 IpcSemaphoreCreate(semKey, semNum, permission, semStartValue)			*/
/*																			*/
/*	  - returns a semaphore identifier:										*/
/*																			*/
294
/* if key doesn't exist: return a new id,      status:= IpcSemIdNotExist    */
295 296 297
/* if key exists:		 return the old id,    status:= IpcSemIdExist		*/
/* if semNum > MAX :	 return # of argument, status:=IpcInvalidArgument	*/
/*																			*/
298 299 300 301
/****************************************************************************/

/*
 * Note:
302 303
 * XXX	This should be split into two different calls.	One should
 * XXX	be used to create a semaphore set.	The other to "attach" a
304 305 306
 * XXX	existing set.  It should be an error for the semaphore set
 * XXX	to to already exist or for it not to, respectively.
 *
307 308
 *		Currently, the semaphore sets are "attached" and an error
 *		is detected only when a later shared memory attach fails.
309 310 311 312
 */

IpcSemaphoreId
IpcSemaphoreCreate(IpcSemaphoreKey semKey,
313 314 315 316 317
				   int semNum,
				   int permission,
				   int semStartValue,
				   int removeOnExit,
				   int *status)
318
{
319 320 321 322 323
	int			i;
	int			errStatus;
	int			semId;
	u_short		array[IPC_NMAXSEM];
	union semun semun;
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338

	/* get a semaphore if non-existent */
	/* check arguments	*/
	if (semNum > IPC_NMAXSEM || semNum <= 0)
	{
		*status = IpcInvalidArgument;
		return (2);				/* returns the number of the invalid
								 * argument   */
	}

	semId = semget(semKey, 0, 0);

	if (semId == -1)
	{
		*status = IpcSemIdNotExist;		/* there doesn't exist a semaphore */
339
#ifdef DEBUG_IPC
M
 
Marc G. Fournier 已提交
340
		EPRINTF("calling semget with %d, %d , %d\n",
341 342 343
				semKey,
				semNum,
				IPC_CREAT | permission);
344
#endif
345 346 347 348
		semId = semget(semKey, semNum, IPC_CREAT | permission);

		if (semId < 0)
		{
M
 
Marc G. Fournier 已提交
349 350 351
			EPRINTF("IpcSemaphoreCreate: semget failed (%s) "
					"key=%d, num=%d, permission=%o",
					strerror(errno), semKey, semNum, permission);
352
			proc_exit(3);
353 354 355 356 357 358 359
		}
		for (i = 0; i < semNum; i++)
			array[i] = semStartValue;
		semun.array = array;
		errStatus = semctl(semId, 0, SETALL, semun);
		if (errStatus == -1)
		{
M
 
Marc G. Fournier 已提交
360 361
			EPRINTF("IpcSemaphoreCreate: semctl failed (%s) id=%d",
					strerror(errno), semId);
362 363 364
		}

		if (removeOnExit)
365
			on_shmem_exit(IPCPrivateSemaphoreKill, (caddr_t) semId);
366 367

	}
368 369 370 371
	else
	{
		/* there is a semaphore id for this key */
		*status = IpcSemIdExist;
372
	}
373

374
#ifdef DEBUG_IPC
M
 
Marc G. Fournier 已提交
375
	EPRINTF("\nIpcSemaphoreCreate, status %d, returns %d\n",
376 377 378 379
			*status,
			semId);
	fflush(stdout);
	fflush(stderr);
380
#endif
381
	return (semId);
382 383 384 385
}


/****************************************************************************/
386 387 388
/*	 IpcSemaphoreSet()			- sets the initial value of the semaphore	*/
/*																			*/
/*		note: the xxx_return variables are only used for debugging.			*/
389
/****************************************************************************/
390
#ifdef NOT_USED
391
static int	IpcSemaphoreSet_return;
392 393 394 395

void
IpcSemaphoreSet(int semId, int semno, int value)
{
396 397
	int			errStatus;
	union semun semun;
398 399 400 401 402 403 404

	semun.val = value;
	errStatus = semctl(semId, semno, SETVAL, semun);
	IpcSemaphoreSet_return = errStatus;

	if (errStatus == -1)
	{
M
 
Marc G. Fournier 已提交
405 406
	    EPRINTF("IpcSemaphoreSet: semctl failed (%s) id=%d",
				strerror(errno), semId);
407
	}
408
}
409

410
#endif
411 412

/****************************************************************************/
413 414
/*	 IpcSemaphoreKill(key)		- removes a semaphore						*/
/*																			*/
415 416 417 418
/****************************************************************************/
void
IpcSemaphoreKill(IpcSemaphoreKey key)
{
419 420
	int			semId;
	union semun semun;
421 422 423 424 425 426

	/* kill semaphore if existent */

	semId = semget(key, 0, 0);
	if (semId != -1)
		semctl(semId, 0, IPC_RMID, semun);
427 428 429
}

/****************************************************************************/
430 431 432
/*	 IpcSemaphoreLock(semId, sem, lock) - locks a semaphore					*/
/*																			*/
/*		note: the xxx_return variables are only used for debugging.			*/
433
/****************************************************************************/
434
static int	IpcSemaphoreLock_return;
435 436 437 438

void
IpcSemaphoreLock(IpcSemaphoreId semId, int sem, int lock)
{
439 440 441
	extern int	errno;
	int			errStatus;
	struct sembuf sops;
442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466

	sops.sem_op = lock;
	sops.sem_flg = 0;
	sops.sem_num = sem;

	/* ----------------
	 *	Note: if errStatus is -1 and errno == EINTR then it means we
	 *		  returned from the operation prematurely because we were
	 *		  sent a signal.  So we try and lock the semaphore again.
	 *		  I am not certain this is correct, but the semantics aren't
	 *		  clear it fixes problems with parallel abort synchronization,
	 *		  namely that after processing an abort signal, the semaphore
	 *		  call returns with -1 (and errno == EINTR) before it should.
	 *		  -cim 3/28/90
	 * ----------------
	 */
	do
	{
		errStatus = semop(semId, &sops, 1);
	} while (errStatus == -1 && errno == EINTR);

	IpcSemaphoreLock_return = errStatus;

	if (errStatus == -1)
	{
M
 
Marc G. Fournier 已提交
467 468
		EPRINTF("IpcSemaphoreLock: semop failed (%s) id=%d",
				strerror(errno), semId);
469
		proc_exit(255);
470
	}
471 472 473
}

/****************************************************************************/
474 475 476
/*	 IpcSemaphoreUnlock(semId, sem, lock)		- unlocks a semaphore		*/
/*																			*/
/*		note: the xxx_return variables are only used for debugging.			*/
477
/****************************************************************************/
478
static int	IpcSemaphoreUnlock_return;
479 480 481 482

void
IpcSemaphoreUnlock(IpcSemaphoreId semId, int sem, int lock)
{
483 484 485
	extern int	errno;
	int			errStatus;
	struct sembuf sops;
486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511

	sops.sem_op = -lock;
	sops.sem_flg = 0;
	sops.sem_num = sem;


	/* ----------------
	 *	Note: if errStatus is -1 and errno == EINTR then it means we
	 *		  returned from the operation prematurely because we were
	 *		  sent a signal.  So we try and lock the semaphore again.
	 *		  I am not certain this is correct, but the semantics aren't
	 *		  clear it fixes problems with parallel abort synchronization,
	 *		  namely that after processing an abort signal, the semaphore
	 *		  call returns with -1 (and errno == EINTR) before it should.
	 *		  -cim 3/28/90
	 * ----------------
	 */
	do
	{
		errStatus = semop(semId, &sops, 1);
	} while (errStatus == -1 && errno == EINTR);

	IpcSemaphoreUnlock_return = errStatus;

	if (errStatus == -1)
	{
M
 
Marc G. Fournier 已提交
512 513
		EPRINTF("IpcSemaphoreUnlock: semop failed (%s) id=%d",
				strerror(errno), semId);
514
		proc_exit(255);
515
	}
516 517 518
}

int
519
IpcSemaphoreGetCount(IpcSemaphoreId semId, int sem)
520
{
521 522
	int			semncnt;
	union semun dummy;			/* for Solaris */
523 524 525

	semncnt = semctl(semId, sem, GETNCNT, dummy);
	return semncnt;
526 527 528
}

int
529
IpcSemaphoreGetValue(IpcSemaphoreId semId, int sem)
530
{
531 532
	int			semval;
	union semun dummy;			/* for Solaris */
533 534 535

	semval = semctl(semId, sem, GETVAL, dummy);
	return semval;
536 537 538
}

/****************************************************************************/
539 540 541 542
/*	 IpcMemoryCreate(memKey)												*/
/*																			*/
/*	  - returns the memory identifier, if creation succeeds					*/
/*		returns IpcMemCreationFailed, if failure							*/
543 544 545 546 547
/****************************************************************************/

IpcMemoryId
IpcMemoryCreate(IpcMemoryKey memKey, uint32 size, int permission)
{
548
	IpcMemoryId shmid;
549 550 551 552 553 554 555 556 557 558 559

	if (memKey == PrivateIPCKey)
	{
		/* private */
		shmid = PrivateMemoryCreate(memKey, size);
	}
	else
		shmid = shmget(memKey, size, IPC_CREAT | permission);

	if (shmid < 0)
	{
M
 
Marc G. Fournier 已提交
560 561 562
		EPRINTF("IpcMemoryCreate: shmget failed (%s) "
				"key=%d, size=%d, permission=%o",
				strerror(errno), memKey, size, permission);
563 564 565 566
		return (IpcMemCreationFailed);
	}

	/* if (memKey == PrivateIPCKey) */
567
	on_shmem_exit(IPCPrivateMemoryKill, (caddr_t) shmid);
568 569

	return (shmid);
570 571 572
}

/****************************************************************************/
573 574
/*	IpcMemoryIdGet(memKey, size)	returns the shared memory Id			*/
/*									or IpcMemIdGetFailed					*/
575 576 577 578
/****************************************************************************/
IpcMemoryId
IpcMemoryIdGet(IpcMemoryKey memKey, uint32 size)
{
579
	IpcMemoryId shmid;
580 581 582 583 584

	shmid = shmget(memKey, size, 0);

	if (shmid < 0)
	{
M
 
Marc G. Fournier 已提交
585 586 587
		EPRINTF("IpcMemoryIdGet: shmget failed (%s) "
				"key=%d, size=%d, permission=%o",
				strerror(errno), memKey, size, 0);
588 589 590 591
		return (IpcMemIdGetFailed);
	}

	return (shmid);
592 593 594
}

/****************************************************************************/
595 596 597
/*	IpcMemoryDetach(status, shmaddr)	removes a shared memory segment		*/
/*										from a backend address space		*/
/*	(only called by backends running under the postmaster)					*/
598
/****************************************************************************/
599
static void
600 601
IpcMemoryDetach(int status, char *shmaddr)
{
602 603
	if (shmdt(shmaddr) < 0)
		elog(NOTICE, "IpcMemoryDetach: shmdt(0x%x): %m", shmaddr);
604 605 606
}

/****************************************************************************/
607 608 609 610 611
/*	IpcMemoryAttach(memId)	  returns the adress of shared memory			*/
/*							  or IpcMemAttachFailed							*/
/*																			*/
/* CALL IT:  addr = (struct <MemoryStructure> *) IpcMemoryAttach(memId);	*/
/*																			*/
612
/****************************************************************************/
613
char *
614 615
IpcMemoryAttach(IpcMemoryId memId)
{
616
	char	   *memAddress;
617 618 619 620 621 622 623 624 625

	if (UsePrivateMemory)
		memAddress = (char *) PrivateMemoryAttach(memId);
	else
		memAddress = (char *) shmat(memId, 0, 0);

	/* if ( *memAddress == -1) { XXX ??? */
	if (memAddress == (char *) -1)
	{
M
 
Marc G. Fournier 已提交
626 627
		EPRINTF("IpcMemoryAttach: shmat failed (%s) id=%d",
				strerror(errno), memId);
628 629 630 631
		return (IpcMemAttachFailed);
	}

	if (!UsePrivateMemory)
632
		on_shmem_exit(IpcMemoryDetach, (caddr_t) memAddress);
633 634

	return ((char *) memAddress);
635 636 637 638
}


/****************************************************************************/
639 640
/*	IpcMemoryKill(memKey)				removes a shared memory segment		*/
/*	(only called by the postmaster and standalone backends)					*/
641 642 643
/****************************************************************************/
void
IpcMemoryKill(IpcMemoryKey memKey)
644
{
645
	IpcMemoryId shmid;
646 647 648 649 650 651 652 653

	if (!UsePrivateMemory && (shmid = shmget(memKey, 0, 0)) >= 0)
	{
		if (shmctl(shmid, IPC_RMID, (struct shmid_ds *) NULL) < 0)
		{
			elog(NOTICE, "IpcMemoryKill: shmctl(%d, %d, 0) failed: %m",
				 shmid, IPC_RMID);
		}
654
	}
655
}
656 657 658

#ifdef HAS_TEST_AND_SET
/* ------------------
659 660 661
 *	use hardware locks to replace semaphores for sequent machines
 *	to avoid costs of swapping processes and to provide unlimited
 *	supply of locks.
662 663
 * ------------------
 */
664 665

/* used in spin.c */
666
SLock	   *SLockArray = NULL;
667

668 669
static SLock **FreeSLockPP;
static int *UnusedSLockIP;
670 671 672
static slock_t *SLockMemoryLock;
static IpcMemoryId SLockMemoryId = -1;

673 674
struct ipcdummy
{								/* to get alignment/size right */
675 676 677 678
	SLock	   *free;
	int			unused;
	slock_t		memlock;
	SLock		slocks[NSLOCKS];
679
};
680
static int	SLockMemorySize = sizeof(struct ipcdummy);
681 682 683 684

void
CreateAndInitSLockMemory(IPCKey key)
{
685 686
	int			id;
	SLock	   *slckP;
687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705

	SLockMemoryId = IpcMemoryCreate(key,
									SLockMemorySize,
									0700);
	AttachSLockMemory(key);
	*FreeSLockPP = NULL;
	*UnusedSLockIP = (int) FIRSTFREELOCKID;
	for (id = 0; id < (int) FIRSTFREELOCKID; id++)
	{
		slckP = &(SLockArray[id]);
		S_INIT_LOCK(&(slckP->locklock));
		slckP->flag = NOLOCK;
		slckP->nshlocks = 0;
		S_INIT_LOCK(&(slckP->shlock));
		S_INIT_LOCK(&(slckP->exlock));
		S_INIT_LOCK(&(slckP->comlock));
		slckP->next = NULL;
	}
	return;
706 707 708 709 710
}

void
AttachSLockMemory(IPCKey key)
{
711 712 713 714 715 716 717 718 719
	struct ipcdummy *slockM;

	if (SLockMemoryId == -1)
		SLockMemoryId = IpcMemoryIdGet(key, SLockMemorySize);
	if (SLockMemoryId == -1)
		elog(FATAL, "SLockMemory not in shared memory");
	slockM = (struct ipcdummy *) IpcMemoryAttach(SLockMemoryId);
	if (slockM == IpcMemAttachFailed)
		elog(FATAL, "AttachSLockMemory: could not attach segment");
720
	FreeSLockPP = (SLock **) &(slockM->free);
721
	UnusedSLockIP = (int *) &(slockM->unused);
722
	SLockMemoryLock = (slock_t *) &(slockM->memlock);
723
	S_INIT_LOCK(SLockMemoryLock);
724
	SLockArray = (SLock *) &(slockM->slocks[0]);
725
	return;
726 727
}

728
#ifdef NOT_USED
729 730 731
bool
LockIsFree(int lockid)
{
732
	return (SLockArray[lockid].flag == NOLOCK);
733
}
734

735
#endif
736

737
#endif							/* HAS_TEST_AND_SET */
738 739

static void
740
IpcConfigTip(void)
741
{
742 743 744
	fprintf(stderr, "This type of error is usually caused by improper\n");
	fprintf(stderr, "shared memory or System V IPC semaphore configuration.\n");
	fprintf(stderr, "See the FAQ for more detailed information\n");
745
}