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 c9b34f23 bthread: use macros for safer thread-local access on ARM 
(#3380)
c9b34f23 is described below

commit c9b34f23b463f84d5fc193d6222fe6652523d854
Author: altman08 <[email protected]>
AuthorDate: Thu Jul 16 10:24:11 2026 +0800

    bthread: use macros for safer thread-local access on ARM (#3380)
    
    Route accesses to tls_task_group, tls_task_group_nosignal, tls_bls and
    several mutex-profiling thread-locals (tls_inside_lock, tls_warn_up,
    tls_pthread_lock_count, tls_csites, tls_ever_created_keytable) through
    the BAIDU_(GET|SET|GET_PTR)_VOLATILE_THREAD_LOCAL macros instead of
    touching the raw __thread variables directly.
    
    On aarch64/clang the compiler can incorrectly cache the address of a
    thread_local variable across a suspend point (e.g. when a bthread is
    rescheduled onto another worker), so raw accesses can silently read a
    stale TaskGroup*/LocalStorage. Going through the accessor macros
    everywhere forces a fresh, non-cached load/store on those platforms
    while staying a plain variable access elsewhere.
    
    Add bthread::tls_bls_ptr() as the single helper for obtaining the
    current LocalStorage*, and update all call sites (bthread.cpp,
    butex.cpp, fd.cpp, key.cpp, mutex.cpp, task_control.cpp,
    brpc/controller.cpp, test/bthread_unittest.cpp) to use it instead of
    declaring their own stale/mistyped extern references to tls_task_group
    or tls_bls.
    
    Also hardens borrow_keytable()/return_keytable() in key.cpp: the
    KeyTableList pointer obtained under the read lock is no longer reused
    after re-acquiring the write lock, since pool->list/pool->destroyed
    may change concurrently via bthread_keytable_pool_destroy(); the
    thread-local list is drained first before falling back to the pool's
    global free list.
---
 src/brpc/controller.cpp      |  4 +-
 src/brpc/span.h              |  4 --
 src/bthread/bthread.cpp      | 22 +++++++----
 src/bthread/butex.cpp        | 20 ++++++----
 src/bthread/fd.cpp           |  8 ++--
 src/bthread/key.cpp          | 90 ++++++++++++++++++++++++++------------------
 src/bthread/mutex.cpp        | 39 +++++++++++--------
 src/bthread/task_control.cpp |  8 ++--
 src/bthread/task_group.cpp   |  6 +--
 src/bthread/task_meta.h      |  4 ++
 test/bthread_unittest.cpp    |  9 ++---
 11 files changed, 125 insertions(+), 89 deletions(-)

diff --git a/src/brpc/controller.cpp b/src/brpc/controller.cpp
index c637eecb..0bcfb412 100644
--- a/src/brpc/controller.cpp
+++ b/src/brpc/controller.cpp
@@ -51,7 +51,7 @@
 #include "bthread/task_group.h"
 
 namespace bthread {
-extern BAIDU_THREAD_LOCAL TaskGroup* tls_task_group;
+EXTERN_BAIDU_VOLATILE_THREAD_LOCAL(TaskGroup*, tls_task_group);
 }
 
 // This is the only place that both client/server must link, so we put
@@ -714,7 +714,7 @@ void Controller::OnVersionedRPCReturned(const 
CompletionInfo& info,
             response_attachment().clear();
 
             // Retry backoff.
-            bthread::TaskGroup* g = bthread::tls_task_group;
+            bthread::TaskGroup* g = 
bthread::BAIDU_GET_VOLATILE_THREAD_LOCAL(tls_task_group);
             int64_t backoff_time_us = retry_policy->GetBackoffTimeMs(this) * 
1000L;
             if (backoff_time_us > 0 &&
                 backoff_time_us < _deadline_us - butil::gettimeofday_us()) {
diff --git a/src/brpc/span.h b/src/brpc/span.h
index 70fdbf4d..efa394b5 100644
--- a/src/brpc/span.h
+++ b/src/brpc/span.h
@@ -36,10 +36,6 @@
 #include "brpc/options.pb.h"                 // ProtocolType
 #include "brpc/span.pb.h"
 
-namespace bthread {
-extern __thread bthread::LocalStorage tls_bls;
-}
-
 namespace brpc {
 
 class Span;
diff --git a/src/bthread/bthread.cpp b/src/bthread/bthread.cpp
index 5bcda94d..7eb6810d 100644
--- a/src/bthread/bthread.cpp
+++ b/src/bthread/bthread.cpp
@@ -86,7 +86,6 @@ pthread_mutex_t g_task_control_mutex = 
PTHREAD_MUTEX_INITIALIZER;
 // are not constructed before main().
 TaskControl* g_task_control = NULL;
 
-extern BAIDU_THREAD_LOCAL TaskGroup* tls_task_group;
 EXTERN_BAIDU_VOLATILE_THREAD_LOCAL(TaskGroup*, tls_task_group);
 extern void (*g_worker_startfn)();
 extern void (*g_tagged_worker_startfn)(bthread_tag_t);
@@ -263,7 +262,7 @@ static bool validate_bthread_concurrency_by_tag(const 
char*, int32_t val) {
     return bthread_setconcurrency_by_tag(val, FLAGS_bthread_current_tag) == 0;
 }
 
-__thread TaskGroup* tls_task_group_nosignal = NULL;
+BAIDU_VOLATILE_THREAD_LOCAL(TaskGroup*, tls_task_group_nosignal, NULL);
 
 BUTIL_FORCE_INLINE int
 start_from_non_worker(bthread_t* __restrict tid,
@@ -283,10 +282,18 @@ start_from_non_worker(bthread_t* __restrict tid,
         // 1. NOSIGNAL is often for creating many bthreads in batch,
         //    inserting into the same TaskGroup maximizes the batch.
         // 2. bthread_flush() needs to know which TaskGroup to flush.
-        TaskGroup* g = tls_task_group_nosignal;
+        auto g = BAIDU_GET_VOLATILE_THREAD_LOCAL(tls_task_group_nosignal);
         if (NULL == g) {
             g = c->choose_one_group(tag);
-            tls_task_group_nosignal = g;
+            BAIDU_SET_VOLATILE_THREAD_LOCAL(tls_task_group_nosignal, g);
+        } else {
+            // tls_task_group_nosignal is not tag-aware: mixing different
+            // tags with BTHREAD_NOSIGNAL on the same non-worker thread is
+            // not supported, otherwise bthreads would be silently inserted
+            // into a TaskGroup of the wrong tag.
+            CHECK_EQ(g->tag(), tag) << "Mixing different tags with "
+                "BTHREAD_NOSIGNAL on the same thread is not supported, "
+                "expected tag=" << g->tag() << " but got tag=" << tag;
         }
         return g->start_background<true>(tid, attr, fn, arg);
     }
@@ -298,7 +305,8 @@ start_from_non_worker(bthread_t* __restrict tid,
 // tag equal to thread local
 // tag equal to BTHREAD_TAG_INVALID
 BUTIL_FORCE_INLINE bool can_run_thread_local(const bthread_attr_t* __restrict 
attr) {
-    return attr == nullptr || attr->tag == tls_task_group->tag() ||
+    return attr == nullptr ||
+           attr->tag == BAIDU_GET_VOLATILE_THREAD_LOCAL(tls_task_group)->tag() 
||
            attr->tag == BTHREAD_TAG_INVALID;
 }
 
@@ -360,10 +368,10 @@ void bthread_flush() {
     if (g) {
         return g->flush_nosignal_tasks();
     }
-    g = bthread::tls_task_group_nosignal;
+    g = bthread::BAIDU_GET_VOLATILE_THREAD_LOCAL(tls_task_group_nosignal);
     if (g) {
         // NOSIGNAL tasks were created in this non-worker.
-        bthread::tls_task_group_nosignal = NULL;
+        bthread::BAIDU_SET_VOLATILE_THREAD_LOCAL(tls_task_group_nosignal, 
NULL);
         return g->flush_nosignal_tasks_remote();
     }
 }
diff --git a/src/bthread/butex.cpp b/src/bthread/butex.cpp
index 92de900c..d833465c 100644
--- a/src/bthread/butex.cpp
+++ b/src/bthread/butex.cpp
@@ -187,7 +187,7 @@ int wait_pthread(ButexPthreadWaiter& pw, const timespec* 
abstime) {
     }
 }
 
-extern BAIDU_THREAD_LOCAL TaskGroup* tls_task_group;
+EXTERN_BAIDU_VOLATILE_THREAD_LOCAL(TaskGroup*, tls_task_group);
 
 // Returns 0 when no need to unschedule or successfully unscheduled,
 // -1 otherwise.
@@ -280,7 +280,8 @@ void butex_destroy(void* butex) {
 
 // if TaskGroup tls_task_group is belong to tag
 inline bool is_same_tag(bthread_tag_t tag) {
-    return tls_task_group && tls_task_group->tag() == tag;
+    auto g = BAIDU_GET_VOLATILE_THREAD_LOCAL(tls_task_group);
+    return g && g->tag() == tag;
 }
 
 //  nosignal is true & tag is same can return true
@@ -290,7 +291,8 @@ inline bool check_nosignal(bool nosignal, bthread_tag_t 
tag) {
 
 // if tag is same return tls_task_group else choose one group with tag
 inline TaskGroup* get_task_group(TaskControl* c, bthread_tag_t tag) {
-    return is_same_tag(tag) ? tls_task_group : c->choose_one_group(tag);
+    return is_same_tag(tag) ? BAIDU_GET_VOLATILE_THREAD_LOCAL(tls_task_group)
+                            : c->choose_one_group(tag);
 }
 
 inline void run_in_local_task_group(TaskGroup* g, TaskMeta* next_meta, bool 
nosignal) {
@@ -320,7 +322,7 @@ int butex_wake(void* arg, bool nosignal) {
     ButexBthreadWaiter* bbw = static_cast<ButexBthreadWaiter*>(front);
     unsleep_if_necessary(bbw, get_global_timer_thread());
     TaskGroup* g = get_task_group(bbw->control, bbw->task_meta->attr.tag);
-    if (g == tls_task_group) {
+    if (g == BAIDU_GET_VOLATILE_THREAD_LOCAL(tls_task_group)) {
         run_in_local_task_group(g, bbw->task_meta, nosignal);
     } else {
         g->ready_to_run_remote(bbw->task_meta, check_nosignal(nosignal, 
g->tag()));
@@ -384,7 +386,7 @@ int butex_wake_n(void* arg, size_t n, bool nosignal) {
         }
     }
     auto g = get_task_group(next->control, next->task_meta->attr.tag);
-    if (g == tls_task_group) {
+    if (g == BAIDU_GET_VOLATILE_THREAD_LOCAL(tls_task_group)) {
         run_in_local_task_group(g, next->task_meta, nosignal);
     } else {
         g->ready_to_run_remote(next->task_meta, check_nosignal(nosignal, 
g->tag()));
@@ -488,7 +490,9 @@ int butex_requeue(void* arg, void* arg2) {
     }
     ButexBthreadWaiter* bbw = static_cast<ButexBthreadWaiter*>(front);
     unsleep_if_necessary(bbw, get_global_timer_thread());
-    auto g = is_same_tag(bbw->task_meta->attr.tag) ? tls_task_group : NULL;
+    auto g = is_same_tag(bbw->task_meta->attr.tag)
+                 ? BAIDU_GET_VOLATILE_THREAD_LOCAL(tls_task_group)
+                 : NULL;
     if (g) {
         TaskGroup::exchange(&g, bbw->task_meta);
     } else {
@@ -597,7 +601,7 @@ void wait_for_butex(void* arg) {
     // the two functions. The on-stack ButexBthreadWaiter is safe to use and
     // bw->waiter_state will not change again.
     // unsleep_if_necessary(bw, get_global_timer_thread());
-    tls_task_group->ready_to_run(bw->task_meta);
+    
BAIDU_GET_VOLATILE_THREAD_LOCAL(tls_task_group)->ready_to_run(bw->task_meta);
     // FIXME: jump back to original thread is buggy.
     
     // // Value unmatched or waiter is already woken up by TimerThread, jump
@@ -677,7 +681,7 @@ int butex_wait(void* arg, int expected_value, const 
timespec* abstime, bool prep
         butil::atomic_thread_fence(butil::memory_order_acquire);
         return -1;
     }
-    TaskGroup* g = tls_task_group;
+    TaskGroup* g = BAIDU_GET_VOLATILE_THREAD_LOCAL(tls_task_group);
     if (NULL == g || g->is_current_pthread_task()) {
         return butex_wait_from_pthread(g, b, expected_value, abstime, prepend);
     }
diff --git a/src/bthread/fd.cpp b/src/bthread/fd.cpp
index 17ca63dc..36e9b313 100644
--- a/src/bthread/fd.cpp
+++ b/src/bthread/fd.cpp
@@ -44,7 +44,7 @@ extern int pthread_fd_wait(int fd, unsigned events, const 
timespec* abstime);
 
 namespace bthread {
 
-extern BAIDU_THREAD_LOCAL TaskGroup* tls_task_group;
+EXTERN_BAIDU_VOLATILE_THREAD_LOCAL(TaskGroup*, tls_task_group);
 
 template <typename T, size_t NBLOCK, size_t BLOCK_SIZE>
 class LazyArray {
@@ -446,7 +446,7 @@ int bthread_fd_wait(int fd, unsigned events) {
         errno = EINVAL;
         return -1;
     }
-    bthread::TaskGroup* g = bthread::tls_task_group;
+    bthread::TaskGroup* g = 
bthread::BAIDU_GET_VOLATILE_THREAD_LOCAL(tls_task_group);
     if (NULL != g && !g->is_current_pthread_task()) {
         return bthread::get_epoll_thread(fd).fd_wait(
             fd, events, NULL);
@@ -463,7 +463,7 @@ int bthread_fd_timedwait(int fd, unsigned events,
         errno = EINVAL;
         return -1;
     }
-    bthread::TaskGroup* g = bthread::tls_task_group;
+    bthread::TaskGroup* g = 
bthread::BAIDU_GET_VOLATILE_THREAD_LOCAL(tls_task_group);
     if (NULL != g && !g->is_current_pthread_task()) {
         return bthread::get_epoll_thread(fd).fd_wait(
             fd, events, abstime);
@@ -473,7 +473,7 @@ int bthread_fd_timedwait(int fd, unsigned events,
 
 int bthread_connect(int sockfd, const sockaddr* serv_addr,
                     socklen_t addrlen) {
-    bthread::TaskGroup* g = bthread::tls_task_group;
+    bthread::TaskGroup* g = 
bthread::BAIDU_GET_VOLATILE_THREAD_LOCAL(tls_task_group);
     if (NULL == g || g->is_current_pthread_task()) {
         return ::connect(sockfd, serv_addr, addrlen);
     }
diff --git a/src/bthread/key.cpp b/src/bthread/key.cpp
index 74945833..dd62ce47 100644
--- a/src/bthread/key.cpp
+++ b/src/bthread/key.cpp
@@ -49,9 +49,7 @@ EXTERN_BAIDU_VOLATILE_THREAD_LOCAL(TaskGroup*, 
tls_task_group);
 
 class KeyTable;
 
-// defined in task_group.cpp
-extern __thread LocalStorage tls_bls;
-static __thread bool tls_ever_created_keytable = false;
+BAIDU_VOLATILE_THREAD_LOCAL(bool, tls_ever_created_keytable, false);
 
 // We keep thread specific data in a two-level array. The top-level array
 // contains at most KEY_1STLEVEL_SIZE pointers to dynamically allocated
@@ -227,12 +225,12 @@ public:
 
     ~KeyTableList() {
         TaskGroup* g = BAIDU_GET_VOLATILE_THREAD_LOCAL(tls_task_group);
-        KeyTable* old_kt = tls_bls.keytable;
+        KeyTable* old_kt = tls_bls_ptr()->keytable;
         KeyTable* keytable = _head;
         while (keytable) {
             KeyTable* kt = keytable;
             keytable = kt->next;
-            tls_bls.keytable = kt;
+            tls_bls_ptr()->keytable = kt;
             if (g) {
                 g->current_task()->local_storage.keytable = kt;
             }
@@ -242,7 +240,7 @@ public:
             }
             g = BAIDU_GET_VOLATILE_THREAD_LOCAL(tls_task_group);
         }
-        tls_bls.keytable = old_kt;
+        tls_bls_ptr()->keytable = old_kt;
         if (g) {
             g->current_task()->local_storage.keytable = old_kt;
         }
@@ -329,20 +327,33 @@ private:
 KeyTable* borrow_keytable(bthread_keytable_pool_t* pool) {
     if (pool != NULL && (pool->list || pool->free_keytables)) {
         KeyTable* p;
-        pthread_rwlock_rdlock(&pool->rwlock);
-        auto list = (butil::ThreadLocal<bthread::KeyTableList>*)pool->list;
-        if (list) {
-            p = list->get()->remove_front();
-            if (p) {
-                pthread_rwlock_unlock(&pool->rwlock);
-                return p;
+        {
+            pthread_rwlock_rdlock(&pool->rwlock);
+            auto list = (butil::ThreadLocal<bthread::KeyTableList>*)pool->list;
+            if (list) {
+                p = list->get()->remove_front();
+                if (p) {
+                    pthread_rwlock_unlock(&pool->rwlock);
+                    return p;
+                }
             }
+            pthread_rwlock_unlock(&pool->rwlock);
         }
-        pthread_rwlock_unlock(&pool->rwlock);
         if (pool->free_keytables) {
             pthread_rwlock_wrlock(&pool->rwlock);
+            if (pool->destroyed) {
+                pthread_rwlock_unlock(&pool->rwlock);
+                return NULL;
+            }
+            auto list = (butil::ThreadLocal<bthread::KeyTableList>*)pool->list;
             p = (KeyTable*)pool->free_keytables;
             if (list) {
+                p = list->get()->remove_front();
+                if (p) {
+                    pthread_rwlock_unlock(&pool->rwlock);
+                    return p;
+                }
+                p = (KeyTable*)pool->free_keytables;
                 for (uint32_t i = 0; i < FLAGS_borrow_from_globle_size; ++i) {
                     if (p) {
                         pool->free_keytables = p->next;
@@ -357,6 +368,7 @@ KeyTable* borrow_keytable(bthread_keytable_pool_t* pool) {
                 pthread_rwlock_unlock(&pool->rwlock);
                 return result;
             } else {
+                p = (KeyTable*)pool->free_keytables;
                 if (p) {
                     pool->free_keytables = p->next;
                     pthread_rwlock_unlock(&pool->rwlock);
@@ -379,25 +391,31 @@ void return_keytable(bthread_keytable_pool_t* pool, 
KeyTable* kt) {
         delete kt;
         return;
     }
-    pthread_rwlock_rdlock(&pool->rwlock);
-    if (pool->destroyed) {
+    bool need_move = false;
+    {
+        pthread_rwlock_rdlock(&pool->rwlock);
+        if (pool->destroyed) {
+            pthread_rwlock_unlock(&pool->rwlock);
+            delete kt;
+            return;
+        }
+        auto list = (butil::ThreadLocal<bthread::KeyTableList>*)pool->list;
+        list->get()->append(kt);
+        need_move = list->get()->get_length() > FLAGS_key_table_list_size;
         pthread_rwlock_unlock(&pool->rwlock);
-        delete kt;
-        return;
     }
-    auto list = (butil::ThreadLocal<bthread::KeyTableList>*)pool->list;
-    list->get()->append(kt);
-    if (list->get()->get_length() > FLAGS_key_table_list_size) {
-        pthread_rwlock_unlock(&pool->rwlock);
+    if (need_move) {
         pthread_rwlock_wrlock(&pool->rwlock);
-        if (!pool->destroyed) {
+        auto list = (butil::ThreadLocal<bthread::KeyTableList>*)pool->list;
+        if (!pool->destroyed && list != NULL &&
+                list->get()->get_length() > FLAGS_key_table_list_size) {
             int out = list->get()->move_first_n_to_target(
                 (KeyTable**)(&pool->free_keytables),
                 FLAGS_key_table_list_size / 2);
             pool->size += out;
         }
+        pthread_rwlock_unlock(&pool->rwlock);
     }
-    pthread_rwlock_unlock(&pool->rwlock);
 }
 
 static void cleanup_pthread(void* arg) {
@@ -405,7 +423,7 @@ static void cleanup_pthread(void* arg) {
     if (kt) {
         delete kt;
         // After deletion: tls may be set during deletion.
-        tls_bls.keytable = NULL;
+        tls_bls_ptr()->keytable = NULL;
     }
 }
 
@@ -469,18 +487,18 @@ int 
bthread_keytable_pool_destroy(bthread_keytable_pool_t* pool) {
     // Cheat get/setspecific and destroy the keytables.
     bthread::TaskGroup* g =
         bthread::BAIDU_GET_VOLATILE_THREAD_LOCAL(tls_task_group);
-    bthread::KeyTable* old_kt = bthread::tls_bls.keytable;
+    bthread::KeyTable* old_kt = bthread::tls_bls_ptr()->keytable;
     while (saved_free_keytables) {
         bthread::KeyTable* kt = saved_free_keytables;
         saved_free_keytables = kt->next;
-        bthread::tls_bls.keytable = kt;
+        bthread::tls_bls_ptr()->keytable = kt;
         if (g) {
             g->current_task()->local_storage.keytable = kt;
         }
         delete kt;
         g = bthread::BAIDU_GET_VOLATILE_THREAD_LOCAL(tls_task_group);
     }
-    bthread::tls_bls.keytable = old_kt;
+    bthread::tls_bls_ptr()->keytable = old_kt;
     if (g) {
         g->current_task()->local_storage.keytable = old_kt;
     }
@@ -624,13 +642,13 @@ int bthread_key_delete(bthread_key_t key) {
 //  -> bthread_setspecific succeeds to borrow_keytable and overwrites old data
 //     at the position with newly created data, the old data is leaked.
 int bthread_setspecific(bthread_key_t key, void* data) {
-    bthread::KeyTable* kt = bthread::tls_bls.keytable;
+    bthread::KeyTable* kt = bthread::tls_bls_ptr()->keytable;
     if (NULL == kt) {
         kt = new (std::nothrow) bthread::KeyTable;
         if (NULL == kt) {
             return ENOMEM;
         }
-        bthread::tls_bls.keytable = kt;
+        bthread::tls_bls_ptr()->keytable = kt;
         bthread::TaskGroup* const g = 
bthread::BAIDU_GET_VOLATILE_THREAD_LOCAL(tls_task_group);
         if (g) {
             g->current_task()->local_storage.keytable = kt;
@@ -638,8 +656,8 @@ int bthread_setspecific(bthread_key_t key, void* data) {
             // Only cleanup keytable created by pthread.
             // keytable created by bthread will be deleted
             // in `return_keytable' or `bthread_keytable_pool_destroy'.
-            if (!bthread::tls_ever_created_keytable) {
-                bthread::tls_ever_created_keytable = true;
+            if 
(!bthread::BAIDU_GET_VOLATILE_THREAD_LOCAL(tls_ever_created_keytable)) {
+                
bthread::BAIDU_SET_VOLATILE_THREAD_LOCAL(tls_ever_created_keytable, true);
                 CHECK_EQ(0, butil::thread_atexit(bthread::cleanup_pthread, 
kt));
             }
         }
@@ -648,7 +666,7 @@ int bthread_setspecific(bthread_key_t key, void* data) {
 }
 
 void* bthread_getspecific(bthread_key_t key) {
-    bthread::KeyTable* kt = bthread::tls_bls.keytable;
+    bthread::KeyTable* kt = bthread::tls_bls_ptr()->keytable;
     if (kt) {
         return kt->get_data(key);
     }
@@ -658,7 +676,7 @@ void* bthread_getspecific(bthread_key_t key) {
         kt = bthread::borrow_keytable(task->attr.keytable_pool);
         if (kt) {
             g->current_task()->local_storage.keytable = kt;
-            bthread::tls_bls.keytable = kt;
+            bthread::tls_bls_ptr()->keytable = kt;
             return kt->get_data(key);
         }
     }
@@ -666,11 +684,11 @@ void* bthread_getspecific(bthread_key_t key) {
 }
 
 void bthread_assign_data(void* data) {
-    bthread::tls_bls.assigned_data = data;
+    bthread::tls_bls_ptr()->assigned_data = data;
 }
 
 void* bthread_get_assigned_data() {
-    return bthread::tls_bls.assigned_data;
+    return bthread::tls_bls_ptr()->assigned_data;
 }
 
 }  // extern "C"
diff --git a/src/bthread/mutex.cpp b/src/bthread/mutex.cpp
index dff2da3f..a5d2cbd1 100644
--- a/src/bthread/mutex.cpp
+++ b/src/bthread/mutex.cpp
@@ -524,11 +524,11 @@ inline uint64_t hash_mutex_ptr(const Mutex* m) {
 
 // Mark being inside locking so that pthread_mutex calls inside collecting
 // code are never sampled, otherwise deadlock may occur.
-static __thread bool tls_inside_lock = false;
+BAIDU_VOLATILE_THREAD_LOCAL(bool, tls_inside_lock, false);
 
 // Warn up some singleton objects used in contention profiler
 // to avoid deadlock in malloc call stack.
-static __thread bool tls_warn_up = false;
+BAIDU_VOLATILE_THREAD_LOCAL(bool, tls_warn_up, false);
 
 #if BRPC_DEBUG_BTHREAD_SCHE_SAFETY
 // ++tls_pthread_lock_count when pthread locking,
@@ -536,19 +536,22 @@ static __thread bool tls_warn_up = false;
 // Only when it is equal to 0, it is safe for the bthread to be scheduled.
 // Note: If a mutex is locked/unlocked in different thread,
 // `tls_pthread_lock_count' is inaccurate, so this feature cannot be used.
-static __thread int tls_pthread_lock_count = 0;
+BAIDU_VOLATILE_THREAD_LOCAL(int, tls_pthread_lock_count, 0);
 
-#define ADD_TLS_PTHREAD_LOCK_COUNT ++tls_pthread_lock_count
-#define SUB_TLS_PTHREAD_LOCK_COUNT --tls_pthread_lock_count
+#define ADD_TLS_PTHREAD_LOCK_COUNT \
+    ++(*BAIDU_GET_PTR_VOLATILE_THREAD_LOCAL(tls_pthread_lock_count))
+#define SUB_TLS_PTHREAD_LOCK_COUNT \
+    --(*BAIDU_GET_PTR_VOLATILE_THREAD_LOCAL(tls_pthread_lock_count))
 
 void CheckBthreadScheSafety() {
-    if (BAIDU_LIKELY(0 == tls_pthread_lock_count)) {
+    if (BAIDU_LIKELY(0 == 
BAIDU_GET_VOLATILE_THREAD_LOCAL(tls_pthread_lock_count))) {
         return;
     }
 
     // It can only be checked once because the counter is messed up.
     LOG_BACKTRACE_ONCE(ERROR) << "bthread is suspended while holding "
-                              << tls_pthread_lock_count << " pthread locks.";
+                              << 
BAIDU_GET_VOLATILE_THREAD_LOCAL(tls_pthread_lock_count)
+                              << " pthread locks.";
 }
 #else
 #define ADD_TLS_PTHREAD_LOCK_COUNT ((void)0)
@@ -576,7 +579,8 @@ struct TLSPthreadContentionSites {
     uint64_t cp_version;
     MutexAndContentionSite list[TLS_MAX_COUNT];
 };
-static __thread TLSPthreadContentionSites tls_csites = {0,0,{}};
+BAIDU_VOLATILE_THREAD_LOCAL(TLSPthreadContentionSites, tls_csites,
+                            TLSPthreadContentionSites());
 #endif  // DONT_SPEEDUP_PTHREAD_CONTENTION_PROFILER_WITH_TLS
 
 // Guaranteed in linux/win.
@@ -625,9 +629,9 @@ inline bool remove_pthread_contention_site(const Mutex* 
mutex,
 
 // Submit the contention along with the callsite('s stacktrace)
 void submit_contention(const bthread_contention_site_t& csite, int64_t now_ns) 
{
-    tls_inside_lock = true;
+    BAIDU_SET_VOLATILE_THREAD_LOCAL(tls_inside_lock, true);
     BRPC_SCOPE_EXIT {
-        tls_inside_lock = false;
+        BAIDU_SET_VOLATILE_THREAD_LOCAL(tls_inside_lock, false);
     };
 
     butil::debug::StackTrace stack(true); // May lock.
@@ -639,7 +643,8 @@ void submit_contention(const bthread_contention_site_t& 
csite, int64_t now_ns) {
     // 1. Warn up some singleton objects used in `submit_contention'
     // to avoid deadlock in malloc call stack.
     // 2. LocalPool is empty, GlobalPool may allocate memory by malloc.
-    if (!tls_warn_up || butil::local_pool_free_empty<SampledContention>()) {
+    if (!BAIDU_GET_VOLATILE_THREAD_LOCAL(tls_warn_up) ||
+        butil::local_pool_free_empty<SampledContention>()) {
         // In malloc call stack, can not submit contention.
         if (stack.FindSymbol((void*)malloc)) {
             return;
@@ -656,7 +661,7 @@ void submit_contention(const bthread_contention_site_t& 
csite, int64_t now_ns) {
     sc->nframes = stack.CopyAddressTo(sc->stack, arraysize(sc->stack));
     sc->submit(now_ns / 1000);  // may lock
     // Once submit a contention, complete warn up.
-    tls_warn_up = true;
+    BAIDU_SET_VOLATILE_THREAD_LOCAL(tls_warn_up, true);
 }
 
 #if BRPC_DEBUG_LOCK
@@ -872,7 +877,7 @@ BUTIL_FORCE_INLINE int pthread_mutex_lock_impl(Mutex* 
mutex, const struct timesp
     if (!g_cp ||
         // collecting code including backtrace() and submit() may call
         // pthread_mutex_lock and cause deadlock. Don't sample.
-        tls_inside_lock) {
+        BAIDU_GET_VOLATILE_THREAD_LOCAL(tls_inside_lock)) {
         return pthread_mutex_lock_internal(mutex, abstime);
     }
     // Don't slow down non-contended locks.
@@ -885,7 +890,8 @@ BUTIL_FORCE_INLINE int pthread_mutex_lock_impl(Mutex* 
mutex, const struct timesp
 
     bthread_contention_site_t* csite = NULL;
 #ifndef DONT_SPEEDUP_PTHREAD_CONTENTION_PROFILER_WITH_TLS
-    TLSPthreadContentionSites& fast_alt = tls_csites;
+    TLSPthreadContentionSites& fast_alt =
+        *BAIDU_GET_PTR_VOLATILE_THREAD_LOCAL(tls_csites);
     if (fast_alt.cp_version != g_cp_version) {
         fast_alt.cp_version = g_cp_version;
         fast_alt.count = 0;
@@ -927,7 +933,7 @@ BUTIL_FORCE_INLINE int pthread_mutex_trylock_impl(Mutex* 
mutex) {
 template <typename Mutex>
 BUTIL_FORCE_INLINE int pthread_mutex_unlock_impl(Mutex* mutex) {
     // Don't change behavior of unlock when profiler is off.
-    if (!g_cp || tls_inside_lock) {
+    if (!g_cp || BAIDU_GET_VOLATILE_THREAD_LOCAL(tls_inside_lock)) {
         // This branch brings an issue that an entry created by
         // add_pthread_contention_site may not be cleared. Thus we add a
         // 16-bit rolling version in the entry to find out such entry.
@@ -937,7 +943,8 @@ BUTIL_FORCE_INLINE int pthread_mutex_unlock_impl(Mutex* 
mutex) {
     bool miss_in_tls = true;
     bthread_contention_site_t saved_csite = {0,0};
 #ifndef DONT_SPEEDUP_PTHREAD_CONTENTION_PROFILER_WITH_TLS
-    TLSPthreadContentionSites& fast_alt = tls_csites;
+    TLSPthreadContentionSites& fast_alt =
+        *BAIDU_GET_PTR_VOLATILE_THREAD_LOCAL(tls_csites);
     for (int i = fast_alt.count - 1; i >= 0; --i) {
         if (fast_alt.list[i].mutex == mutex) {
             if (is_contention_site_valid(fast_alt.list[i].csite)) {
diff --git a/src/bthread/task_control.cpp b/src/bthread/task_control.cpp
index beb41306..3ad3aa50 100644
--- a/src/bthread/task_control.cpp
+++ b/src/bthread/task_control.cpp
@@ -70,7 +70,7 @@ DECLARE_int32(bthread_min_concurrency);
 DECLARE_int32(bthread_parking_lot_of_each_tag);
 
 extern pthread_mutex_t g_task_control_mutex;
-extern BAIDU_THREAD_LOCAL TaskGroup* tls_task_group;
+EXTERN_BAIDU_VOLATILE_THREAD_LOCAL(TaskGroup*, tls_task_group);
 void (*g_worker_startfn)() = NULL;
 void (*g_tagged_worker_startfn)(bthread_tag_t) = NULL;
 
@@ -128,7 +128,7 @@ void* TaskControl::worker_thread(void* arg) {
     }
     BT_VLOG << "Created worker=" << pthread_self() << " tid=" << g->_tid
             << " bthread=" << g->main_tid() << " tag=" << g->tag();
-    tls_task_group = g;
+    BAIDU_SET_VOLATILE_THREAD_LOCAL(tls_task_group, g);
     c->_nworkers << 1;
     c->tag_nworkers(g->tag()) << 1;
 
@@ -138,7 +138,7 @@ void* TaskControl::worker_thread(void* arg) {
     BT_VLOG << "Destroying worker=" << pthread_self() << " bthread="
             << g->main_tid() << " idle=" << stat.cputime_ns / 1000000.0
             << "ms uptime=" << g->current_uptime_ns() / 1000000.0 << "ms";
-    tls_task_group = NULL;
+    BAIDU_SET_VOLATILE_THREAD_LOCAL(tls_task_group, NULL);
     g->destroy_self();
     c->_nworkers << -1;
     c->tag_nworkers(g->tag()) << -1;
@@ -619,7 +619,7 @@ int TaskControl::_destroy_group(TaskGroup* g) {
 }
 
 bool TaskControl::steal_task(bthread_t* tid, size_t* seed, size_t offset) {
-    auto tag = tls_task_group->tag();
+    auto tag = BAIDU_GET_VOLATILE_THREAD_LOCAL(tls_task_group)->tag();
 
     if (_enable_priority_queue) {
         for (int i = 0;
diff --git a/src/bthread/task_group.cpp b/src/bthread/task_group.cpp
index 46f9a133..e54f9475 100644
--- a/src/bthread/task_group.cpp
+++ b/src/bthread/task_group.cpp
@@ -484,10 +484,10 @@ void TaskGroup::task_runner(intptr_t skip_remained) {
         // which allocates bthread-local stream arrays via 
bthread_setspecific).
         // If span cleanup ran after keytable cleanup, such allocations would
         // re-populate the keytable and never be reclaimed, causing memory 
leak.
-        LocalStorage* tls_bls_ptr = 
BAIDU_GET_PTR_VOLATILE_THREAD_LOCAL(tls_bls);
+        LocalStorage* tls_bls_ptr = bthread::tls_bls_ptr();
         if (tls_bls_ptr->rpcz_parent_span && g_rpcz_parent_span_dtor) {
             g_rpcz_parent_span_dtor(tls_bls_ptr->rpcz_parent_span);
-            tls_bls_ptr = BAIDU_GET_PTR_VOLATILE_THREAD_LOCAL(tls_bls);
+            tls_bls_ptr = bthread::tls_bls_ptr();
             tls_bls_ptr->rpcz_parent_span = NULL;
             m->local_storage.rpcz_parent_span = NULL;
         }
@@ -499,7 +499,7 @@ void TaskGroup::task_runner(intptr_t skip_remained) {
         if (kt != NULL) {
             return_keytable(m->attr.keytable_pool, kt);
             // After deletion: tls may be set during deletion.
-            tls_bls_ptr = BAIDU_GET_PTR_VOLATILE_THREAD_LOCAL(tls_bls);
+            tls_bls_ptr = bthread::tls_bls_ptr();
             tls_bls_ptr->keytable = NULL;
             m->local_storage.keytable = NULL; // optional
         }
diff --git a/src/bthread/task_meta.h b/src/bthread/task_meta.h
index 074af430..7c9e6379 100644
--- a/src/bthread/task_meta.h
+++ b/src/bthread/task_meta.h
@@ -53,6 +53,10 @@ const static LocalStorage LOCAL_STORAGE_INIT = 
BTHREAD_LOCAL_STORAGE_INITIALIZER
 
 EXTERN_BAIDU_VOLATILE_THREAD_LOCAL(LocalStorage, tls_bls);
 
+inline LocalStorage* tls_bls_ptr() {
+    return BAIDU_GET_PTR_VOLATILE_THREAD_LOCAL(tls_bls);
+}
+
 enum TaskStatus {
     TASK_STATUS_UNKNOWN,
     TASK_STATUS_CREATED,
diff --git a/test/bthread_unittest.cpp b/test/bthread_unittest.cpp
index bd31a3c4..b6d5ca7f 100644
--- a/test/bthread_unittest.cpp
+++ b/test/bthread_unittest.cpp
@@ -34,7 +34,6 @@ int main(int argc, char* argv[]) {
 }
 
 namespace bthread {
-extern __thread bthread::LocalStorage tls_bls;
 #ifdef BRPC_BTHREAD_TRACER
 extern std::string stack_trace(bthread_t tid);
 #endif // BRPC_BTHREAD_TRACER
@@ -536,21 +535,21 @@ static const bthread_attr_t BTHREAD_ATTR_NORMAL_WITH_SPAN 
=
 
 void* test_parent_span(void* p) {
     uint64_t *q = (uint64_t *)p;
-    *q = (uint64_t)(bthread::tls_bls.rpcz_parent_span);
+    *q = (uint64_t)(bthread::tls_bls_ptr()->rpcz_parent_span);
     LOG(INFO) << "span id in thread is " << *q;
     return NULL;
 }
 
 void* test_grandson_parent_span(void* p) {
     uint64_t* q = (uint64_t*)p;
-    *q = (uint64_t)(bthread::tls_bls.rpcz_parent_span);
+    *q = (uint64_t)(bthread::tls_bls_ptr()->rpcz_parent_span);
     LOG(INFO) << "parent span id in thread is " << *q;
     return NULL;
 }
 
 void* test_son_parent_span(void* p) {
     uint64_t* q = (uint64_t*)p;
-    *q = (uint64_t)(bthread::tls_bls.rpcz_parent_span);
+    *q = (uint64_t)(bthread::tls_bls_ptr()->rpcz_parent_span);
     LOG(INFO) << "parent span id in thread is " << *q;
     bthread_t th;
     uint64_t multi_p;
@@ -581,7 +580,7 @@ TEST_F(BthreadTest, test_span) {
     uint64_t target = 0xBADBEAFUL;
     LOG(INFO) << "target span id is " << target;
 
-    bthread::tls_bls.rpcz_parent_span = (void*)target;
+    bthread::tls_bls_ptr()->rpcz_parent_span = (void*)target;
     bthread_t th1;
     ASSERT_EQ(0, bthread_start_urgent(&th1, &BTHREAD_ATTR_NORMAL_WITH_SPAN, 
test_parent_span, &p1));
     ASSERT_EQ(0, bthread_join(th1, NULL));


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

Reply via email to