diff --git a/src/backend/port/posix_sema.c b/src/backend/port/posix_sema.c
index 2b4b11c..603dc5a 100644
*** a/src/backend/port/posix_sema.c
--- b/src/backend/port/posix_sema.c
***************
*** 6,11 ****
--- 6,19 ----
   * We prefer the unnamed style of POSIX semaphore (the kind made with
   * sem_init).  We can cope with the kind made with sem_open, however.
   *
+  * In either implementation, typedef PGSemaphore is equivalent to "sem_t *".
+  * With unnamed semaphores, the sem_t structs live in an array in shared
+  * memory.  With named semaphores, that's not true because we cannot persuade
+  * sem_open to do its allocation there.  Therefore, the named-semaphore code
+  * *does not cope with EXEC_BACKEND*.  The sem_t structs will just be in the
+  * postmaster's private memory, where they are successfully inherited by
+  * forked backends, but they could not be accessed by exec'd backends.
+  *
   *
   * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
   * Portions Copyright (c) 1994, Regents of the University of California
***************
*** 18,45 ****
  #include "postgres.h"
  
  #include <fcntl.h>
  #include <signal.h>
  #include <unistd.h>
  
  #include "miscadmin.h"
  #include "storage/ipc.h"
  #include "storage/pg_sema.h"
  
  
! #ifdef USE_NAMED_POSIX_SEMAPHORES
! /* PGSemaphore is pointer to pointer to sem_t */
! #define PG_SEM_REF(x)	(*(x))
! #else
! /* PGSemaphore is pointer to sem_t */
! #define PG_SEM_REF(x)	(x)
  #endif
  
  
  #define IPCProtection	(0600)	/* access/modify by user only */
  
  static sem_t **mySemPointers;	/* keep track of created semaphores */
  static int	numSems;			/* number of semas acquired so far */
! static int	maxSems;			/* allocated size of mySemaPointers array */
  static int	nextSemKey;			/* next name to try */
  
  
--- 26,63 ----
  #include "postgres.h"
  
  #include <fcntl.h>
+ #include <semaphore.h>
  #include <signal.h>
  #include <unistd.h>
  
  #include "miscadmin.h"
  #include "storage/ipc.h"
  #include "storage/pg_sema.h"
+ #include "storage/shmem.h"
  
  
! /* see file header comment */
! #if defined(USE_NAMED_POSIX_SEMAPHORES) && defined(EXEC_BACKEND)
! #error cannot use named POSIX semaphores with EXEC_BACKEND
  #endif
  
+ /* typedef PGSemaphore is equivalent to pointer to sem_t */
+ typedef struct PGSemaphoreData
+ {
+ 	sem_t		pgsem;
+ } PGSemaphoreData;
+ 
+ #define PG_SEM_REF(x)	(&(x)->pgsem)
  
  #define IPCProtection	(0600)	/* access/modify by user only */
  
+ #ifdef USE_NAMED_POSIX_SEMAPHORES
  static sem_t **mySemPointers;	/* keep track of created semaphores */
+ #else
+ static PGSemaphore sharedSemas; /* array of PGSemaphoreData in shared memory */
+ #endif
  static int	numSems;			/* number of semas acquired so far */
! static int	maxSems;			/* allocated size of above arrays */
  static int	nextSemKey;			/* next name to try */
  
  
*************** PosixSemaphoreKill(sem_t * sem)
*** 134,139 ****
--- 152,172 ----
  
  
  /*
+  * Report amount of shared memory needed for semaphores
+  */
+ Size
+ PGSemaphoreShmemSize(int maxSemas)
+ {
+ #ifdef USE_NAMED_POSIX_SEMAPHORES
+ 	/* No shared memory needed in this case */
+ 	return 0;
+ #else
+ 	/* Need a PGSemaphoreData per semaphore */
+ 	return mul_size(maxSemas, sizeof(PGSemaphoreData));
+ #endif
+ }
+ 
+ /*
   * PGReserveSemaphores --- initialize semaphore support
   *
   * This is called during postmaster start or shared memory reinitialization.
*************** PosixSemaphoreKill(sem_t * sem)
*** 147,161 ****
   * zero will be passed.
   *
   * In the Posix implementation, we acquire semaphores on-demand; the
!  * maxSemas parameter is just used to size the array that keeps track of
!  * acquired semas for subsequent releasing.
   */
  void
  PGReserveSemaphores(int maxSemas, int port)
  {
  	mySemPointers = (sem_t **) malloc(maxSemas * sizeof(sem_t *));
  	if (mySemPointers == NULL)
  		elog(PANIC, "out of memory");
  	numSems = 0;
  	maxSems = maxSemas;
  	nextSemKey = port * 1000;
--- 180,212 ----
   * zero will be passed.
   *
   * In the Posix implementation, we acquire semaphores on-demand; the
!  * maxSemas parameter is just used to size the arrays.  For unnamed
!  * semaphores, there is an array of PGSemaphoreData structs in shared memory.
!  * For named semaphores, we keep a postmaster-local array of sem_t pointers,
!  * which we use for releasing the semphores when done.
!  * (This design minimizes the dependency of postmaster shutdown on the
!  * contents of shared memory, which a failed backend might have clobbered.
!  * We can't do much about the possibility of sem_destroy() crashing, but
!  * we don't have to expose the counters to other processes.)
   */
  void
  PGReserveSemaphores(int maxSemas, int port)
  {
+ #ifdef USE_NAMED_POSIX_SEMAPHORES
  	mySemPointers = (sem_t **) malloc(maxSemas * sizeof(sem_t *));
  	if (mySemPointers == NULL)
  		elog(PANIC, "out of memory");
+ #else
+ 
+ 	/*
+ 	 * We must use ShmemAllocUnlocked(), since the spinlock protecting
+ 	 * ShmemAlloc() won't be ready yet.  (This ordering is necessary when we
+ 	 * are emulating spinlocks with semaphores.)
+ 	 */
+ 	sharedSemas = (PGSemaphore)
+ 		ShmemAllocUnlocked(PGSemaphoreShmemSize(maxSemas));
+ #endif
+ 
  	numSems = 0;
  	maxSems = maxSemas;
  	nextSemKey = port * 1000;
*************** ReleaseSemaphores(int status, Datum arg)
*** 173,191 ****
  {
  	int			i;
  
  	for (i = 0; i < numSems; i++)
  		PosixSemaphoreKill(mySemPointers[i]);
  	free(mySemPointers);
  }
  
  /*
   * PGSemaphoreCreate
   *
!  * Initialize a PGSemaphore structure to represent a sema with count 1
   */
! void
! PGSemaphoreCreate(PGSemaphore sema)
  {
  	sem_t	   *newsem;
  
  	/* Can't do this in a backend, because static state is postmaster's */
--- 224,250 ----
  {
  	int			i;
  
+ #ifdef USE_NAMED_POSIX_SEMAPHORES
  	for (i = 0; i < numSems; i++)
  		PosixSemaphoreKill(mySemPointers[i]);
  	free(mySemPointers);
+ #endif
+ 
+ #ifdef USE_UNNAMED_POSIX_SEMAPHORES
+ 	for (i = 0; i < numSems; i++)
+ 		PosixSemaphoreKill(PG_SEM_REF(sharedSemas + i));
+ #endif
  }
  
  /*
   * PGSemaphoreCreate
   *
!  * Allocate a PGSemaphore structure with initial count 1
   */
! PGSemaphore
! PGSemaphoreCreate(void)
  {
+ 	PGSemaphore sema;
  	sem_t	   *newsem;
  
  	/* Can't do this in a backend, because static state is postmaster's */
*************** PGSemaphoreCreate(PGSemaphore sema)
*** 195,208 ****
  		elog(PANIC, "too many semaphores created");
  
  #ifdef USE_NAMED_POSIX_SEMAPHORES
! 	*sema = newsem = PosixSemaphoreCreate();
  #else
! 	PosixSemaphoreCreate(sema);
! 	newsem = sema;
  #endif
  
! 	/* Remember new sema for ReleaseSemaphores */
! 	mySemPointers[numSems++] = newsem;
  }
  
  /*
--- 254,272 ----
  		elog(PANIC, "too many semaphores created");
  
  #ifdef USE_NAMED_POSIX_SEMAPHORES
! 	newsem = PosixSemaphoreCreate();
! 	/* Remember new sema for ReleaseSemaphores */
! 	mySemPointers[numSems] = newsem;
! 	sema = (PGSemaphore) newsem;
  #else
! 	sema = &sharedSemas[numSems];
! 	newsem = PG_SEM_REF(sema);
! 	PosixSemaphoreCreate(newsem);
  #endif
  
! 	numSems++;
! 
! 	return sema;
  }
  
  /*
diff --git a/src/backend/port/sysv_sema.c b/src/backend/port/sysv_sema.c
index f6f1516..531d426 100644
*** a/src/backend/port/sysv_sema.c
--- b/src/backend/port/sysv_sema.c
***************
*** 27,33 ****
--- 27,40 ----
  #include "miscadmin.h"
  #include "storage/ipc.h"
  #include "storage/pg_sema.h"
+ #include "storage/shmem.h"
+ 
  
+ typedef struct PGSemaphoreData
+ {
+ 	int			semId;			/* semaphore set identifier */
+ 	int			semNum;			/* semaphore number within set */
+ } PGSemaphoreData;
  
  #ifndef HAVE_UNION_SEMUN
  union semun
*************** typedef int IpcSemaphoreId;		/* semaphor
*** 54,59 ****
--- 61,69 ----
  #define PGSemaMagic		537		/* must be less than SEMVMX */
  
  
+ static PGSemaphore sharedSemas; /* array of PGSemaphoreData in shared memory */
+ static int	numSharedSemas;		/* number of PGSemaphoreDatas used so far */
+ static int	maxSharedSemas;		/* allocated size of PGSemaphoreData array */
  static IpcSemaphoreId *mySemaSets;		/* IDs of sema sets acquired so far */
  static int	numSemaSets;		/* number of sema sets acquired so far */
  static int	maxSemaSets;		/* allocated size of mySemaSets array */
*************** IpcSemaphoreCreate(int numSems)
*** 274,279 ****
--- 284,298 ----
  
  
  /*
+  * Report amount of shared memory needed for semaphores
+  */
+ Size
+ PGSemaphoreShmemSize(int maxSemas)
+ {
+ 	return mul_size(maxSemas, sizeof(PGSemaphoreData));
+ }
+ 
+ /*
   * PGReserveSemaphores --- initialize semaphore support
   *
   * This is called during postmaster start or shared memory reinitialization.
*************** IpcSemaphoreCreate(int numSems)
*** 287,298 ****
   * zero will be passed.
   *
   * In the SysV implementation, we acquire semaphore sets on-demand; the
!  * maxSemas parameter is just used to size the array that keeps track of
!  * acquired sets for subsequent releasing.
   */
  void
  PGReserveSemaphores(int maxSemas, int port)
  {
  	maxSemaSets = (maxSemas + SEMAS_PER_SET - 1) / SEMAS_PER_SET;
  	mySemaSets = (IpcSemaphoreId *)
  		malloc(maxSemaSets * sizeof(IpcSemaphoreId));
--- 306,331 ----
   * zero will be passed.
   *
   * In the SysV implementation, we acquire semaphore sets on-demand; the
!  * maxSemas parameter is just used to size the arrays.  There is an array
!  * of PGSemaphoreData structs in shared memory, and a postmaster-local array
!  * with one entry per SysV semaphore set, which we use for releasing the
!  * semaphore sets when done.  (This design ensures that postmaster shutdown
!  * doesn't rely on the contents of shared memory, which a failed backend might
!  * have clobbered.)
   */
  void
  PGReserveSemaphores(int maxSemas, int port)
  {
+ 	/*
+ 	 * We must use ShmemAllocUnlocked(), since the spinlock protecting
+ 	 * ShmemAlloc() won't be ready yet.  (This ordering is necessary when we
+ 	 * are emulating spinlocks with semaphores.)
+ 	 */
+ 	sharedSemas = (PGSemaphore)
+ 		ShmemAllocUnlocked(PGSemaphoreShmemSize(maxSemas));
+ 	numSharedSemas = 0;
+ 	maxSharedSemas = maxSemas;
+ 
  	maxSemaSets = (maxSemas + SEMAS_PER_SET - 1) / SEMAS_PER_SET;
  	mySemaSets = (IpcSemaphoreId *)
  		malloc(maxSemaSets * sizeof(IpcSemaphoreId));
*************** ReleaseSemaphores(int status, Datum arg)
*** 323,333 ****
  /*
   * PGSemaphoreCreate
   *
!  * Initialize a PGSemaphore structure to represent a sema with count 1
   */
! void
! PGSemaphoreCreate(PGSemaphore sema)
  {
  	/* Can't do this in a backend, because static state is postmaster's */
  	Assert(!IsUnderPostmaster);
  
--- 356,368 ----
  /*
   * PGSemaphoreCreate
   *
!  * Allocate a PGSemaphore structure with initial count 1
   */
! PGSemaphore
! PGSemaphoreCreate(void)
  {
+ 	PGSemaphore sema;
+ 
  	/* Can't do this in a backend, because static state is postmaster's */
  	Assert(!IsUnderPostmaster);
  
*************** PGSemaphoreCreate(PGSemaphore sema)
*** 340,350 ****
--- 375,391 ----
  		numSemaSets++;
  		nextSemaNumber = 0;
  	}
+ 	/* Use the next shared PGSemaphoreData */
+ 	if (numSharedSemas >= maxSharedSemas)
+ 		elog(PANIC, "too many semaphores created");
+ 	sema = &sharedSemas[numSharedSemas++];
  	/* Assign the next free semaphore in the current set */
  	sema->semId = mySemaSets[numSemaSets - 1];
  	sema->semNum = nextSemaNumber++;
  	/* Initialize it to count 1 */
  	IpcSemaphoreInitialize(sema->semId, sema->semNum, 1);
+ 
+ 	return sema;
  }
  
  /*
diff --git a/src/backend/port/win32_sema.c b/src/backend/port/win32_sema.c
index c688210..c8b12be 100644
*** a/src/backend/port/win32_sema.c
--- b/src/backend/port/win32_sema.c
*************** static int	maxSems;			/* allocated size 
*** 23,28 ****
--- 23,39 ----
  
  static void ReleaseSemaphores(int code, Datum arg);
  
+ 
+ /*
+  * Report amount of shared memory needed for semaphores
+  */
+ Size
+ PGSemaphoreShmemSize(int maxSemas)
+ {
+ 	/* No shared memory needed on Windows */
+ 	return 0;
+ }
+ 
  /*
   * PGReserveSemaphores --- initialize semaphore support
   *
*************** ReleaseSemaphores(int code, Datum arg)
*** 62,71 ****
  /*
   * PGSemaphoreCreate
   *
!  * Initialize a PGSemaphore structure to represent a sema with count 1
   */
! void
! PGSemaphoreCreate(PGSemaphore sema)
  {
  	HANDLE		cur_handle;
  	SECURITY_ATTRIBUTES sec_attrs;
--- 73,82 ----
  /*
   * PGSemaphoreCreate
   *
!  * Allocate a PGSemaphore structure with initial count 1
   */
! PGSemaphore
! PGSemaphoreCreate(void)
  {
  	HANDLE		cur_handle;
  	SECURITY_ATTRIBUTES sec_attrs;
*************** PGSemaphoreCreate(PGSemaphore sema)
*** 86,97 ****
  	if (cur_handle)
  	{
  		/* Successfully done */
- 		*sema = cur_handle;
  		mySemSet[numSems++] = cur_handle;
  	}
  	else
  		ereport(PANIC,
! 				(errmsg("could not create semaphore: error code %lu", GetLastError())));
  }
  
  /*
--- 97,110 ----
  	if (cur_handle)
  	{
  		/* Successfully done */
  		mySemSet[numSems++] = cur_handle;
  	}
  	else
  		ereport(PANIC,
! 				(errmsg("could not create semaphore: error code %lu",
! 						GetLastError())));
! 
! 	return (PGSemaphore) cur_handle;
  }
  
  /*
*************** PGSemaphoreReset(PGSemaphore sema)
*** 106,112 ****
  	 * There's no direct API for this in Win32, so we have to ratchet the
  	 * semaphore down to 0 with repeated trylock's.
  	 */
! 	while (PGSemaphoreTryLock(sema));
  }
  
  /*
--- 119,126 ----
  	 * There's no direct API for this in Win32, so we have to ratchet the
  	 * semaphore down to 0 with repeated trylock's.
  	 */
! 	while (PGSemaphoreTryLock(sema))
! 		 /* loop */ ;
  }
  
  /*
*************** PGSemaphoreLock(PGSemaphore sema)
*** 127,133 ****
  	 * pending signals are serviced.
  	 */
  	wh[0] = pgwin32_signal_event;
! 	wh[1] = *sema;
  
  	/*
  	 * As in other implementations of PGSemaphoreLock, we need to check for
--- 141,147 ----
  	 * pending signals are serviced.
  	 */
  	wh[0] = pgwin32_signal_event;
! 	wh[1] = sema;
  
  	/*
  	 * As in other implementations of PGSemaphoreLock, we need to check for
*************** PGSemaphoreLock(PGSemaphore sema)
*** 182,190 ****
  void
  PGSemaphoreUnlock(PGSemaphore sema)
  {
! 	if (!ReleaseSemaphore(*sema, 1, NULL))
  		ereport(FATAL,
! 				(errmsg("could not unlock semaphore: error code %lu", GetLastError())));
  }
  
  /*
--- 196,205 ----
  void
  PGSemaphoreUnlock(PGSemaphore sema)
  {
! 	if (!ReleaseSemaphore(sema, 1, NULL))
  		ereport(FATAL,
! 				(errmsg("could not unlock semaphore: error code %lu",
! 						GetLastError())));
  }
  
  /*
*************** PGSemaphoreTryLock(PGSemaphore sema)
*** 197,203 ****
  {
  	DWORD		ret;
  
! 	ret = WaitForSingleObject(*sema, 0);
  
  	if (ret == WAIT_OBJECT_0)
  	{
--- 212,218 ----
  {
  	DWORD		ret;
  
! 	ret = WaitForSingleObject(sema, 0);
  
  	if (ret == WAIT_OBJECT_0)
  	{
*************** PGSemaphoreTryLock(PGSemaphore sema)
*** 213,219 ****
  
  	/* Otherwise we are in trouble */
  	ereport(FATAL,
! 	(errmsg("could not try-lock semaphore: error code %lu", GetLastError())));
  
  	/* keep compiler quiet */
  	return false;
--- 228,235 ----
  
  	/* Otherwise we are in trouble */
  	ereport(FATAL,
! 			(errmsg("could not try-lock semaphore: error code %lu",
! 					GetLastError())));
  
  	/* keep compiler quiet */
  	return false;
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 59073e0..827e0d5 100644
*** a/src/backend/postmaster/postmaster.c
--- b/src/backend/postmaster/postmaster.c
*************** typedef struct
*** 484,490 ****
  	VariableCache ShmemVariableCache;
  	Backend    *ShmemBackendArray;
  #ifndef HAVE_SPINLOCKS
! 	PGSemaphore SpinlockSemaArray;
  #endif
  	int			NamedLWLockTrancheRequests;
  	NamedLWLockTranche *NamedLWLockTrancheArray;
--- 484,490 ----
  	VariableCache ShmemVariableCache;
  	Backend    *ShmemBackendArray;
  #ifndef HAVE_SPINLOCKS
! 	PGSemaphore *SpinlockSemaArray;
  #endif
  	int			NamedLWLockTrancheRequests;
  	NamedLWLockTranche *NamedLWLockTrancheArray;
diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c
index 01bddce..29febb4 100644
*** a/src/backend/storage/ipc/ipci.c
--- b/src/backend/storage/ipc/ipci.c
*************** CreateSharedMemoryAndSemaphores(bool mak
*** 102,107 ****
--- 102,111 ----
  		Size		size;
  		int			numSemas;
  
+ 		/* Compute number of semaphores we'll need */
+ 		numSemas = ProcGlobalSemas();
+ 		numSemas += SpinlockSemas();
+ 
  		/*
  		 * Size of the Postgres shared-memory block is estimated via
  		 * moderately-accurate estimates for the big hogs, plus 100K for the
*************** CreateSharedMemoryAndSemaphores(bool mak
*** 112,117 ****
--- 116,122 ----
  		 * need to be so careful during the actual allocation phase.
  		 */
  		size = 100000;
+ 		size = add_size(size, PGSemaphoreShmemSize(numSemas));
  		size = add_size(size, SpinlockSemaSize());
  		size = add_size(size, hash_estimate_size(SHMEM_INDEX_SIZE,
  												 sizeof(ShmemIndexEnt)));
*************** CreateSharedMemoryAndSemaphores(bool mak
*** 166,174 ****
  		/*
  		 * Create semaphores
  		 */
- 		numSemas = ProcGlobalSemas();
- 		numSemas += SpinlockSemas();
  		PGReserveSemaphores(numSemas, port);
  	}
  	else
  	{
--- 171,185 ----
  		/*
  		 * Create semaphores
  		 */
  		PGReserveSemaphores(numSemas, port);
+ 
+ 		/*
+ 		 * If spinlocks are disabled, initialize emulation layer (which
+ 		 * depends on semaphores, so the order is important here).
+ 		 */
+ #ifndef HAVE_SPINLOCKS
+ 		SpinlockSemaInit();
+ #endif
  	}
  	else
  	{
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index e5d487d..bf38470 100644
*** a/src/backend/storage/ipc/procarray.c
--- b/src/backend/storage/ipc/procarray.c
*************** ProcArrayGroupClearXid(PGPROC *proc, Tra
*** 522,528 ****
  		for (;;)
  		{
  			/* acts as a read barrier */
! 			PGSemaphoreLock(&proc->sem);
  			if (!proc->procArrayGroupMember)
  				break;
  			extraWaits++;
--- 522,528 ----
  		for (;;)
  		{
  			/* acts as a read barrier */
! 			PGSemaphoreLock(proc->sem);
  			if (!proc->procArrayGroupMember)
  				break;
  			extraWaits++;
*************** ProcArrayGroupClearXid(PGPROC *proc, Tra
*** 532,538 ****
  
  		/* Fix semaphore count for any absorbed wakeups */
  		while (extraWaits-- > 0)
! 			PGSemaphoreUnlock(&proc->sem);
  		return;
  	}
  
--- 532,538 ----
  
  		/* Fix semaphore count for any absorbed wakeups */
  		while (extraWaits-- > 0)
! 			PGSemaphoreUnlock(proc->sem);
  		return;
  	}
  
*************** ProcArrayGroupClearXid(PGPROC *proc, Tra
*** 591,597 ****
  		proc->procArrayGroupMember = false;
  
  		if (proc != MyProc)
! 			PGSemaphoreUnlock(&proc->sem);
  	}
  }
  
--- 591,597 ----
  		proc->procArrayGroupMember = false;
  
  		if (proc != MyProc)
! 			PGSemaphoreUnlock(proc->sem);
  	}
  }
  
diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c
index cc3af2d..a516194 100644
*** a/src/backend/storage/ipc/shmem.c
--- b/src/backend/storage/ipc/shmem.c
*************** InitShmemAllocation(void)
*** 117,152 ****
  	Assert(shmhdr != NULL);
  
  	/*
! 	 * If spinlocks are disabled, initialize emulation layer.  We have to do
! 	 * the space allocation the hard way, since obviously ShmemAlloc can't be
! 	 * called yet.
  	 */
! #ifndef HAVE_SPINLOCKS
! 	{
! 		PGSemaphore spinsemas;
  
! 		spinsemas = (PGSemaphore) (((char *) shmhdr) + shmhdr->freeoffset);
! 		shmhdr->freeoffset += MAXALIGN(SpinlockSemaSize());
! 		SpinlockSemaInit(spinsemas);
! 		Assert(shmhdr->freeoffset <= shmhdr->totalsize);
! 	}
! #endif
  
  	/*
! 	 * Initialize the spinlock used by ShmemAlloc; we have to do this the hard
! 	 * way, too, for the same reasons as above.
  	 */
- 	ShmemLock = (slock_t *) (((char *) shmhdr) + shmhdr->freeoffset);
- 	shmhdr->freeoffset += MAXALIGN(sizeof(slock_t));
- 	Assert(shmhdr->freeoffset <= shmhdr->totalsize);
- 
- 	/* Make sure the first allocation begins on a cache line boundary. */
  	aligned = (char *)
  		(CACHELINEALIGN((((char *) shmhdr) + shmhdr->freeoffset)));
  	shmhdr->freeoffset = aligned - (char *) shmhdr;
  
- 	SpinLockInit(ShmemLock);
- 
  	/* ShmemIndex can't be set up yet (need LWLocks first) */
  	shmhdr->index = NULL;
  	ShmemIndex = (HTAB *) NULL;
--- 117,138 ----
  	Assert(shmhdr != NULL);
  
  	/*
! 	 * Initialize the spinlock used by ShmemAlloc.  We must use
! 	 * ShmemAllocUnlocked, since obviously ShmemAlloc can't be called yet.
  	 */
! 	ShmemLock = (slock_t *) ShmemAllocUnlocked(sizeof(slock_t));
  
! 	SpinLockInit(ShmemLock);
  
  	/*
! 	 * Allocations after this point should go through ShmemAlloc, which
! 	 * expects to allocate everything on cache line boundaries.  Make sure the
! 	 * first allocation begins on a cache line boundary.
  	 */
  	aligned = (char *)
  		(CACHELINEALIGN((((char *) shmhdr) + shmhdr->freeoffset)));
  	shmhdr->freeoffset = aligned - (char *) shmhdr;
  
  	/* ShmemIndex can't be set up yet (need LWLocks first) */
  	shmhdr->index = NULL;
  	ShmemIndex = (HTAB *) NULL;
*************** ShmemAllocNoError(Size size)
*** 230,235 ****
--- 216,260 ----
  }
  
  /*
+  * ShmemAllocUnlocked -- allocate max-aligned chunk from shared memory
+  *
+  * Allocate space without locking ShmemLock.  This should be used for,
+  * and only for, allocations that must happen before ShmemLock is ready.
+  *
+  * We consider maxalign, rather than cachealign, sufficient here.
+  */
+ void *
+ ShmemAllocUnlocked(Size size)
+ {
+ 	Size		newStart;
+ 	Size		newFree;
+ 	void	   *newSpace;
+ 
+ 	/*
+ 	 * Ensure allocated space is adequately aligned.
+ 	 */
+ 	size = MAXALIGN(size);
+ 
+ 	Assert(ShmemSegHdr != NULL);
+ 
+ 	newStart = ShmemSegHdr->freeoffset;
+ 
+ 	newFree = newStart + size;
+ 	if (newFree > ShmemSegHdr->totalsize)
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_OUT_OF_MEMORY),
+ 				 errmsg("out of shared memory (%zu bytes requested)",
+ 						size)));
+ 	ShmemSegHdr->freeoffset = newFree;
+ 
+ 	newSpace = (void *) ((char *) ShmemBase + newStart);
+ 
+ 	Assert(newSpace == (void *) MAXALIGN(newSpace));
+ 
+ 	return newSpace;
+ }
+ 
+ /*
   * ShmemAddrIsValid -- test if an address refers to shared memory
   *
   * Returns TRUE if the pointer points within the shared memory segment.
diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c
index ffb2f72..03c4c78 100644
*** a/src/backend/storage/lmgr/lwlock.c
--- b/src/backend/storage/lmgr/lwlock.c
*************** LWLockWakeup(LWLock *lock)
*** 1012,1018 ****
  		 */
  		pg_write_barrier();
  		waiter->lwWaiting = false;
! 		PGSemaphoreUnlock(&waiter->sem);
  	}
  }
  
--- 1012,1018 ----
  		 */
  		pg_write_barrier();
  		waiter->lwWaiting = false;
! 		PGSemaphoreUnlock(waiter->sem);
  	}
  }
  
*************** LWLockDequeueSelf(LWLock *lock)
*** 1129,1135 ****
  		 */
  		for (;;)
  		{
! 			PGSemaphoreLock(&MyProc->sem);
  			if (!MyProc->lwWaiting)
  				break;
  			extraWaits++;
--- 1129,1135 ----
  		 */
  		for (;;)
  		{
! 			PGSemaphoreLock(MyProc->sem);
  			if (!MyProc->lwWaiting)
  				break;
  			extraWaits++;
*************** LWLockDequeueSelf(LWLock *lock)
*** 1139,1145 ****
  		 * Fix the process wait semaphore's count for any absorbed wakeups.
  		 */
  		while (extraWaits-- > 0)
! 			PGSemaphoreUnlock(&MyProc->sem);
  	}
  
  #ifdef LOCK_DEBUG
--- 1139,1145 ----
  		 * Fix the process wait semaphore's count for any absorbed wakeups.
  		 */
  		while (extraWaits-- > 0)
! 			PGSemaphoreUnlock(MyProc->sem);
  	}
  
  #ifdef LOCK_DEBUG
*************** LWLockAcquire(LWLock *lock, LWLockMode m
*** 1283,1289 ****
  
  		for (;;)
  		{
! 			PGSemaphoreLock(&proc->sem);
  			if (!proc->lwWaiting)
  				break;
  			extraWaits++;
--- 1283,1289 ----
  
  		for (;;)
  		{
! 			PGSemaphoreLock(proc->sem);
  			if (!proc->lwWaiting)
  				break;
  			extraWaits++;
*************** LWLockAcquire(LWLock *lock, LWLockMode m
*** 1320,1326 ****
  	 * Fix the process wait semaphore's count for any absorbed wakeups.
  	 */
  	while (extraWaits-- > 0)
! 		PGSemaphoreUnlock(&proc->sem);
  
  	return result;
  }
--- 1320,1326 ----
  	 * Fix the process wait semaphore's count for any absorbed wakeups.
  	 */
  	while (extraWaits-- > 0)
! 		PGSemaphoreUnlock(proc->sem);
  
  	return result;
  }
*************** LWLockAcquireOrWait(LWLock *lock, LWLock
*** 1444,1450 ****
  
  			for (;;)
  			{
! 				PGSemaphoreLock(&proc->sem);
  				if (!proc->lwWaiting)
  					break;
  				extraWaits++;
--- 1444,1450 ----
  
  			for (;;)
  			{
! 				PGSemaphoreLock(proc->sem);
  				if (!proc->lwWaiting)
  					break;
  				extraWaits++;
*************** LWLockAcquireOrWait(LWLock *lock, LWLock
*** 1481,1487 ****
  	 * Fix the process wait semaphore's count for any absorbed wakeups.
  	 */
  	while (extraWaits-- > 0)
! 		PGSemaphoreUnlock(&proc->sem);
  
  	if (mustwait)
  	{
--- 1481,1487 ----
  	 * Fix the process wait semaphore's count for any absorbed wakeups.
  	 */
  	while (extraWaits-- > 0)
! 		PGSemaphoreUnlock(proc->sem);
  
  	if (mustwait)
  	{
*************** LWLockWaitForVar(LWLock *lock, uint64 *v
*** 1662,1668 ****
  
  		for (;;)
  		{
! 			PGSemaphoreLock(&proc->sem);
  			if (!proc->lwWaiting)
  				break;
  			extraWaits++;
--- 1662,1668 ----
  
  		for (;;)
  		{
! 			PGSemaphoreLock(proc->sem);
  			if (!proc->lwWaiting)
  				break;
  			extraWaits++;
*************** LWLockWaitForVar(LWLock *lock, uint64 *v
*** 1692,1698 ****
  	 * Fix the process wait semaphore's count for any absorbed wakeups.
  	 */
  	while (extraWaits-- > 0)
! 		PGSemaphoreUnlock(&proc->sem);
  
  	/*
  	 * Now okay to allow cancel/die interrupts.
--- 1692,1698 ----
  	 * Fix the process wait semaphore's count for any absorbed wakeups.
  	 */
  	while (extraWaits-- > 0)
! 		PGSemaphoreUnlock(proc->sem);
  
  	/*
  	 * Now okay to allow cancel/die interrupts.
*************** LWLockUpdateVar(LWLock *lock, uint64 *va
*** 1759,1765 ****
  		/* check comment in LWLockWakeup() about this barrier */
  		pg_write_barrier();
  		waiter->lwWaiting = false;
! 		PGSemaphoreUnlock(&waiter->sem);
  	}
  }
  
--- 1759,1765 ----
  		/* check comment in LWLockWakeup() about this barrier */
  		pg_write_barrier();
  		waiter->lwWaiting = false;
! 		PGSemaphoreUnlock(waiter->sem);
  	}
  }
  
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 83e9ca1..fc199a6 100644
*** a/src/backend/storage/lmgr/proc.c
--- b/src/backend/storage/lmgr/proc.c
*************** InitProcGlobal(void)
*** 224,230 ****
  		 */
  		if (i < MaxBackends + NUM_AUXILIARY_PROCS)
  		{
! 			PGSemaphoreCreate(&(procs[i].sem));
  			InitSharedLatch(&(procs[i].procLatch));
  			LWLockInitialize(&(procs[i].backendLock), LWTRANCHE_PROC);
  		}
--- 224,230 ----
  		 */
  		if (i < MaxBackends + NUM_AUXILIARY_PROCS)
  		{
! 			procs[i].sem = PGSemaphoreCreate();
  			InitSharedLatch(&(procs[i].procLatch));
  			LWLockInitialize(&(procs[i].backendLock), LWTRANCHE_PROC);
  		}
*************** InitProcess(void)
*** 420,426 ****
  	 * be careful and reinitialize its value here.  (This is not strictly
  	 * necessary anymore, but seems like a good idea for cleanliness.)
  	 */
! 	PGSemaphoreReset(&MyProc->sem);
  
  	/*
  	 * Arrange to clean up at backend exit.
--- 420,426 ----
  	 * be careful and reinitialize its value here.  (This is not strictly
  	 * necessary anymore, but seems like a good idea for cleanliness.)
  	 */
! 	PGSemaphoreReset(MyProc->sem);
  
  	/*
  	 * Arrange to clean up at backend exit.
*************** InitAuxiliaryProcess(void)
*** 575,581 ****
  	 * be careful and reinitialize its value here.  (This is not strictly
  	 * necessary anymore, but seems like a good idea for cleanliness.)
  	 */
! 	PGSemaphoreReset(&MyProc->sem);
  
  	/*
  	 * Arrange to clean up at process exit.
--- 575,581 ----
  	 * be careful and reinitialize its value here.  (This is not strictly
  	 * necessary anymore, but seems like a good idea for cleanliness.)
  	 */
! 	PGSemaphoreReset(MyProc->sem);
  
  	/*
  	 * Arrange to clean up at process exit.
diff --git a/src/backend/storage/lmgr/spin.c b/src/backend/storage/lmgr/spin.c
index 5039141..a6510a0 100644
*** a/src/backend/storage/lmgr/spin.c
--- b/src/backend/storage/lmgr/spin.c
***************
*** 23,33 ****
  #include "postgres.h"
  
  #include "storage/pg_sema.h"
  #include "storage/spin.h"
  
  
  #ifndef HAVE_SPINLOCKS
! PGSemaphore SpinlockSemaArray;
  #endif
  
  /*
--- 23,34 ----
  #include "postgres.h"
  
  #include "storage/pg_sema.h"
+ #include "storage/shmem.h"
  #include "storage/spin.h"
  
  
  #ifndef HAVE_SPINLOCKS
! PGSemaphore *SpinlockSemaArray;
  #endif
  
  /*
*************** PGSemaphore SpinlockSemaArray;
*** 37,43 ****
  Size
  SpinlockSemaSize(void)
  {
! 	return SpinlockSemas() * sizeof(PGSemaphoreData);
  }
  
  #ifdef HAVE_SPINLOCKS
--- 38,44 ----
  Size
  SpinlockSemaSize(void)
  {
! 	return SpinlockSemas() * sizeof(PGSemaphore);
  }
  
  #ifdef HAVE_SPINLOCKS
*************** SpinlockSemas(void)
*** 67,82 ****
  }
  
  /*
!  * Initialize semaphores.
   */
! extern void
! SpinlockSemaInit(PGSemaphore spinsemas)
  {
! 	int			i;
  	int			nsemas = SpinlockSemas();
  
  	for (i = 0; i < nsemas; ++i)
! 		PGSemaphoreCreate(&spinsemas[i]);
  	SpinlockSemaArray = spinsemas;
  }
  
--- 68,91 ----
  }
  
  /*
!  * Initialize spinlock emulation.
!  *
!  * This must be called after PGReserveSemaphores().
   */
! void
! SpinlockSemaInit(void)
  {
! 	PGSemaphore *spinsemas;
  	int			nsemas = SpinlockSemas();
+ 	int			i;
  
+ 	/*
+ 	 * We must use ShmemAllocUnlocked(), since the spinlock protecting
+ 	 * ShmemAlloc() obviously can't be ready yet.
+ 	 */
+ 	spinsemas = (PGSemaphore *) ShmemAllocUnlocked(SpinlockSemaSize());
  	for (i = 0; i < nsemas; ++i)
! 		spinsemas[i] = PGSemaphoreCreate();
  	SpinlockSemaArray = spinsemas;
  }
  
*************** s_unlock_sema(volatile slock_t *lock)
*** 109,115 ****
  
  	if (lockndx <= 0 || lockndx > NUM_SPINLOCK_SEMAPHORES)
  		elog(ERROR, "invalid spinlock number: %d", lockndx);
! 	PGSemaphoreUnlock(&SpinlockSemaArray[lockndx - 1]);
  }
  
  bool
--- 118,124 ----
  
  	if (lockndx <= 0 || lockndx > NUM_SPINLOCK_SEMAPHORES)
  		elog(ERROR, "invalid spinlock number: %d", lockndx);
! 	PGSemaphoreUnlock(SpinlockSemaArray[lockndx - 1]);
  }
  
  bool
*************** tas_sema(volatile slock_t *lock)
*** 128,134 ****
  	if (lockndx <= 0 || lockndx > NUM_SPINLOCK_SEMAPHORES)
  		elog(ERROR, "invalid spinlock number: %d", lockndx);
  	/* Note that TAS macros return 0 if *success* */
! 	return !PGSemaphoreTryLock(&SpinlockSemaArray[lockndx - 1]);
  }
  
  #endif   /* !HAVE_SPINLOCKS */
--- 137,143 ----
  	if (lockndx <= 0 || lockndx > NUM_SPINLOCK_SEMAPHORES)
  		elog(ERROR, "invalid spinlock number: %d", lockndx);
  	/* Note that TAS macros return 0 if *success* */
! 	return !PGSemaphoreTryLock(SpinlockSemaArray[lockndx - 1]);
  }
  
  #endif   /* !HAVE_SPINLOCKS */
diff --git a/src/include/storage/pg_sema.h b/src/include/storage/pg_sema.h
index 2c94183..63546eb 100644
*** a/src/include/storage/pg_sema.h
--- b/src/include/storage/pg_sema.h
***************
*** 21,72 ****
  #define PG_SEMA_H
  
  /*
!  * PGSemaphoreData and pointer type PGSemaphore are the data structure
!  * representing an individual semaphore.  The contents of PGSemaphoreData
!  * vary across implementations and must never be touched by platform-
!  * independent code.  PGSemaphoreData structures are always allocated
!  * in shared memory (to support implementations where the data changes during
!  * lock/unlock).
   *
!  * pg_config.h must define exactly one of the USE_xxx_SEMAPHORES symbols.
   */
! 
! #ifdef USE_NAMED_POSIX_SEMAPHORES
! 
! #include <semaphore.h>
! 
! typedef sem_t *PGSemaphoreData;
! #endif
! 
! #ifdef USE_UNNAMED_POSIX_SEMAPHORES
! 
! #include <semaphore.h>
! 
! typedef sem_t PGSemaphoreData;
! #endif
! 
! #ifdef USE_SYSV_SEMAPHORES
! 
! typedef struct PGSemaphoreData
! {
! 	int			semId;			/* semaphore set identifier */
! 	int			semNum;			/* semaphore number within set */
! } PGSemaphoreData;
! #endif
! 
! #ifdef USE_WIN32_SEMAPHORES
! 
! typedef HANDLE PGSemaphoreData;
  #endif
  
- typedef PGSemaphoreData *PGSemaphore;
  
  
  /* Module initialization (called during postmaster start or shmem reinit) */
  extern void PGReserveSemaphores(int maxSemas, int port);
  
! /* Initialize a PGSemaphore structure to represent a sema with count 1 */
! extern void PGSemaphoreCreate(PGSemaphore sema);
  
  /* Reset a previously-initialized PGSemaphore to have count 0 */
  extern void PGSemaphoreReset(PGSemaphore sema);
--- 21,50 ----
  #define PG_SEMA_H
  
  /*
!  * struct PGSemaphoreData and pointer type PGSemaphore are the data structure
!  * representing an individual semaphore.  The contents of PGSemaphoreData vary
!  * across implementations and must never be touched by platform-independent
!  * code; hence, PGSemaphoreData is declared as an opaque struct here.
   *
!  * However, Windows is sufficiently unlike our other ports that it doesn't
!  * seem worth insisting on ABI compatibility for Windows too.  Hence, on
!  * that platform just define PGSemaphore as HANDLE.
   */
! #ifndef USE_WIN32_SEMAPHORES
! typedef struct PGSemaphoreData *PGSemaphore;
! #else
! typedef HANDLE PGSemaphore;
  #endif
  
  
+ /* Report amount of shared memory needed */
+ extern Size PGSemaphoreShmemSize(int maxSemas);
  
  /* Module initialization (called during postmaster start or shmem reinit) */
  extern void PGReserveSemaphores(int maxSemas, int port);
  
! /* Allocate a PGSemaphore structure with initial count 1 */
! extern PGSemaphore PGSemaphoreCreate(void);
  
  /* Reset a previously-initialized PGSemaphore to have count 0 */
  extern void PGSemaphoreReset(PGSemaphore sema);
diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h
index 6fa7125..0344f42 100644
*** a/src/include/storage/proc.h
--- b/src/include/storage/proc.h
*************** struct PGPROC
*** 87,93 ****
  	SHM_QUEUE	links;			/* list link if process is in a list */
  	PGPROC	  **procgloballist; /* procglobal list that owns this PGPROC */
  
! 	PGSemaphoreData sem;		/* ONE semaphore to sleep on */
  	int			waitStatus;		/* STATUS_WAITING, STATUS_OK or STATUS_ERROR */
  
  	Latch		procLatch;		/* generic latch for process */
--- 87,93 ----
  	SHM_QUEUE	links;			/* list link if process is in a list */
  	PGPROC	  **procgloballist; /* procglobal list that owns this PGPROC */
  
! 	PGSemaphore sem;			/* ONE semaphore to sleep on */
  	int			waitStatus;		/* STATUS_WAITING, STATUS_OK or STATUS_ERROR */
  
  	Latch		procLatch;		/* generic latch for process */
*************** struct PGPROC
*** 116,122 ****
  	proclist_node lwWaitLink;	/* position in LW lock wait list */
  
  	/* Support for condition variables. */
! 	proclist_node	cvWaitLink;	/* position in CV wait list */
  
  	/* Info about lock the process is currently waiting for, if any. */
  	/* waitLock and waitProcLock are NULL if not currently waiting. */
--- 116,122 ----
  	proclist_node lwWaitLink;	/* position in LW lock wait list */
  
  	/* Support for condition variables. */
! 	proclist_node cvWaitLink;	/* position in CV wait list */
  
  	/* Info about lock the process is currently waiting for, if any. */
  	/* waitLock and waitProcLock are NULL if not currently waiting. */
diff --git a/src/include/storage/shmem.h b/src/include/storage/shmem.h
index 2560e6c..e4faebf 100644
*** a/src/include/storage/shmem.h
--- b/src/include/storage/shmem.h
*************** extern void InitShmemAccess(void *seghdr
*** 36,41 ****
--- 36,42 ----
  extern void InitShmemAllocation(void);
  extern void *ShmemAlloc(Size size);
  extern void *ShmemAllocNoError(Size size);
+ extern void *ShmemAllocUnlocked(Size size);
  extern bool ShmemAddrIsValid(const void *addr);
  extern void InitShmemIndex(void);
  extern HTAB *ShmemInitHash(const char *name, long init_size, long max_size,
diff --git a/src/include/storage/spin.h b/src/include/storage/spin.h
index 5041225..b95c9bc 100644
*** a/src/include/storage/spin.h
--- b/src/include/storage/spin.h
*************** extern int	SpinlockSemas(void);
*** 70,77 ****
  extern Size SpinlockSemaSize(void);
  
  #ifndef HAVE_SPINLOCKS
! extern void SpinlockSemaInit(PGSemaphore);
! extern PGSemaphore SpinlockSemaArray;
  #endif
  
  #endif   /* SPIN_H */
--- 70,77 ----
  extern Size SpinlockSemaSize(void);
  
  #ifndef HAVE_SPINLOCKS
! extern void SpinlockSemaInit(void);
! extern PGSemaphore *SpinlockSemaArray;
  #endif
  
  #endif   /* SPIN_H */
