This is an automated email from the ASF dual-hosted git repository.

chenBright pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/brpc.git


The following commit(s) were added to refs/heads/master by this push:
     new 1d3ada37 bthread: implement lock-free AtomicInteger128 for RISC-V 
(#3355)
1d3ada37 is described below

commit 1d3ada378b76178ba5108255d3b555ff0c2dfaf3
Author: Felix-Gong <[email protected]>
AuthorDate: Tue Jul 7 14:13:24 2026 +0800

    bthread: implement lock-free AtomicInteger128 for RISC-V (#3355)
    
    * bthread: implement lock-free AtomicInteger128 for RISC-V
    
    Replace mutex-based fallback with seqlock implementation for RISC-V
    platform. This brings RISC-V in line with x86 (SSE) and ARM (NEON)
    lock-free implementations.
    
    Seqlock algorithm:
    - Reader: read sequence, read data, verify sequence, retry if stale
    - Writer: increment sequence, write data, increment sequence
    - All memory accesses use fence instructions for ordering
    
    Performance improvement:
    - bthread_start_urgent latency: 1.5-2% reduction
    - adding_func throughput: 25% improvement (541ns vs 722ns)
    
    Signed-off-by: Xiaofei Gong <[email protected]>
    Signed-off-by: YuanSheng <[email protected]>
    
    * fix: correct RISC-V inline assembly constraints for AtomicInteger128
    
    - Use "m" (input) for ld instructions reading memory
    - Use "=m" (output) for sd instructions writing memory
    - Swap operand order in sd templates to match RISC-V syntax (register, 
memory)
    
    The previous "+m" constraints in input operand positions caused compilation
    errors on RISC-V. This fix ensures proper constraint usage:
    - ld: memory is input "m", register is output "=r"
    - sd: register is input "r", memory is output "=m"
    
    Signed-off-by: Xiaofei Gong <[email protected]>
    Signed-off-by: YuanSheng <[email protected]>
    
    ---------
    
    Signed-off-by: Xiaofei Gong <[email protected]>
    Signed-off-by: YuanSheng <[email protected]>
---
 src/bthread/task_group.cpp | 92 ++++++++++++++++++++++++++++++++++++++--------
 src/bthread/task_group.h   |  4 +-
 2 files changed, 80 insertions(+), 16 deletions(-)

diff --git a/src/bthread/task_group.cpp b/src/bthread/task_group.cpp
index ddfa4738..46f9a133 100644
--- a/src/bthread/task_group.cpp
+++ b/src/bthread/task_group.cpp
@@ -85,37 +85,99 @@ BAIDU_VOLATILE_THREAD_LOCAL(void*, tls_unique_user_ptr, 
NULL);
 const TaskStatistics EMPTY_STAT = { 0, 0, 0 };
 
 AtomicInteger128::Value AtomicInteger128::load() const {
-#if __x86_64__ || __ARM_NEON
-    // Supress compiler warning.
-    (void)_mutex;
-#endif // __x86_64__ || __ARM_NEON
-
-#if __x86_64__ || __ARM_NEON
 #ifdef __x86_64__
+    (void)_mutex;
+    (void)_seq;
     __m128i value = _mm_load_si128(reinterpret_cast<const __m128i*>(&_value));
-#else // __ARM_NEON
+    return {value[0], value[1]};
+#elif defined(__ARM_NEON)
+    (void)_mutex;
+    (void)_seq;
     int64x2_t value = vld1q_s64(reinterpret_cast<const int64_t*>(&_value));
-#endif // __x86_64__
     return {value[0], value[1]};
-#else // __x86_64__ || __ARM_NEON
-    // RISC-V and other architectures use mutex fallback
+#elif defined(__riscv) && __riscv_xlen == 64
+    (void)_mutex;
+    // RISC-V: Seqlock-based atomic 128-bit load.
+    int64_t v1, v2;
+    uint64_t seq0, seq1;
+    do {
+        __asm__ volatile(
+            "ld %0, %1\n\t"
+            : "=r"(seq0)
+            : "m"(_seq)
+            : "memory"
+        );
+        if (seq0 & 1) continue;
+        __asm__ volatile("fence r, rw\n\t" ::: "memory");
+        __asm__ volatile(
+            "ld %0, %2\n\t"
+            "ld %1, %3\n\t"
+            : "=r"(v1), "=r"(v2)
+            : "m"(_value.v1), "m"(_value.v2)
+            : "memory"
+        );
+        __asm__ volatile("fence r, rw\n\t" ::: "memory");
+        __asm__ volatile(
+            "ld %0, %1\n\t"
+            : "=r"(seq1)
+            : "m"(_seq)
+            : "memory"
+        );
+    } while (seq0 != seq1);
+    return {v1, v2};
+#else
     BAIDU_SCOPED_LOCK(const_cast<FastPthreadMutex&>(_mutex));
     return _value;
-#endif // __x86_64__ || __ARM_NEON
+#endif
 }
 
 void AtomicInteger128::store(Value value) {
-#if __x86_64__
+#ifdef __x86_64__
+    (void)_seq;
     __m128i v = _mm_load_si128(reinterpret_cast<__m128i*>(&value));
     _mm_store_si128(reinterpret_cast<__m128i*>(&_value), v);
-#elif __ARM_NEON
+#elif defined(__ARM_NEON)
+    (void)_seq;
     int64x2_t v = vld1q_s64(reinterpret_cast<int64_t*>(&value));
     vst1q_s64(reinterpret_cast<int64_t*>(&_value), v);
+#elif defined(__riscv) && __riscv_xlen == 64
+    (void)_mutex;
+    // RISC-V: Seqlock-based atomic 128-bit store.
+    uint64_t old_seq;
+    __asm__ volatile(
+        "ld %0, %1\n\t"
+        : "=r"(old_seq)
+        : "m"(_seq)
+        : "memory"
+    );
+    uint64_t new_seq = old_seq + 1;
+    __asm__ volatile(
+        "fence w, w\n\t"
+        "sd %1, %0\n\t"
+        : "=m"(_seq)
+        : "r"(new_seq)
+        : "memory"
+    );
+    __asm__ volatile("fence w, w\n\t" ::: "memory");
+    __asm__ volatile(
+        "sd %2, %0\n\t"
+        "sd %3, %1\n\t"
+        : "=m"(_value.v1), "=m"(_value.v2)
+        : "r"(value.v1), "r"(value.v2)
+        : "memory"
+    );
+    __asm__ volatile("fence w, w\n\t" ::: "memory");
+    new_seq++;
+    __asm__ volatile(
+        "sd %1, %0\n\t"
+        : "=m"(_seq)
+        : "r"(new_seq)
+        : "memory"
+    );
 #else
-    // RISC-V and other architectures use mutex fallback
     BAIDU_SCOPED_LOCK(const_cast<FastPthreadMutex&>(_mutex));
     _value = value;
-#endif // __x86_64__ || __ARM_NEON
+#endif
 }
 
 
diff --git a/src/bthread/task_group.h b/src/bthread/task_group.h
index fc0c5cb4..c21e06ba 100644
--- a/src/bthread/task_group.h
+++ b/src/bthread/task_group.h
@@ -73,8 +73,10 @@ public:
 
 private:
     Value _value{};
-    // Used to protect `_cpu_time_stat' when __x86_64__, __ARM_NEON, and 
__riscv is not defined.
+    // Used to protect `_cpu_time_stat' on architectures without lock-free 
128-bit atomics.
     FastPthreadMutex _mutex;
+    // Sequence counter for RISC-V seqlock implementation.
+    uint64_t _seq = 0;
 };
 
 // Thread-local group of tasks.


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to