mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
7822917fc2
You can now do things like implement mutexes using futexes in your redbean lua code. This provides the fastest possible inter-process communication for your production systems when SQLite alone as ipc or things like pipes aren't sufficient.
114 lines
4.8 KiB
C
114 lines
4.8 KiB
C
#ifndef NSYNC_ATOMIC_INTERNAL_H_
|
|
#define NSYNC_ATOMIC_INTERNAL_H_
|
|
#include "libc/intrin/atomic.h"
|
|
#include "libc/intrin/cmpxchg.h"
|
|
#include "third_party/nsync/atomic.h"
|
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
|
COSMOPOLITAN_C_START_
|
|
|
|
/* Atomic operations on nsync_atomic_uint32_ quantities
|
|
CAS, load, and store.
|
|
|
|
Normally, these are used only on nsync_atomic_uint32_ values, but on
|
|
Linux they may be invoked on int values, because futexes operate on
|
|
int values. A compile-time check in the futex code ensures that both
|
|
int and nsync_atomic_uint32_ are 32 bits.
|
|
|
|
Memory barriers:
|
|
|
|
Operations with the suffixes _ACQ and _RELACQ ensure that the
|
|
operation appears to complete before other memory operations
|
|
subsequently performed by the same thread, as seen by other
|
|
threads. (In the case of ATM_CAS_ACQ, this applies only if
|
|
the operation returns a non-zero value.)
|
|
|
|
Operations with the suffixes _REL and _RELACQ ensure that the
|
|
operation appears to complete after other memory operations
|
|
previously performed by the same thread, as seen by other
|
|
threads. (In the case of ATM_CAS_REL, this applies only if
|
|
the operation returns a non-zero value.)
|
|
|
|
// Atomically,
|
|
// int ATM_CAS (nsync_atomic_uint32_ *p,
|
|
// uint32_t old_value, uint32_t new_value) {
|
|
// if (*p == old_value) {
|
|
// *p = new_value;
|
|
// return (some-non-zero-value);
|
|
// } else {
|
|
// return (0);
|
|
// }
|
|
// }
|
|
// *_ACQ, *_REL, *_RELACQ variants are available,
|
|
// with the barrier semantics described above.
|
|
int ATM_CAS (nsync_atomic_uint32_ *p, uint32_t old_value,
|
|
uint32_t new_value);
|
|
|
|
// Atomically,
|
|
// uint32_t ATM_LOAD (nsync_atomic_uint32_ *p) { return (*p); }
|
|
// A *_ACQ variant is available,
|
|
// with the barrier semantics described above.
|
|
uint32_t ATM_LOAD (nsync_atomic_uint32_ *p);
|
|
|
|
// Atomically,
|
|
// void ATM_STORE (nsync_atomic_uint32_ *p, uint32_t value) {
|
|
// *p = value;
|
|
// }
|
|
// A *_REL variant is available,
|
|
// with the barrier semantics described above.
|
|
void ATM_STORE (nsync_atomic_uint32_ *p, uint32_t value);
|
|
*/
|
|
|
|
static inline int atm_cas_nomb_u32_(nsync_atomic_uint32_ *p, uint32_t o,
|
|
uint32_t n) {
|
|
return atomic_compare_exchange_strong_explicit(NSYNC_ATOMIC_UINT32_PTR_(p),
|
|
&o, n, memory_order_relaxed,
|
|
memory_order_relaxed);
|
|
}
|
|
|
|
static inline int atm_cas_acq_u32_(nsync_atomic_uint32_ *p, uint32_t o,
|
|
uint32_t n) {
|
|
return atomic_compare_exchange_strong_explicit(NSYNC_ATOMIC_UINT32_PTR_(p),
|
|
&o, n, memory_order_acquire,
|
|
memory_order_relaxed);
|
|
}
|
|
|
|
static inline int atm_cas_rel_u32_(nsync_atomic_uint32_ *p, uint32_t o,
|
|
uint32_t n) {
|
|
return atomic_compare_exchange_strong_explicit(NSYNC_ATOMIC_UINT32_PTR_(p),
|
|
&o, n, memory_order_release,
|
|
memory_order_relaxed);
|
|
}
|
|
|
|
static inline int atm_cas_relacq_u32_(nsync_atomic_uint32_ *p, uint32_t o,
|
|
uint32_t n) {
|
|
return atomic_compare_exchange_strong_explicit(NSYNC_ATOMIC_UINT32_PTR_(p),
|
|
&o, n, memory_order_acq_rel,
|
|
memory_order_relaxed);
|
|
}
|
|
|
|
#define ATM_CAS_HELPER_(barrier, p, o, n) \
|
|
(atm_cas_##barrier##_u32_((p), (o), (n)))
|
|
|
|
#define ATM_CAS(p, o, n) ATM_CAS_HELPER_(nomb, (p), (o), (n))
|
|
#define ATM_CAS_ACQ(p, o, n) ATM_CAS_HELPER_(acq, (p), (o), (n))
|
|
#define ATM_CAS_REL(p, o, n) ATM_CAS_HELPER_(rel, (p), (o), (n))
|
|
#define ATM_CAS_RELACQ(p, o, n) ATM_CAS_HELPER_(relacq, (p), (o), (n))
|
|
|
|
/* Need a cast to remove "const" from some uses. */
|
|
#define ATM_LOAD(p) \
|
|
(atomic_load_explicit((nsync_atomic_uint32_ *)NSYNC_ATOMIC_UINT32_PTR_(p), \
|
|
memory_order_relaxed))
|
|
#define ATM_LOAD_ACQ(p) \
|
|
(atomic_load_explicit((nsync_atomic_uint32_ *)NSYNC_ATOMIC_UINT32_PTR_(p), \
|
|
memory_order_acquire))
|
|
|
|
#define ATM_STORE(p, v) \
|
|
(atomic_store_explicit(NSYNC_ATOMIC_UINT32_PTR_(p), (v), \
|
|
memory_order_relaxed))
|
|
#define ATM_STORE_REL(p, v) \
|
|
(atomic_store_explicit(NSYNC_ATOMIC_UINT32_PTR_(p), (v), \
|
|
memory_order_release))
|
|
|
|
COSMOPOLITAN_C_END_
|
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
|
#endif /* NSYNC_ATOMIC_INTERNAL_H_ */
|