arch,lib/seqlock: implement seqlock with C++ atomic if compiled with C++
authorKefu Chai <tchaikov@gmail.com>
Wed, 11 Aug 2021 04:29:39 +0000 (12:29 +0800)
committerKefu Chai <tchaikov@gmail.com>
Wed, 25 Aug 2021 16:10:56 +0000 (00:10 +0800)
because some functions declared by <stdatomic.h> share the same names
with those declared by <atomic>, for instance `kill_dependency()` is
defined as a macro by <stdatomic.h>, while it is defined as a template
function in <atomic>.

this renders it impossible to compile an ioengine written in C++ if
its source file includes both <atomic> and <fio.h>. the latter includes
<stdatomic.h> via arch/arch.h. the compile error would look like:

In file included from ../src/test/fio/fio_ceph_objectstore.cc:26:
In file included from src/fio/fio.h:18:
In file included from src/fio/thread_options.h:8:
In file included from src/fio/gettime.h:7:
src/fio/lib/seqlock.h:21:9: error: expected ')'
                seq = atomic_load_acquire(&s->sequence);
                      ^
src/fio/arch/../lib/../arch/arch.h:47:32: note: expanded from macro 'atomic_load_acquire'
        atomic_load_explicit((_Atomic typeof(*(p)) *)(p),       \
                                      ^
src/fio/lib/seqlock.h:21:9: note: to match this '('

to address this issue, instead of using the functions in <stdatomic.h> to
implement seqlock, use the primitives offered by C++ standard library
if the source code is compiled using a C++ compiler.

Signed-off-by: Kefu Chai <tchaikov@gmail.com>
arch/arch.h
lib/seqlock.h

index a25779d4fd8521fe56a38027c182e5c7fcd5a4d5..fca003beabf4e606aa1b80af853f973009e8c7ed 100644 (file)
@@ -1,7 +1,11 @@
 #ifndef ARCH_H
 #define ARCH_H
 
+#ifdef __cplusplus
+#include <atomic>
+#else
 #include <stdatomic.h>
+#endif
 
 #include "../lib/types.h"
 
@@ -36,6 +40,21 @@ extern unsigned long arch_flags;
 
 #define ARCH_CPU_CLOCK_WRAPS
 
+#ifdef __cplusplus
+#define atomic_add(p, v)                                               \
+       std::atomic_fetch_add(p, (v))
+#define atomic_sub(p, v)                                               \
+       std::atomic_fetch_sub(p, (v))
+#define atomic_load_relaxed(p)                                 \
+       std::atomic_load_explicit(p,                            \
+                            std::memory_order_relaxed)
+#define atomic_load_acquire(p)                                 \
+       std::atomic_load_explicit(p,                            \
+                            std::memory_order_acquire)
+#define atomic_store_release(p, v)                             \
+       std::atomic_store_explicit(p, (v),                      \
+                            std::memory_order_release)
+#else
 #define atomic_add(p, v)                                       \
        atomic_fetch_add((_Atomic typeof(*(p)) *)(p), v)
 #define atomic_sub(p, v)                                       \
@@ -49,6 +68,7 @@ extern unsigned long arch_flags;
 #define atomic_store_release(p, v)                             \
        atomic_store_explicit((_Atomic typeof(*(p)) *)(p), (v), \
                              memory_order_release)
+#endif
 
 /* IWYU pragma: begin_exports */
 #if defined(__i386__)
index 56f3e37dab5b35750a390714c3af2d9579de5628..ef3aa0918df461ba3f60cf99b9d2d1f83b17095b 100644 (file)
@@ -5,7 +5,11 @@
 #include "../arch/arch.h"
 
 struct seqlock {
+#ifdef __cplusplus
+       std::atomic<unsigned int> sequence;
+#else
        volatile unsigned int sequence;
+#endif
 };
 
 static inline void seqlock_init(struct seqlock *s)