aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/port/posix_sema.c98
-rw-r--r--src/backend/port/sysv_sema.c51
-rw-r--r--src/backend/port/win32_sema.c38
-rw-r--r--src/backend/postmaster/postmaster.c2
-rw-r--r--src/backend/storage/ipc/ipci.c15
-rw-r--r--src/backend/storage/ipc/procarray.c6
-rw-r--r--src/backend/storage/ipc/shmem.c67
-rw-r--r--src/backend/storage/lmgr/lwlock.c20
-rw-r--r--src/backend/storage/lmgr/proc.c6
-rw-r--r--src/backend/storage/lmgr/spin.c27
-rw-r--r--src/include/storage/pg_sema.h52
-rw-r--r--src/include/storage/proc.h4
-rw-r--r--src/include/storage/shmem.h1
-rw-r--r--src/include/storage/spin.h4
14 files changed, 268 insertions, 123 deletions
diff --git a/src/backend/port/posix_sema.c b/src/backend/port/posix_sema.c
index 2b4b11ce4e5..603dc5a41c2 100644
--- a/src/backend/port/posix_sema.c
+++ b/src/backend/port/posix_sema.c
@@ -6,6 +6,14 @@
* 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,28 +26,38 @@
#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"
-#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)
+/* 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 mySemaPointers array */
+static int maxSems; /* allocated size of above arrays */
static int nextSemKey; /* next name to try */
@@ -134,6 +152,21 @@ PosixSemaphoreKill(sem_t * sem)
/*
+ * 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.
@@ -147,15 +180,33 @@ PosixSemaphoreKill(sem_t * sem)
* 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.
+ * 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;
@@ -173,19 +224,27 @@ ReleaseSemaphores(int status, Datum arg)
{
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
*
- * Initialize a PGSemaphore structure to represent a sema with count 1
+ * Allocate a PGSemaphore structure with initial count 1
*/
-void
-PGSemaphoreCreate(PGSemaphore sema)
+PGSemaphore
+PGSemaphoreCreate(void)
{
+ PGSemaphore sema;
sem_t *newsem;
/* Can't do this in a backend, because static state is postmaster's */
@@ -195,14 +254,19 @@ PGSemaphoreCreate(PGSemaphore sema)
elog(PANIC, "too many semaphores created");
#ifdef USE_NAMED_POSIX_SEMAPHORES
- *sema = newsem = PosixSemaphoreCreate();
+ newsem = PosixSemaphoreCreate();
+ /* Remember new sema for ReleaseSemaphores */
+ mySemPointers[numSems] = newsem;
+ sema = (PGSemaphore) newsem;
#else
- PosixSemaphoreCreate(sema);
- newsem = sema;
+ sema = &sharedSemas[numSems];
+ newsem = PG_SEM_REF(sema);
+ PosixSemaphoreCreate(newsem);
#endif
- /* Remember new sema for ReleaseSemaphores */
- mySemPointers[numSems++] = newsem;
+ numSems++;
+
+ return sema;
}
/*
diff --git a/src/backend/port/sysv_sema.c b/src/backend/port/sysv_sema.c
index f6f15169200..531d4265504 100644
--- a/src/backend/port/sysv_sema.c
+++ b/src/backend/port/sysv_sema.c
@@ -27,8 +27,15 @@
#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
{
@@ -54,6 +61,9 @@ typedef int IpcSemaphoreId; /* semaphore ID returned by semget(2) */
#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 */
@@ -274,6 +284,15 @@ IpcSemaphoreCreate(int numSems)
/*
+ * 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.
@@ -287,12 +306,26 @@ IpcSemaphoreCreate(int numSems)
* 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.
+ * 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));
@@ -323,11 +356,13 @@ ReleaseSemaphores(int status, Datum arg)
/*
* PGSemaphoreCreate
*
- * Initialize a PGSemaphore structure to represent a sema with count 1
+ * Allocate a PGSemaphore structure with initial count 1
*/
-void
-PGSemaphoreCreate(PGSemaphore sema)
+PGSemaphore
+PGSemaphoreCreate(void)
{
+ PGSemaphore sema;
+
/* Can't do this in a backend, because static state is postmaster's */
Assert(!IsUnderPostmaster);
@@ -340,11 +375,17 @@ PGSemaphoreCreate(PGSemaphore sema)
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 c688210e241..c8b12bedbee 100644
--- a/src/backend/port/win32_sema.c
+++ b/src/backend/port/win32_sema.c
@@ -23,6 +23,17 @@ static int maxSems; /* allocated size of mySemaSet array */
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
*
@@ -62,10 +73,10 @@ ReleaseSemaphores(int code, Datum arg)
/*
* PGSemaphoreCreate
*
- * Initialize a PGSemaphore structure to represent a sema with count 1
+ * Allocate a PGSemaphore structure with initial count 1
*/
-void
-PGSemaphoreCreate(PGSemaphore sema)
+PGSemaphore
+PGSemaphoreCreate(void)
{
HANDLE cur_handle;
SECURITY_ATTRIBUTES sec_attrs;
@@ -86,12 +97,14 @@ PGSemaphoreCreate(PGSemaphore sema)
if (cur_handle)
{
/* Successfully done */
- *sema = cur_handle;
mySemSet[numSems++] = cur_handle;
}
else
ereport(PANIC,
- (errmsg("could not create semaphore: error code %lu", GetLastError())));
+ (errmsg("could not create semaphore: error code %lu",
+ GetLastError())));
+
+ return (PGSemaphore) cur_handle;
}
/*
@@ -106,7 +119,8 @@ PGSemaphoreReset(PGSemaphore sema)
* 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));
+ while (PGSemaphoreTryLock(sema))
+ /* loop */ ;
}
/*
@@ -127,7 +141,7 @@ PGSemaphoreLock(PGSemaphore sema)
* pending signals are serviced.
*/
wh[0] = pgwin32_signal_event;
- wh[1] = *sema;
+ wh[1] = sema;
/*
* As in other implementations of PGSemaphoreLock, we need to check for
@@ -182,9 +196,10 @@ PGSemaphoreLock(PGSemaphore sema)
void
PGSemaphoreUnlock(PGSemaphore sema)
{
- if (!ReleaseSemaphore(*sema, 1, NULL))
+ if (!ReleaseSemaphore(sema, 1, NULL))
ereport(FATAL,
- (errmsg("could not unlock semaphore: error code %lu", GetLastError())));
+ (errmsg("could not unlock semaphore: error code %lu",
+ GetLastError())));
}
/*
@@ -197,7 +212,7 @@ PGSemaphoreTryLock(PGSemaphore sema)
{
DWORD ret;
- ret = WaitForSingleObject(*sema, 0);
+ ret = WaitForSingleObject(sema, 0);
if (ret == WAIT_OBJECT_0)
{
@@ -213,7 +228,8 @@ PGSemaphoreTryLock(PGSemaphore sema)
/* Otherwise we are in trouble */
ereport(FATAL,
- (errmsg("could not try-lock semaphore: error code %lu", GetLastError())));
+ (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 16dc075a3a1..535f6c4e5a0 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -484,7 +484,7 @@ typedef struct
VariableCache ShmemVariableCache;
Backend *ShmemBackendArray;
#ifndef HAVE_SPINLOCKS
- PGSemaphore SpinlockSemaArray;
+ PGSemaphore *SpinlockSemaArray;
#endif
int NamedLWLockTrancheRequests;
NamedLWLockTranche *NamedLWLockTrancheArray;
diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c
index 01bddcea16c..29febb46c47 100644
--- a/src/backend/storage/ipc/ipci.c
+++ b/src/backend/storage/ipc/ipci.c
@@ -102,6 +102,10 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
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
@@ -112,6 +116,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
* 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)));
@@ -166,9 +171,15 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
/*
* Create semaphores
*/
- numSemas = ProcGlobalSemas();
- numSemas += SpinlockSemas();
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 e5d487dbb74..bf38470f01d 100644
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -522,7 +522,7 @@ ProcArrayGroupClearXid(PGPROC *proc, TransactionId latestXid)
for (;;)
{
/* acts as a read barrier */
- PGSemaphoreLock(&proc->sem);
+ PGSemaphoreLock(proc->sem);
if (!proc->procArrayGroupMember)
break;
extraWaits++;
@@ -532,7 +532,7 @@ ProcArrayGroupClearXid(PGPROC *proc, TransactionId latestXid)
/* Fix semaphore count for any absorbed wakeups */
while (extraWaits-- > 0)
- PGSemaphoreUnlock(&proc->sem);
+ PGSemaphoreUnlock(proc->sem);
return;
}
@@ -591,7 +591,7 @@ ProcArrayGroupClearXid(PGPROC *proc, TransactionId latestXid)
proc->procArrayGroupMember = false;
if (proc != MyProc)
- PGSemaphoreUnlock(&proc->sem);
+ PGSemaphoreUnlock(proc->sem);
}
}
diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c
index cc3af2d6156..a51619407f4 100644
--- a/src/backend/storage/ipc/shmem.c
+++ b/src/backend/storage/ipc/shmem.c
@@ -117,36 +117,22 @@ InitShmemAllocation(void)
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.
+ * Initialize the spinlock used by ShmemAlloc. We must use
+ * ShmemAllocUnlocked, since obviously ShmemAlloc can't be called yet.
*/
-#ifndef HAVE_SPINLOCKS
- {
- PGSemaphore spinsemas;
+ ShmemLock = (slock_t *) ShmemAllocUnlocked(sizeof(slock_t));
- spinsemas = (PGSemaphore) (((char *) shmhdr) + shmhdr->freeoffset);
- shmhdr->freeoffset += MAXALIGN(SpinlockSemaSize());
- SpinlockSemaInit(spinsemas);
- Assert(shmhdr->freeoffset <= shmhdr->totalsize);
- }
-#endif
+ SpinLockInit(ShmemLock);
/*
- * Initialize the spinlock used by ShmemAlloc; we have to do this the hard
- * way, too, for the same reasons as above.
+ * 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.
*/
- 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;
@@ -230,6 +216,45 @@ ShmemAllocNoError(Size size)
}
/*
+ * 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 ffb2f72953c..03c4c7825eb 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -1012,7 +1012,7 @@ LWLockWakeup(LWLock *lock)
*/
pg_write_barrier();
waiter->lwWaiting = false;
- PGSemaphoreUnlock(&waiter->sem);
+ PGSemaphoreUnlock(waiter->sem);
}
}
@@ -1129,7 +1129,7 @@ LWLockDequeueSelf(LWLock *lock)
*/
for (;;)
{
- PGSemaphoreLock(&MyProc->sem);
+ PGSemaphoreLock(MyProc->sem);
if (!MyProc->lwWaiting)
break;
extraWaits++;
@@ -1139,7 +1139,7 @@ LWLockDequeueSelf(LWLock *lock)
* Fix the process wait semaphore's count for any absorbed wakeups.
*/
while (extraWaits-- > 0)
- PGSemaphoreUnlock(&MyProc->sem);
+ PGSemaphoreUnlock(MyProc->sem);
}
#ifdef LOCK_DEBUG
@@ -1283,7 +1283,7 @@ LWLockAcquire(LWLock *lock, LWLockMode mode)
for (;;)
{
- PGSemaphoreLock(&proc->sem);
+ PGSemaphoreLock(proc->sem);
if (!proc->lwWaiting)
break;
extraWaits++;
@@ -1320,7 +1320,7 @@ LWLockAcquire(LWLock *lock, LWLockMode mode)
* Fix the process wait semaphore's count for any absorbed wakeups.
*/
while (extraWaits-- > 0)
- PGSemaphoreUnlock(&proc->sem);
+ PGSemaphoreUnlock(proc->sem);
return result;
}
@@ -1444,7 +1444,7 @@ LWLockAcquireOrWait(LWLock *lock, LWLockMode mode)
for (;;)
{
- PGSemaphoreLock(&proc->sem);
+ PGSemaphoreLock(proc->sem);
if (!proc->lwWaiting)
break;
extraWaits++;
@@ -1481,7 +1481,7 @@ LWLockAcquireOrWait(LWLock *lock, LWLockMode mode)
* Fix the process wait semaphore's count for any absorbed wakeups.
*/
while (extraWaits-- > 0)
- PGSemaphoreUnlock(&proc->sem);
+ PGSemaphoreUnlock(proc->sem);
if (mustwait)
{
@@ -1662,7 +1662,7 @@ LWLockWaitForVar(LWLock *lock, uint64 *valptr, uint64 oldval, uint64 *newval)
for (;;)
{
- PGSemaphoreLock(&proc->sem);
+ PGSemaphoreLock(proc->sem);
if (!proc->lwWaiting)
break;
extraWaits++;
@@ -1692,7 +1692,7 @@ LWLockWaitForVar(LWLock *lock, uint64 *valptr, uint64 oldval, uint64 *newval)
* Fix the process wait semaphore's count for any absorbed wakeups.
*/
while (extraWaits-- > 0)
- PGSemaphoreUnlock(&proc->sem);
+ PGSemaphoreUnlock(proc->sem);
/*
* Now okay to allow cancel/die interrupts.
@@ -1759,7 +1759,7 @@ LWLockUpdateVar(LWLock *lock, uint64 *valptr, uint64 val)
/* check comment in LWLockWakeup() about this barrier */
pg_write_barrier();
waiter->lwWaiting = false;
- PGSemaphoreUnlock(&waiter->sem);
+ PGSemaphoreUnlock(waiter->sem);
}
}
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 276261bd7b3..e9555f2d8fc 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -224,7 +224,7 @@ InitProcGlobal(void)
*/
if (i < MaxBackends + NUM_AUXILIARY_PROCS)
{
- PGSemaphoreCreate(&(procs[i].sem));
+ procs[i].sem = PGSemaphoreCreate();
InitSharedLatch(&(procs[i].procLatch));
LWLockInitialize(&(procs[i].backendLock), LWTRANCHE_PROC);
}
@@ -420,7 +420,7 @@ InitProcess(void)
* be careful and reinitialize its value here. (This is not strictly
* necessary anymore, but seems like a good idea for cleanliness.)
*/
- PGSemaphoreReset(&MyProc->sem);
+ PGSemaphoreReset(MyProc->sem);
/*
* Arrange to clean up at backend exit.
@@ -575,7 +575,7 @@ InitAuxiliaryProcess(void)
* be careful and reinitialize its value here. (This is not strictly
* necessary anymore, but seems like a good idea for cleanliness.)
*/
- PGSemaphoreReset(&MyProc->sem);
+ 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 50391414305..a6510a07e94 100644
--- a/src/backend/storage/lmgr/spin.c
+++ b/src/backend/storage/lmgr/spin.c
@@ -23,11 +23,12 @@
#include "postgres.h"
#include "storage/pg_sema.h"
+#include "storage/shmem.h"
#include "storage/spin.h"
#ifndef HAVE_SPINLOCKS
-PGSemaphore SpinlockSemaArray;
+PGSemaphore *SpinlockSemaArray;
#endif
/*
@@ -37,7 +38,7 @@ PGSemaphore SpinlockSemaArray;
Size
SpinlockSemaSize(void)
{
- return SpinlockSemas() * sizeof(PGSemaphoreData);
+ return SpinlockSemas() * sizeof(PGSemaphore);
}
#ifdef HAVE_SPINLOCKS
@@ -67,16 +68,24 @@ SpinlockSemas(void)
}
/*
- * Initialize semaphores.
+ * Initialize spinlock emulation.
+ *
+ * This must be called after PGReserveSemaphores().
*/
-extern void
-SpinlockSemaInit(PGSemaphore spinsemas)
+void
+SpinlockSemaInit(void)
{
- int i;
+ 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)
- PGSemaphoreCreate(&spinsemas[i]);
+ spinsemas[i] = PGSemaphoreCreate();
SpinlockSemaArray = spinsemas;
}
@@ -109,7 +118,7 @@ s_unlock_sema(volatile slock_t *lock)
if (lockndx <= 0 || lockndx > NUM_SPINLOCK_SEMAPHORES)
elog(ERROR, "invalid spinlock number: %d", lockndx);
- PGSemaphoreUnlock(&SpinlockSemaArray[lockndx - 1]);
+ PGSemaphoreUnlock(SpinlockSemaArray[lockndx - 1]);
}
bool
@@ -128,7 +137,7 @@ tas_sema(volatile slock_t *lock)
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]);
+ 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 2c9418320e6..63546ebc96a 100644
--- a/src/include/storage/pg_sema.h
+++ b/src/include/storage/pg_sema.h
@@ -21,52 +21,30 @@
#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).
+ * 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.
*
- * pg_config.h must define exactly one of the USE_xxx_SEMAPHORES symbols.
+ * 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.
*/
-
-#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;
+#ifndef USE_WIN32_SEMAPHORES
+typedef struct PGSemaphoreData *PGSemaphore;
+#else
+typedef HANDLE PGSemaphore;
#endif
-typedef PGSemaphoreData *PGSemaphore;
+/* 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);
-/* Initialize a PGSemaphore structure to represent a sema with count 1 */
-extern void PGSemaphoreCreate(PGSemaphore sema);
+/* 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 6fa71253d86..0344f4277c3 100644
--- a/src/include/storage/proc.h
+++ b/src/include/storage/proc.h
@@ -87,7 +87,7 @@ struct PGPROC
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 */
+ PGSemaphore sem; /* ONE semaphore to sleep on */
int waitStatus; /* STATUS_WAITING, STATUS_OK or STATUS_ERROR */
Latch procLatch; /* generic latch for process */
@@ -116,7 +116,7 @@ struct PGPROC
proclist_node lwWaitLink; /* position in LW lock wait list */
/* Support for condition variables. */
- proclist_node cvWaitLink; /* position in CV wait list */
+ 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 2560e6c6da5..e4faebf2b63 100644
--- a/src/include/storage/shmem.h
+++ b/src/include/storage/shmem.h
@@ -36,6 +36,7 @@ extern void InitShmemAccess(void *seghdr);
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 50412258b9e..b95c9bc3334 100644
--- a/src/include/storage/spin.h
+++ b/src/include/storage/spin.h
@@ -70,8 +70,8 @@ extern int SpinlockSemas(void);
extern Size SpinlockSemaSize(void);
#ifndef HAVE_SPINLOCKS
-extern void SpinlockSemaInit(PGSemaphore);
-extern PGSemaphore SpinlockSemaArray;
+extern void SpinlockSemaInit(void);
+extern PGSemaphore *SpinlockSemaArray;
#endif
#endif /* SPIN_H */