aboutsummaryrefslogtreecommitdiff
path: root/src/backend/port/posix_sema.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/port/posix_sema.c')
-rw-r--r--src/backend/port/posix_sema.c98
1 files changed, 81 insertions, 17 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;
}
/*