aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/postmaster/postmaster.c9
-rw-r--r--src/backend/storage/ipc/ipci.c1
-rw-r--r--src/backend/storage/ipc/shmem.c21
-rw-r--r--src/backend/storage/lmgr/spin.c52
-rw-r--r--src/include/pg_config_manual.h8
-rw-r--r--src/include/storage/s_lock.h5
-rw-r--r--src/include/storage/spin.h9
7 files changed, 80 insertions, 25 deletions
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 504d98e2b35..b8b51f1e635 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -440,6 +440,9 @@ typedef struct
slock_t *ShmemLock;
VariableCache ShmemVariableCache;
Backend *ShmemBackendArray;
+#ifndef HAVE_SPINLOCKS
+ PGSemaphore SpinlockSemaArray;
+#endif
LWLock *LWLockArray;
slock_t *ProcStructLock;
PROC_HDR *ProcGlobal;
@@ -4927,6 +4930,9 @@ save_backend_variables(BackendParameters *param, Port *port,
param->ShmemVariableCache = ShmemVariableCache;
param->ShmemBackendArray = ShmemBackendArray;
+#ifndef HAVE_SPINLOCKS
+ param->SpinlockSemaArray = SpinlockSemaArray;
+#endif
param->LWLockArray = LWLockArray;
param->ProcStructLock = ProcStructLock;
param->ProcGlobal = ProcGlobal;
@@ -5153,6 +5159,9 @@ restore_backend_variables(BackendParameters *param, Port *port)
ShmemVariableCache = param->ShmemVariableCache;
ShmemBackendArray = param->ShmemBackendArray;
+#ifndef HAVE_SPINLOCKS
+ SpinlockSemaArray = param->SpinlockSemaArray;
+#endif
LWLockArray = param->LWLockArray;
ProcStructLock = param->ProcStructLock;
ProcGlobal = param->ProcGlobal;
diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c
index dded397a617..d50a870d11c 100644
--- a/src/backend/storage/ipc/ipci.c
+++ b/src/backend/storage/ipc/ipci.c
@@ -102,6 +102,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
* need to be so careful during the actual allocation phase.
*/
size = 100000;
+ size = add_size(size, SpinlockSemaSize());
size = add_size(size, hash_estimate_size(SHMEM_INDEX_SIZE,
sizeof(ShmemIndexEnt)));
size = add_size(size, BufferShmemSize());
diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c
index 5868405d063..aa23162bc7f 100644
--- a/src/backend/storage/ipc/shmem.c
+++ b/src/backend/storage/ipc/shmem.c
@@ -116,9 +116,24 @@ InitShmemAllocation(void)
Assert(shmhdr != NULL);
/*
- * Initialize the spinlock used by ShmemAlloc. We have to do the space
- * allocation the hard way, since obviously ShmemAlloc can't be called
- * yet.
+ * 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));
diff --git a/src/backend/storage/lmgr/spin.c b/src/backend/storage/lmgr/spin.c
index 479e71225f9..df3378fb989 100644
--- a/src/backend/storage/lmgr/spin.c
+++ b/src/backend/storage/lmgr/spin.c
@@ -25,9 +25,24 @@
#include "miscadmin.h"
#include "replication/walsender.h"
#include "storage/lwlock.h"
+#include "storage/pg_sema.h"
#include "storage/spin.h"
+#ifndef HAVE_SPINLOCKS
+PGSemaphore SpinlockSemaArray;
+#endif
+
+/*
+ * Report the amount of shared memory needed to store semaphores for spinlock
+ * support.
+ */
+Size
+SpinlockSemaSize(void)
+{
+ return SpinlockSemas() * sizeof(PGSemaphoreData);
+}
+
#ifdef HAVE_SPINLOCKS
/*
@@ -51,21 +66,20 @@ SpinlockSemas(void)
int
SpinlockSemas(void)
{
- int nsemas;
-
- /*
- * It would be cleaner to distribute this logic into the affected modules,
- * similar to the way shmem space estimation is handled.
- *
- * For now, though, there are few enough users of spinlocks that we just
- * keep the knowledge here.
- */
- nsemas = NumLWLocks(); /* one for each lwlock */
- nsemas += NBuffers; /* one for each buffer header */
- nsemas += max_wal_senders; /* one for each wal sender process */
- nsemas += 30; /* plus a bunch for other small-scale use */
-
- return nsemas;
+ return NUM_SPINLOCK_SEMAPHORES;
+}
+
+/*
+ * Initialize semaphores.
+ */
+extern void
+SpinlockSemaInit(PGSemaphore spinsemas)
+{
+ int i;
+
+ for (i = 0; i < NUM_SPINLOCK_SEMAPHORES; ++i)
+ PGSemaphoreCreate(&spinsemas[i]);
+ SpinlockSemaArray = spinsemas;
}
/*
@@ -75,13 +89,15 @@ SpinlockSemas(void)
void
s_init_lock_sema(volatile slock_t *lock)
{
- PGSemaphoreCreate((PGSemaphore) lock);
+ static int counter = 0;
+
+ *lock = (++counter) % NUM_SPINLOCK_SEMAPHORES;
}
void
s_unlock_sema(volatile slock_t *lock)
{
- PGSemaphoreUnlock((PGSemaphore) lock);
+ PGSemaphoreUnlock(&SpinlockSemaArray[*lock]);
}
bool
@@ -96,7 +112,7 @@ int
tas_sema(volatile slock_t *lock)
{
/* Note that TAS macros return 0 if *success* */
- return !PGSemaphoreTryLock((PGSemaphore) lock);
+ return !PGSemaphoreTryLock(&SpinlockSemaArray[*lock]);
}
#endif /* !HAVE_SPINLOCKS */
diff --git a/src/include/pg_config_manual.h b/src/include/pg_config_manual.h
index ee7dab0bd60..5e2ae6f88e7 100644
--- a/src/include/pg_config_manual.h
+++ b/src/include/pg_config_manual.h
@@ -57,6 +57,14 @@
#define NUM_USER_DEFINED_LWLOCKS 4
/*
+ * When we don't have native spinlocks, we use semaphores to simulate them.
+ * Decreasing this value reduces consumption of OS resources; increasing it
+ * may improve performance, but supplying a real spinlock implementation is
+ * probably far better.
+ */
+#define NUM_SPINLOCK_SEMAPHORES 1024
+
+/*
* Define this if you want to allow the lo_import and lo_export SQL
* functions to be executed by ordinary users. By default these
* functions are only available to the Postgres superuser. CAUTION:
diff --git a/src/include/storage/s_lock.h b/src/include/storage/s_lock.h
index b7bed522da3..6a070d4b475 100644
--- a/src/include/storage/s_lock.h
+++ b/src/include/storage/s_lock.h
@@ -93,11 +93,8 @@
#ifndef S_LOCK_H
#define S_LOCK_H
-#include "storage/pg_sema.h"
-
#ifdef HAVE_SPINLOCKS /* skip spinlocks if requested */
-
#if defined(__GNUC__) || defined(__INTEL_COMPILER)
/*************************************************************************
* All the gcc inlines
@@ -1031,7 +1028,7 @@ spin_delay(void)
* to fall foul of kernel limits on number of semaphores, so don't use this
* unless you must! The subroutines appear in spin.c.
*/
-typedef PGSemaphoreData slock_t;
+typedef int slock_t;
extern bool s_lock_free_sema(volatile slock_t *lock);
extern void s_unlock_sema(volatile slock_t *lock);
diff --git a/src/include/storage/spin.h b/src/include/storage/spin.h
index 3f6cacfb0e5..7d793bbcccb 100644
--- a/src/include/storage/spin.h
+++ b/src/include/storage/spin.h
@@ -57,6 +57,9 @@
#define SPIN_H
#include "storage/s_lock.h"
+#ifndef HAVE_SPINLOCKS
+#include "storage/pg_sema.h"
+#endif
#define SpinLockInit(lock) S_INIT_LOCK(lock)
@@ -69,5 +72,11 @@
extern int SpinlockSemas(void);
+extern Size SpinlockSemaSize(void);
+
+#ifndef HAVE_SPINLOCKS
+extern void SpinlockSemaInit(PGSemaphore);
+extern PGSemaphore SpinlockSemaArray;
+#endif
#endif /* SPIN_H */