]> git.proxmox.com Git - mirror_ovs.git/blobdiff - lib/ovs-atomic-msvc.h
stopwatch: Remove tabs from output.
[mirror_ovs.git] / lib / ovs-atomic-msvc.h
index 11f5ad23990c17435c71d52855e402dcadc6873f..9def887d34364e919d10532e586d874d5ed10c6a 100644 (file)
@@ -41,6 +41,13 @@ typedef enum {
     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
@@ -91,29 +98,53 @@ atomic_signal_fence(memory_order order)
 
 #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)                               \
@@ -121,9 +152,9 @@ atomic_signal_fence(memory_order order)
 
 #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) {                                     \
@@ -149,13 +180,20 @@ atomic_signal_fence(memory_order order)
 #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)
@@ -181,27 +219,33 @@ atomic_signal_fence(memory_order order)
 
 /* 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();                                               \
     }
@@ -307,7 +351,8 @@ atomic_signal_fence(memory_order order)
 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 {
@@ -333,7 +378,8 @@ static inline bool
 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 {