diff --git a/doc/src/sgml/ref/postmaster.sgml b/doc/src/sgml/ref/postmaster.sgml
index beb6c0ee93f661301e00cc4a85c36e5ec8148298..5bf5e4cb92b205ce12839b9f6b70c7124843427d 100644
--- a/doc/src/sgml/ref/postmaster.sgml
+++ b/doc/src/sgml/ref/postmaster.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/postmaster.sgml,v 1.16 2000/11/22 01:41:13 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/postmaster.sgml,v 1.17 2000/11/28 23:27:54 tgl Exp $
 Postgres documentation
 -->
 
@@ -400,32 +400,6 @@ $ ps -e | grep postmast
        </para>
       </listitem>
      </varlistentry>
-
-     <varlistentry>
-      <term><computeroutput>
-IpcMemoryAttach: shmat() failed: Permission denied
-       </computeroutput></term>
-      <listitem>
-       <para>
-	A likely explanation is that another user attempted to start a
-	<application>postmaster</application>
-	process on the same port which acquired shared resources and then 
-	died.  Since Postgres shared memory keys are based on the port number 
-	assigned to the
-	<application>postmaster</application>,
-	such conflicts are likely if there is more than one installation on 
-	a single host.  If there are no other
-	<application>postmaster</application>
-	processes currently running (see above), run
-	<application>ipcclean</application>
-	and try again.  If other <application>postmaster</application>
-	images
-	are running, you will have to find the owners of those processes to
-	coordinate the assignment of port numbers and/or removal of unused
-	shared memory segments.
-       </para>
-      </listitem>
-     </varlistentry>
     </variablelist>
    </para>
   </refsect2>
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index b31a6182ee2f0c2cf0e89dfc0ac8ee5829fc3d10..c70dbc7b4fbe8edef792a7ab01f1a542c52a10bf 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.35 2000/11/27 05:36:12 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.36 2000/11/28 23:27:54 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -85,12 +85,6 @@ typedef struct XLogCtlWrite
 } XLogCtlWrite;
 
 
-#ifndef HAS_TEST_AND_SET
-#define TAS(lck)		0
-#define S_UNLOCK(lck)
-#define S_INIT_LOCK(lck)
-#endif
-
 typedef struct XLogCtlData
 {
 	XLogCtlInsert	Insert;
@@ -102,12 +96,10 @@ typedef struct XLogCtlData
 	uint32			XLogCacheByte;
 	uint32			XLogCacheBlck;
 	StartUpID		ThisStartUpID;
-#ifdef HAS_TEST_AND_SET
 	slock_t			insert_lck;
 	slock_t			info_lck;
 	slock_t			lgwr_lck;
 	slock_t			chkp_lck;		/* checkpoint lock */
-#endif
 } XLogCtlData;
 
 static XLogCtlData *XLogCtl = NULL;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index e364d53b9df0e14a9893a046e10864b8a41811b8..6316262d042ff9e654763d07caf648a8bc2840fe 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.72 2000/11/21 21:15:59 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.73 2000/11/28 23:27:54 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -119,8 +119,8 @@ static Dllist *pendingNotifies = NULL;
 static volatile int notifyInterruptEnabled = 0;
 static volatile int notifyInterruptOccurred = 0;
 
-/* True if we've registered an on_shmem_exit cleanup (or at least tried to). */
-static int	unlistenExitRegistered = 0;
+/* True if we've registered an on_shmem_exit cleanup */
+static bool unlistenExitRegistered = false;
 
 
 static void Async_UnlistenAll(void);
@@ -253,9 +253,8 @@ Async_Listen(char *relname, int pid)
 	 */
 	if (!unlistenExitRegistered)
 	{
-		if (on_shmem_exit(Async_UnlistenOnExit, 0) < 0)
-			elog(NOTICE, "Async_Listen: out of shmem_exit slots");
-		unlistenExitRegistered = 1;
+		on_shmem_exit(Async_UnlistenOnExit, 0);
+		unlistenExitRegistered = true;
 	}
 }
 
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 3b2eb95d4fc2bd881d6d6533cad1474213cae96d..9fa4ebb368901cf848727c4c3b74616e3f60a482 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.193 2000/11/27 04:03:20 inoue Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.194 2000/11/28 23:27:55 tgl Exp $
  *
  * NOTES
  *
@@ -117,26 +117,6 @@ int PostPortNumber;
 char * UnixSocketDir;
 char * Virtual_host;
 
-/*
- * This is a sequence number that indicates how many times we've had to
- * throw away the shared memory and start over because we doubted its
- * integrity.	It starts off at zero and is incremented every time we
- * start over.  We use this to ensure that we use a new IPC shared memory
- * key for the new shared memory segment in case the old segment isn't
- * entirely gone yet.
- *
- * The sequence actually cycles back to 0 after 9, so pathologically there
- * could be an IPC failure if 10 sets of backends are all stuck and won't
- * release IPC resources.
- */
-static short shmem_seq = 0;
-
-/*
- * This is the base IPC shared memory key.  Other keys are generated by
- * adding to this.
- */
-static IpcMemoryKey ipc_key;
-
 /*
  * MaxBackends is the actual limit on the number of backends we will
  * start. The default is established by configure, but it can be
@@ -1292,39 +1272,6 @@ ConnFree(Port *conn)
 	free(conn);
 }
 
-/*
- * get_host_port -- return a pseudo port number (16 bits)
- * derived from the primary IP address of Virtual_host.
- */
-static unsigned short
-get_host_port(void)
-{
-	static unsigned short hostPort = 0;
-
-	if (hostPort == 0)
-	{
-		SockAddr	saddr;
-		struct hostent *hp;
-
-		hp = gethostbyname(Virtual_host);
-		if ((hp == NULL) || (hp->h_addrtype != AF_INET))
-		{
-			char msg[1024];
-			snprintf(msg, sizeof(msg),
-				 "FATAL: get_host_port: gethostbyname(%s) failed\n",
-				 Virtual_host);
-			fputs(msg, stderr);
-			pqdebug("%s", msg);
-			exit(1);
-		}
-		memmove((char *) &(saddr.in.sin_addr),
-			(char *) hp->h_addr,
-			hp->h_length);
-		hostPort = ntohl(saddr.in.sin_addr.s_addr) & 0xFFFF;
-	}
-
-	return hostPort;
-}
 
 /*
  * reset_shared -- reset shared memory and semaphores
@@ -1333,40 +1280,16 @@ static void
 reset_shared(unsigned short port)
 {
 	/*
-	 * A typical ipc_key is 5432001, which is port 5432, sequence
-	 * number 0, and 01 as the index in IPCKeyGetBufferMemoryKey().
-	 * The 32-bit INT_MAX is 2147483 6 47.
-	 *
-	 * The default algorithm for calculating the IPC keys assumes that all
-	 * instances of postmaster on a given host are listening on different
-	 * ports.  In order to work (prevent shared memory collisions) if you
-	 * run multiple PostgreSQL instances on the same port and different IP
-	 * addresses on a host, we change the algorithm if you give postmaster
-	 * the -h option, or set PGHOST, to a value other than the internal
-	 * default.
-	 *
-	 * If Virtual_host is set, then we generate the IPC keys using the
-	 * last two octets of the IP address instead of the port number.
-	 * This algorithm assumes that no one will run multiple PostgreSQL
-	 * instances on one host using two IP addresses that have the same two
-	 * last octets in different class C networks.  If anyone does, it
-	 * would be rare.
-	 *
-	 * So, if you use -h or PGHOST, don't try to run two instances of
-	 * PostgreSQL on the same IP address but different ports.  If you
-	 * don't use them, then you must use different ports (via -p or
-	 * PGPORT).  And, of course, don't try to use both approaches on one
-	 * host.
+	 * Reset assignment of shared mem and semaphore IPC keys.
+	 * Doing this means that in normal cases we'll assign the same keys
+	 * on each "cycle of life", and thereby avoid leaving dead IPC objects
+	 * floating around if the postmaster crashes and is restarted.
 	 */
-
-	if (Virtual_host[0] != '\0')
-		port = get_host_port();
-
-	ipc_key = port * 1000 + shmem_seq * 100;
-	CreateSharedMemoryAndSemaphores(ipc_key, MaxBackends);
-	shmem_seq += 1;
-	if (shmem_seq >= 10)
-		shmem_seq -= 10;
+	IpcInitKeyAssignment(port);
+	/*
+	 * Create or re-create shared memory and semaphores.
+	 */
+	CreateSharedMemoryAndSemaphores(false, MaxBackends);
 }
 
 
diff --git a/src/backend/storage/buffer/buf_init.c b/src/backend/storage/buffer/buf_init.c
index 3c40009422da9bed0d11b6a2125c430b2917ead7..0fda21972f60947c8290c084c2bcd8c21bb16c27 100644
--- a/src/backend/storage/buffer/buf_init.c
+++ b/src/backend/storage/buffer/buf_init.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_init.c,v 1.37 2000/10/23 04:10:06 vadim Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_init.c,v 1.38 2000/11/28 23:27:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -56,13 +56,6 @@ int			Num_Descriptors;
 BufferDesc *BufferDescriptors;
 BufferBlock BufferBlocks;
 
-#ifndef HAS_TEST_AND_SET
-long	   *NWaitIOBackendP;
-
-#endif
-
-extern IpcSemaphoreId WaitIOSemId;
-
 long	   *PrivateRefCount;	/* also used in freelist.c */
 bits8	   *BufferLocks;		/* flag bits showing locks I have set */
 BufferTag  *BufferTagLastDirtied;		/* tag buffer had when last
@@ -139,7 +132,7 @@ long int	LocalBufferFlushCount;
  * amount of available memory.
  */
 void
-InitBufferPool(IPCKey key)
+InitBufferPool(void)
 {
 	bool		foundBufs,
 				foundDescs;
@@ -170,18 +163,6 @@ InitBufferPool(IPCKey key)
 		ShmemInitStruct("Buffer Blocks",
 						NBuffers * BLCKSZ, &foundBufs);
 
-#ifndef HAS_TEST_AND_SET
-	{
-		bool		foundNWaitIO;
-
-		NWaitIOBackendP = (long *) ShmemInitStruct("#Backends Waiting IO",
-												   sizeof(long),
-												   &foundNWaitIO);
-		if (!foundNWaitIO)
-			*NWaitIOBackendP = 0;
-	}
-#endif
-
 	if (foundDescs || foundBufs)
 	{
 
@@ -214,10 +195,8 @@ InitBufferPool(IPCKey key)
 			buf->flags = (BM_DELETED | BM_FREE | BM_VALID);
 			buf->refcount = 0;
 			buf->buf_id = i;
-#ifdef HAS_TEST_AND_SET
 			S_INIT_LOCK(&(buf->io_in_progress_lock));
 			S_INIT_LOCK(&(buf->cntx_lock));
-#endif
 		}
 
 		/* close the circular queue */
@@ -231,22 +210,6 @@ InitBufferPool(IPCKey key)
 
 	SpinRelease(BufMgrLock);
 
-#ifndef HAS_TEST_AND_SET
-	{
-		extern IpcSemaphoreId WaitIOSemId;
-		extern IpcSemaphoreId WaitCLSemId;
-
-		WaitIOSemId = IpcSemaphoreCreate(IPCKeyGetWaitIOSemaphoreKey(key),
-										 1, IPCProtection, 0, 1);
-		if (WaitIOSemId < 0)
-			elog(FATAL, "InitBufferPool: IpcSemaphoreCreate(WaitIOSemId) failed");
-		WaitCLSemId = IpcSemaphoreCreate(IPCKeyGetWaitCLSemaphoreKey(key),
-										 1, IPCProtection,
-									   IpcSemaphoreDefaultStartValue, 1);
-		if (WaitCLSemId < 0)
-			elog(FATAL, "InitBufferPool: IpcSemaphoreCreate(WaitCLSemId) failed");
-	}
-#endif
 	PrivateRefCount = (long *) calloc(NBuffers, sizeof(long));
 	BufferLocks = (bits8 *) calloc(NBuffers, sizeof(bits8));
 	BufferTagLastDirtied = (BufferTag *) calloc(NBuffers, sizeof(BufferTag));
@@ -262,7 +225,7 @@ InitBufferPool(IPCKey key)
  * ----------------------------------------------------
  */
 int
-BufferShmemSize()
+BufferShmemSize(void)
 {
 	int			size = 0;
 
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 907e819474378f478981458e94b01a78d4f313b8..8ed03138fac13be36884ebf5653fa78c9da046d8 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.94 2000/11/20 16:47:31 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.95 2000/11/28 23:27:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -93,12 +93,6 @@ extern void AbortBufferIO(void);
 */
 #define BUFFER_IS_BROKEN(buf) ((buf->flags & BM_IO_ERROR) && !(buf->flags & BM_DIRTY))
 
-#ifndef HAS_TEST_AND_SET
-static void SignalIO(BufferDesc *buf);
-extern long *NWaitIOBackendP;	/* defined in buf_init.c */
-
-#endif	 /* HAS_TEST_AND_SET */
-
 static Buffer ReadBufferWithBufferLock(Relation relation, BlockNumber blockNum,
 						 bool bufferLockHeld);
 static BufferDesc *BufferAlloc(Relation reln, BlockNumber blockNum,
@@ -1187,27 +1181,7 @@ BufferSync()
  *
  * Should be entered with buffer manager spinlock held; releases it before
  * waiting and re-acquires it afterwards.
- *
- * OLD NOTES:
- *		Because IO_IN_PROGRESS conflicts are
- *		expected to be rare, there is only one BufferIO
- *		lock in the entire system.	All processes block
- *		on this semaphore when they try to use a buffer
- *		that someone else is faulting in.  Whenever a
- *		process finishes an IO and someone is waiting for
- *		the buffer, BufferIO is signaled (SignalIO).  All
- *		waiting processes then wake up and check to see
- *		if their buffer is now ready.  This implementation
- *		is simple, but efficient enough if WaitIO is
- *		rarely called by multiple processes simultaneously.
- *
- * NEW NOTES:
- *		The above is true only on machines without test-and-set
- *		semaphores (which we hope are few, these days).  On better
- *		hardware, each buffer has a spinlock that we can wait on.
  */
-#ifdef HAS_TEST_AND_SET
-
 static void
 WaitIO(BufferDesc *buf, SPINLOCK spinlock)
 {
@@ -1224,43 +1198,6 @@ WaitIO(BufferDesc *buf, SPINLOCK spinlock)
 	}
 }
 
-#else							/* !HAS_TEST_AND_SET */
-
-IpcSemaphoreId WaitIOSemId;
-IpcSemaphoreId WaitCLSemId;
-
-static void
-WaitIO(BufferDesc *buf, SPINLOCK spinlock)
-{
-	bool		inProgress;
-
-	for (;;)
-	{
-
-		/* wait until someone releases IO lock */
-		(*NWaitIOBackendP)++;
-		SpinRelease(spinlock);
-		IpcSemaphoreLock(WaitIOSemId, 0, 1);
-		SpinAcquire(spinlock);
-		inProgress = (buf->flags & BM_IO_IN_PROGRESS);
-		if (!inProgress)
-			break;
-	}
-}
-
-/*
- * SignalIO
- */
-static void
-SignalIO(BufferDesc *buf)
-{
-	/* somebody better be waiting. */
-	Assert(buf->refcount > 1);
-	IpcSemaphoreUnlock(WaitIOSemId, 0, *NWaitIOBackendP);
-	*NWaitIOBackendP = 0;
-}
-
-#endif	 /* HAS_TEST_AND_SET */
 
 long		NDirectFileRead;	/* some I/O's are direct file access.
 								 * bypass bufmgr */
@@ -2297,11 +2234,7 @@ UnlockBuffers()
 		Assert(BufferIsValid(i + 1));
 		buf = &(BufferDescriptors[i]);
 
-#ifdef HAS_TEST_AND_SET
 		S_LOCK(&(buf->cntx_lock));
-#else
-		IpcSemaphoreLock(WaitCLSemId, 0, IpcExclusiveLock);
-#endif
 
 		if (BufferLocks[i] & BL_R_LOCK)
 		{
@@ -2324,11 +2257,9 @@ UnlockBuffers()
 			Assert(buf->w_lock);
 			buf->w_lock = false;
 		}
-#ifdef HAS_TEST_AND_SET
+
 		S_UNLOCK(&(buf->cntx_lock));
-#else
-		IpcSemaphoreUnlock(WaitCLSemId, 0, IpcExclusiveLock);
-#endif
+
 		BufferLocks[i] = 0;
 	}
 }
@@ -2346,11 +2277,7 @@ LockBuffer(Buffer buffer, int mode)
 	buf = &(BufferDescriptors[buffer - 1]);
 	buflock = &(BufferLocks[buffer - 1]);
 
-#ifdef HAS_TEST_AND_SET
 	S_LOCK(&(buf->cntx_lock));
-#else
-	IpcSemaphoreLock(WaitCLSemId, 0, IpcExclusiveLock);
-#endif
 
 	if (mode == BUFFER_LOCK_UNLOCK)
 	{
@@ -2380,15 +2307,9 @@ LockBuffer(Buffer buffer, int mode)
 		Assert(!(*buflock & (BL_R_LOCK | BL_W_LOCK | BL_RI_LOCK)));
 		while (buf->ri_lock || buf->w_lock)
 		{
-#ifdef HAS_TEST_AND_SET
 			S_UNLOCK(&(buf->cntx_lock));
 			s_lock_sleep(i++);
 			S_LOCK(&(buf->cntx_lock));
-#else
-			IpcSemaphoreUnlock(WaitCLSemId, 0, IpcExclusiveLock);
-			s_lock_sleep(i++);
-			IpcSemaphoreLock(WaitCLSemId, 0, IpcExclusiveLock);
-#endif
 		}
 		(buf->r_locks)++;
 		*buflock |= BL_R_LOCK;
@@ -2412,15 +2333,9 @@ LockBuffer(Buffer buffer, int mode)
 				*buflock |= BL_RI_LOCK;
 				buf->ri_lock = true;
 			}
-#ifdef HAS_TEST_AND_SET
 			S_UNLOCK(&(buf->cntx_lock));
 			s_lock_sleep(i++);
 			S_LOCK(&(buf->cntx_lock));
-#else
-			IpcSemaphoreUnlock(WaitCLSemId, 0, IpcExclusiveLock);
-			s_lock_sleep(i++);
-			IpcSemaphoreLock(WaitCLSemId, 0, IpcExclusiveLock);
-#endif
 		}
 		buf->w_lock = true;
 		*buflock |= BL_W_LOCK;
@@ -2438,12 +2353,7 @@ LockBuffer(Buffer buffer, int mode)
 	else
 		elog(ERROR, "LockBuffer: unknown lock mode %d", mode);
 
-#ifdef HAS_TEST_AND_SET
 	S_UNLOCK(&(buf->cntx_lock));
-#else
-	IpcSemaphoreUnlock(WaitCLSemId, 0, IpcExclusiveLock);
-#endif
-
 }
 
 /*
@@ -2471,7 +2381,6 @@ StartBufferIO(BufferDesc *buf, bool forInput)
 	Assert(!InProgressBuf);
 	Assert(!(buf->flags & BM_IO_IN_PROGRESS));
 	buf->flags |= BM_IO_IN_PROGRESS;
-#ifdef	HAS_TEST_AND_SET
 
 	/*
 	 * There used to be
@@ -2485,7 +2394,7 @@ StartBufferIO(BufferDesc *buf, bool forInput)
 	 * happen -- tgl
 	 */
 	S_LOCK(&(buf->io_in_progress_lock));
-#endif	 /* HAS_TEST_AND_SET */
+
 	InProgressBuf = buf;
 	IsForInput = forInput;
 }
@@ -2502,12 +2411,7 @@ static void
 TerminateBufferIO(BufferDesc *buf)
 {
 	Assert(buf == InProgressBuf);
-#ifdef	HAS_TEST_AND_SET
 	S_UNLOCK(&(buf->io_in_progress_lock));
-#else
-	if (buf->refcount > 1)
-		SignalIO(buf);
-#endif	 /* HAS_TEST_AND_SET */
 	InProgressBuf = (BufferDesc *) 0;
 }
 
diff --git a/src/backend/storage/buffer/s_lock.c b/src/backend/storage/buffer/s_lock.c
index 883c150b92384ed83b2e9cbe1f009abba5aadba0..72b167977d52a387775f4bfa4d0759eaa6a2ba6b 100644
--- a/src/backend/storage/buffer/s_lock.c
+++ b/src/backend/storage/buffer/s_lock.c
@@ -1,22 +1,22 @@
 /*-------------------------------------------------------------------------
  *
  * s_lock.c
- *	  buffer manager interface routines
+ *	  Spinlock support routines
  *
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/buffer/Attic/s_lock.c,v 1.25 2000/11/16 05:51:01 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/buffer/Attic/s_lock.c,v 1.26 2000/11/28 23:27:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
+#include "postgres.h"
 
 #include <sys/time.h>
 #include <unistd.h>
 
-#include "postgres.h"
 #include "storage/s_lock.h"
 
 
diff --git a/src/backend/storage/buffer/xlog_bufmgr.c b/src/backend/storage/buffer/xlog_bufmgr.c
index ff6bff29a1d82ead0266a4760dcc8e92f4f96bb5..9672510547a8a5917e3ea140e5eae6af74a8a327 100644
--- a/src/backend/storage/buffer/xlog_bufmgr.c
+++ b/src/backend/storage/buffer/xlog_bufmgr.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/buffer/Attic/xlog_bufmgr.c,v 1.4 2000/11/22 02:19:14 inoue Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/buffer/Attic/xlog_bufmgr.c,v 1.5 2000/11/28 23:27:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -88,12 +88,6 @@ extern void AbortBufferIO(void);
 */
 #define BUFFER_IS_BROKEN(buf) ((buf->flags & BM_IO_ERROR) && !(buf->flags & BM_DIRTY))
 
-#ifndef HAS_TEST_AND_SET
-static void SignalIO(BufferDesc *buf);
-extern long *NWaitIOBackendP;	/* defined in buf_init.c */
-
-#endif	 /* HAS_TEST_AND_SET */
-
 static Buffer ReadBufferWithBufferLock(Relation relation, BlockNumber blockNum,
 						 bool bufferLockHeld);
 static BufferDesc *BufferAlloc(Relation reln, BlockNumber blockNum,
@@ -853,27 +847,7 @@ BufferSync()
  *
  * Should be entered with buffer manager spinlock held; releases it before
  * waiting and re-acquires it afterwards.
- *
- * OLD NOTES:
- *		Because IO_IN_PROGRESS conflicts are
- *		expected to be rare, there is only one BufferIO
- *		lock in the entire system.	All processes block
- *		on this semaphore when they try to use a buffer
- *		that someone else is faulting in.  Whenever a
- *		process finishes an IO and someone is waiting for
- *		the buffer, BufferIO is signaled (SignalIO).  All
- *		waiting processes then wake up and check to see
- *		if their buffer is now ready.  This implementation
- *		is simple, but efficient enough if WaitIO is
- *		rarely called by multiple processes simultaneously.
- *
- * NEW NOTES:
- *		The above is true only on machines without test-and-set
- *		semaphores (which we hope are few, these days).  On better
- *		hardware, each buffer has a spinlock that we can wait on.
  */
-#ifdef HAS_TEST_AND_SET
-
 static void
 WaitIO(BufferDesc *buf, SPINLOCK spinlock)
 {
@@ -890,43 +864,6 @@ WaitIO(BufferDesc *buf, SPINLOCK spinlock)
 	}
 }
 
-#else							/* !HAS_TEST_AND_SET */
-
-IpcSemaphoreId WaitIOSemId;
-IpcSemaphoreId WaitCLSemId;
-
-static void
-WaitIO(BufferDesc *buf, SPINLOCK spinlock)
-{
-	bool		inProgress;
-
-	for (;;)
-	{
-
-		/* wait until someone releases IO lock */
-		(*NWaitIOBackendP)++;
-		SpinRelease(spinlock);
-		IpcSemaphoreLock(WaitIOSemId, 0, 1);
-		SpinAcquire(spinlock);
-		inProgress = (buf->flags & BM_IO_IN_PROGRESS);
-		if (!inProgress)
-			break;
-	}
-}
-
-/*
- * SignalIO
- */
-static void
-SignalIO(BufferDesc *buf)
-{
-	/* somebody better be waiting. */
-	Assert(buf->refcount > 1);
-	IpcSemaphoreUnlock(WaitIOSemId, 0, *NWaitIOBackendP);
-	*NWaitIOBackendP = 0;
-}
-
-#endif	 /* HAS_TEST_AND_SET */
 
 long		NDirectFileRead;	/* some I/O's are direct file access.
 								 * bypass bufmgr */
@@ -1965,11 +1902,7 @@ UnlockBuffers()
 		Assert(BufferIsValid(i + 1));
 		buf = &(BufferDescriptors[i]);
 
-#ifdef HAS_TEST_AND_SET
 		S_LOCK(&(buf->cntx_lock));
-#else
-		IpcSemaphoreLock(WaitCLSemId, 0, IpcExclusiveLock);
-#endif
 
 		if (BufferLocks[i] & BL_R_LOCK)
 		{
@@ -1992,11 +1925,9 @@ UnlockBuffers()
 			Assert(buf->w_lock);
 			buf->w_lock = false;
 		}
-#ifdef HAS_TEST_AND_SET
+
 		S_UNLOCK(&(buf->cntx_lock));
-#else
-		IpcSemaphoreUnlock(WaitCLSemId, 0, IpcExclusiveLock);
-#endif
+
 		BufferLocks[i] = 0;
 	}
 }
@@ -2014,11 +1945,7 @@ LockBuffer(Buffer buffer, int mode)
 	buf = &(BufferDescriptors[buffer - 1]);
 	buflock = &(BufferLocks[buffer - 1]);
 
-#ifdef HAS_TEST_AND_SET
 	S_LOCK(&(buf->cntx_lock));
-#else
-	IpcSemaphoreLock(WaitCLSemId, 0, IpcExclusiveLock);
-#endif
 
 	if (mode == BUFFER_LOCK_UNLOCK)
 	{
@@ -2048,15 +1975,9 @@ LockBuffer(Buffer buffer, int mode)
 		Assert(!(*buflock & (BL_R_LOCK | BL_W_LOCK | BL_RI_LOCK)));
 		while (buf->ri_lock || buf->w_lock)
 		{
-#ifdef HAS_TEST_AND_SET
 			S_UNLOCK(&(buf->cntx_lock));
 			s_lock_sleep(i++);
 			S_LOCK(&(buf->cntx_lock));
-#else
-			IpcSemaphoreUnlock(WaitCLSemId, 0, IpcExclusiveLock);
-			s_lock_sleep(i++);
-			IpcSemaphoreLock(WaitCLSemId, 0, IpcExclusiveLock);
-#endif
 		}
 		(buf->r_locks)++;
 		*buflock |= BL_R_LOCK;
@@ -2080,15 +2001,9 @@ LockBuffer(Buffer buffer, int mode)
 				*buflock |= BL_RI_LOCK;
 				buf->ri_lock = true;
 			}
-#ifdef HAS_TEST_AND_SET
 			S_UNLOCK(&(buf->cntx_lock));
 			s_lock_sleep(i++);
 			S_LOCK(&(buf->cntx_lock));
-#else
-			IpcSemaphoreUnlock(WaitCLSemId, 0, IpcExclusiveLock);
-			s_lock_sleep(i++);
-			IpcSemaphoreLock(WaitCLSemId, 0, IpcExclusiveLock);
-#endif
 		}
 		buf->w_lock = true;
 		*buflock |= BL_W_LOCK;
@@ -2109,12 +2024,7 @@ LockBuffer(Buffer buffer, int mode)
 	else
 		elog(ERROR, "LockBuffer: unknown lock mode %d", mode);
 
-#ifdef HAS_TEST_AND_SET
 	S_UNLOCK(&(buf->cntx_lock));
-#else
-	IpcSemaphoreUnlock(WaitCLSemId, 0, IpcExclusiveLock);
-#endif
-
 }
 
 /*
@@ -2142,7 +2052,6 @@ StartBufferIO(BufferDesc *buf, bool forInput)
 	Assert(!InProgressBuf);
 	Assert(!(buf->flags & BM_IO_IN_PROGRESS));
 	buf->flags |= BM_IO_IN_PROGRESS;
-#ifdef	HAS_TEST_AND_SET
 
 	/*
 	 * There used to be
@@ -2156,7 +2065,7 @@ StartBufferIO(BufferDesc *buf, bool forInput)
 	 * happen -- tgl
 	 */
 	S_LOCK(&(buf->io_in_progress_lock));
-#endif	 /* HAS_TEST_AND_SET */
+
 	InProgressBuf = buf;
 	IsForInput = forInput;
 }
@@ -2173,12 +2082,7 @@ static void
 TerminateBufferIO(BufferDesc *buf)
 {
 	Assert(buf == InProgressBuf);
-#ifdef	HAS_TEST_AND_SET
 	S_UNLOCK(&(buf->io_in_progress_lock));
-#else
-	if (buf->refcount > 1)
-		SignalIO(buf);
-#endif	 /* HAS_TEST_AND_SET */
 	InProgressBuf = (BufferDesc *) 0;
 }
 
diff --git a/src/backend/storage/ipc/ipc.c b/src/backend/storage/ipc/ipc.c
index 98d90bc62e02eeadbefc0ad6d7ce077efddf541b..920f7f9bfeb7d7115bd11eee83a928dcbdbc20fb 100644
--- a/src/backend/storage/ipc/ipc.c
+++ b/src/backend/storage/ipc/ipc.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipc.c,v 1.53 2000/11/21 21:16:01 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipc.c,v 1.54 2000/11/28 23:27:56 tgl Exp $
  *
  * NOTES
  *
@@ -30,6 +30,7 @@
 #include <sys/types.h>
 #include <sys/file.h>
 #include <errno.h>
+#include <unistd.h>
 
 #include "storage/ipc.h"
 #include "storage/s_lock.h"
@@ -51,6 +52,7 @@
 #include <sys/ipc.h>
 #endif
 
+
 /*
  * This flag is set during proc_exit() to change elog()'s behavior,
  * so that an elog() from an on_proc_exit routine cannot get us out
@@ -58,12 +60,31 @@
  */
 bool		proc_exit_inprogress = false;
 
-static int	UsePrivateMemory = 0;
+static IpcSemaphoreId InternalIpcSemaphoreCreate(IpcSemaphoreKey semKey,
+						   int numSems, int permission,
+						   int semStartValue, bool removeOnExit);
+static void CallbackSemaphoreKill(int status, Datum semId);
+static void *InternalIpcMemoryCreate(IpcMemoryKey memKey, uint32 size,
+									 int permission);
+static void IpcMemoryDetach(int status, Datum shmaddr);
+static void IpcMemoryDelete(int status, Datum shmId);
+static void *PrivateMemoryCreate(uint32 size);
+static void PrivateMemoryDelete(int status, Datum memaddr);
 
-static void IpcMemoryDetach(int status, char *shmaddr);
 
 /* ----------------------------------------------------------------
  *						exit() handling stuff
+ *
+ * These functions are in generally the same spirit as atexit(2),
+ * but provide some additional features we need --- in particular,
+ * we want to register callbacks to invoke when we are disconnecting
+ * from a broken shared-memory context but not exiting the postmaster.
+ *
+ * Callback functions can take zero, one, or two args: the first passed
+ * arg is the integer exitcode, the second is the Datum supplied when
+ * the callback was registered.
+ *
+ * XXX these functions probably ought to live in some other module.
  * ----------------------------------------------------------------
  */
 
@@ -73,43 +94,12 @@ static struct ONEXIT
 {
 	void		(*function) ();
 	Datum		arg;
-}			on_proc_exit_list[MAX_ON_EXITS], on_shmem_exit_list[MAX_ON_EXITS];
+}			on_proc_exit_list[MAX_ON_EXITS],
+			on_shmem_exit_list[MAX_ON_EXITS];
 
 static int	on_proc_exit_index,
 			on_shmem_exit_index;
 
-typedef struct _PrivateMemStruct
-{
-	int			id;
-	char	   *memptr;
-} PrivateMem;
-
-static PrivateMem IpcPrivateMem[16];
-
-
-static int
-PrivateMemoryCreate(IpcMemoryKey memKey,
-					uint32 size)
-{
-	static int	memid = 0;
-
-	UsePrivateMemory = 1;
-
-	IpcPrivateMem[memid].id = memid;
-	IpcPrivateMem[memid].memptr = malloc(size);
-	if (IpcPrivateMem[memid].memptr == NULL)
-		elog(ERROR, "PrivateMemoryCreate: not enough memory to malloc");
-	MemSet(IpcPrivateMem[memid].memptr, 0, size);		/* XXX PURIFY */
-
-	return memid++;
-}
-
-static char *
-PrivateMemoryAttach(IpcMemoryId memid)
-{
-	return IpcPrivateMem[memid].memptr;
-}
-
 
 /* ----------------------------------------------------------------
  *		proc_exit
@@ -156,9 +146,9 @@ proc_exit(int code)
 }
 
 /* ------------------
- * Run all of the on_shmem_exit routines but don't exit in the end.
+ * Run all of the on_shmem_exit routines --- but don't actually exit.
  * This is used by the postmaster to re-initialize shared memory and
- * semaphores after a backend dies horribly
+ * semaphores after a backend dies horribly.
  * ------------------
  */
 void
@@ -188,18 +178,16 @@ shmem_exit(int code)
  *		functions invoked by proc_exit().	-cim 2/6/90
  * ----------------------------------------------------------------
  */
-int
+void
 on_proc_exit(void (*function) (), Datum arg)
 {
 	if (on_proc_exit_index >= MAX_ON_EXITS)
-		return -1;
+		elog(FATAL, "Out of on_proc_exit slots");
 
 	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;
 }
 
 /* ----------------------------------------------------------------
@@ -209,24 +197,25 @@ on_proc_exit(void (*function) (), Datum arg)
  *		functions invoked by shmem_exit().	-cim 2/6/90
  * ----------------------------------------------------------------
  */
-int
+void
 on_shmem_exit(void (*function) (), Datum arg)
 {
 	if (on_shmem_exit_index >= MAX_ON_EXITS)
-		return -1;
+		elog(FATAL, "Out of on_shmem_exit slots");
 
 	on_shmem_exit_list[on_shmem_exit_index].function = function;
 	on_shmem_exit_list[on_shmem_exit_index].arg = arg;
 
 	++on_shmem_exit_index;
-
-	return 0;
 }
 
 /* ----------------------------------------------------------------
  *		on_exit_reset
  *
- *		this function clears all proc_exit() registered functions.
+ *		this function clears all on_proc_exit() and on_shmem_exit()
+ *		registered functions.  This is used just after forking a backend,
+ *		so that the backend doesn't believe it should call the postmaster's
+ *		on-exit routines when it exits...
  * ----------------------------------------------------------------
  */
 void
@@ -236,190 +225,135 @@ on_exit_reset(void)
 	on_proc_exit_index = 0;
 }
 
-/****************************************************************************/
-/*	 IPCPrivateSemaphoreKill(status, semId)									*/
-/*																			*/
-/****************************************************************************/
-static void
-IPCPrivateSemaphoreKill(int status, int semId)
-{
-	union semun semun;
-	semun.val = 0;		/* unused */
-
-	if (semctl(semId, 0, IPC_RMID, semun) == -1)
-		elog(NOTICE, "IPCPrivateSemaphoreKill: semctl(%d, 0, IPC_RMID, ...) failed: %s",
-			 semId, strerror(errno));
-}
-
-
-/****************************************************************************/
-/*	 IPCPrivateMemoryKill(status, shmId)									*/
-/*																			*/
-/****************************************************************************/
-static void
-IPCPrivateMemoryKill(int status, int shmId)
-{
-	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);
-  		}
-    }
-}
 
-/*
- * Note:
- * XXX	This should be split into two different calls.	One should
- * XXX	be used to create a semaphore set.	The other to "attach" a
- * XXX	existing set.  It should be an error for the semaphore set
- * XXX	to to already exist or for it not to, respectively.
+/* ----------------------------------------------------------------
+ *						Semaphore support
  *
- *		Currently, the semaphore sets are "attached" and an error
- *		is detected only when a later shared memory attach fails.
+ * These routines represent a fairly thin layer on top of SysV semaphore
+ * functionality.
+ * ----------------------------------------------------------------
  */
 
-IpcSemaphoreId
-IpcSemaphoreCreate(IpcSemaphoreKey semKey,
-				   int semNum,
-				   int permission,
-				   int semStartValue,
-				   int removeOnExit)
+/* ----------------------------------------------------------------
+ *	InternalIpcSemaphoreCreate(semKey, numSems, permission,
+ *							   semStartValue, removeOnExit)
+ *
+ * Attempt to create a new semaphore set with the specified key.
+ * Will fail (return -1) if such a set already exists.
+ * On success, a callback is optionally registered with on_shmem_exit
+ * to delete the semaphore set when on_shmem_exit is called.
+ *
+ * If we fail with a failure code other than collision-with-existing-set,
+ * print out an error and abort.  Other types of errors are not recoverable.
+ * ----------------------------------------------------------------
+ */
+static IpcSemaphoreId
+InternalIpcSemaphoreCreate(IpcSemaphoreKey semKey,
+						   int numSems, int permission,
+						   int semStartValue, bool removeOnExit)
 {
 	int			semId;
 	int			i;
-	int			errStatus;
 	u_short		array[IPC_NMAXSEM];
 	union semun semun;
 
-	/* check arguments	*/
-	if (semNum > IPC_NMAXSEM || semNum <= 0)
-		return (-1);
+	Assert(numSems > 0 && numSems <= IPC_NMAXSEM);
 
-	semId = semget(semKey, 0, 0);
+	semId = semget(semKey, numSems, IPC_CREAT | IPC_EXCL | permission);
 
-	if (semId == -1)
+	if (semId < 0)
 	{
-#ifdef DEBUG_IPC
-		fprintf(stderr, "calling semget(%d, %d, 0%o)\n",
-			semKey, semNum, (unsigned)(IPC_CREAT|permission));
-#endif
+		/*
+		 * Fail quietly if error indicates a collision with existing set.
+		 * One would expect EEXIST, given that we said IPC_EXCL, but perhaps
+		 * we could get a permission violation instead?
+		 */
+		if (errno == EEXIST || errno == EACCES)
+			return -1;
+		/*
+		 * Else complain and abort
+		 */
+		fprintf(stderr, "IpcSemaphoreCreate: semget(key=%d, num=%d, 0%o) failed: %s\n",
+				(int) semKey, numSems, (IPC_CREAT|IPC_EXCL|permission),
+				strerror(errno));
 
-		semId = semget(semKey, semNum, IPC_CREAT | permission);
+		if (errno == ENOSPC)
+			fprintf(stderr,
+					"\nThis error does *not* mean that you have run out of disk space.\n\n"
+					"It occurs either because system limit for the maximum number of\n"
+					"semaphore sets (SEMMNI), or the system wide maximum number of\n"
+					"semaphores (SEMMNS), would be exceeded.  You need to raise the\n"
+					"respective kernel parameter.  Look into the PostgreSQL documentation\n"
+					"for details.\n\n");
 
-		if (semId < 0)
-		{
-			fprintf(stderr, "IpcSemaphoreCreate: semget(key=%d, num=%d, 0%o) failed: %s\n",
-					semKey, semNum, (unsigned)(permission|IPC_CREAT),
-					strerror(errno));
-
-			if (errno == ENOSPC)
-				fprintf(stderr,
-						"\nThis error does *not* mean that you have run out of disk space.\n\n"
-						"It occurs either because system limit for the maximum number of\n"
-						"semaphore sets (SEMMNI), or the system wide maximum number of\n"
-						"semaphores (SEMMNS), would be exceeded.  You need to raise the\n"
-						"respective kernel parameter.  Look into the PostgreSQL documentation\n"
-						"for details.\n\n");
-
-			return (-1);
-		}
-		for (i = 0; i < semNum; i++)
-			array[i] = semStartValue;
-		semun.array = array;
-		errStatus = semctl(semId, 0, SETALL, semun);
-		if (errStatus == -1)
-		{
-			fprintf(stderr, "IpcSemaphoreCreate: semctl(id=%d, 0, SETALL, ...) failed: %s\n",
-					semId, strerror(errno));
+		proc_exit(1);
+	}
 
-			if (errno == ERANGE)
-				fprintf(stderr,
-						"You possibly need to raise your kernel's SEMVMX value to be at least\n"
-						"%d.  Look into the PostgreSQL documentation for details.\n",
-						semStartValue);
+	/* Initialize new semas to specified start value */
+	for (i = 0; i < numSems; i++)
+		array[i] = semStartValue;
+	semun.array = array;
+	if (semctl(semId, 0, SETALL, semun) < 0)
+	{
+		fprintf(stderr, "IpcSemaphoreCreate: semctl(id=%d, 0, SETALL, ...) failed: %s\n",
+				semId, strerror(errno));
 
-			semctl(semId, 0, IPC_RMID, semun);
-			return (-1);
-		}
+		if (errno == ERANGE)
+			fprintf(stderr,
+					"You possibly need to raise your kernel's SEMVMX value to be at least\n"
+					"%d.  Look into the PostgreSQL documentation for details.\n",
+					semStartValue);
 
-		if (removeOnExit)
-			on_shmem_exit(IPCPrivateSemaphoreKill, (Datum) semId);
+		IpcSemaphoreKill(semId);
+		proc_exit(1);
 	}
 
-
-#ifdef DEBUG_IPC
-	fprintf(stderr, "IpcSemaphoreCreate returns %d\n", semId);
-	fflush(stdout);
-	fflush(stderr);
-#endif
+	/* Register on-exit routine to delete the new set */
+	if (removeOnExit)
+		on_shmem_exit(CallbackSemaphoreKill, Int32GetDatum(semId));
 
 	return semId;
 }
 
-
 /****************************************************************************/
-/*	 IpcSemaphoreSet()			- sets the initial value of the semaphore	*/
+/*	 IpcSemaphoreKill(semId)	- removes a semaphore set					*/
 /*																			*/
-/*		note: the xxx_return variables are only used for debugging.			*/
 /****************************************************************************/
-#ifdef NOT_USED
-static int	IpcSemaphoreSet_return;
-
 void
-IpcSemaphoreSet(int semId, int semno, int value)
+IpcSemaphoreKill(IpcSemaphoreId semId)
 {
-	int			errStatus;
 	union semun semun;
 
-	semun.val = value;
-	errStatus = semctl(semId, semno, SETVAL, semun);
-	IpcSemaphoreSet_return = errStatus;
+	semun.val = 0;		/* unused, but keep compiler quiet */
 
-	if (errStatus == -1)
-        fprintf(stderr, "IpcSemaphoreSet: semctl(id=%d) failed: %s\n",
+	if (semctl(semId, 0, IPC_RMID, semun) < 0)
+		fprintf(stderr, "IpcSemaphoreKill: semctl(%d, 0, IPC_RMID, ...) failed: %s\n",
 				semId, strerror(errno));
+	/* We used to report a failure via elog(NOTICE), but that's pretty
+	 * pointless considering any client has long since disconnected ...
+	 */
 }
 
-#endif /* NOT_USED */
-
 /****************************************************************************/
-/*	 IpcSemaphoreKill(key)		- removes a semaphore						*/
-/*																			*/
+/*	 CallbackSemaphoreKill(status, semId)									*/
+/*	(called as an on_shmem_exit callback, hence funny argument list)		*/
 /****************************************************************************/
-void
-IpcSemaphoreKill(IpcSemaphoreKey key)
+static void
+CallbackSemaphoreKill(int status, Datum semId)
 {
-	int			semId;
-	union semun semun;
-	semun.val = 0;		/* unused */
-
-	/* kill semaphore if existent */
-
-	semId = semget(key, 0, 0);
-	if (semId != -1)
-		semctl(semId, 0, IPC_RMID, semun);
+	IpcSemaphoreKill(DatumGetInt32(semId));
 }
 
 /****************************************************************************/
-/*	 IpcSemaphoreLock(semId, sem, lock) - locks a semaphore					*/
-/*																			*/
-/*		note: the xxx_return variables are only used for debugging.			*/
+/*	 IpcSemaphoreLock(semId, sem) - locks a semaphore						*/
 /****************************************************************************/
-static int	IpcSemaphoreLock_return;
-
 void
-IpcSemaphoreLock(IpcSemaphoreId semId, int sem, int lock)
+IpcSemaphoreLock(IpcSemaphoreId semId, int sem)
 {
 	int			errStatus;
 	struct sembuf sops;
 
-	sops.sem_op = lock;
+	sops.sem_op = -1;			/* decrement */
 	sops.sem_flg = 0;
 	sops.sem_num = sem;
 
@@ -427,11 +361,6 @@ IpcSemaphoreLock(IpcSemaphoreId semId, int sem, int lock)
 	 *	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
@@ -439,8 +368,6 @@ IpcSemaphoreLock(IpcSemaphoreId semId, int sem, int lock)
 		errStatus = semop(semId, &sops, 1);
 	} while (errStatus == -1 && errno == EINTR);
 
-	IpcSemaphoreLock_return = errStatus;
-
 	if (errStatus == -1)
 	{
         fprintf(stderr, "IpcSemaphoreLock: semop(id=%d) failed: %s\n",
@@ -450,19 +377,15 @@ IpcSemaphoreLock(IpcSemaphoreId semId, int sem, int lock)
 }
 
 /****************************************************************************/
-/*	 IpcSemaphoreUnlock(semId, sem, lock)		- unlocks a semaphore		*/
-/*																			*/
-/*		note: the xxx_return variables are only used for debugging.			*/
+/*	 IpcSemaphoreUnlock(semId, sem)		- unlocks a semaphore				*/
 /****************************************************************************/
-static int	IpcSemaphoreUnlock_return;
-
 void
-IpcSemaphoreUnlock(IpcSemaphoreId semId, int sem, int lock)
+IpcSemaphoreUnlock(IpcSemaphoreId semId, int sem)
 {
 	int			errStatus;
 	struct sembuf sops;
 
-	sops.sem_op = -lock;
+	sops.sem_op = 1;			/* increment */
 	sops.sem_flg = 0;
 	sops.sem_num = sem;
 
@@ -470,12 +393,8 @@ IpcSemaphoreUnlock(IpcSemaphoreId semId, int sem, int lock)
 	/* ----------------
 	 *	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
+	 *		  sent a signal.  So we try and unlock the semaphore again.
+	 *		  Not clear this can really happen, but might as well cope.
 	 * ----------------
 	 */
 	do
@@ -483,8 +402,6 @@ IpcSemaphoreUnlock(IpcSemaphoreId semId, int sem, int lock)
 		errStatus = semop(semId, &sops, 1);
 	} while (errStatus == -1 && errno == EINTR);
 
-	IpcSemaphoreUnlock_return = errStatus;
-
 	if (errStatus == -1)
 	{
 		fprintf(stderr, "IpcSemaphoreUnlock: semop(id=%d) failed: %s\n",
@@ -493,53 +410,115 @@ IpcSemaphoreUnlock(IpcSemaphoreId semId, int sem, int lock)
 	}
 }
 
+/****************************************************************************/
+/*	 IpcSemaphoreTryLock(semId, sem)	- conditionally locks a semaphore	*/
+/* Lock the semaphore if it's free, but don't block.						*/
+/****************************************************************************/
+bool
+IpcSemaphoreTryLock(IpcSemaphoreId semId, int sem)
+{
+	int			errStatus;
+	struct sembuf sops;
+
+	sops.sem_op = -1;			/* decrement */
+	sops.sem_flg = IPC_NOWAIT;	/* but don't block */
+	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.
+	 * ----------------
+	 */
+	do
+	{
+		errStatus = semop(semId, &sops, 1);
+	} while (errStatus == -1 && errno == EINTR);
+
+	if (errStatus == -1)
+	{
+		/* Expect EAGAIN or EWOULDBLOCK (platform-dependent) */
+#ifdef EAGAIN
+		if (errno == EAGAIN)
+			return false;		/* failed to lock it */
+#endif
+#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
+		if (errno == EWOULDBLOCK)
+			return false;		/* failed to lock it */
+#endif
+		/* Otherwise we got trouble */
+        fprintf(stderr, "IpcSemaphoreTryLock: semop(id=%d) failed: %s\n",
+				semId, strerror(errno));
+		proc_exit(255);
+	}
+
+	return true;
+}
+
+/* Get the current value (semval) of the semaphore */
 int
-IpcSemaphoreGetCount(IpcSemaphoreId semId, int sem)
+IpcSemaphoreGetValue(IpcSemaphoreId semId, int sem)
 {
-	int			semncnt;
 	union semun dummy;			/* for Solaris */
 	dummy.val = 0;		/* unused */
 
-	semncnt = semctl(semId, sem, GETNCNT, dummy);
-	return semncnt;
+	return semctl(semId, sem, GETVAL, dummy);
 }
 
-int
-IpcSemaphoreGetValue(IpcSemaphoreId semId, int sem)
+/* Get the PID of the last process to do semop() on the semaphore */
+static pid_t
+IpcSemaphoreGetLastPID(IpcSemaphoreId semId, int sem)
 {
-	int			semval;
 	union semun dummy;			/* for Solaris */
 	dummy.val = 0;		/* unused */
 
-	semval = semctl(semId, sem, GETVAL, dummy);
-	return semval;
+	return semctl(semId, sem, GETPID, dummy);
 }
 
-/****************************************************************************/
-/*	 IpcMemoryCreate(memKey)												*/
-/*																			*/
-/*	  - returns the memory identifier, if creation succeeds					*/
-/*		returns IpcMemCreationFailed, if failure							*/
-/****************************************************************************/
 
-IpcMemoryId
-IpcMemoryCreate(IpcMemoryKey memKey, uint32 size, int permission)
+/* ----------------------------------------------------------------
+ *						Shared memory support
+ *
+ * These routines represent a fairly thin layer on top of SysV shared
+ * memory functionality.
+ * ----------------------------------------------------------------
+ */
+
+/* ----------------------------------------------------------------
+ *	InternalIpcMemoryCreate(memKey, size, permission)
+ *
+ * Attempt to create a new shared memory segment with the specified key.
+ * Will fail (return NULL) if such a segment already exists.  If successful,
+ * attach the segment to the current process and return its attached address.
+ * On success, callbacks are registered with on_shmem_exit to detach and
+ * delete the segment when on_shmem_exit is called.
+ *
+ * If we fail with a failure code other than collision-with-existing-segment,
+ * print out an error and abort.  Other types of errors are not recoverable.
+ * ----------------------------------------------------------------
+ */
+static void *
+InternalIpcMemoryCreate(IpcMemoryKey memKey, uint32 size, int permission)
 {
 	IpcMemoryId shmid;
+	void	   *memAddress;
 
-	if (memKey == PrivateIPCKey)
-	{
-		/* private */
-		shmid = PrivateMemoryCreate(memKey, size);
-	}
-	else
-
-		shmid = shmget(memKey, size, IPC_CREAT | permission);
+	shmid = shmget(memKey, size, IPC_CREAT | IPC_EXCL | permission);
 
 	if (shmid < 0)
 	{
-		fprintf(stderr, "IpcMemoryCreate: shmget(key=%d, size=%d, 0%o) failed: %s\n",
-				(int)memKey, size, (unsigned)(IPC_CREAT|permission),
+		/*
+		 * Fail quietly if error indicates a collision with existing segment.
+		 * One would expect EEXIST, given that we said IPC_EXCL, but perhaps
+		 * we could get a permission violation instead?
+		 */
+		if (errno == EEXIST || errno == EACCES)
+			return NULL;
+		/*
+		 * Else complain and abort
+		 */
+		fprintf(stderr, "IpcMemoryCreate: shmget(key=%d, size=%u, 0%o) failed: %s\n",
+				(int) memKey, size, (IPC_CREAT | IPC_EXCL | permission),
 				strerror(errno));
 
 		if (errno == EINVAL)
@@ -547,7 +526,7 @@ IpcMemoryCreate(IpcMemoryKey memKey, uint32 size, int permission)
 					"\nThis error can be caused by one of three things:\n\n"
 					"1. The maximum size for shared memory segments on your system was\n"
 					"   exceeded.  You need to raise the SHMMAX parameter in your kernel\n"
-					"   to be at least %d bytes.\n\n"
+					"   to be at least %u bytes.\n\n"
 					"2. The requested shared memory segment was too small for your system.\n"
 					"   You need to lower the SHMMIN parameter in your kernel.\n\n"
 					"3. The requested shared memory segment already exists but is of the\n"
@@ -567,179 +546,302 @@ IpcMemoryCreate(IpcMemoryKey memKey, uint32 size, int permission)
 					"reached.  The PostgreSQL Administrator's Guide contains more\n"
 					"information about shared memory configuration.\n\n");
 
-		return IpcMemCreationFailed;
+		proc_exit(1);
 	}
 
+	/* Register on-exit routine to delete the new segment */
+	on_shmem_exit(IpcMemoryDelete, Int32GetDatum(shmid));
 
-	/* if (memKey == PrivateIPCKey) */
-	on_shmem_exit(IPCPrivateMemoryKill, (Datum) shmid);
+	/* OK, should be able to attach to the segment */
+	memAddress = shmat(shmid, 0, 0);
 
-	return shmid;
-}
-
-/****************************************************************************/
-/*	IpcMemoryIdGet(memKey, size)	returns the shared memory Id			*/
-/*									or IpcMemIdGetFailed					*/
-/****************************************************************************/
-IpcMemoryId
-IpcMemoryIdGet(IpcMemoryKey memKey, uint32 size)
-{
-	IpcMemoryId shmid;
-
-	shmid = shmget(memKey, size, 0);
-
-	if (shmid < 0)
+	if (memAddress == (void *) -1)
 	{
-		fprintf(stderr, "IpcMemoryIdGet: shmget(key=%d, size=%d, 0) failed: %s\n",
-				memKey, size, strerror(errno));
-		return IpcMemIdGetFailed;
+        fprintf(stderr, "IpcMemoryCreate: shmat(id=%d) failed: %s\n",
+				shmid, strerror(errno));
+		proc_exit(1);
 	}
 
-	return shmid;
+	/* Register on-exit routine to detach new segment before deleting */
+	on_shmem_exit(IpcMemoryDetach, PointerGetDatum(memAddress));
+
+	return memAddress;
 }
 
 /****************************************************************************/
 /*	IpcMemoryDetach(status, shmaddr)	removes a shared memory segment		*/
-/*										from a backend address space		*/
-/*	(only called by backends running under the postmaster)					*/
+/*										from process' address spaceq		*/
+/*	(called as an on_shmem_exit callback, hence funny argument list)		*/
 /****************************************************************************/
 static void
-IpcMemoryDetach(int status, char *shmaddr)
+IpcMemoryDetach(int status, Datum shmaddr)
 {
-	if (shmdt(shmaddr) < 0)
-		elog(NOTICE, "IpcMemoryDetach: shmdt(0x%p) failed: %m", shmaddr);
+	if (shmdt(DatumGetPointer(shmaddr)) < 0)
+		fprintf(stderr, "IpcMemoryDetach: shmdt(%p) failed: %s\n",
+				DatumGetPointer(shmaddr), strerror(errno));
+	/* We used to report a failure via elog(NOTICE), but that's pretty
+	 * pointless considering any client has long since disconnected ...
+	 */
 }
 
 /****************************************************************************/
-/*	IpcMemoryAttach(memId)	  returns the adress of shared memory			*/
-/*							  or IpcMemAttachFailed							*/
-/*																			*/
-/* CALL IT:  addr = (struct <MemoryStructure> *) IpcMemoryAttach(memId);	*/
-/*																			*/
+/*	IpcMemoryDelete(status, shmId)		deletes a shared memory segment		*/
+/*	(called as an on_shmem_exit callback, hence funny argument list)		*/
 /****************************************************************************/
-char *
-IpcMemoryAttach(IpcMemoryId memId)
+static void
+IpcMemoryDelete(int status, Datum shmId)
 {
-	char	   *memAddress;
+	if (shmctl(DatumGetInt32(shmId), IPC_RMID, (struct shmid_ds *) NULL) < 0)
+		fprintf(stderr, "IpcMemoryDelete: shmctl(%d, %d, 0) failed: %s\n",
+				DatumGetInt32(shmId), IPC_RMID, strerror(errno));
+	/* We used to report a failure via elog(NOTICE), but that's pretty
+	 * pointless considering any client has long since disconnected ...
+	 */
+}
 
-	if (UsePrivateMemory)
-		memAddress = (char *) PrivateMemoryAttach(memId);
-	else
-		memAddress = (char *) shmat(memId, 0, 0);
+/* ----------------------------------------------------------------
+ *						private memory support
+ *
+ * Rather than allocating shmem segments with IPC_PRIVATE key, we
+ * just malloc() the requested amount of space.  This code emulates
+ * the needed shmem functions.
+ * ----------------------------------------------------------------
+ */
 
-	/* if ( *memAddress == -1) { XXX ??? */
-	if (memAddress == (char *) -1)
+static void *
+PrivateMemoryCreate(uint32 size)
+{
+	void	   *memAddress;
+
+	memAddress = malloc(size);
+	if (!memAddress)
 	{
-        fprintf(stderr, "IpcMemoryAttach: shmat(id=%d) failed: %s\n",
-				memId, strerror(errno));
-		return IpcMemAttachFailed;
+		fprintf(stderr, "PrivateMemoryCreate: malloc(%u) failed\n", size);
+		proc_exit(1);
 	}
+	MemSet(memAddress, 0, size);		/* keep Purify quiet */
 
-	if (!UsePrivateMemory)
-		on_shmem_exit(IpcMemoryDetach, PointerGetDatum(memAddress));
+	/* Register on-exit routine to release storage */
+	on_shmem_exit(PrivateMemoryDelete, PointerGetDatum(memAddress));
 
-	return (char *) memAddress;
+	return memAddress;
 }
 
-
-/****************************************************************************/
-/*	IpcMemoryKill(memKey)				removes a shared memory segment		*/
-/*	(only called by the postmaster and standalone backends)					*/
-/****************************************************************************/
-void
-IpcMemoryKill(IpcMemoryKey memKey)
+static void
+PrivateMemoryDelete(int status, Datum memaddr)
 {
-	IpcMemoryId shmid;
-
-	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);
-		}
-	}
+	free(DatumGetPointer(memaddr));
 }
 
-#ifdef HAS_TEST_AND_SET
+
 /* ------------------
- *	use hardware locks to replace semaphores for sequent machines
- *	to avoid costs of swapping processes and to provide unlimited
- *	supply of locks.
+ *				Routines to assign keys for new IPC objects
+ *
+ * The idea here is to detect and re-use keys that may have been assigned
+ * by a crashed postmaster or backend.
  * ------------------
  */
 
-/* used in spin.c */
-SLock	   *SLockArray = NULL;
+static IpcMemoryKey NextShmemSegID = 0;
+static IpcSemaphoreKey NextSemaID = 0;
 
-static SLock **FreeSLockPP;
-static int *UnusedSLockIP;
-static slock_t *SLockMemoryLock;
-static IpcMemoryId SLockMemoryId = -1;
+/*
+ * (Re) initialize key assignment at startup of postmaster or standalone
+ * backend, also at postmaster reset.
+ */
+void
+IpcInitKeyAssignment(int port)
+{
+	NextShmemSegID = port * 1000;
+	NextSemaID = port * 1000;
+}
 
-struct ipcdummy
-{								/* to get alignment/size right */
-	SLock	   *free;
-	int			unused;
-	slock_t		memlock;
-	SLock		slocks[MAX_SPINS + 1];
-};
+/*
+ * Create a shared memory segment of the given size and initialize its
+ * standard header.  Dead Postgres segments are recycled if found,
+ * but we do not fail upon collision with non-Postgres shmem segments.
+ */
+PGShmemHeader *
+IpcMemoryCreate(uint32 size, bool private, int permission)
+{
+	void   *memAddress;
+	PGShmemHeader *hdr;
 
-#define SLOCKMEMORYSIZE		sizeof(struct ipcdummy)
+	/* Room for a header? */
+	Assert(size > MAXALIGN(sizeof(PGShmemHeader)));
 
-void
-CreateAndInitSLockMemory(IPCKey key)
-{
-	int			id;
-	SLock	   *slckP;
-
-	SLockMemoryId = IpcMemoryCreate(key,
-									SLOCKMEMORYSIZE,
-									0700);
-	AttachSLockMemory(key);
-	*FreeSLockPP = NULL;
-	*UnusedSLockIP = (int) FIRSTFREELOCKID;
-	for (id = 0; id < (int) FIRSTFREELOCKID; id++)
+	/* Loop till we find a free IPC key */
+	for (NextShmemSegID++ ; ; NextShmemSegID++)
 	{
-		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;
+		IpcMemoryId shmid;
+
+		/* Special case if creating a private segment --- just malloc() it */
+		if (private)
+		{
+			memAddress = PrivateMemoryCreate(size);
+			break;
+		}
+
+		/* Try to create new segment */
+		memAddress = InternalIpcMemoryCreate(NextShmemSegID, size, permission);
+		if (memAddress)
+			break;				/* successful create and attach */
+
+		/* See if it looks to be leftover from a dead Postgres process */
+		shmid = shmget(NextShmemSegID, sizeof(PGShmemHeader), 0);
+		if (shmid < 0)
+			continue;			/* failed: must be some other app's */
+		memAddress = shmat(shmid, 0, 0);
+		if (memAddress == (void *) -1)
+			continue;			/* failed: must be some other app's */
+		hdr = (PGShmemHeader *) memAddress;
+		if (hdr->magic != PGShmemMagic)
+		{
+			shmdt(memAddress);
+			continue;			/* segment belongs to a non-Postgres app */
+		}
+		/*
+		 * If the creator PID is my own PID or does not belong to any
+		 * extant process, it's safe to zap it.
+		 */
+		if (hdr->creatorPID != getpid())
+		{
+			if (kill(hdr->creatorPID, 0) == 0 ||
+				errno != ESRCH)
+			{
+				shmdt(memAddress);
+				continue;		/* segment belongs to a live process */
+			}
+		}
+		/*
+		 * The segment appears to be from a dead Postgres process, or
+		 * from a previous cycle of life in this same process.  Zap it,
+		 * if possible.  This probably shouldn't fail, but if it does,
+		 * assume the segment belongs to someone else after all,
+		 * and continue quietly.
+		 */
+		shmdt(memAddress);
+		if (shmctl(shmid, IPC_RMID, (struct shmid_ds *) NULL) < 0)
+			continue;
+		/*
+		 * Now try again to create the segment.
+		 */
+		memAddress = InternalIpcMemoryCreate(NextShmemSegID, size, permission);
+		if (memAddress)
+			break;				/* successful create and attach */
+		/*
+		 * Can only get here if some other process managed to create the
+		 * same shmem key before we did.  Let him have that one,
+		 * loop around to try next key.
+		 */
 	}
-	return;
-}
+	/*
+	 * OK, we created a new segment.  Mark it as created by this process.
+	 * The order of assignments here is critical so that another Postgres
+	 * process can't see the header as valid but belonging to an invalid
+	 * PID!
+	 */
+	hdr = (PGShmemHeader *) memAddress;
+	hdr->creatorPID = getpid();
+	hdr->magic = PGShmemMagic;
+	/*
+	 * Initialize space allocation status for segment.
+	 */
+	hdr->totalsize = size;
+	hdr->freeoffset = MAXALIGN(sizeof(PGShmemHeader));
 
-void
-AttachSLockMemory(IPCKey key)
-{
-	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");
-	FreeSLockPP = (SLock **) &(slockM->free);
-	UnusedSLockIP = (int *) &(slockM->unused);
-	SLockMemoryLock = (slock_t *) &(slockM->memlock);
-	S_INIT_LOCK(SLockMemoryLock);
-	SLockArray = (SLock *) &(slockM->slocks[0]);
-	return;
+	return hdr;
 }
 
-#ifdef NOT_USED
-bool
-LockIsFree(int lockid)
+/*
+ * Create a semaphore set with the given number of useful semaphores
+ * (an additional sema is actually allocated to serve as identifier).
+ * Dead Postgres sema sets are recycled if found, but we do not fail
+ * upon collision with non-Postgres sema sets.
+ */
+IpcSemaphoreId
+IpcSemaphoreCreate(int numSems, int permission,
+				   int semStartValue, bool removeOnExit)
 {
-	return SLockArray[lockid].flag == NOLOCK;
-}
+	IpcSemaphoreId	semId;
+	union semun semun;
 
-#endif
+	/* Loop till we find a free IPC key */
+	for (NextSemaID++ ; ; NextSemaID++)
+	{
+		pid_t	creatorPID;
+
+		/* Try to create new semaphore set */
+		semId = InternalIpcSemaphoreCreate(NextSemaID, numSems+1,
+										   permission, semStartValue,
+										   removeOnExit);
+		if (semId >= 0)
+			break;				/* successful create */
 
-#endif	 /* HAS_TEST_AND_SET */
+		/* See if it looks to be leftover from a dead Postgres process */
+		semId = semget(NextSemaID, numSems+1, 0);
+		if (semId < 0)
+			continue;			/* failed: must be some other app's */
+		if (IpcSemaphoreGetValue(semId, numSems) != PGSemaMagic)
+			continue;			/* sema belongs to a non-Postgres app */
+		/*
+		 * If the creator PID is my own PID or does not belong to any
+		 * extant process, it's safe to zap it.
+		 */
+		creatorPID = IpcSemaphoreGetLastPID(semId, numSems);
+		if (creatorPID <= 0)
+			continue;			/* oops, GETPID failed */
+		if (creatorPID != getpid())
+		{
+			if (kill(creatorPID, 0) == 0 ||
+				errno != ESRCH)
+				continue;		/* sema belongs to a live process */
+		}
+		/*
+		 * The sema set appears to be from a dead Postgres process, or
+		 * from a previous cycle of life in this same process.  Zap it,
+		 * if possible.  This probably shouldn't fail, but if it does,
+		 * assume the sema set belongs to someone else after all,
+		 * and continue quietly.
+		 */
+		semun.val = 0;			/* unused, but keep compiler quiet */
+		if (semctl(semId, 0, IPC_RMID, semun) < 0)
+			continue;
+		/*
+		 * Now try again to create the sema set.
+		 */
+		semId = InternalIpcSemaphoreCreate(NextSemaID, numSems+1,
+										   permission, semStartValue,
+										   removeOnExit);
+		if (semId >= 0)
+			break;				/* successful create */
+		/*
+		 * Can only get here if some other process managed to create the
+		 * same sema key before we did.  Let him have that one,
+		 * loop around to try next key.
+		 */
+	}
+	/*
+	 * OK, we created a new sema set.  Mark it as created by this process.
+	 * We do this by setting the spare semaphore to PGSemaMagic-1 and then
+	 * incrementing it with semop().  That leaves it with value PGSemaMagic
+	 * and sempid referencing this process.
+	 */
+	semun.val = PGSemaMagic-1;
+	if (semctl(semId, numSems, SETVAL, semun) < 0)
+	{
+		fprintf(stderr, "IpcSemaphoreCreate: semctl(id=%d, %d, SETVAL, %d) failed: %s\n",
+				semId, numSems, PGSemaMagic-1, strerror(errno));
+
+		if (errno == ERANGE)
+			fprintf(stderr,
+					"You possibly need to raise your kernel's SEMVMX value to be at least\n"
+					"%d.  Look into the PostgreSQL documentation for details.\n",
+					PGSemaMagic);
+
+		proc_exit(1);
+	}
+	IpcSemaphoreUnlock(semId, numSems);
+
+	return semId;
+}
diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c
index 5c7e88af73e42d1069b27a163e469a9c62e6c5d7..7a5813df57d0952ee7c2eb964a278cce6ed2ce06 100644
--- a/src/backend/storage/ipc/ipci.c
+++ b/src/backend/storage/ipc/ipci.c
@@ -8,148 +8,91 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipci.c,v 1.34 2000/11/21 21:16:01 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipci.c,v 1.35 2000/11/28 23:27:56 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
-#include <sys/types.h>
-
 #include "postgres.h"
 
+#include <sys/types.h>
+
 #include "miscadmin.h"
 #include "access/xlog.h"
 #include "storage/bufmgr.h"
+#include "storage/proc.h"
 #include "storage/sinval.h"
+#include "storage/spin.h"
 
-/*
- * SystemPortAddressCreateMemoryKey
- *		Returns a memory key given a port address.
- */
-IPCKey
-SystemPortAddressCreateIPCKey(SystemPortAddress address)
-{
-	Assert(address < 32768);	/* XXX */
-
-	return SystemPortAddressGetIPCKey(address);
-}
 
 /*
  * CreateSharedMemoryAndSemaphores
  *		Creates and initializes shared memory and semaphores.
+ *
+ * This is called by the postmaster or by a standalone backend.
+ * It is NEVER called by a backend forked from the postmaster;
+ * for such a backend, the shared memory is already ready-to-go.
+ *
+ * If "private" is true then we only need private memory, not shared
+ * memory.  This is true for a standalone backend, false for a postmaster.
  */
-/**************************************************
-
-  CreateSharedMemoryAndSemaphores
-  is called exactly *ONCE* by the postmaster.
-  It is *NEVER* called by the postgres backend,
-  except in the case of a standalone backend.
-
-  0) destroy any existing semaphores for both buffer
-  and lock managers.
-  1) create the appropriate *SHARED* memory segments
-  for the two resource managers.
-  2) create shared semaphores as needed.
-
-  **************************************************/
-
 void
-CreateSharedMemoryAndSemaphores(IPCKey key, int maxBackends)
+CreateSharedMemoryAndSemaphores(bool private, int maxBackends)
 {
 	int			size;
-
-#ifdef HAS_TEST_AND_SET
-
-	/*
-	 * Create shared memory for slocks
-	 */
-	CreateAndInitSLockMemory(IPCKeyGetSLockSharedMemoryKey(key));
-#endif
-
-	/*
-	 * Kill and create the buffer manager buffer pool (and semaphore)
-	 */
-	CreateSpinlocks(IPCKeyGetSpinLockSemaphoreKey(key));
+	PGShmemHeader *seghdr;
 
 	/*
-	 * Size of the primary shared-memory block is estimated via
+	 * Size of the Postgres shared-memory block is estimated via
 	 * moderately-accurate estimates for the big hogs, plus 100K for the
 	 * stuff that's too small to bother with estimating.
 	 */
-	size = BufferShmemSize() + LockShmemSize(maxBackends) + XLOGShmemSize();
+	size = BufferShmemSize() + LockShmemSize(maxBackends) +
+		XLOGShmemSize() + SLockShmemSize() + SInvalShmemSize(maxBackends);
 #ifdef STABLE_MEMORY_STORAGE
 	size += MMShmemSize();
 #endif
 	size += 100000;
-	/* might as well round it off to a multiple of a K or so... */
-	size += 1024 - (size % 1024);
+	/* might as well round it off to a multiple of a typical page size */
+	size += 8192 - (size % 8192);
 
 	if (DebugLvl > 1)
-	{
-		fprintf(stderr, "binding ShmemCreate(key=%x, size=%d)\n",
-				IPCKeyGetBufferMemoryKey(key), size);
-	}
-	ShmemCreate(IPCKeyGetBufferMemoryKey(key), size);
-	ShmemIndexReset();
-	InitShmem(key, size);
-	XLOGShmemInit();
-	InitBufferPool(key);
+		fprintf(stderr, "invoking IpcMemoryCreate(size=%d)\n", size);
 
-	/* ----------------
-	 *	do the lock table stuff
-	 * ----------------
+	/*
+	 * Create the shmem segment
 	 */
-	InitLocks();
-	if (InitLockTable() == INVALID_TABLEID)
-		elog(FATAL, "Couldn't create the lock table");
+	seghdr = IpcMemoryCreate(size, private, IPCProtection);
 
-	/* ----------------
-	 *	do process table stuff
-	 * ----------------
+	/*
+	 * First initialize spinlocks --- needed by InitShmemAllocation()
 	 */
-	InitProcGlobal(key, maxBackends);
-
-	CreateSharedInvalidationState(key, maxBackends);
-}
-
+	CreateSpinlocks(seghdr);
 
-/*
- * AttachSharedMemoryAndSemaphores
- *		Attachs existant shared memory and semaphores.
- */
-void
-AttachSharedMemoryAndSemaphores(IPCKey key)
-{
-	/* ----------------
-	 *	create rather than attach if using private key
-	 * ----------------
+	/*
+	 * Set up shmem.c hashtable
 	 */
-	if (key == PrivateIPCKey)
-	{
-		CreateSharedMemoryAndSemaphores(key, 16);
-		return;
-	}
+	InitShmemAllocation(seghdr);
 
-#ifdef HAS_TEST_AND_SET
-	/* ----------------
-	 *	attach the slock shared memory
-	 * ----------------
-	 */
-	AttachSLockMemory(IPCKeyGetSLockSharedMemoryKey(key));
-#endif
-	/* ----------------
-	 *	attach the buffer manager buffer pool (and semaphore)
-	 * ----------------
+	/*
+	 * Set up xlog and buffers
 	 */
-	InitShmem(key, 0);
-	InitBufferPool(key);
+	XLOGShmemInit();
+	InitBufferPool();
 
-	/* ----------------
-	 *	initialize lock table stuff
-	 * ----------------
+	/*
+	 * Set up lock manager
 	 */
 	InitLocks();
 	if (InitLockTable() == INVALID_TABLEID)
-		elog(FATAL, "Couldn't attach to the lock table");
+		elog(FATAL, "Couldn't create the lock table");
+
+	/*
+	 * Set up process table
+	 */
+	InitProcGlobal(maxBackends);
 
-	AttachSharedInvalidationState(key);
+	/*
+	 * Set up shared-inval messaging
+	 */
+	CreateSharedInvalidationState(maxBackends);
 }
diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c
index c5048a389b1ade3bb88cc2ad0d7e9908349e428a..1592294708752bf92e8822eea4b4bda217d9de89 100644
--- a/src/backend/storage/ipc/shmem.c
+++ b/src/backend/storage/ipc/shmem.c
@@ -8,14 +8,14 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.54 2000/11/21 21:16:01 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.55 2000/11/28 23:27:56 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 /*
  * POSTGRES processes share one or more regions of shared memory.
  * The shared memory is created by a postmaster and is inherited
- * by each backends via fork().  The routines in this file are used for
+ * by each backend via fork().  The routines in this file are used for
  * allocating and binding to shared memory data structures.
  *
  * NOTES:
@@ -56,153 +56,57 @@
  *
  *		See InitSem() in sem.c for an example of how to use the
  *	shmem index.
- *
  */
 
 #include "postgres.h"
+
 #include "access/transam.h"
 #include "utils/tqual.h"
 
 /* shared memory global variables */
 
-unsigned long ShmemBase = 0;	/* start and end address of shared memory */
-static unsigned long ShmemEnd = 0;
-static unsigned long ShmemSize = 0;		/* current size (and default) */
+static PGShmemHeader *ShmemSegHdr; /* shared mem segment header */
+
+SHMEM_OFFSET ShmemBase;			/* start address of shared memory */
+
+static SHMEM_OFFSET ShmemEnd;	/* end+1 address of shared memory */
 
 SPINLOCK	ShmemLock;			/* lock for shared memory allocation */
 
 SPINLOCK	ShmemIndexLock;		/* lock for shmem index access */
 
-static unsigned long *ShmemFreeStart = NULL;	/* pointer to the OFFSET
-												 * of first free shared
-												 * memory */
-static unsigned long *ShmemIndexOffset = NULL;	/* start of the shmem
-												 * index table (for
-												 * bootstrap) */
-static int	ShmemBootstrap = FALSE;		/* flag becomes true when shared
-										 * mem is created by POSTMASTER */
-
-static HTAB *ShmemIndex = NULL;
-
-/* ---------------------
- * ShmemIndexReset() - Resets the shmem index to NULL....
- * useful when the postmaster destroys existing shared memory
- * and creates all new segments after a backend crash.
- * ----------------------
- */
-void
-ShmemIndexReset(void)
-{
-	ShmemIndex = (HTAB *) NULL;
-}
+static HTAB *ShmemIndex = NULL;	/* primary index hashtable for shmem */
 
-/*
- *	CreateSharedRegion()
- *
- *	This routine is called once by the postmaster to
- *	initialize the shared buffer pool.	Assume there is
- *	only one postmaster so no synchronization is necessary
- *	until after this routine completes successfully.
- *
- * key is a unique identifier for the shmem region.
- * size is the size of the region.
- */
-static IpcMemoryId ShmemId;
+static bool ShmemBootstrap = false;	/* bootstrapping shmem index? */
 
-void
-ShmemCreate(unsigned int key, unsigned int size)
-{
-	if (size)
-		ShmemSize = size;
-	/* create shared mem region */
-	if ((ShmemId = IpcMemoryCreate(key, ShmemSize, IPCProtection))
-		== IpcMemCreationFailed)
-	{
-		elog(FATAL, "ShmemCreate: cannot create region");
-		exit(1);
-	}
-
-	/*
-	 * ShmemBootstrap is true if shared memory has been created, but not
-	 * yet initialized.  Only the postmaster/creator-of-all-things should
-	 * have this flag set.
-	 */
-	ShmemBootstrap = TRUE;
-}
 
 /*
- *	InitShmem() -- map region into process address space
- *		and initialize shared data structures.
- *
+ *	InitShmemAllocation() --- set up shared-memory allocation and index table.
  */
-int
-InitShmem(unsigned int key, unsigned int size)
+void
+InitShmemAllocation(PGShmemHeader *seghdr)
 {
-	Pointer		sharedRegion;
-	unsigned long currFreeSpace;
-
 	HASHCTL		info;
 	int			hash_flags;
 	ShmemIndexEnt *result,
 				item;
 	bool		found;
-	IpcMemoryId shmid;
-
-	/* if zero key, use default memory size */
-	if (size)
-		ShmemSize = size;
-
-	/* default key is 0 */
-
-	/* attach to shared memory region (SysV or BSD OS specific) */
-	if (ShmemBootstrap && key == PrivateIPCKey)
-		/* if we are running backend alone */
-		shmid = ShmemId;
-	else
-		shmid = IpcMemoryIdGet(IPCKeyGetBufferMemoryKey(key), ShmemSize);
-	sharedRegion = IpcMemoryAttach(shmid);
-	if (sharedRegion == NULL)
-	{
-		elog(FATAL, "AttachSharedRegion: couldn't attach to shmem\n");
-		return FALSE;
-	}
-
-	/* get pointers to the dimensions of shared memory */
-	ShmemBase = (unsigned long) sharedRegion;
-	ShmemEnd = (unsigned long) sharedRegion + ShmemSize;
-
-	/* First long in shared memory is the available-space pointer */
-	ShmemFreeStart = (unsigned long *) ShmemBase;
-	/* next is a shmem pointer to the shmem index */
-	ShmemIndexOffset = ShmemFreeStart + 1;
-	/* next is ShmemVariableCache */
-	ShmemVariableCache = (VariableCache) (ShmemIndexOffset + 1);
-
-	/* here is where to start dynamic allocation */
-	currFreeSpace = MAXALIGN(sizeof(*ShmemFreeStart) +
-							 sizeof(*ShmemIndexOffset) +
-							 sizeof(*ShmemVariableCache));
 
-	/*
-	 * bootstrap initialize spin locks so we can start to use the
-	 * allocator and shmem index.
-	 */
-	InitSpinLocks();
+	/* Set up basic pointers to shared memory */
+	ShmemSegHdr = seghdr;
+	ShmemBase = (SHMEM_OFFSET) seghdr;
+	ShmemEnd = ShmemBase + seghdr->totalsize;
 
 	/*
-	 * We have just allocated additional space for two spinlocks. Now
-	 * setup the global free space count
+	 * Since ShmemInitHash calls ShmemInitStruct, which expects the
+	 * ShmemIndex hashtable to exist already, we have a bit of a circularity
+	 * problem in initializing the ShmemIndex itself.  We set ShmemBootstrap
+	 * to tell ShmemInitStruct to fake it.
 	 */
-	if (ShmemBootstrap)
-	{
-		*ShmemFreeStart = currFreeSpace;
-		memset(ShmemVariableCache, 0, sizeof(*ShmemVariableCache));
-	}
-
-	/* if ShmemFreeStart is NULL, then the allocator won't work */
-	Assert(*ShmemFreeStart);
+	ShmemIndex = (HTAB *) NULL;
+	ShmemBootstrap = true;
 
-	/* create OR attach to the shared memory shmem index */
+	/* create the shared memory shmem index */
 	info.keysize = SHMEM_INDEX_KEYSIZE;
 	info.datasize = SHMEM_INDEX_DATASIZE;
 	hash_flags = HASH_ELEM;
@@ -211,60 +115,43 @@ InitShmem(unsigned int key, unsigned int size)
 	ShmemIndex = ShmemInitHash("ShmemIndex",
 							   SHMEM_INDEX_SIZE, SHMEM_INDEX_SIZE,
 							   &info, hash_flags);
-
 	if (!ShmemIndex)
-	{
-		elog(FATAL, "InitShmem: couldn't initialize Shmem Index");
-		return FALSE;
-	}
+		elog(FATAL, "InitShmemAllocation: couldn't initialize Shmem Index");
 
 	/*
-	 * Now, check the shmem index for an entry to the shmem index.	If
-	 * there is an entry there, someone else created the table. Otherwise,
-	 * we did and we have to initialize it.
+	 * Now, create an entry in the hashtable for the index itself.
 	 */
 	MemSet(item.key, 0, SHMEM_INDEX_KEYSIZE);
 	strncpy(item.key, "ShmemIndex", SHMEM_INDEX_KEYSIZE);
 
 	result = (ShmemIndexEnt *)
 		hash_search(ShmemIndex, (char *) &item, HASH_ENTER, &found);
-
-
 	if (!result)
-	{
-		elog(FATAL, "InitShmem: corrupted shmem index");
-		return FALSE;
-	}
-
-	if (!found)
-	{
+		elog(FATAL, "InitShmemAllocation: corrupted shmem index");
 
-		/*
-		 * bootstrapping shmem: we have to initialize the shmem index now.
-		 */
+	Assert(ShmemBootstrap && !found);
 
-		Assert(ShmemBootstrap);
-		result->location = MAKE_OFFSET(ShmemIndex->hctl);
-		*ShmemIndexOffset = result->location;
-		result->size = SHMEM_INDEX_SIZE;
+	result->location = MAKE_OFFSET(ShmemIndex->hctl);
+	result->size = SHMEM_INDEX_SIZE;
 
-		ShmemBootstrap = FALSE;
+	ShmemBootstrap = false;
 
-	}
-	else
-		Assert(!ShmemBootstrap);
-	/* now release the lock acquired in ShmemHashInit */
+	/* now release the lock acquired in ShmemInitStruct */
 	SpinRelease(ShmemIndexLock);
 
-	Assert(result->location == MAKE_OFFSET(ShmemIndex->hctl));
-
-	return TRUE;
+	/*
+	 * Initialize ShmemVariableCache for transaction manager.
+	 */
+	ShmemVariableCache = (VariableCache)
+		ShmemAlloc(sizeof(*ShmemVariableCache));
+	memset(ShmemVariableCache, 0, sizeof(*ShmemVariableCache));
 }
 
 /*
- * ShmemAlloc -- allocate max-aligned byte string from shared memory
+ * ShmemAlloc -- allocate max-aligned chunk from shared memory
+ *
+ * Assumes ShmemLock and ShmemSegHdr are initialized.
  *
- * Assumes ShmemLock and ShmemFreeStart are initialized.
  * Returns: real pointer to memory or NULL if we are out
  *		of space.  Has to return a real pointer in order
  *		to be compatible with malloc().
@@ -272,7 +159,7 @@ InitShmem(unsigned int key, unsigned int size)
 void *
 ShmemAlloc(Size size)
 {
-	unsigned long tmpFree;
+	uint32		newFree;
 	void	   *newSpace;
 
 	/*
@@ -280,15 +167,15 @@ ShmemAlloc(Size size)
 	 */
 	size = MAXALIGN(size);
 
-	Assert(*ShmemFreeStart);
+	Assert(ShmemSegHdr);
 
 	SpinAcquire(ShmemLock);
 
-	tmpFree = *ShmemFreeStart + size;
-	if (tmpFree <= ShmemSize)
+	newFree = ShmemSegHdr->freeoffset + size;
+	if (newFree <= ShmemSegHdr->totalsize)
 	{
-		newSpace = (void *) MAKE_PTR(*ShmemFreeStart);
-		*ShmemFreeStart += size;
+		newSpace = (void *) MAKE_PTR(ShmemSegHdr->freeoffset);
+		ShmemSegHdr->freeoffset = newFree;
 	}
 	else
 		newSpace = NULL;
@@ -306,7 +193,7 @@ ShmemAlloc(Size size)
  *
  * Returns TRUE if the pointer is valid.
  */
-int
+bool
 ShmemIsValid(unsigned long addr)
 {
 	return (addr < ShmemEnd) && (addr >= ShmemBase);
@@ -394,16 +281,15 @@ ShmemPIDLookup(int pid, SHMEM_OFFSET *locationPtr)
 	sprintf(item.key, "PID %d", pid);
 
 	SpinAcquire(ShmemIndexLock);
+
 	result = (ShmemIndexEnt *)
 		hash_search(ShmemIndex, (char *) &item, HASH_ENTER, &found);
 
 	if (!result)
 	{
-
 		SpinRelease(ShmemIndexLock);
 		elog(ERROR, "ShmemInitPID: ShmemIndex corrupted");
 		return FALSE;
-
 	}
 
 	if (found)
@@ -438,19 +324,19 @@ ShmemPIDDestroy(int pid)
 	sprintf(item.key, "PID %d", pid);
 
 	SpinAcquire(ShmemIndexLock);
+
 	result = (ShmemIndexEnt *)
 		hash_search(ShmemIndex, (char *) &item, HASH_REMOVE, &found);
 
 	if (found)
 		location = result->location;
+
 	SpinRelease(ShmemIndexLock);
 
 	if (!result)
 	{
-
 		elog(ERROR, "ShmemPIDDestroy: PID table corrupted");
 		return INVALID_OFFSET;
-
 	}
 
 	if (found)
@@ -487,53 +373,31 @@ ShmemInitStruct(char *name, Size size, bool *foundPtr)
 
 	if (!ShmemIndex)
 	{
-#ifdef USE_ASSERT_CHECKING
-		char	   *strname = "ShmemIndex";
-
-#endif
-
 		/*
-		 * If the shmem index doesn't exist, we fake it.
+		 * If the shmem index doesn't exist, we are bootstrapping: we must
+		 * be trying to init the shmem index itself.
 		 *
-		 * If we are creating the first shmem index, then let shmemalloc()
-		 * allocate the space for a new HTAB.  Otherwise, find the old one
-		 * and return that.  Notice that the ShmemIndexLock is held until
-		 * the shmem index has been completely initialized.
+		 * Notice that the ShmemIndexLock is held until the shmem index has
+		 * been completely initialized.
 		 */
-		Assert(strcmp(name, strname) == 0);
-		if (ShmemBootstrap)
-		{
-			/* in POSTMASTER/Single process */
-
-			*foundPtr = FALSE;
-			return ShmemAlloc(size);
-		}
-		else
-		{
-			Assert(*ShmemIndexOffset);
-
-			*foundPtr = TRUE;
-			return (void *) MAKE_PTR(*ShmemIndexOffset);
-		}
-
-
-	}
-	else
-	{
-		/* look it up in the shmem index */
-		result = (ShmemIndexEnt *)
-			hash_search(ShmemIndex, (char *) &item, HASH_ENTER, foundPtr);
+		Assert(strcmp(name, "ShmemIndex") == 0);
+		Assert(ShmemBootstrap);
+		*foundPtr = FALSE;
+		return ShmemAlloc(size);
 	}
 
+	/* look it up in the shmem index */
+	result = (ShmemIndexEnt *)
+		hash_search(ShmemIndex, (char *) &item, HASH_ENTER, foundPtr);
+
 	if (!result)
 	{
 		SpinRelease(ShmemIndexLock);
-
 		elog(ERROR, "ShmemInitStruct: Shmem Index corrupted");
 		return NULL;
-
 	}
-	else if (*foundPtr)
+
+	if (*foundPtr)
 	{
 
 		/*
diff --git a/src/backend/storage/ipc/sinval.c b/src/backend/storage/ipc/sinval.c
index fb2e4804dd3c23b8f4e865b791947cb11bcb4aab..c87fcd3660292bfb876fdbda63f37cdfcfc0ab85 100644
--- a/src/backend/storage/ipc/sinval.c
+++ b/src/backend/storage/ipc/sinval.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinval.c,v 1.23 2000/11/12 20:51:51 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinval.c,v 1.24 2000/11/28 23:27:56 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -27,52 +27,23 @@
 SPINLOCK	SInvalLock = (SPINLOCK) NULL;
 
 /****************************************************************************/
-/*	CreateSharedInvalidationState()		 Create a buffer segment			*/
+/*	CreateSharedInvalidationState()		 Initialize SI buffer				*/
 /*																			*/
 /*	should be called only by the POSTMASTER									*/
 /****************************************************************************/
 void
-CreateSharedInvalidationState(IPCKey key, int maxBackends)
+CreateSharedInvalidationState(int maxBackends)
 {
-	int			status;
-
-	/* SInvalLock gets set in spin.c, during spinlock init */
-	status = SISegmentInit(true, IPCKeyGetSIBufferMemoryBlock(key),
-						   maxBackends);
-
-	if (status == -1)
-		elog(FATAL, "CreateSharedInvalidationState: failed segment init");
-}
-
-/****************************************************************************/
-/*	AttachSharedInvalidationState(key)	 Attach to existing buffer segment	*/
-/*																			*/
-/*	should be called by each backend during startup							*/
-/****************************************************************************/
-void
-AttachSharedInvalidationState(IPCKey key)
-{
-	int			status;
-
-	if (key == PrivateIPCKey)
-	{
-		CreateSharedInvalidationState(key, 16);
-		return;
-	}
-	/* SInvalLock gets set in spin.c, during spinlock init */
-	status = SISegmentInit(false, IPCKeyGetSIBufferMemoryBlock(key), 0);
-
-	if (status == -1)
-		elog(FATAL, "AttachSharedInvalidationState: failed segment init");
+	/* SInvalLock must be initialized already, during spinlock init */
+	SIBufferInit(maxBackends);
 }
 
 /*
- * InitSharedInvalidationState
+ * InitBackendSharedInvalidationState
  *		Initialize new backend's state info in buffer segment.
- *		Must be called after AttachSharedInvalidationState().
  */
 void
-InitSharedInvalidationState(void)
+InitBackendSharedInvalidationState(void)
 {
 	SpinAcquire(SInvalLock);
 	if (!SIBackendInit(shmInvalBuffer))
diff --git a/src/backend/storage/ipc/sinvaladt.c b/src/backend/storage/ipc/sinvaladt.c
index f4b2998343314e6eeb30188171d28074e3077b03..c7612759793fcd6831bcad9440b98d761853426d 100644
--- a/src/backend/storage/ipc/sinvaladt.c
+++ b/src/backend/storage/ipc/sinvaladt.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.35 2000/11/12 20:51:51 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.36 2000/11/28 23:27:56 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -25,95 +25,38 @@
 
 SISeg	   *shmInvalBuffer;
 
-static void SISegmentAttach(IpcMemoryId shmid);
-static void SISegInit(SISeg *segP, int maxBackends);
 static void CleanupInvalidationState(int status, Datum arg);
 static void SISetProcStateInvalid(SISeg *segP);
 
-/*
- * SISegmentInit
- *		Create a new SI memory segment, or attach to an existing one
- *
- * This is called with createNewSegment = true by the postmaster (or by
- * a standalone backend), and subsequently with createNewSegment = false
- * by backends started by the postmaster.
- *
- * Note: maxBackends param is only valid when createNewSegment is true
- */
-int
-SISegmentInit(bool createNewSegment, IPCKey key, int maxBackends)
-{
-	int			segSize;
-	IpcMemoryId shmId;
-
-	if (createNewSegment)
-	{
-		/* Kill existing segment, if any */
-		IpcMemoryKill(key);
-
-		/*
-		 * Figure space needed. Note sizeof(SISeg) includes the first
-		 * ProcState entry.
-		 */
-		segSize = sizeof(SISeg) + sizeof(ProcState) * (maxBackends - 1);
-
-		/* Get a shared segment */
-		shmId = IpcMemoryCreate(key, segSize, IPCProtection);
-		if (shmId < 0)
-		{
-			perror("SISegmentInit: segment create failed");
-			return -1;			/* an error */
-		}
-
-		/* Attach to the shared cache invalidation segment */
-		/* sets the global variable shmInvalBuffer */
-		SISegmentAttach(shmId);
-
-		/* Init shared memory contents */
-		SISegInit(shmInvalBuffer, maxBackends);
-	}
-	else
-	{
-		/* find existing segment */
-		shmId = IpcMemoryIdGet(key, 0);
-		if (shmId < 0)
-		{
-			perror("SISegmentInit: segment get failed");
-			return -1;			/* an error */
-		}
-
-		/* Attach to the shared cache invalidation segment */
-		/* sets the global variable shmInvalBuffer */
-		SISegmentAttach(shmId);
-	}
-	return 1;
-}
 
 /*
- * SISegmentAttach
- *		Attach to specified shared memory segment
+ * SInvalShmemSize --- return shared-memory space needed
  */
-static void
-SISegmentAttach(IpcMemoryId shmid)
+int
+SInvalShmemSize(int maxBackends)
 {
-	shmInvalBuffer = (SISeg *) IpcMemoryAttach(shmid);
-
-	if (shmInvalBuffer == IpcMemAttachFailed)
-	{
-		/* XXX use validity function */
-		elog(FATAL, "SISegmentAttach: Could not attach segment: %m");
-	}
+	/*
+	 * Figure space needed. Note sizeof(SISeg) includes the first
+	 * ProcState entry.
+	 */
+	return sizeof(SISeg) + sizeof(ProcState) * (maxBackends - 1);
 }
 
 /*
- * SISegInit
- *		Initialize contents of a new shared memory sinval segment
+ * SIBufferInit
+ *		Create and initialize a new SI message buffer
  */
-static void
-SISegInit(SISeg *segP, int maxBackends)
+void
+SIBufferInit(int maxBackends)
 {
+	int			segSize;
+	SISeg	   *segP;
 	int			i;
 
+	/* Allocate space in shared memory */
+	segSize = SInvalShmemSize(maxBackends);
+	shmInvalBuffer = segP = (SISeg *) ShmemAlloc(segSize);
+
 	/* Clear message counters, save size of procState array */
 	segP->minMsgNum = 0;
 	segP->maxMsgNum = 0;
diff --git a/src/backend/storage/ipc/spin.c b/src/backend/storage/ipc/spin.c
index 674ee06a9a34f3959c4123b6adcafa171d26100b..a93ae69e0327f71c7920c8b16d64347f5d0c49f9 100644
--- a/src/backend/storage/ipc/spin.c
+++ b/src/backend/storage/ipc/spin.c
@@ -3,31 +3,24 @@
  * spin.c
  *	  routines for managing spin locks
  *
+ * POSTGRES has two kinds of locks: semaphores (which put the
+ * process to sleep) and spinlocks (which are supposed to be
+ * short term locks).  Spinlocks are implemented via test-and-set (TAS)
+ * instructions if possible, else via semaphores.  The semaphore method
+ * is too slow to be useful :-(
+ *
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/ipc/Attic/spin.c,v 1.25 2000/05/31 00:28:29 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/ipc/Attic/spin.c,v 1.26 2000/11/28 23:27:56 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
-/*
- * POSTGRES has two kinds of locks: semaphores (which put the
- * process to sleep) and spinlocks (which are supposed to be
- * short term locks).  Currently both are implemented as SysV
- * semaphores, but presumably this can change if we move to
- * a machine with a test-and-set (TAS) instruction.  Its probably
- * a good idea to think about (and allocate) short term and long
- * term semaphores separately anyway.
- *
- * NOTE: These routines are not supposed to be widely used in Postgres.
- *		 They are preserved solely for the purpose of porting Mark Sullivan's
- *		 buffer manager to Postgres.
- */
-#include <errno.h>
 #include "postgres.h"
 
+#include <errno.h>
 #ifndef HAS_TEST_AND_SET
 #include <sys/sem.h>
 #endif
@@ -35,39 +28,33 @@
 #include "storage/proc.h"
 #include "storage/s_lock.h"
 
-
-/* globals used in this file */
-IpcSemaphoreId SpinLockId;
-
-#ifdef HAS_TEST_AND_SET
-/* real spin lock implementations */
-
-void
-CreateSpinlocks(IPCKey key)
-{
-	/* the spin lock shared memory must have been created by now */
-	return;
-}
-
-void
-InitSpinLocks(void)
-{
-	extern SPINLOCK ShmemLock;
-	extern SPINLOCK ShmemIndexLock;
-	extern SPINLOCK BufMgrLock;
-	extern SPINLOCK LockMgrLock;
-	extern SPINLOCK ProcStructLock;
-	extern SPINLOCK SInvalLock;
-	extern SPINLOCK OidGenLockId;
-	extern SPINLOCK XidGenLockId;
-	extern SPINLOCK ControlFileLockId;
+/* Probably should move these to an appropriate header file */
+extern SPINLOCK ShmemLock;
+extern SPINLOCK ShmemIndexLock;
+extern SPINLOCK BufMgrLock;
+extern SPINLOCK LockMgrLock;
+extern SPINLOCK ProcStructLock;
+extern SPINLOCK SInvalLock;
+extern SPINLOCK OidGenLockId;
+extern SPINLOCK XidGenLockId;
+extern SPINLOCK ControlFileLockId;
 
 #ifdef STABLE_MEMORY_STORAGE
-	extern SPINLOCK MMCacheLock;
+extern SPINLOCK MMCacheLock;
 
 #endif
 
-	/* These six spinlocks have fixed location is shmem */
+
+/*
+ * Initialize identifiers for permanent spinlocks during startup
+ *
+ * The same identifiers are used for both TAS and semaphore implementations,
+ * although in one case they are indexes into a shmem array and in the other
+ * they are semaphore numbers.
+ */
+static void
+InitSpinLockIDs(void)
+{
 	ShmemLock = (SPINLOCK) SHMEMLOCKID;
 	ShmemIndexLock = (SPINLOCK) SHMEMINDEXLOCKID;
 	BufMgrLock = (SPINLOCK) BUFMGRLOCKID;
@@ -81,11 +68,18 @@ InitSpinLocks(void)
 #ifdef STABLE_MEMORY_STORAGE
 	MMCacheLock = (SPINLOCK) MMCACHELOCKID;
 #endif
-
-	return;
 }
 
 
+#ifdef HAS_TEST_AND_SET
+
+/* real spin lock implementation */
+
+typedef struct slock
+{
+	slock_t		shlock;
+} SLock;
+
 #ifdef LOCK_DEBUG
 bool Trace_spinlocks = false;
 
@@ -93,193 +87,268 @@ inline static void
 PRINT_SLDEBUG(const char * where, SPINLOCK lockid, const SLock * lock)
 {
     if (Trace_spinlocks)
-        elog(DEBUG,
-             "%s: id=%d (locklock=%d, flag=%d, nshlocks=%d, shlock=%d, exlock=%d)",
-             where, lockid,
-             lock->locklock, lock->flag, lock->nshlocks, lock->shlock, lock->exlock);
+        elog(DEBUG, "%s: id=%d", where, lockid);
 }
 #else  /* not LOCK_DEBUG */
 #define PRINT_SLDEBUG(a,b,c)
 #endif /* not LOCK_DEBUG */
 
 
-/* from ipc.c */
-extern SLock *SLockArray;
+static SLock *SLockArray = NULL;
+
+#define SLOCKMEMORYSIZE		((int) MAX_SPINS * sizeof(SLock))
+
+/*
+ * SLockShmemSize --- return shared-memory space needed
+ */
+int
+SLockShmemSize(void)
+{
+	return MAXALIGN(SLOCKMEMORYSIZE);
+}
+
+/*
+ * CreateSpinlocks --- create and initialize spinlocks during startup
+ */
+void
+CreateSpinlocks(PGShmemHeader *seghdr)
+{
+	int			id;
+
+	/*
+	 * We must allocate the space "by hand" because shmem.c isn't up yet
+	 */
+	SLockArray = (SLock *) (((char *) seghdr) + seghdr->freeoffset);
+	seghdr->freeoffset += MAXALIGN(SLOCKMEMORYSIZE);
+	Assert(seghdr->freeoffset <= seghdr->totalsize);
+
+	/*
+	 * Initialize all spinlocks to "unlocked" state
+	 */
+	for (id = 0; id < (int) MAX_SPINS; id++)
+	{
+		SLock	   *slckP = &(SLockArray[id]);
+
+		S_INIT_LOCK(&(slckP->shlock));
+	}
+
+	/*
+	 * Assign indexes for fixed spinlocks
+	 */
+	InitSpinLockIDs();
+}
 
 void
 SpinAcquire(SPINLOCK lockid)
 {
-	SLock	   *slckP;
+	SLock	   *slckP = &(SLockArray[lockid]);
 
-	/* This used to be in ipc.c, but move here to reduce function calls */
-	slckP = &(SLockArray[lockid]);
 	PRINT_SLDEBUG("SpinAcquire", lockid, slckP);
-ex_try_again:
-	S_LOCK(&(slckP->locklock));
-	switch (slckP->flag)
-	{
-		case NOLOCK:
-			slckP->flag = EXCLUSIVELOCK;
-			S_LOCK(&(slckP->exlock));
-			S_LOCK(&(slckP->shlock));
-			S_UNLOCK(&(slckP->locklock));
-            PRINT_SLDEBUG("OUT", lockid, slckP);
-			break;
-		case SHAREDLOCK:
-		case EXCLUSIVELOCK:
-			S_UNLOCK(&(slckP->locklock));
-			S_LOCK(&(slckP->exlock));
-			S_UNLOCK(&(slckP->exlock));
-			goto ex_try_again;
-	}
+	S_LOCK(&(slckP->shlock));
 	PROC_INCR_SLOCK(lockid);
-    PRINT_SLDEBUG("SpinAcquire/success", lockid, slckP);
+    PRINT_SLDEBUG("SpinAcquire/done", lockid, slckP);
 }
 
 void
 SpinRelease(SPINLOCK lockid)
 {
-	SLock	   *slckP;
-
-	/* This used to be in ipc.c, but move here to reduce function calls */
-	slckP = &(SLockArray[lockid]);
+	SLock	   *slckP = &(SLockArray[lockid]);
 
 	/*
 	 * Check that we are actually holding the lock we are releasing. This
 	 * can be done only after MyProc has been initialized.
 	 */
     Assert(!MyProc || MyProc->sLocks[lockid] > 0);
-	Assert(slckP->flag != NOLOCK);
-
 
 	PROC_DECR_SLOCK(lockid);
     PRINT_SLDEBUG("SpinRelease", lockid, slckP);
-	S_LOCK(&(slckP->locklock));
-	/* -------------
-	 *	give favor to read processes
-	 * -------------
+	S_UNLOCK(&(slckP->shlock));
+    PRINT_SLDEBUG("SpinRelease/done", lockid, slckP);
+}
+
+#else /* !HAS_TEST_AND_SET */
+
+/*
+ * No TAS, so spinlocks are implemented using SysV semaphores.
+ *
+ * We support two slightly different APIs here: SpinAcquire/SpinRelease
+ * work with SPINLOCK integer indexes for the permanent spinlocks, which
+ * are all assumed to live in the first spinlock semaphore set.  There
+ * is also an emulation of the s_lock.h TAS-spinlock macros; for that case,
+ * typedef slock_t stores the semId and sem number of the sema to use.
+ * The semas needed are created by CreateSpinlocks and doled out by
+ * s_init_lock_sema.
+ *
+ * Since many systems have a rather small SEMMSL limit on semas per set,
+ * we allocate the semaphores required in sets of SPINLOCKS_PER_SET semas.
+ * This value is deliberately made equal to PROC_NSEMS_PER_SET so that all
+ * sema sets allocated by Postgres will be the same size; that eases the
+ * semaphore-recycling logic in IpcSemaphoreCreate().
+ *
+ * Note that the SpinLockIds array is not in shared memory; it is filled
+ * by the postmaster and then inherited through fork() by backends.  This
+ * is OK because its contents do not change after system startup.
+ */
+
+#define SPINLOCKS_PER_SET  PROC_NSEMS_PER_SET
+
+static IpcSemaphoreId *SpinLockIds = NULL;
+
+static int numSpinSets = 0;		/* number of sema sets used */
+static int numSpinLocks = 0;	/* total number of semas allocated */
+static int nextSpinLock = 0;	/* next free spinlock index */
+
+static void SpinFreeAllSemaphores(void);
+
+/*
+ * SLockShmemSize --- return shared-memory space needed
+ */
+int
+SLockShmemSize(void)
+{
+	return 0;
+}
+
+/*
+ * CreateSpinlocks --- create and initialize spinlocks during startup
+ */
+void
+CreateSpinlocks(PGShmemHeader *seghdr)
+{
+	int		i;
+
+	if (SpinLockIds == NULL)
+	{
+		/*
+		 * Compute number of spinlocks needed.  If this logic gets any more
+		 * complicated, it should be distributed into the affected modules,
+		 * similar to the way shmem space estimation is handled.
+		 *
+		 * For now, though, we just need the fixed spinlocks (MAX_SPINS),
+		 * two spinlocks per shared disk buffer, and four spinlocks for XLOG.
+		 */
+		numSpinLocks = (int) MAX_SPINS + 2 * NBuffers + 4;
+
+		/* might as well round up to a multiple of SPINLOCKS_PER_SET */
+		numSpinSets = (numSpinLocks - 1) / SPINLOCKS_PER_SET + 1;
+		numSpinLocks = numSpinSets * SPINLOCKS_PER_SET;
+
+		SpinLockIds = (IpcSemaphoreId *)
+			malloc(numSpinSets * sizeof(IpcSemaphoreId));
+		Assert(SpinLockIds != NULL);
+	}
+
+	for (i = 0; i < numSpinSets; i++)
+		SpinLockIds[i] = -1;
+
+	/*
+	 * Arrange to delete semas on exit --- set this up now so that we
+	 * will clean up if allocation fails.  We use our own freeproc,
+	 * rather than IpcSemaphoreCreate's removeOnExit option, because
+	 * we don't want to fill up the on_shmem_exit list with a separate
+	 * entry for each semaphore set.
 	 */
-	slckP->flag = NOLOCK;
-	if (slckP->nshlocks > 0)
+	on_shmem_exit(SpinFreeAllSemaphores, 0);
+
+	/* Create sema sets and set all semas to count 1 */
+	for (i = 0; i < numSpinSets; i++)
 	{
-		while (slckP->nshlocks > 0)
-		{
-			S_UNLOCK(&(slckP->shlock));
-			S_LOCK(&(slckP->comlock));
-		}
-		S_UNLOCK(&(slckP->shlock));
+		SpinLockIds[i] = IpcSemaphoreCreate(SPINLOCKS_PER_SET,
+											IPCProtection,
+											1,
+											false);
 	}
-	else
-		S_UNLOCK(&(slckP->shlock));
-	S_UNLOCK(&(slckP->exlock));
-	S_UNLOCK(&(slckP->locklock));
-    PRINT_SLDEBUG("SpinRelease/released", lockid, slckP);
+
+	/*
+	 * Assign indexes for fixed spinlocks
+	 */
+	Assert(MAX_SPINS <= SPINLOCKS_PER_SET);
+	InitSpinLockIDs();
+
+	/* Init counter for allocating dynamic spinlocks */
+	nextSpinLock = MAX_SPINS;
 }
 
-#else /* !HAS_TEST_AND_SET */
-/* Spinlocks are implemented using SysV semaphores */
+/*
+ * SpinFreeAllSemaphores -
+ *	  called at shmem_exit time, ie when exiting the postmaster or
+ *	  destroying shared state for a failed set of backends.
+ *	  Free up all the semaphores allocated for spinlocks.
+ */
+static void
+SpinFreeAllSemaphores(void)
+{
+	int			i;
 
-static bool AttachSpinLocks(IPCKey key);
-static bool SpinIsLocked(SPINLOCK lock);
+	for (i = 0; i < numSpinSets; i++)
+	{
+		if (SpinLockIds[i] >= 0)
+			IpcSemaphoreKill(SpinLockIds[i]);
+	}
+}
 
 /*
- * SpinAcquire -- try to grab a spinlock
+ * SpinAcquire -- grab a fixed spinlock
  *
  * FAILS if the semaphore is corrupted.
  */
 void
 SpinAcquire(SPINLOCK lock)
 {
-	IpcSemaphoreLock(SpinLockId, lock, IpcExclusiveLock);
+	IpcSemaphoreLock(SpinLockIds[0], lock);
 	PROC_INCR_SLOCK(lock);
 }
 
 /*
- * SpinRelease -- release a spin lock
+ * SpinRelease -- release a fixed spin lock
  *
  * FAILS if the semaphore is corrupted
  */
 void
 SpinRelease(SPINLOCK lock)
 {
-	Assert(SpinIsLocked(lock));
-	PROC_DECR_SLOCK(lock);
-	IpcSemaphoreUnlock(SpinLockId, lock, IpcExclusiveLock);
-}
-
-static bool
-SpinIsLocked(SPINLOCK lock)
-{
+#ifdef USE_ASSERT_CHECKING
+	/* Check it's locked */
 	int			semval;
 
-	semval = IpcSemaphoreGetValue(SpinLockId, lock);
-	return semval < IpcSemaphoreDefaultStartValue;
+	semval = IpcSemaphoreGetValue(SpinLockIds[0], lock);
+	Assert(semval < 1);
+#endif
+	PROC_DECR_SLOCK(lock);
+	IpcSemaphoreUnlock(SpinLockIds[0], lock);
 }
 
 /*
- * CreateSpinlocks -- Create a sysV semaphore array for
- *		the spinlocks
- *
+ * s_lock.h hardware-spinlock emulation
  */
+
 void
-CreateSpinlocks(IPCKey key)
+s_init_lock_sema(volatile slock_t *lock)
 {
-
-	SpinLockId = IpcSemaphoreCreate(key, MAX_SPINS, IPCProtection,
-									IpcSemaphoreDefaultStartValue, 1);
-
-	if (SpinLockId <= 0)
-		elog(STOP, "CreateSpinlocks: cannot create spin locks");
-
-	return;
+	if (nextSpinLock >= numSpinLocks)
+		elog(FATAL, "s_init_lock_sema: not enough semaphores");
+	lock->semId = SpinLockIds[nextSpinLock / SPINLOCKS_PER_SET];
+	lock->sem = nextSpinLock % SPINLOCKS_PER_SET;
+	nextSpinLock++;
 }
 
-/*
- * InitSpinLocks -- Spinlock bootstrapping
- *
- * We need several spinlocks for bootstrapping:
- * ShmemIndexLock (for the shmem index table) and
- * ShmemLock (for the shmem allocator), BufMgrLock (for buffer
- * pool exclusive access), LockMgrLock (for the lock table), and
- * ProcStructLock (a spin lock for the shared process structure).
- * If there's a Sony WORM drive attached, we also have a spinlock
- * (SJCacheLock) for it.  Same story for the main memory storage mgr.
- *
- */
 void
-InitSpinLocks(void)
+s_unlock_sema(volatile slock_t *lock)
 {
-	extern SPINLOCK ShmemLock;
-	extern SPINLOCK ShmemIndexLock;
-	extern SPINLOCK BufMgrLock;
-	extern SPINLOCK LockMgrLock;
-	extern SPINLOCK ProcStructLock;
-	extern SPINLOCK SInvalLock;
-	extern SPINLOCK OidGenLockId;
-	extern SPINLOCK XidGenLockId;
-	extern SPINLOCK ControlFileLockId;
-
-#ifdef STABLE_MEMORY_STORAGE
-	extern SPINLOCK MMCacheLock;
-
-#endif
-
-	/* These five (or six) spinlocks have fixed location is shmem */
-	ShmemLock = (SPINLOCK) SHMEMLOCKID;
-	ShmemIndexLock = (SPINLOCK) SHMEMINDEXLOCKID;
-	BufMgrLock = (SPINLOCK) BUFMGRLOCKID;
-	LockMgrLock = (SPINLOCK) LOCKMGRLOCKID;
-	ProcStructLock = (SPINLOCK) PROCSTRUCTLOCKID;
-	SInvalLock = (SPINLOCK) SINVALLOCKID;
-	OidGenLockId = (SPINLOCK) OIDGENLOCKID;
-	XidGenLockId = (SPINLOCK) XIDGENLOCKID;
-	ControlFileLockId = (SPINLOCK) CNTLFILELOCKID;
+	IpcSemaphoreUnlock(lock->semId, lock->sem);
+}
 
-#ifdef STABLE_MEMORY_STORAGE
-	MMCacheLock = (SPINLOCK) MMCACHELOCKID;
-#endif
+bool
+s_lock_free_sema(volatile slock_t *lock)
+{
+	return IpcSemaphoreGetValue(lock->semId, lock->sem) > 0;
+}
 
-	return;
+int
+tas_sema(volatile slock_t *lock)
+{
+	/* Note that TAS macros return 0 if *success* */
+	return ! IpcSemaphoreTryLock(lock->semId, lock->sem);
 }
 
 #endif /* !HAS_TEST_AND_SET */
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 14325e53183d7f91bd7d04c6c9be7d2f1d233680..cf99be3b11500ede5e97e354b75552712acc5de5 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.72 2000/11/08 22:10:00 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.73 2000/11/28 23:27:56 tgl Exp $
  *
  * NOTES
  *	  Outside modules can create a lock table and acquire/release
@@ -56,6 +56,7 @@ static char *lock_types[] =
 	"AccessExclusiveLock"
 };
 
+static char *DeadLockMessage = "Deadlock detected.\n\tSee the lock(l) manual page for a possible cause.";
 
 
 #ifdef LOCK_DEBUG
@@ -943,8 +944,7 @@ WaitOnLock(LOCKMETHOD lockmethod, LOCK *lock, LOCKMODE lockmode)
 				  lock) != NO_ERROR)
 	{
 		/* -------------------
-		 * This could have happend as a result of a deadlock,
-		 * see HandleDeadLock().
+		 * We failed as a result of a deadlock, see HandleDeadLock().
 		 * Decrement the lock nHolding and holders fields as
 		 * we are no longer waiting on this lock.
 		 * -------------------
@@ -957,8 +957,7 @@ WaitOnLock(LOCKMETHOD lockmethod, LOCK *lock, LOCKMODE lockmode)
 		if (lock->activeHolders[lockmode] == lock->holders[lockmode])
 			lock->waitMask &= BITS_OFF[lockmode];
 		SpinRelease(lockMethodTable->ctl->masterLock);
-		elog(ERROR, "WaitOnLock: error on wakeup - Aborting this transaction");
-
+		elog(ERROR, DeadLockMessage);
 		/* not reached */
 	}
 
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 2da1495cd3b5416a164a5dd6dda444af67d62567..0193a7ad2e73746f200a1aa8afa8a713b86897b5 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.83 2000/10/07 14:39:13 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.84 2000/11/28 23:27:56 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -47,7 +47,7 @@
  *		This is so that we can support more backends. (system-wide semaphore
  *		sets run out pretty fast.)				  -ay 4/95
  *
- * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.83 2000/10/07 14:39:13 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.84 2000/11/28 23:27:56 tgl Exp $
  */
 #include "postgres.h"
 
@@ -91,10 +91,8 @@ static PROC_HDR *ProcGlobal = NULL;
 PROC	   *MyProc = NULL;
 
 static void ProcKill(int exitStatus, Datum pid);
-static void ProcGetNewSemKeyAndNum(IPCKey *key, int *semNum);
-static void ProcFreeSem(IpcSemaphoreKey semKey, int semNum);
-
-static char *DeadLockMessage = "Deadlock detected -- See the lock(l) manual page for a possible cause.";
+static void ProcGetNewSemIdAndNum(IpcSemaphoreId *semId, int *semNum);
+static void ProcFreeSem(IpcSemaphoreId semId, int semNum);
 
 /*
  * InitProcGlobal -
@@ -116,7 +114,7 @@ static char *DeadLockMessage = "Deadlock detected -- See the lock(l) manual page
  *	  rather than later.
  */
 void
-InitProcGlobal(IPCKey key, int maxBackends)
+InitProcGlobal(int maxBackends)
 {
 	bool		found = false;
 
@@ -135,39 +133,35 @@ InitProcGlobal(IPCKey key, int maxBackends)
 		int			i;
 
 		ProcGlobal->freeProcs = INVALID_OFFSET;
-		ProcGlobal->currKey = IPCGetProcessSemaphoreInitKey(key);
-		for (i = 0; i < MAX_PROC_SEMS / PROC_NSEMS_PER_SET; i++)
+		for (i = 0; i < PROC_SEM_MAP_ENTRIES; i++)
+		{
+			ProcGlobal->procSemIds[i] = -1;
 			ProcGlobal->freeSemMap[i] = 0;
+		}
 
 		/*
 		 * Arrange to delete semas on exit --- set this up now so that we
-		 * will clean up if pre-allocation fails...
+		 * will clean up if pre-allocation fails.  We use our own freeproc,
+		 * rather than IpcSemaphoreCreate's removeOnExit option, because
+		 * we don't want to fill up the on_shmem_exit list with a separate
+		 * entry for each semaphore set.
 		 */
 		on_shmem_exit(ProcFreeAllSemaphores, 0);
 
 		/*
-		 * Pre-create the semaphores for the first maxBackends processes,
-		 * unless we are running as a standalone backend.
+		 * Pre-create the semaphores for the first maxBackends processes.
 		 */
-		if (key != PrivateIPCKey)
+		Assert(maxBackends > 0 && maxBackends <= MAXBACKENDS);
+
+		for (i = 0; i < ((maxBackends-1)/PROC_NSEMS_PER_SET+1); i++)
 		{
-			for (i = 0;
-				 i < (maxBackends + PROC_NSEMS_PER_SET - 1) / PROC_NSEMS_PER_SET;
-				 i++)
-			{
-				IPCKey		semKey = ProcGlobal->currKey + i;
-				int			semId;
-
-				semId = IpcSemaphoreCreate(semKey,
-										   PROC_NSEMS_PER_SET,
-										   IPCProtection,
-										   IpcSemaphoreDefaultStartValue,
-										   0);
-				if (semId < 0)
-					elog(FATAL, "InitProcGlobal: IpcSemaphoreCreate failed");
-				/* mark this sema set allocated */
-				ProcGlobal->freeSemMap[i] = (1 << PROC_NSEMS_PER_SET);
-			}
+			IpcSemaphoreId		semId;
+
+			semId = IpcSemaphoreCreate(PROC_NSEMS_PER_SET,
+									   IPCProtection,
+									   1,
+									   false);
+			ProcGlobal->procSemIds[i] = semId;
 		}
 	}
 }
@@ -178,7 +172,7 @@ InitProcGlobal(IPCKey key, int maxBackends)
  * ------------------------
  */
 void
-InitProcess(IPCKey key)
+InitProcess(void)
 {
 	bool		found = false;
 	unsigned long location,
@@ -186,7 +180,7 @@ InitProcess(IPCKey key)
 
 	SpinAcquire(ProcStructLock);
 
-	/* attach to the free list */
+	/* attach to the ProcGlobal structure */
 	ProcGlobal = (PROC_HDR *)
 		ShmemInitStruct("Proc Header", sizeof(PROC_HDR), &found);
 	if (!found)
@@ -199,10 +193,9 @@ InitProcess(IPCKey key)
 	{
 		SpinRelease(ProcStructLock);
 		elog(ERROR, "ProcInit: you already exist");
-		return;
 	}
 
-	/* try to get a proc from the free list first */
+	/* try to get a proc struct from the free list first */
 
 	myOffset = ProcGlobal->freeProcs;
 
@@ -243,36 +236,22 @@ InitProcess(IPCKey key)
 
 	if (IsUnderPostmaster)
 	{
-		IPCKey		semKey;
-		int			semNum;
-		int			semId;
-		union semun semun;
-
-		ProcGetNewSemKeyAndNum(&semKey, &semNum);
+		IpcSemaphoreId	semId;
+		int				semNum;
+		union semun		semun;
 
-		/*
-		 * Note: because of the pre-allocation done in InitProcGlobal,
-		 * this call should always attach to an existing semaphore. It
-		 * will (try to) create a new group of semaphores only if the
-		 * postmaster tries to start more backends than it said it would.
-		 */
-		semId = IpcSemaphoreCreate(semKey,
-								   PROC_NSEMS_PER_SET,
-								   IPCProtection,
-								   IpcSemaphoreDefaultStartValue,
-								   0);
+		ProcGetNewSemIdAndNum(&semId, &semNum);
 
 		/*
 		 * we might be reusing a semaphore that belongs to a dead backend.
 		 * So be careful and reinitialize its value here.
 		 */
-		semun.val = IpcSemaphoreDefaultStartValue;
+		semun.val = 1;
 		semctl(semId, semNum, SETVAL, semun);
 
-		IpcSemaphoreLock(semId, semNum, IpcExclusiveLock);
+		IpcSemaphoreLock(semId, semNum);
 		MyProc->sem.semId = semId;
 		MyProc->sem.semNum = semNum;
-		MyProc->sem.semKey = semKey;
 	}
 	else
 		MyProc->sem.semId = -1;
@@ -304,7 +283,7 @@ InitProcess(IPCKey key)
 	 */
 	location = MAKE_OFFSET(MyProc);
 	if ((!ShmemPIDLookup(MyProcPid, &location)) || (location != MAKE_OFFSET(MyProc)))
-		elog(STOP, "InitProc: ShmemPID table broken");
+		elog(STOP, "InitProcess: ShmemPID table broken");
 
 	MyProc->errType = NO_ERROR;
 	SHMQueueElemInit(&(MyProc->links));
@@ -363,10 +342,7 @@ ProcReleaseLocks()
 /*
  * ProcRemove -
  *	  used by the postmaster to clean up the global tables. This also frees
- *	  up the semaphore used for the lmgr of the process. (We have to do
- *	  this is the postmaster instead of doing a IpcSemaphoreKill on exiting
- *	  the process because the semaphore set is shared among backends and
- *	  we don't want to remove other's semaphores on exit.)
+ *	  up the semaphore used for the lmgr of the process.
  */
 bool
 ProcRemove(int pid)
@@ -383,7 +359,7 @@ ProcRemove(int pid)
 
 	SpinAcquire(ProcStructLock);
 
-	ProcFreeSem(proc->sem.semKey, proc->sem.semNum);
+	ProcFreeSem(proc->sem.semId, proc->sem.semNum);
 
 	proc->links.next = ProcGlobal->freeProcs;
 	ProcGlobal->freeProcs = MAKE_OFFSET(proc);
@@ -490,6 +466,7 @@ ProcQueueInit(PROC_QUEUE *queue)
  *
  */
 static bool lockWaiting = false;
+
 void
 SetWaitingForLock(bool waiting)
 {
@@ -514,12 +491,12 @@ SetWaitingForLock(bool waiting)
 		}
 	}
 }
+
 void
 LockWaitCancel(void)
 {
-/* BeOS doesn't have setitimer, but has set_alarm */
 #ifndef __BEOS__ 	
-struct itimerval timeval,
+	struct itimerval timeval,
 				dummy;
 
 	if (!lockWaiting)
@@ -529,6 +506,7 @@ struct itimerval timeval,
 	MemSet(&timeval, 0, sizeof(struct itimerval));
 	setitimer(ITIMER_REAL, &timeval, &dummy);
 #else
+	/* BeOS doesn't have setitimer, but has set_alarm */
 	if (!lockWaiting)
 		return;
 	lockWaiting = false;
@@ -547,6 +525,8 @@ struct itimerval timeval,
  * semaphore is cleared by default, so the first time we try
  * to acquire it, we sleep.
  *
+ * Result is NO_ERROR if we acquired the lock, STATUS_ERROR if not (deadlock).
+ *
  * ASSUME: that no one will fiddle with the queue until after
  *		we release the spin lock.
  *
@@ -566,7 +546,6 @@ ProcSleep(PROC_QUEUE *waitQueue,/* lock->waitProcs */
 	int			aheadHolders[MAX_LOCKMODES];
 	bool		selfConflict = (lockctl->conflictTab[token] & myMask),
 				prevSame = false;
-	bool		deadlock_checked = false;
 #ifndef __BEOS__
 	struct itimerval timeval,
 				dummy;
@@ -595,8 +574,8 @@ ProcSleep(PROC_QUEUE *waitQueue,/* lock->waitProcs */
 			/* is he waiting for me ? */
 			if (lockctl->conflictTab[proc->token] & MyProc->holdLock)
 			{
+				/* Yes, report deadlock failure */
 				MyProc->errType = STATUS_ERROR;
-				elog(NOTICE, DeadLockMessage);
 				goto rt;
 			}
 			/* being waiting for him - go past */
@@ -642,10 +621,16 @@ ins:;
 	lock->waitMask |= myMask;
 	SpinRelease(spinlock);
 
+	MyProc->errType = NO_ERROR;		/* initialize result for success */
+
 	/* --------------
-	 * We set this so we can wake up periodically and check for a deadlock.
-	 * If a deadlock is detected, the handler releases the processes
-	 * semaphore and aborts the current transaction.
+	 * Set timer so we can wake up after awhile and check for a deadlock.
+	 * If a deadlock is detected, the handler releases the process's
+	 * semaphore and sets MyProc->errType = STATUS_ERROR, allowing us to
+	 * know that we must report failure rather than success.
+	 *
+	 * By delaying the check until we've waited for a bit, we can avoid
+	 * running the rather expensive deadlock-check code in most cases.
 	 *
 	 * Need to zero out struct to set the interval and the micro seconds fields
 	 * to 0.
@@ -655,49 +640,42 @@ ins:;
 	MemSet(&timeval, 0, sizeof(struct itimerval));
 	timeval.it_value.tv_sec = DeadlockTimeout / 1000;
 	timeval.it_value.tv_usec = (DeadlockTimeout % 1000) * 1000;
+	if (setitimer(ITIMER_REAL, &timeval, &dummy))
+		elog(FATAL, "ProcSleep: Unable to set timer for process wakeup");
 #else
-    /* usecs */
-    time_interval = DeadlockTimeout * 1000000;
+    time_interval = DeadlockTimeout * 1000000; /* usecs */
+	if (set_alarm(time_interval, B_ONE_SHOT_RELATIVE_ALARM) < 0)
+		elog(FATAL, "ProcSleep: Unable to set timer for process wakeup");
 #endif
 
 	SetWaitingForLock(true);
-	do
-	{
-		MyProc->errType = NO_ERROR;		/* reset flag after deadlock check */
 
-		if (!deadlock_checked)
-#ifndef __BEOS__
-			if (setitimer(ITIMER_REAL, &timeval, &dummy))
-#else
-            if (set_alarm(time_interval, B_ONE_SHOT_RELATIVE_ALARM) < 0)
-#endif
-				elog(FATAL, "ProcSleep: Unable to set timer for process wakeup");
-		deadlock_checked = true;
-
-		/* --------------
-		 * if someone wakes us between SpinRelease and IpcSemaphoreLock,
-		 * IpcSemaphoreLock will not block.  The wakeup is "saved" by
-		 * the semaphore implementation.
-		 * --------------
-		 */
-		IpcSemaphoreLock(MyProc->sem.semId, MyProc->sem.semNum,
-						 IpcExclusiveLock);
-	} while (MyProc->errType == STATUS_NOT_FOUND);		/* sleep after deadlock
-														 * check */
+	/* --------------
+	 * If someone wakes us between SpinRelease and IpcSemaphoreLock,
+	 * IpcSemaphoreLock will not block.  The wakeup is "saved" by
+	 * the semaphore implementation.  Note also that if HandleDeadLock
+	 * is invoked but does not detect a deadlock, IpcSemaphoreLock()
+	 * will continue to wait.  There used to be a loop here, but it
+	 * was useless code...
+	 * --------------
+	 */
+	IpcSemaphoreLock(MyProc->sem.semId, MyProc->sem.semNum);
+
 	lockWaiting = false;
 
 	/* ---------------
-	 * We were awoken before a timeout - now disable the timer
+	 * Disable the timer, if it's still running
 	 * ---------------
 	 */
 #ifndef __BEOS__
 	timeval.it_value.tv_sec = 0;
 	timeval.it_value.tv_usec = 0;
 	if (setitimer(ITIMER_REAL, &timeval, &dummy))
+		elog(FATAL, "ProcSleep: Unable to disable timer for process wakeup");
 #else
     if (set_alarm(B_INFINITE_TIMEOUT, B_PERIODIC_ALARM) < 0)
+		elog(FATAL, "ProcSleep: Unable to disable timer for process wakeup");
 #endif
-		elog(FATAL, "ProcSleep: Unable to diable timer for process wakeup");
 
 	/* ----------------
 	 * We were assumed to be in a critical section when we went
@@ -742,7 +720,7 @@ ProcWakeup(PROC *proc, int errType)
 
 	proc->errType = errType;
 
-	IpcSemaphoreUnlock(proc->sem.semId, proc->sem.semNum, IpcExclusiveLock);
+	IpcSemaphoreUnlock(proc->sem.semId, proc->sem.semNum);
 
 	return retProc;
 }
@@ -855,27 +833,11 @@ HandleDeadLock(SIGNAL_ARGS)
 	 * Before we are awoken the process releasing the lock grants it to
 	 * us so we know that we don't have to wait anymore.
 	 *
-	 * Damn these names are LONG! -mer
+	 * We check by looking to see if we've been unlinked from the wait queue.
+	 * This is quicker than checking our semaphore's state, since no kernel
+	 * call is needed, and it is safe because we hold the locktable lock.
 	 * ---------------------
 	 */
-	if (IpcSemaphoreGetCount(MyProc->sem.semId, MyProc->sem.semNum) ==
-		IpcSemaphoreDefaultStartValue)
-	{
-		UnlockLockTable();
-		return;
-	}
-
-	/*
-	 * you would think this would be unnecessary, but...
-	 *
-	 * this also means we've been removed already.  in some ports (e.g.,
-	 * sparc and aix) the semop(2) implementation is such that we can
-	 * actually end up in this handler after someone has removed us from
-	 * the queue and bopped the semaphore *but the test above fails to
-	 * detect the semaphore update* (presumably something weird having to
-	 * do with the order in which the semaphore wakeup signal and SIGALRM
-	 * get handled).
-	 */
 	if (MyProc->links.prev == INVALID_OFFSET ||
 		MyProc->links.next == INVALID_OFFSET)
 	{
@@ -888,19 +850,18 @@ HandleDeadLock(SIGNAL_ARGS)
         DumpAllLocks();
 #endif
 
-	MyProc->errType = STATUS_NOT_FOUND;
 	if (!DeadLockCheck(MyProc, MyProc->waitLock))
 	{
+		/* No deadlock, so keep waiting */
 		UnlockLockTable();
 		return;
 	}
 
-	mywaitlock = MyProc->waitLock;
-
 	/* ------------------------
 	 * Get this process off the lock's wait queue
 	 * ------------------------
 	 */
+	mywaitlock = MyProc->waitLock;
 	Assert(mywaitlock->waitProcs.size > 0);
 	lockWaiting = false;
 	--mywaitlock->waitProcs.size;
@@ -908,12 +869,10 @@ HandleDeadLock(SIGNAL_ARGS)
 	SHMQueueElemInit(&(MyProc->links));
 
 	/* ------------------
-	 * Unlock my semaphore so that the count is right for next time.
-	 * I was awoken by a signal, not by someone unlocking my semaphore.
+	 * Unlock my semaphore so that the interrupted ProcSleep() call can finish.
 	 * ------------------
 	 */
-	IpcSemaphoreUnlock(MyProc->sem.semId, MyProc->sem.semNum,
-					   IpcExclusiveLock);
+	IpcSemaphoreUnlock(MyProc->sem.semId, MyProc->sem.semNum);
 
 	/* -------------
 	 * Set MyProc->errType to STATUS_ERROR so that we abort after
@@ -928,9 +887,6 @@ HandleDeadLock(SIGNAL_ARGS)
 	 * conditions.	i don't claim to understand this...
 	 */
 	UnlockLockTable();
-
-	elog(NOTICE, DeadLockMessage);
-	return;
 }
 
 void
@@ -959,31 +915,32 @@ ProcReleaseSpins(PROC *proc)
  *****************************************************************************/
 
 /*
- * ProcGetNewSemKeyAndNum -
+ * ProcGetNewSemIdAndNum -
  *	  scan the free semaphore bitmap and allocate a single semaphore from
- *	  a semaphore set. (If the semaphore set doesn't exist yet,
- *	  IpcSemaphoreCreate will create it. Otherwise, we use the existing
- *	  semaphore set.)
+ *	  a semaphore set.
  */
 static void
-ProcGetNewSemKeyAndNum(IPCKey *key, int *semNum)
+ProcGetNewSemIdAndNum(IpcSemaphoreId *semId, int *semNum)
 {
 	int			i;
+	IpcSemaphoreId *procSemIds = ProcGlobal->procSemIds;
 	int32	   *freeSemMap = ProcGlobal->freeSemMap;
-	int32		fullmask = (1 << (PROC_NSEMS_PER_SET + 1)) - 1;
+	int32		fullmask = (1 << PROC_NSEMS_PER_SET) - 1;
 
 	/*
 	 * we hold ProcStructLock when entering this routine. We scan through
 	 * the bitmap to look for a free semaphore.
 	 */
 
-	for (i = 0; i < MAX_PROC_SEMS / PROC_NSEMS_PER_SET; i++)
+	for (i = 0; i < PROC_SEM_MAP_ENTRIES; i++)
 	{
 		int			mask = 1;
 		int			j;
 
 		if (freeSemMap[i] == fullmask)
 			continue;			/* this set is fully allocated */
+		if (procSemIds[i] < 0)
+			continue;			/* this set hasn't been initialized */
 
 		for (j = 0; j < PROC_NSEMS_PER_SET; j++)
 		{
@@ -991,12 +948,11 @@ ProcGetNewSemKeyAndNum(IPCKey *key, int *semNum)
 			{
 
 				/*
-				 * a free semaphore found. Mark it as allocated. Also set
-				 * the bit indicating whole set is allocated.
+				 * a free semaphore found. Mark it as allocated.
 				 */
-				freeSemMap[i] |= mask + (1 << PROC_NSEMS_PER_SET);
+				freeSemMap[i] |= mask;
 
-				*key = ProcGlobal->currKey + i;
+				*semId = procSemIds[i];
 				*semNum = j;
 				return;
 			}
@@ -1005,7 +961,7 @@ ProcGetNewSemKeyAndNum(IPCKey *key, int *semNum)
 	}
 
 	/* if we reach here, all the semaphores are in use. */
-	elog(ERROR, "InitProc: cannot allocate a free semaphore");
+	elog(ERROR, "ProcGetNewSemIdAndNum: cannot allocate a free semaphore");
 }
 
 /*
@@ -1013,23 +969,22 @@ ProcGetNewSemKeyAndNum(IPCKey *key, int *semNum)
  *	  free up our semaphore in the semaphore set.
  */
 static void
-ProcFreeSem(IpcSemaphoreKey semKey, int semNum)
+ProcFreeSem(IpcSemaphoreId semId, int semNum)
 {
-	int			mask;
+	int32		mask;
 	int			i;
-	int32	   *freeSemMap = ProcGlobal->freeSemMap;
 
-	i = semKey - ProcGlobal->currKey;
 	mask = ~(1 << semNum);
-	freeSemMap[i] &= mask;
 
-	/*
-	 * Formerly we'd release a semaphore set if it was now completely
-	 * unused, but now we keep the semaphores to ensure we won't run out
-	 * when starting new backends --- cf. InitProcGlobal.  Note that the
-	 * PROC_NSEMS_PER_SET+1'st bit of the freeSemMap entry remains set to
-	 * indicate it is still allocated; ProcFreeAllSemaphores() needs that.
-	 */
+	for (i = 0; i < PROC_SEM_MAP_ENTRIES; i++)
+	{
+		if (ProcGlobal->procSemIds[i] == semId)
+		{
+			ProcGlobal->freeSemMap[i] &= mask;
+			return;
+		}
+	}
+	fprintf(stderr, "ProcFreeSem: no ProcGlobal entry for semId %d\n", semId);
 }
 
 /*
@@ -1039,14 +994,13 @@ ProcFreeSem(IpcSemaphoreKey semKey, int semNum)
  *	  Free up all the semaphores allocated to the lmgrs of the backends.
  */
 static void
-ProcFreeAllSemaphores()
+ProcFreeAllSemaphores(void)
 {
 	int			i;
-	int32	   *freeSemMap = ProcGlobal->freeSemMap;
 
-	for (i = 0; i < MAX_PROC_SEMS / PROC_NSEMS_PER_SET; i++)
+	for (i = 0; i < PROC_SEM_MAP_ENTRIES; i++)
 	{
-		if (freeSemMap[i] != 0)
-			IpcSemaphoreKill(ProcGlobal->currKey + i);
+		if (ProcGlobal->procSemIds[i] >= 0)
+			IpcSemaphoreKill(ProcGlobal->procSemIds[i]);
 	}
 }
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index bee4f7e9219063ac0870f3617f4f45ceb0a5be76..0454ffc8486a4316c17c4bf99cd66a96a6b03bbf 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.72 2000/11/16 22:30:39 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.73 2000/11/28 23:27:57 tgl Exp $
  *
  *
  *-------------------------------------------------------------------------
@@ -45,7 +45,6 @@
 static void ReverifyMyDatabase(const char *name);
 static void InitCommunication(void);
 
-static IPCKey PostgresIpcKey;
 
 /*** InitPostgres support ***/
 
@@ -141,7 +140,7 @@ ReverifyMyDatabase(const char *name)
  * --------------------------------
  */
 static void
-InitCommunication()
+InitCommunication(void)
 {
 	/* ----------------
 	 *	initialize shared memory and semaphores appropriately.
@@ -151,26 +150,11 @@ InitCommunication()
 	{
 		/* ----------------
 		 *	we're running a postgres backend by itself with
-		 *	no front end or postmaster.
+		 *	no front end or postmaster.  Create private "shmem"
+		 *	and semaphores.  Setting MaxBackends = 16 is arbitrary.
 		 * ----------------
 		 */
-		char	   *ipc_key;	/* value of environment variable */
-		IPCKey		key;
-
-		ipc_key = getenv("IPC_KEY");
-
-		if (!PointerIsValid(ipc_key))
-		{
-			/* Normal standalone backend */
-			key = PrivateIPCKey;
-		}
-		else
-		{
-			/* Allow standalone's IPC key to be set */
-			key = atoi(ipc_key);
-		}
-		PostgresIpcKey = key;
-		AttachSharedMemoryAndSemaphores(key);
+		CreateSharedMemoryAndSemaphores(true, 16);
 	}
 }
 
@@ -295,7 +279,7 @@ InitPostgres(const char *dbname, const char *username)
 	/*
 	 * Set up my per-backend PROC struct in shared memory.
 	 */
-	InitProcess(PostgresIpcKey);
+	InitProcess();
 
 	/*
 	 * Initialize my entry in the shared-invalidation manager's array of
@@ -307,7 +291,7 @@ InitPostgres(const char *dbname, const char *username)
 	 */
 	MyBackendId = InvalidBackendId;
 
-	InitSharedInvalidationState();
+	InitBackendSharedInvalidationState();
 
 	if (MyBackendId > MAXBACKENDS || MyBackendId <= 0)
 		elog(FATAL, "cinit2: bad backend id %d", MyBackendId);
@@ -365,11 +349,11 @@ BaseInit(void)
 	 */
 	InitCommunication();
 	DebugFileOpen();
+
 	smgrinit();
 
 	EnablePortalManager();		/* memory for portal/transaction stuff */
 
 	/* initialize the local buffer manager */
 	InitLocalBuffer();
-
 }
diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h
index fc15e59859b8e9386212c06edb14c432fc5ceb3a..ae41711887848dcddc68d07e588aee8b726e722b 100644
--- a/src/include/storage/buf_internals.h
+++ b/src/include/storage/buf_internals.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: buf_internals.h,v 1.43 2000/11/08 22:10:02 tgl Exp $
+ * $Id: buf_internals.h,v 1.44 2000/11/28 23:27:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -16,6 +16,7 @@
 
 #include "storage/buf.h"
 #include "storage/lmgr.h"
+#include "storage/s_lock.h"
 
 /* Buf Mgr constants */
 /* in bufmgr.c */
@@ -100,11 +101,9 @@ typedef struct sbufdesc
 	BufFlags	flags;			/* see bit definitions above */
 	unsigned	refcount;		/* # of times buffer is pinned */
 
-#ifdef HAS_TEST_AND_SET
-	/* can afford a dedicated lock if test-and-set locks are available */
-	slock_t		io_in_progress_lock;
+	slock_t		io_in_progress_lock; /* to block for I/O to complete */
 	slock_t		cntx_lock;		/* to lock access to page context */
-#endif	 /* HAS_TEST_AND_SET */
+
 	unsigned	r_locks;		/* # of shared locks */
 	bool		ri_lock;		/* read-intent lock */
 	bool		w_lock;			/* context exclusively locked */
diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h
index 22c0ccde7d5c607f25af84dbc0a91498caef9616..275146eea80f6b9e377f80fee094bf3be9934e2e 100644
--- a/src/include/storage/bufmgr.h
+++ b/src/include/storage/bufmgr.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: bufmgr.h,v 1.43 2000/11/08 22:10:02 tgl Exp $
+ * $Id: bufmgr.h,v 1.44 2000/11/28 23:27:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -154,7 +154,7 @@ extern Buffer ReleaseAndReadBuffer(Buffer buffer, Relation relation,
 					 BlockNumber blockNum);
 extern int	FlushBuffer(Buffer buffer, bool sync, bool release);
 
-extern void InitBufferPool(IPCKey key);
+extern void InitBufferPool(void);
 extern void PrintBufferUsage(FILE *statfp);
 extern void ResetBufferUsage(void);
 extern void ResetBufferPool(bool isCommit);
diff --git a/src/include/storage/ipc.h b/src/include/storage/ipc.h
index eea082a574eb0f1c12a1af875862f3ad73693792..b633297d5f675b25ea65e530b554168d51b4d60b 100644
--- a/src/include/storage/ipc.h
+++ b/src/include/storage/ipc.h
@@ -7,14 +7,10 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: ipc.h,v 1.42 2000/10/07 14:39:17 momjian Exp $
- *
- * NOTES
- *	  This file is very architecture-specific.	This stuff should actually
- *	  be factored into the port/ directories.
+ * $Id: ipc.h,v 1.43 2000/11/28 23:27:57 tgl Exp $
  *
  * Some files that would normally need to include only sys/ipc.h must
- * instead included this file because on Ultrix, sys/ipc.h is not designed
+ * instead include this file because on Ultrix, sys/ipc.h is not designed
  * to be included multiple times.  This file (by virtue of the ifndef IPC_H)
  * is.
  *-------------------------------------------------------------------------
@@ -26,11 +22,9 @@
 
 #include <sys/types.h>
 #ifdef HAVE_SYS_IPC_H
-#include <sys/ipc.h>			/* For IPC_PRIVATE */
+#include <sys/ipc.h>
 #endif /* HAVE_SYS_IPC_H */
 
-#include "config.h"
-
 #ifndef HAVE_UNION_SEMUN
 union semun
 {
@@ -38,79 +32,41 @@ union semun
 	struct semid_ds *buf;
 	unsigned short *array;
 };
-
 #endif
 
-typedef uint16 SystemPortAddress;
-
-/* semaphore definitions */
+/* generic IPC definitions */
 
 #define IPCProtection	(0600)	/* access/modify by user only */
 
-#define IPC_NMAXSEM		25		/* maximum number of semaphores */
-#define IpcSemaphoreDefaultStartValue	255
-#define IpcSharedLock									(-1)
-#define IpcExclusiveLock						  (-255)
-
-#define IpcUnknownStatus		(-1)
-#define IpcInvalidArgument		(-2)
-#define IpcSemIdExist			(-3)
-#define IpcSemIdNotExist		(-4)
-
-typedef uint32 IpcSemaphoreKey; /* semaphore key */
-typedef int IpcSemaphoreId;
-
-/* shared memory definitions */
-
-#define IpcMemCreationFailed	(-1)
-#define IpcMemIdGetFailed		(-2)
-#define IpcMemAttachFailed		0
-
-typedef uint32 IPCKey;
-
-#define PrivateIPCKey	IPC_PRIVATE
-#define DefaultIPCKey	17317
+/* semaphore definitions */
 
-typedef uint32 IpcMemoryKey;	/* shared memory key */
-typedef int IpcMemoryId;
+typedef uint32 IpcSemaphoreKey; /* semaphore key passed to semget(2) */
+typedef int IpcSemaphoreId;		/* semaphore ID returned by semget(2) */
 
+#define IPC_NMAXSEM		32		/* maximum number of semaphores per semID */
 
-/* ipc.c */
-extern bool proc_exit_inprogress;
+#define PGSemaMagic  537		/* must be less than SEMVMX */
 
-extern void proc_exit(int code);
-extern void shmem_exit(int code);
-extern int	on_shmem_exit(void (*function) (), Datum arg);
-extern int	on_proc_exit(void (*function) (), Datum arg);
-extern void on_exit_reset(void);
+/* shared memory definitions */
 
-extern IpcSemaphoreId IpcSemaphoreCreate(IpcSemaphoreKey semKey,
-				   int semNum, int permission, int semStartValue,
-				   int removeOnExit);
-extern void IpcSemaphoreKill(IpcSemaphoreKey key);
-extern void IpcSemaphoreLock(IpcSemaphoreId semId, int sem, int lock);
-extern void IpcSemaphoreUnlock(IpcSemaphoreId semId, int sem, int lock);
-extern int	IpcSemaphoreGetCount(IpcSemaphoreId semId, int sem);
-extern int	IpcSemaphoreGetValue(IpcSemaphoreId semId, int sem);
-extern IpcMemoryId IpcMemoryCreate(IpcMemoryKey memKey, uint32 size,
-				int permission);
-extern IpcMemoryId IpcMemoryIdGet(IpcMemoryKey memKey, uint32 size);
-extern char *IpcMemoryAttach(IpcMemoryId memId);
-extern void IpcMemoryKill(IpcMemoryKey memKey);
-extern void CreateAndInitSLockMemory(IPCKey key);
-extern void AttachSLockMemory(IPCKey key);
+typedef uint32 IpcMemoryKey;	/* shared memory key passed to shmget(2) */
+typedef int IpcMemoryId;		/* shared memory ID returned by shmget(2) */
 
+typedef struct					/* standard header for all Postgres shmem */
+{
+	int32		magic;			/* magic # to identify Postgres segments */
+#define PGShmemMagic  679834892
+	pid_t		creatorPID;		/* PID of creating process */
+	uint32		totalsize;		/* total size of segment */
+	uint32		freeoffset;		/* offset to first free space */
+} PGShmemHeader;
 
-#ifdef HAS_TEST_AND_SET
 
-#define NOLOCK			0
-#define SHAREDLOCK		1
-#define EXCLUSIVELOCK	2
+/* spinlock definitions */
 
 typedef enum _LockId_
 {
 	BUFMGRLOCKID,
-	LOCKLOCKID,
 	OIDGENLOCKID,
 	XIDGENLOCKID,
 	CNTLFILELOCKID,
@@ -118,100 +74,40 @@ typedef enum _LockId_
 	SHMEMINDEXLOCKID,
 	LOCKMGRLOCKID,
 	SINVALLOCKID,
-
-#ifdef STABLE_MEMORY_STORAGE
-	MMCACHELOCKID,
-#endif
-
 	PROCSTRUCTLOCKID,
-	FIRSTFREELOCKID
-} _LockId_;
-
-#define MAX_SPINS		FIRSTFREELOCKID
-
-typedef struct slock
-{
-	slock_t		locklock;
-	unsigned char flag;
-	short		nshlocks;
-	slock_t		shlock;
-	slock_t		exlock;
-	slock_t		comlock;
-	struct slock *next;
-} SLock;
-
-#else							/* HAS_TEST_AND_SET */
-
-typedef enum _LockId_
-{
-	SHMEMLOCKID,
-	SHMEMINDEXLOCKID,
-	BUFMGRLOCKID,
-	LOCKMGRLOCKID,
-	SINVALLOCKID,
 
 #ifdef STABLE_MEMORY_STORAGE
 	MMCACHELOCKID,
 #endif
 
-	PROCSTRUCTLOCKID,
-	OIDGENLOCKID,
-	XIDGENLOCKID,
-	CNTLFILELOCKID,
-	FIRSTFREELOCKID
+	MAX_SPINS					/* must be last item! */
 } _LockId_;
 
-#define MAX_SPINS		FIRSTFREELOCKID
 
-#endif	 /* HAS_TEST_AND_SET */
+/* ipc.c */
+extern bool proc_exit_inprogress;
 
-/*
- * the following are originally in ipci.h but the prototypes have circular
- * dependencies and most files include both ipci.h and ipc.h anyway, hence
- * combined.
- *
- */
+extern void proc_exit(int code);
+extern void shmem_exit(int code);
+extern void on_proc_exit(void (*function) (), Datum arg);
+extern void on_shmem_exit(void (*function) (), Datum arg);
+extern void on_exit_reset(void);
 
-/*
- * Note:
- *		These must not hash to DefaultIPCKey or PrivateIPCKey.
- */
-#define SystemPortAddressGetIPCKey(address) \
-		(28597 * (address) + 17491)
+extern void IpcInitKeyAssignment(int port);
 
-/*
- * these keys are originally numbered from 1 to 12 consecutively but not
- * all are used. The unused ones are removed.			- ay 4/95.
- */
-#define IPCKeyGetBufferMemoryKey(key) \
-		((key == PrivateIPCKey) ? key : 1 + (key))
-
-#define IPCKeyGetSIBufferMemoryBlock(key) \
-		((key == PrivateIPCKey) ? key : 7 + (key))
-
-#define IPCKeyGetSLockSharedMemoryKey(key) \
-		((key == PrivateIPCKey) ? key : 10 + (key))
-
-#define IPCKeyGetSpinLockSemaphoreKey(key) \
-		((key == PrivateIPCKey) ? key : 11 + (key))
-#define IPCKeyGetWaitIOSemaphoreKey(key) \
-		((key == PrivateIPCKey) ? key : 12 + (key))
-#define IPCKeyGetWaitCLSemaphoreKey(key) \
-		((key == PrivateIPCKey) ? key : 13 + (key))
-
-/* --------------------------
- * NOTE: This macro must always give the highest numbered key as every backend
- * process forked off by the postmaster will be trying to acquire a semaphore
- * with a unique key value starting at key+14 and incrementing up.	Each
- * backend uses the current key value then increments it by one.
- * --------------------------
- */
-#define IPCGetProcessSemaphoreInitKey(key) \
-		((key == PrivateIPCKey) ? key : 14 + (key))
+extern IpcSemaphoreId IpcSemaphoreCreate(int numSems, int permission,
+										 int semStartValue,
+										 bool removeOnExit);
+extern void IpcSemaphoreKill(IpcSemaphoreId semId);
+extern void IpcSemaphoreLock(IpcSemaphoreId semId, int sem);
+extern void IpcSemaphoreUnlock(IpcSemaphoreId semId, int sem);
+extern bool IpcSemaphoreTryLock(IpcSemaphoreId semId, int sem);
+extern int	IpcSemaphoreGetValue(IpcSemaphoreId semId, int sem);
+
+extern PGShmemHeader *IpcMemoryCreate(uint32 size, bool private,
+									  int permission);
 
 /* ipci.c */
-extern IPCKey SystemPortAddressCreateIPCKey(SystemPortAddress address);
-extern void CreateSharedMemoryAndSemaphores(IPCKey key, int maxBackends);
-extern void AttachSharedMemoryAndSemaphores(IPCKey key);
+extern void CreateSharedMemoryAndSemaphores(bool private, int maxBackends);
 
 #endif	 /* IPC_H */
diff --git a/src/include/storage/lmgr.h b/src/include/storage/lmgr.h
index 71a59cb9cc72df16ad5042b60b5b3f9e79c0cc0d..f859dc0762f222adb032d052752f6f5be3d50834 100644
--- a/src/include/storage/lmgr.h
+++ b/src/include/storage/lmgr.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: lmgr.h,v 1.25 2000/06/08 22:37:54 momjian Exp $
+ * $Id: lmgr.h,v 1.26 2000/11/28 23:27:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -47,7 +47,4 @@ extern void UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode);
 extern void XactLockTableInsert(TransactionId xid);
 extern void XactLockTableWait(TransactionId xid);
 
-/* proc.c */
-extern void InitProcGlobal(IPCKey key, int maxBackends);
-
 #endif	 /* LMGR_H */
diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h
index edc6359fc43e4e2d8d044e1ca9a6875a988eb17f..41305d80831ddd01b6bf09e31305c65c0e761b15 100644
--- a/src/include/storage/proc.h
+++ b/src/include/storage/proc.h
@@ -1,13 +1,13 @@
 /*-------------------------------------------------------------------------
  *
  * proc.h
- *
+ *	  per-process shared memory data structures
  *
  *
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: proc.h,v 1.31 2000/05/31 00:28:38 petere Exp $
+ * $Id: proc.h,v 1.32 2000/11/28 23:27:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -23,9 +23,8 @@ extern int DeadlockTimeout;
 typedef struct
 {
 	int			sleeplock;
-	int			semNum;
 	IpcSemaphoreId semId;
-	IpcSemaphoreKey semKey;
+	int			semNum;
 } SEMA;
 
 /*
@@ -33,7 +32,6 @@ typedef struct
  */
 typedef struct proc
 {
-
 	/* proc->links MUST BE THE FIRST ELEMENT OF STRUCT (see ProcWakeup()) */
 
 	SHM_QUEUE	links;			/* proc can be waiting for one event(lock) */
@@ -63,34 +61,6 @@ typedef struct proc
 								 * transaction */
 } PROC;
 
-
-/*
- * PROC_NSEMS_PER_SET is the number of semaphores in each sys-V semaphore set
- * we allocate.  It must be *less than* 32 (or however many bits in an int
- * on your machine), or our free-semaphores bitmap won't work.  You also must
- * not set it higher than your kernel's SEMMSL (max semaphores per set)
- * parameter, which is often around 25.
- *
- * MAX_PROC_SEMS is the maximum number of per-process semaphores (those used
- * by the lock mgr) we can keep track of.  It must be a multiple of
- * PROC_NSEMS_PER_SET.
- */
-#define  PROC_NSEMS_PER_SET		16
-#define  MAX_PROC_SEMS			(((MAXBACKENDS-1)/PROC_NSEMS_PER_SET+1)*PROC_NSEMS_PER_SET)
-
-typedef struct procglobal
-{
-	SHMEM_OFFSET freeProcs;
-	IPCKey		currKey;
-	int32		freeSemMap[MAX_PROC_SEMS / PROC_NSEMS_PER_SET];
-
-	/*
-	 * In each freeSemMap entry, the PROC_NSEMS_PER_SET least-significant
-	 * bits flag whether individual semaphores are in use, and the next
-	 * higher bit is set to show that the entire set is allocated.
-	 */
-} PROC_HDR;
-
 extern PROC *MyProc;
 
 #define PROC_INCR_SLOCK(lock) \
@@ -115,16 +85,46 @@ do { \
 
 extern SPINLOCK ProcStructLock;
 
+
+/*
+ * There is one ProcGlobal struct for the whole installation.
+ *
+ * PROC_NSEMS_PER_SET is the number of semaphores in each sys-V semaphore set
+ * we allocate.  It must be no more than 32 (or however many bits in an int
+ * on your machine), or our free-semaphores bitmap won't work.  It also must
+ * be *less than* your kernel's SEMMSL (max semaphores per set) parameter,
+ * which is often around 25.  (Less than, because we allocate one extra sema
+ * in each set for identification purposes.)
+ *
+ * PROC_SEM_MAP_ENTRIES is the number of semaphore sets we need to allocate
+ * to keep track of up to MAXBACKENDS backends.
+ */
+#define  PROC_NSEMS_PER_SET		16
+#define  PROC_SEM_MAP_ENTRIES	((MAXBACKENDS-1)/PROC_NSEMS_PER_SET+1)
+
+typedef struct procglobal
+{
+	/* Head of list of free PROC structures */
+	SHMEM_OFFSET freeProcs;
+
+	/* Info about semaphore sets used for per-process semaphores */
+	IpcSemaphoreId procSemIds[PROC_SEM_MAP_ENTRIES];
+	int32		freeSemMap[PROC_SEM_MAP_ENTRIES];
+
+	/*
+	 * In each freeSemMap entry, bit i is set if the i'th semaphore of the
+	 * set is allocated to a process.  (i counts from 0 at the LSB)
+	 */
+} PROC_HDR;
+
 /*
  * Function Prototypes
  */
-extern void InitProcess(IPCKey key);
+extern void InitProcGlobal(int maxBackends);
+extern void InitProcess(void);
 extern void ProcReleaseLocks(void);
 extern bool ProcRemove(int pid);
 
-/* extern bool ProcKill(int exitStatus, int pid); */
-/* make static in storage/lmgr/proc.c -- jolly */
-
 extern void ProcQueueInit(PROC_QUEUE *queue);
 extern int ProcSleep(PROC_QUEUE *queue, LOCKMETHODCTL *lockctl, int token,
 		  LOCK *lock);
diff --git a/src/include/storage/s_lock.h b/src/include/storage/s_lock.h
index 9f0fd7c68e3f703bac3db352e4bc9d8e5f6fd3ba..d50e3564bb7eb0cc9007a13f5b250199883d1eb2 100644
--- a/src/include/storage/s_lock.h
+++ b/src/include/storage/s_lock.h
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/include/storage/s_lock.h,v 1.73 2000/10/22 22:15:03 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/include/storage/s_lock.h,v 1.74 2000/11/28 23:27:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -26,7 +26,7 @@
  *		void S_LOCK_FREE(slock_t *lock)
  *			Tests if the lock is free. Returns non-zero if free, 0 if locked.
  *
- *		The S_LOCK() macro	implements a primitive but still useful random
+ *		The S_LOCK() macro implements a primitive but still useful random
  *		backoff to avoid hordes of busywaiting lockers chewing CPU.
  *
  *		Effectively:
@@ -64,7 +64,7 @@
  *		manual for POWER in any case.
  *
  */
-#if !defined(S_LOCK_H)
+#ifndef S_LOCK_H
 #define S_LOCK_H
 
 #include "storage/ipc.h"
@@ -403,8 +403,8 @@ extern void s_lock(volatile slock_t *lock, const char *file, const int line);
 
 #define S_LOCK(lock) \
 	do { \
-		if (TAS((volatile slock_t *) lock)) \
-			s_lock((volatile slock_t *) lock, __FILE__, __LINE__); \
+		if (TAS((volatile slock_t *) (lock))) \
+			s_lock((volatile slock_t *) (lock), __FILE__, __LINE__); \
 	} while (0)
 #endif	 /* S_LOCK */
 
@@ -421,12 +421,46 @@ extern void s_lock(volatile slock_t *lock, const char *file, const int line);
 #endif	 /* S_INIT_LOCK */
 
 #if !defined(TAS)
-int			tas(volatile slock_t *lock);		/* port/.../tas.s, or
+extern int	tas(volatile slock_t *lock);		/* port/.../tas.s, or
 												 * s_lock.c */
 
-#define TAS(lock)		tas((volatile slock_t *) lock)
+#define TAS(lock)		tas((volatile slock_t *) (lock))
 #endif	 /* TAS */
 
+
+#else	 /* !HAS_TEST_AND_SET */
+
+/*
+ * Fake spinlock implementation using SysV semaphores --- slow and prone
+ * to fall foul of kernel limits on number of semaphores, so don't use this
+ * unless you must!
+ */
+
+typedef struct
+{
+	/* reference to semaphore used to implement this spinlock */
+	IpcSemaphoreId	semId;
+	int				sem;
+} slock_t;
+
+extern bool s_lock_free_sema(volatile slock_t *lock);
+extern void s_unlock_sema(volatile slock_t *lock);
+extern void s_init_lock_sema(volatile slock_t *lock);
+extern int tas_sema(volatile slock_t *lock);
+
+extern void s_lock(volatile slock_t *lock, const char *file, const int line);
+
+#define S_LOCK(lock) \
+	do { \
+		if (TAS((volatile slock_t *) (lock))) \
+			s_lock((volatile slock_t *) (lock), __FILE__, __LINE__); \
+	} while (0)
+
+#define S_LOCK_FREE(lock)   s_lock_free_sema(lock)
+#define S_UNLOCK(lock)   s_unlock_sema(lock)
+#define S_INIT_LOCK(lock)   s_init_lock_sema(lock)
+#define TAS(lock)   tas_sema(lock)
+
 #endif	 /* HAS_TEST_AND_SET */
-#endif	 /* S_LOCK_H */
 
+#endif	 /* S_LOCK_H */
diff --git a/src/include/storage/shmem.h b/src/include/storage/shmem.h
index 35545f95191fab380f68e6d6e857507df8d2a8ee..8b2cc4487f0aa400e79275a4ec36190e288535ed 100644
--- a/src/include/storage/shmem.h
+++ b/src/include/storage/shmem.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: shmem.h,v 1.23 2000/06/28 03:33:27 tgl Exp $
+ * $Id: shmem.h,v 1.24 2000/11/28 23:27:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,17 +18,23 @@
 #include "utils/hsearch.h"
 
 
-/* The shared memory region can start at a different address
+/*
+ * The shared memory region can start at a different address
  * in every process.  Shared memory "pointers" are actually
  * offsets relative to the start of the shared memory region(s).
+ *
+ * In current usage, this is not actually a problem, but we keep
+ * the code that used to handle it...
  */
 typedef unsigned long SHMEM_OFFSET;
 
 #define INVALID_OFFSET (-1)
 #define BAD_LOCATION (-1)
 
-/* start of the lowest shared memory region.  For now, assume that
- * there is only one shared memory region
+/*
+ * Start of the primary shared memory region, in this process' address space.
+ * The macros in this header file can only cope with offsets into this
+ * shared memory region!
  */
 extern SHMEM_OFFSET ShmemBase;
 
@@ -39,14 +45,14 @@ extern SHMEM_OFFSET ShmemBase;
 
 /* coerce a pointer into a shmem offset */
 #define MAKE_OFFSET(xx_ptr)\
-  (SHMEM_OFFSET) (((unsigned long)(xx_ptr))-ShmemBase)
+  ((SHMEM_OFFSET) (((unsigned long)(xx_ptr))-ShmemBase))
 
 #define SHM_PTR_VALID(xx_ptr)\
-  (((unsigned long)xx_ptr) > ShmemBase)
+  (((unsigned long)(xx_ptr)) > ShmemBase)
 
 /* cannot have an offset to ShmemFreeStart (offset 0) */
 #define SHM_OFFSET_VALID(xx_offs)\
-  ((xx_offs != 0) && (xx_offs != INVALID_OFFSET))
+  (((xx_offs) != 0) && ((xx_offs) != INVALID_OFFSET))
 
 
 extern SPINLOCK ShmemLock;
@@ -60,11 +66,9 @@ typedef struct SHM_QUEUE
 } SHM_QUEUE;
 
 /* shmem.c */
-extern void ShmemIndexReset(void);
-extern void ShmemCreate(unsigned int key, unsigned int size);
-extern int	InitShmem(unsigned int key, unsigned int size);
+extern void InitShmemAllocation(PGShmemHeader *seghdr);
 extern void *ShmemAlloc(Size size);
-extern int	ShmemIsValid(unsigned long addr);
+extern bool ShmemIsValid(unsigned long addr);
 extern HTAB *ShmemInitHash(char *name, long init_size, long max_size,
 			  HASHCTL *infoP, int hash_flags);
 extern bool ShmemPIDLookup(int pid, SHMEM_OFFSET *locationPtr);
diff --git a/src/include/storage/sinval.h b/src/include/storage/sinval.h
index 4c80f760faa508899d6865a99f7fccdc0e92c257..1cadb54fd246f4201d96c1f83e7197674ee15eae 100644
--- a/src/include/storage/sinval.h
+++ b/src/include/storage/sinval.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: sinval.h,v 1.15 2000/11/12 20:51:52 tgl Exp $
+ * $Id: sinval.h,v 1.16 2000/11/28 23:27:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,9 +19,9 @@
 
 extern SPINLOCK SInvalLock;
 
-extern void CreateSharedInvalidationState(IPCKey key, int maxBackends);
-extern void AttachSharedInvalidationState(IPCKey key);
-extern void InitSharedInvalidationState(void);
+extern int	SInvalShmemSize(int maxBackends);
+extern void CreateSharedInvalidationState(int maxBackends);
+extern void InitBackendSharedInvalidationState(void);
 extern void RegisterSharedInvalid(int cacheId, Index hashIndex,
 					  ItemPointer pointer);
 extern void InvalidateSharedInvalid(void (*invalFunction) (),
diff --git a/src/include/storage/sinvaladt.h b/src/include/storage/sinvaladt.h
index b9704d34e4d9753056cbcbf360d43a7de124cb46..c31caf53bf5e7e641233a9afcd851f41fe77e97f 100644
--- a/src/include/storage/sinvaladt.h
+++ b/src/include/storage/sinvaladt.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: sinvaladt.h,v 1.23 2000/11/12 20:51:52 tgl Exp $
+ * $Id: sinvaladt.h,v 1.24 2000/11/28 23:27:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -107,15 +107,13 @@ typedef struct SISeg
 } SISeg;
 
 
-extern SISeg *shmInvalBuffer;	/* pointer to the shared buffer segment,
-								 * set by SISegmentAttach() */
+extern SISeg *shmInvalBuffer;	/* pointer to the shared inval buffer */
 
 
 /*
  * prototypes for functions in sinvaladt.c
  */
-extern int SISegmentInit(bool createNewSegment, IPCKey key,
-			  int maxBackends);
+extern void SIBufferInit(int maxBackends);
 extern int	SIBackendInit(SISeg *segP);
 
 extern bool SIInsertDataEntry(SISeg *segP, SharedInvalidData *data);
diff --git a/src/include/storage/spin.h b/src/include/storage/spin.h
index 656e1097a239a5fa5e63acafff0c677af0c64dce..53efabcadb1edab4da5505b17f69fc8f496d9294 100644
--- a/src/include/storage/spin.h
+++ b/src/include/storage/spin.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: spin.h,v 1.12 2000/05/31 00:28:38 petere Exp $
+ * $Id: spin.h,v 1.13 2000/11/28 23:27:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,11 +19,10 @@
 /*
  * two implementations of spin locks
  *
- * sequent, sparc, sun3: real spin locks. uses a TAS instruction; see
- * src/storage/ipc/s_lock.c for details.
- *
- * default: fake spin locks using semaphores.  see spin.c
+ * Where TAS instruction is available: real spin locks.
+ * See src/storage/ipc/s_lock.c for details.
  *
+ * Otherwise: fake spin locks using semaphores.  see spin.c
  */
 
 typedef int SPINLOCK;
@@ -32,8 +31,10 @@ typedef int SPINLOCK;
 extern bool Trace_spinlocks;
 #endif
 
-extern void CreateSpinlocks(IPCKey key);
-extern void InitSpinLocks(void);
+
+extern int	SLockShmemSize(void);
+extern void CreateSpinlocks(PGShmemHeader *seghdr);
+
 extern void SpinAcquire(SPINLOCK lockid);
 extern void SpinRelease(SPINLOCK lockid);