Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'intern/atomic/intern/atomic_ops_unix.h')
-rw-r--r--intern/atomic/intern/atomic_ops_unix.h223
1 files changed, 203 insertions, 20 deletions
diff --git a/intern/atomic/intern/atomic_ops_unix.h b/intern/atomic/intern/atomic_ops_unix.h
index b08a0e9bc28..dcafbc67949 100644
--- a/intern/atomic/intern/atomic_ops_unix.h
+++ b/intern/atomic/intern/atomic_ops_unix.h
@@ -60,9 +60,108 @@
# define JE_FORCE_SYNC_COMPARE_AND_SWAP_8
#endif
-/******************************************************************************/
-/* 64-bit operations. */
-#if (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) || defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_8))
+/* Define the `ATOMIC_FORCE_USE_FALLBACK` to force lock-based fallback implementation to be used
+ * (even on platforms where there is native implementation available via compiler.
+ * Useful for development purposes. */
+#undef ATOMIC_FORCE_USE_FALLBACK
+
+/* -------------------------------------------------------------------- */
+/** \name Spin-lock implementation
+ *
+ * Used to implement atomics on unsupported platforms.
+ * The spin implementation is shared for all platforms to make sure it compiles and tested.
+ * \{ */
+
+typedef struct AtomicSpinLock {
+ volatile int lock;
+
+ /* Pad the structure size to a cache-line, to avoid unwanted sharing with other data. */
+ int pad[32 - sizeof(int)];
+} __attribute__((aligned(32))) AtomicSpinLock;
+
+ATOMIC_INLINE void atomic_spin_lock(volatile AtomicSpinLock *lock)
+{
+ while (__sync_lock_test_and_set(&lock->lock, 1)) {
+ while (lock->lock) {
+ }
+ }
+}
+
+ATOMIC_INLINE void atomic_spin_unlock(volatile AtomicSpinLock *lock)
+{
+ __sync_lock_release(&lock->lock);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Common part of locking fallback implementation
+ * \{ */
+
+/* Global lock, shared by all atomic operations implementations.
+ *
+ * Could be split into per-size locks, although added complexity and being more error-proone does
+ * not seem to worth it for a fall-back implementation. */
+static _ATOMIC_MAYBE_UNUSED AtomicSpinLock _atomic_global_lock = {0};
+
+#define ATOMIC_LOCKING_OP_AND_FETCH_DEFINE(_type, _op_name, _op) \
+ ATOMIC_INLINE _type##_t atomic_##_op_name##_and_fetch_##_type(_type##_t *p, _type##_t x) \
+ { \
+ atomic_spin_lock(&_atomic_global_lock); \
+ const _type##_t original_value = *(p); \
+ const _type##_t new_value = original_value _op(x); \
+ *(p) = new_value; \
+ atomic_spin_unlock(&_atomic_global_lock); \
+ return new_value; \
+ }
+
+#define ATOMIC_LOCKING_FETCH_AND_OP_DEFINE(_type, _op_name, _op) \
+ ATOMIC_INLINE _type##_t atomic_fetch_and_##_op_name##_##_type(_type##_t *p, _type##_t x) \
+ { \
+ atomic_spin_lock(&_atomic_global_lock); \
+ const _type##_t original_value = *(p); \
+ *(p) = original_value _op(x); \
+ atomic_spin_unlock(&_atomic_global_lock); \
+ return original_value; \
+ }
+
+#define ATOMIC_LOCKING_ADD_AND_FETCH_DEFINE(_type) \
+ ATOMIC_LOCKING_OP_AND_FETCH_DEFINE(_type, add, +)
+
+#define ATOMIC_LOCKING_SUB_AND_FETCH_DEFINE(_type) \
+ ATOMIC_LOCKING_OP_AND_FETCH_DEFINE(_type, sub, -)
+
+#define ATOMIC_LOCKING_FETCH_AND_ADD_DEFINE(_type) \
+ ATOMIC_LOCKING_FETCH_AND_OP_DEFINE(_type, add, +)
+
+#define ATOMIC_LOCKING_FETCH_AND_SUB_DEFINE(_type) \
+ ATOMIC_LOCKING_FETCH_AND_OP_DEFINE(_type, sub, -)
+
+#define ATOMIC_LOCKING_FETCH_AND_OR_DEFINE(_type) ATOMIC_LOCKING_FETCH_AND_OP_DEFINE(_type, or, |)
+
+#define ATOMIC_LOCKING_FETCH_AND_AND_DEFINE(_type) \
+ ATOMIC_LOCKING_FETCH_AND_OP_DEFINE(_type, and, &)
+
+#define ATOMIC_LOCKING_CAS_DEFINE(_type) \
+ ATOMIC_INLINE _type##_t atomic_cas_##_type(_type##_t *v, _type##_t old, _type##_t _new) \
+ { \
+ atomic_spin_lock(&_atomic_global_lock); \
+ const _type##_t original_value = *v; \
+ if (*v == old) { \
+ *v = _new; \
+ } \
+ atomic_spin_unlock(&_atomic_global_lock); \
+ return original_value; \
+ }
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name 64-bit operations
+ * \{ */
+
+#if !defined(ATOMIC_FORCE_USE_FALLBACK) && \
+ (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) || defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_8))
/* Unsigned */
ATOMIC_INLINE uint64_t atomic_add_and_fetch_uint64(uint64_t *p, uint64_t x)
{
@@ -115,7 +214,7 @@ ATOMIC_INLINE int64_t atomic_cas_int64(int64_t *v, int64_t old, int64_t _new)
return __sync_val_compare_and_swap(v, old, _new);
}
-#elif (defined(__amd64__) || defined(__x86_64__))
+#elif !defined(ATOMIC_FORCE_USE_FALLBACK) && (defined(__amd64__) || defined(__x86_64__))
/* Unsigned */
ATOMIC_INLINE uint64_t atomic_fetch_and_add_uint64(uint64_t *p, uint64_t x)
{
@@ -190,12 +289,36 @@ ATOMIC_INLINE int64_t atomic_cas_int64(int64_t *v, int64_t old, int64_t _new)
return ret;
}
#else
-# error "Missing implementation for 64-bit atomic operations"
+
+/* Unsigned */
+
+ATOMIC_LOCKING_ADD_AND_FETCH_DEFINE(uint64)
+ATOMIC_LOCKING_SUB_AND_FETCH_DEFINE(uint64)
+
+ATOMIC_LOCKING_FETCH_AND_ADD_DEFINE(uint64)
+ATOMIC_LOCKING_FETCH_AND_SUB_DEFINE(uint64)
+
+ATOMIC_LOCKING_CAS_DEFINE(uint64)
+
+/* Signed */
+ATOMIC_LOCKING_ADD_AND_FETCH_DEFINE(int64)
+ATOMIC_LOCKING_SUB_AND_FETCH_DEFINE(int64)
+
+ATOMIC_LOCKING_FETCH_AND_ADD_DEFINE(int64)
+ATOMIC_LOCKING_FETCH_AND_SUB_DEFINE(int64)
+
+ATOMIC_LOCKING_CAS_DEFINE(int64)
+
#endif
-/******************************************************************************/
-/* 32-bit operations. */
-#if (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_4))
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name 32-bit operations
+ * \{ */
+
+#if !defined(ATOMIC_FORCE_USE_FALLBACK) && \
+ (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_4))
/* Unsigned */
ATOMIC_INLINE uint32_t atomic_add_and_fetch_uint32(uint32_t *p, uint32_t x)
{
@@ -228,7 +351,8 @@ ATOMIC_INLINE int32_t atomic_cas_int32(int32_t *v, int32_t old, int32_t _new)
return __sync_val_compare_and_swap(v, old, _new);
}
-#elif (defined(__i386__) || defined(__amd64__) || defined(__x86_64__))
+#elif !defined(ATOMIC_FORCE_USE_FALLBACK) && \
+ (defined(__i386__) || defined(__amd64__) || defined(__x86_64__))
/* Unsigned */
ATOMIC_INLINE uint32_t atomic_add_and_fetch_uint32(uint32_t *p, uint32_t x)
{
@@ -286,10 +410,25 @@ ATOMIC_INLINE int32_t atomic_cas_int32(int32_t *v, int32_t old, int32_t _new)
}
#else
-# error "Missing implementation for 32-bit atomic operations"
+
+/* Unsigned */
+
+ATOMIC_LOCKING_ADD_AND_FETCH_DEFINE(uint32)
+ATOMIC_LOCKING_SUB_AND_FETCH_DEFINE(uint32)
+
+ATOMIC_LOCKING_CAS_DEFINE(uint32)
+
+/* Signed */
+
+ATOMIC_LOCKING_ADD_AND_FETCH_DEFINE(int32)
+ATOMIC_LOCKING_SUB_AND_FETCH_DEFINE(int32)
+
+ATOMIC_LOCKING_CAS_DEFINE(int32)
+
#endif
-#if (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_4))
+#if !defined(ATOMIC_FORCE_USE_FALLBACK) && \
+ (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_4))
/* Unsigned */
ATOMIC_INLINE uint32_t atomic_fetch_and_add_uint32(uint32_t *p, uint32_t x)
{
@@ -323,12 +462,27 @@ ATOMIC_INLINE int32_t atomic_fetch_and_and_int32(int32_t *p, int32_t x)
}
#else
-# error "Missing implementation for 32-bit atomic operations"
+
+/* Unsigned */
+ATOMIC_LOCKING_FETCH_AND_ADD_DEFINE(uint32)
+ATOMIC_LOCKING_FETCH_AND_OR_DEFINE(uint32)
+ATOMIC_LOCKING_FETCH_AND_AND_DEFINE(uint32)
+
+/* Signed */
+ATOMIC_LOCKING_FETCH_AND_ADD_DEFINE(int32)
+ATOMIC_LOCKING_FETCH_AND_OR_DEFINE(int32)
+ATOMIC_LOCKING_FETCH_AND_AND_DEFINE(int32)
+
#endif
-/******************************************************************************/
-/* 16-bit operations. */
-#if (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) || defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_2))
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name 16-bit operations
+ * \{ */
+
+#if !defined(ATOMIC_FORCE_USE_FALLBACK) && \
+ (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) || defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_2))
/* Signed */
ATOMIC_INLINE int16_t atomic_fetch_and_and_int16(int16_t *p, int16_t b)
@@ -341,12 +495,21 @@ ATOMIC_INLINE int16_t atomic_fetch_and_or_int16(int16_t *p, int16_t b)
}
#else
-# error "Missing implementation for 16-bit atomic operations"
+
+ATOMIC_LOCKING_FETCH_AND_AND_DEFINE(int16)
+ATOMIC_LOCKING_FETCH_AND_OR_DEFINE(int16)
+
#endif
-/******************************************************************************/
-/* 8-bit operations. */
-#if (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1) || defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_1))
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name 8-bit operations
+ * \{ */
+
+#if !defined(ATOMIC_FORCE_USE_FALLBACK) && \
+ (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1) || defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_1))
+
/* Unsigned */
ATOMIC_INLINE uint8_t atomic_fetch_and_and_uint8(uint8_t *p, uint8_t b)
{
@@ -368,7 +531,27 @@ ATOMIC_INLINE int8_t atomic_fetch_and_or_int8(int8_t *p, int8_t b)
}
#else
-# error "Missing implementation for 8-bit atomic operations"
+
+/* Unsigned */
+ATOMIC_LOCKING_FETCH_AND_AND_DEFINE(uint8)
+ATOMIC_LOCKING_FETCH_AND_OR_DEFINE(uint8)
+
+/* Signed */
+ATOMIC_LOCKING_FETCH_AND_AND_DEFINE(int8)
+ATOMIC_LOCKING_FETCH_AND_OR_DEFINE(int8)
+
#endif
+/** \} */
+
+#undef ATOMIC_LOCKING_OP_AND_FETCH_DEFINE
+#undef ATOMIC_LOCKING_FETCH_AND_OP_DEFINE
+#undef ATOMIC_LOCKING_ADD_AND_FETCH_DEFINE
+#undef ATOMIC_LOCKING_SUB_AND_FETCH_DEFINE
+#undef ATOMIC_LOCKING_FETCH_AND_ADD_DEFINE
+#undef ATOMIC_LOCKING_FETCH_AND_SUB_DEFINE
+#undef ATOMIC_LOCKING_FETCH_AND_OR_DEFINE
+#undef ATOMIC_LOCKING_FETCH_AND_AND_DEFINE
+#undef ATOMIC_LOCKING_CAS_DEFINE
+
#endif /* __ATOMIC_OPS_UNIX_H__ */