memory_order_seq_cst
} memory_order;
+#if _MSC_VER > 1800 && defined(_M_IX86)
+/* From WDK 10 _InlineInterlocked* functions are renamed to
+ * _InlineInterlocked* although the documentation does not specify it */
+#define _InterlockedExchangeAdd64 _InlineInterlockedExchangeAdd64
+#define _InterlockedExchange64 _InlineInterlockedExchange64
+#endif
+
#define ATOMIC_BOOL_LOCK_FREE 2
#define ATOMIC_CHAR_LOCK_FREE 2
#define ATOMIC_SHORT_LOCK_FREE 2
#define atomic_store32(DST, SRC, ORDER) \
if (ORDER == memory_order_seq_cst) { \
- InterlockedExchange((int32_t volatile *) (DST), \
- (int32_t) (SRC)); \
+ InterlockedExchange((long volatile *) (DST), \
+ (long) (SRC)); \
} else { \
*(DST) = (SRC); \
}
-/* 64 bit writes are atomic on i586 if 64 bit aligned. */
+/* MSVC converts 64 bit writes into two instructions. So there is
+ * a possibility that an interrupt can make a 64 bit write non-atomic even
+ * when 8 byte aligned. So use InterlockedExchange64().
+ *
+ * For atomic stores, 'consume' and 'acquire' semantics are not valid. But we
+ * are using 'Exchange' to get atomic stores here and we only have
+ * InterlockedExchange64(), InterlockedExchangeNoFence64() and
+ * InterlockedExchange64Acquire() available. So we are forced to use
+ * InterlockedExchange64() which uses full memory barrier for everything
+ * greater than 'memory_order_relaxed'. */
+#ifdef _M_IX86
#define atomic_store64(DST, SRC, ORDER) \
- if (((size_t) (DST) & (sizeof *(DST) - 1)) \
- || ORDER == memory_order_seq_cst) { \
+ if (ORDER == memory_order_relaxed) { \
+ InterlockedExchangeNoFence64((int64_t volatile *) (DST), \
+ (int64_t) (SRC)); \
+ } else { \
+ InterlockedExchange64((int64_t volatile *) (DST), (int64_t) (SRC));\
+ }
+#elif _M_X64
+/* 64 bit writes are atomic on amd64 if 64 bit aligned. */
+#define atomic_store64(DST, SRC, ORDER) \
+ if (ORDER == memory_order_seq_cst) { \
InterlockedExchange64((int64_t volatile *) (DST), \
- (int64_t) (SRC)); \
+ (int64_t) (SRC)); \
} else { \
*(DST) = (SRC); \
}
+#endif
-/* Used for 8 and 16 bit variations. */
-#define atomic_storeX(X, DST, SRC, ORDER) \
- if (ORDER == memory_order_seq_cst) { \
- InterlockedExchange##X((int##X##_t volatile *) (DST), \
- (int##X##_t) (SRC)); \
- } else { \
- *(DST) = (SRC); \
+#define atomic_store8(DST, SRC, ORDER) \
+ if (ORDER == memory_order_seq_cst) { \
+ InterlockedExchange8((char volatile *) (DST), (char) (SRC)); \
+ } else { \
+ *(DST) = (SRC); \
+ }
+
+#define atomic_store16(DST, SRC, ORDER) \
+ if (ORDER == memory_order_seq_cst) { \
+ InterlockedExchange16((short volatile *) (DST), (short) (SRC)); \
+ } else { \
+ *(DST) = (SRC); \
}
#define atomic_store(DST, SRC) \
#define atomic_store_explicit(DST, SRC, ORDER) \
if (sizeof *(DST) == 1) { \
- atomic_storeX(8, DST, SRC, ORDER) \
+ atomic_store8(DST, SRC, ORDER) \
} else if (sizeof *(DST) == 2) { \
- atomic_storeX(16, DST, SRC, ORDER) \
+ atomic_store16( DST, SRC, ORDER) \
} else if (sizeof *(DST) == 4) { \
atomic_store32(DST, SRC, ORDER) \
} else if (sizeof *(DST) == 8) { \
#define atomic_readX(SRC, DST, ORDER) \
*(DST) = *(SRC);
-/* 64 bit reads are atomic on i586 if 64 bit aligned. */
+/* MSVC converts 64 bit reads into two instructions. So there is
+ * a possibility that an interrupt can make a 64 bit read non-atomic even
+ * when 8 byte aligned. So use fully memory barrier InterlockedOr64(). */
+#ifdef _M_IX86
#define atomic_read64(SRC, DST, ORDER) \
- if (((size_t) (SRC) & (sizeof *(SRC) - 1)) == 0) { \
- *(DST) = *(SRC); \
- } else { \
- *(DST) = InterlockedOr64((int64_t volatile *) (SRC), 0); \
- }
+ __pragma (warning(push)) \
+ __pragma (warning(disable:4047)) \
+ *(DST) = InterlockedOr64((int64_t volatile *) (SRC), 0); \
+ __pragma (warning(pop))
+#elif _M_X64
+/* 64 bit reads are atomic on amd64 if 64 bit aligned. */
+#define atomic_read64(SRC, DST, ORDER) \
+ *(DST) = *(SRC);
+#endif
#define atomic_read(SRC, DST) \
atomic_read_explicit(SRC, DST, memory_order_seq_cst)
/* Arithmetic addition calls. */
-#define atomic_add32(RMW, ARG, ORIG, ORDER) \
- *(ORIG) = InterlockedExchangeAdd((int32_t volatile *) (RMW), \
- (int32_t) (ARG));
+#define atomic_add8(RMW, ARG, ORIG, ORDER) \
+ *(ORIG) = _InterlockedExchangeAdd8((char volatile *) (RMW), \
+ (char) (ARG));
-/* For 8, 16 and 64 bit variations. */
-#define atomic_add_generic(X, RMW, ARG, ORIG, ORDER) \
- *(ORIG) = _InterlockedExchangeAdd##X((int##X##_t volatile *) (RMW), \
- (int##X##_t) (ARG));
+#define atomic_add16(RMW, ARG, ORIG, ORDER) \
+ *(ORIG) = _InterlockedExchangeAdd16((short volatile *) (RMW), \
+ (short) (ARG));
+
+#define atomic_add32(RMW, ARG, ORIG, ORDER) \
+ *(ORIG) = InterlockedExchangeAdd((long volatile *) (RMW), \
+ (long) (ARG));
+#define atomic_add64(RMW, ARG, ORIG, ORDER) \
+ *(ORIG) = _InterlockedExchangeAdd64((int64_t volatile *) (RMW), \
+ (int64_t) (ARG));
#define atomic_add(RMW, ARG, ORIG) \
atomic_add_explicit(RMW, ARG, ORIG, memory_order_seq_cst)
#define atomic_add_explicit(RMW, ARG, ORIG, ORDER) \
if (sizeof *(RMW) == 1) { \
- atomic_op(add, 8, RMW, ARG, ORIG, ORDER) \
+ atomic_add8(RMW, ARG, ORIG, ORDER) \
} else if (sizeof *(RMW) == 2) { \
- atomic_op(add, 16, RMW, ARG, ORIG, ORDER) \
+ atomic_add16(RMW, ARG, ORIG, ORDER) \
} else if (sizeof *(RMW) == 4) { \
atomic_add32(RMW, ARG, ORIG, ORDER) \
} else if (sizeof *(RMW) == 8) { \
- atomic_op(add, 64, RMW, ARG, ORIG, ORDER) \
+ atomic_add64(RMW, ARG, ORIG, ORDER) \
} else { \
abort(); \
}
static inline bool
atomic_compare_exchange8(int8_t volatile *dst, int8_t *expected, int8_t src)
{
- int8_t previous = _InterlockedCompareExchange8(dst, src, *expected);
+ int8_t previous = _InterlockedCompareExchange8((char volatile *)dst,
+ src, *expected);
if (previous == *expected) {
return true;
} else {
atomic_compare_exchange32(int32_t volatile *dst, int32_t *expected,
int32_t src)
{
- int32_t previous = InterlockedCompareExchange(dst, src, *expected);
+ int32_t previous = InterlockedCompareExchange((long volatile *)dst,
+ src, *expected);
if (previous == *expected) {
return true;
} else {