mirror of
https://github.com/postgres/postgres.git
synced 2025-12-04 12:02:48 +03:00
If the compiler/arch combination does not provide compiler barriers, provide a fallback. That fallback simply consists out of a function call into a externally defined function. That should guarantee compiler barrierer semantics except for compilers that do inter translation unit/global optimization - those better provide an actual compiler barrier. Hopefully this fixes Tom's report of linker failures due to pg_compiler_barrier_impl not being provided. I'm not backpatching this commit as it builds on the new atomics infrastructure. If we decide an equivalent fix needs to be backpatched, I'll do so in a separate commit. Discussion: 27746.1420930690@sss.pgh.pa.us Per report from Tom Lane.
136 lines
3.2 KiB
C
136 lines
3.2 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* atomics.c
|
|
* Non-Inline parts of the atomics implementation
|
|
*
|
|
* Portions Copyright (c) 2013-2015, PostgreSQL Global Development Group
|
|
*
|
|
*
|
|
* IDENTIFICATION
|
|
* src/backend/port/atomics.c
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
#include "postgres.h"
|
|
|
|
/*
|
|
* We want the functions below to be inline; but if the compiler doesn't
|
|
* support that, fall back on providing them as regular functions. See
|
|
* STATIC_IF_INLINE in c.h.
|
|
*/
|
|
#define ATOMICS_INCLUDE_DEFINITIONS
|
|
|
|
#include "port/atomics.h"
|
|
#include "storage/spin.h"
|
|
|
|
#ifdef PG_HAVE_MEMORY_BARRIER_EMULATION
|
|
void
|
|
pg_spinlock_barrier(void)
|
|
{
|
|
S_LOCK(&dummy_spinlock);
|
|
S_UNLOCK(&dummy_spinlock);
|
|
}
|
|
#endif
|
|
|
|
#ifdef PG_HAVE_COMPILER_BARRIER_EMULATION
|
|
void
|
|
pg_extern_compiler_barrier(void)
|
|
{
|
|
/* do nothing */
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef PG_HAVE_ATOMIC_FLAG_SIMULATION
|
|
|
|
void
|
|
pg_atomic_init_flag_impl(volatile pg_atomic_flag *ptr)
|
|
{
|
|
StaticAssertStmt(sizeof(ptr->sema) >= sizeof(slock_t),
|
|
"size mismatch of atomic_flag vs slock_t");
|
|
|
|
#ifndef HAVE_SPINLOCKS
|
|
/*
|
|
* NB: If we're using semaphore based TAS emulation, be careful to use a
|
|
* separate set of semaphores. Otherwise we'd get in trouble if a atomic
|
|
* var would be manipulated while spinlock is held.
|
|
*/
|
|
s_init_lock_sema((slock_t *) &ptr->sema, true);
|
|
#else
|
|
SpinLockInit((slock_t *) &ptr->sema);
|
|
#endif
|
|
}
|
|
|
|
bool
|
|
pg_atomic_test_set_flag_impl(volatile pg_atomic_flag *ptr)
|
|
{
|
|
return TAS((slock_t *) &ptr->sema);
|
|
}
|
|
|
|
void
|
|
pg_atomic_clear_flag_impl(volatile pg_atomic_flag *ptr)
|
|
{
|
|
S_UNLOCK((slock_t *) &ptr->sema);
|
|
}
|
|
|
|
#endif /* PG_HAVE_ATOMIC_FLAG_SIMULATION */
|
|
|
|
#ifdef PG_HAVE_ATOMIC_U32_SIMULATION
|
|
void
|
|
pg_atomic_init_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 val_)
|
|
{
|
|
StaticAssertStmt(sizeof(ptr->sema) >= sizeof(slock_t),
|
|
"size mismatch of atomic_flag vs slock_t");
|
|
|
|
/*
|
|
* If we're using semaphore based atomic flags, be careful about nested
|
|
* usage of atomics while a spinlock is held.
|
|
*/
|
|
#ifndef HAVE_SPINLOCKS
|
|
s_init_lock_sema((slock_t *) &ptr->sema, true);
|
|
#else
|
|
SpinLockInit((slock_t *) &ptr->sema);
|
|
#endif
|
|
ptr->value = val_;
|
|
}
|
|
|
|
bool
|
|
pg_atomic_compare_exchange_u32_impl(volatile pg_atomic_uint32 *ptr,
|
|
uint32 *expected, uint32 newval)
|
|
{
|
|
bool ret;
|
|
/*
|
|
* Do atomic op under a spinlock. It might look like we could just skip
|
|
* the cmpxchg if the lock isn't available, but that'd just emulate a
|
|
* 'weak' compare and swap. I.e. one that allows spurious failures. Since
|
|
* several algorithms rely on a strong variant and that is efficiently
|
|
* implementable on most major architectures let's emulate it here as
|
|
* well.
|
|
*/
|
|
SpinLockAcquire((slock_t *) &ptr->sema);
|
|
|
|
/* perform compare/exchange logic*/
|
|
ret = ptr->value == *expected;
|
|
*expected = ptr->value;
|
|
if (ret)
|
|
ptr->value = newval;
|
|
|
|
/* and release lock */
|
|
SpinLockRelease((slock_t *) &ptr->sema);
|
|
|
|
return ret;
|
|
}
|
|
|
|
uint32
|
|
pg_atomic_fetch_add_u32_impl(volatile pg_atomic_uint32 *ptr, int32 add_)
|
|
{
|
|
uint32 oldval;
|
|
SpinLockAcquire((slock_t *) &ptr->sema);
|
|
oldval = ptr->value;
|
|
ptr->value += add_;
|
|
SpinLockRelease((slock_t *) &ptr->sema);
|
|
return oldval;
|
|
}
|
|
|
|
#endif /* PG_HAVE_ATOMIC_U32_SIMULATION */
|