1
0
mirror of https://github.com/postgres/postgres.git synced 2026-10-23 13:29:09 +03:00

Better express platform requirements in s_lock.h.

Presently, s_lock.h insists that every platform provide TAS(), and
its header comment doesn't say which of the macros a new platform
actually needs to supply.  The real contract is that a platform
must provide either S_LOCK() or a TAS() for the default S_LOCK() to
be built on.

To better express that, this commit moves the "no spinlock support"
error to where the default S_LOCK() is defined, compiles s_lock()
only when the default S_LOCK() is in use, and provides a default
TAS_SPIN() only when there is a TAS() to base it on.  The direct
callers of s_lock() in the spinlock tests are adjusted to match.
The header comment is reworked accordingly, dropping the note about
pre-9.5 volatile requirements and the caution about TAS()
spuriously failing along the way.

Co-authored-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/afkUeI7UhacZ5ZFm%40nathan
This commit is contained in:
Nathan Bossart
2026-09-28 13:52:42 -05:00
parent e8a82ddeaf
commit d9b5a63f49
3 changed files with 26 additions and 26 deletions

View File

@@ -91,6 +91,7 @@ s_lock_stuck(const char *file, int line, const char *func)
#endif
}
#ifdef USE_DEFAULT_S_LOCK
/*
* s_lock(lock) - platform-independent portion of waiting for a spinlock.
*/
@@ -110,6 +111,7 @@ s_lock(volatile slock_t *lock, const char *file, int line, const char *func)
return delayStatus.delays;
}
#endif
#ifdef USE_DEFAULT_S_UNLOCK
void
@@ -291,7 +293,7 @@ main()
printf(" if S_LOCK() and TAS() are working.\n");
fflush(stdout);
s_lock(&test_lock.lock, __FILE__, __LINE__, __func__);
S_LOCK(&test_lock.lock);
printf("S_LOCK_TEST: failed, lock not locked\n");
return 1;

View File

@@ -44,23 +44,14 @@
* atomic test-and-set only when it appears free.
*
* TAS() and TAS_SPIN() are NOT part of the API, and should never be called
* directly.
*
* CAUTION: on some platforms TAS() and/or TAS_SPIN() may sometimes report
* failure to acquire a lock even when the lock is not locked. For example,
* on Alpha TAS() will "fail" if interrupted. Therefore a retry loop must
* always be used, even if you are certain the lock is free.
* directly. A platform must provide either S_LOCK() or a TAS() for the
* default S_LOCK() to be built on. Currently, all supported platforms do
* the latter, so that is probably the best place to start if adding a new
* one.
*
* It is the responsibility of these macros to make sure that the compiler
* does not re-order accesses to shared memory to precede the actual lock
* acquisition, or follow the lock release. Prior to PostgreSQL 9.5, this
* was the caller's responsibility, which meant that callers had to use
* volatile-qualified pointers to refer to both the spinlock itself and the
* shared data being accessed within the spinlocked critical section. This
* was notationally awkward, easy to forget (and thus error-prone), and
* prevented some useful compiler optimizations. For these reasons, we
* now require that the macros themselves prevent compiler re-ordering,
* so that the caller doesn't need to take special precautions.
* acquisition, or follow the lock release.
*
* On platforms with weak memory ordering, the TAS(), TAS_SPIN(), and
* S_UNLOCK() macros must further include hardware-level memory fence
@@ -72,7 +63,7 @@
*
* On most supported platforms, TAS() uses a tas() function written
* in assembly language to execute a hardware atomic-test-and-set
* instruction. Equivalent OS-supplied mutex routines could be used too.
* instruction. Equivalent compiler intrinsics are another popular option.
*
*
* Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
@@ -642,19 +633,23 @@ spin_delay(void)
#endif /* !defined(TAS) */
/* Blow up if we didn't have any way to do spinlocks */
#ifndef TAS
#error PostgreSQL does not have spinlock support on this platform. Please report this to pgsql-bugs@lists.postgresql.org.
#endif
/*
* Default Definitions - override these above as needed.
*/
/*
* Make sure S_LOCK is defined, either explicitly for the platform or via a TAS
* macro for the platform.
*/
#if !defined(S_LOCK)
#ifdef TAS
#define USE_DEFAULT_S_LOCK
extern int s_lock(volatile slock_t *lock, const char *file, int line, const char *func);
#define S_LOCK(lock) \
(TAS(lock) ? s_lock((lock), __FILE__, __LINE__, __func__) : 0)
#else
#error PostgreSQL does not have spinlock support on this platform. Please report this to pgsql-bugs@lists.postgresql.org.
#endif /* TAS */
#endif /* S_LOCK */
#if !defined(S_UNLOCK)
@@ -687,15 +682,18 @@ extern void s_unlock(volatile slock_t *lock);
#define SPIN_DELAY() ((void) 0)
#endif /* SPIN_DELAY */
#if !defined(TAS_SPIN)
/*
* TAS_SPIN is only needed by the default S_LOCK's helper function (s_lock()),
* so we only provide a default when there is a TAS to base it on.
*/
#if !defined(TAS_SPIN) && defined(TAS)
#define TAS_SPIN(lock) TAS(lock)
#endif /* TAS_SPIN */
#endif /* ! TAS_SPIN && TAS */
/*
* Platform-independent out-of-line support routines
*/
extern int s_lock(volatile slock_t *lock, const char *file, int line, const char *func);
/* Support for dynamic adjustment of spins_per_delay */
#define DEFAULT_SPINS_PER_DELAY 100

View File

@@ -675,7 +675,7 @@ test_spinlock(void)
S_UNLOCK(&struct_w_lock.lock);
/* and that "contended" acquisition works */
s_lock(&struct_w_lock.lock, "testfile", 17, "testfunc");
S_LOCK(&struct_w_lock.lock);
S_UNLOCK(&struct_w_lock.lock);
/*