已合并
异步栈并发加锁 #2693
异步栈并发加锁 #2693
已合并
Cooper创建于 11 天前
4 个文件变更+120-34
Minterfaces/innerkits/async_stack/async_context_manager.cpp+63-30
@@ -19,6 +19,8 @@
19#include <string>19#include <string>
20#include <cerrno>20#include <cerrno>
21#include <sys/mman.h>21#include <sys/mman.h>
22+#include <sys/syscall.h>
23+#include <unistd.h>
22 24 
23#include "dfx_frame_formatter.h"25#include "dfx_frame_formatter.h"
24#include "dfx_log.h"26#include "dfx_log.h"
@@ -39,7 +41,7 @@ DfxAsyncContextPool* DfxAsyncContextPool::Instance()
39 41 
40bool DfxAsyncContextPool::Init()42bool DfxAsyncContextPool::Init()
41{43{
42- std::lock_guard<std::mutex> lock(mutex_);44+ std::lock_guard<std::shared_mutex> lock(sharedMutex_);
43 if (initialized_.load()) {45 if (initialized_.load()) {
44 return true;46 return true;
45 }47 }
@@ -50,8 +52,9 @@ bool DfxAsyncContextPool::Init()
50 return false;52 return false;
51 }53 }
52 size_t poolMemSize = static_cast<size_t>(poolSize_) * sizeof(DfxAsyncContext);54 size_t poolMemSize = static_cast<size_t>(poolSize_) * sizeof(DfxAsyncContext);
53- pool_ = static_cast<DfxAsyncContext*>(mmap(nullptr, poolMemSize, PROT_READ | PROT_WRITE,55+ pool_ = reinterpret_cast<DfxAsyncContext*>(static_cast<uintptr_t>(
54- MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));56+ syscall(SYS_mmap, nullptr, poolMemSize, PROT_READ | PROT_WRITE,
C
CChenShiCoder10 天前

1.确认了能解决问题吗2.profiler是否hook syscall

likedislike
57+ MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)));
55 if (pool_ == MAP_FAILED) {58 if (pool_ == MAP_FAILED) {
56 pool_ = nullptr;59 pool_ = nullptr;
57 DFXLOGE("init async context pool mmap failed poolSize %{public}u, errno %{public}d",60 DFXLOGE("init async context pool mmap failed poolSize %{public}u, errno %{public}d",
@@ -61,22 +64,20 @@ bool DfxAsyncContextPool::Init()
61 freeListHead_ = &pool_[0];64 freeListHead_ = &pool_[0];
62 for (uint32_t i = 0; i < poolSize_ - 1; i++) {65 for (uint32_t i = 0; i < poolSize_ - 1; i++) {
63 pool_[i].next = &pool_[i + 1];66 pool_[i].next = &pool_[i + 1];
64- pool_[i].valid = false;67+ pool_[i].valid.store(false, std::memory_order_relaxed);
65 }68 }
66 pool_[poolSize_ - 1].next = nullptr;69 pool_[poolSize_ - 1].next = nullptr;
67- pool_[poolSize_ - 1].valid = false;70+ pool_[poolSize_ - 1].valid.store(false, std::memory_order_relaxed);
68 freeListTail_ = &pool_[poolSize_ - 1];71 freeListTail_ = &pool_[poolSize_ - 1];
69 72 
70 freeThreadList_ = &threadCtxPool_[0];73 freeThreadList_ = &threadCtxPool_[0];
71- for (uint32_t i = 0; i < THREAD_POOL_SIZE - 1; i++) {74+ for (uint32_t i = 0; i < THREAD_POOL_SIZE; i++) {
72- memset_s(&(threadCtxPool_[i].contexts), sizeof(threadCtxPool_[i].contexts),75+ (void)memset_s(&(threadCtxPool_[i].contexts), sizeof(threadCtxPool_[i].contexts),
73 0, sizeof(threadCtxPool_[i].contexts));76 0, sizeof(threadCtxPool_[i].contexts));
74- threadCtxPool_[i].valid = false;77+ threadCtxPool_[i].valid.store(false, std::memory_order_relaxed);
75 threadCtxPool_[i].curAsyncContextsCnt = 0;78 threadCtxPool_[i].curAsyncContextsCnt = 0;
76- threadCtxPool_[i].next = &threadCtxPool_[i + 1];79+ threadCtxPool_[i].next = (i == THREAD_POOL_SIZE - 1) ? nullptr : &threadCtxPool_[i + 1];
77 }80 }
78- threadCtxPool_[THREAD_POOL_SIZE - 1].next = nullptr;
79- threadCtxPool_[THREAD_POOL_SIZE - 1].valid = false;
80 81 
81 initialized_.store(true);82 initialized_.store(true);
82 DFXLOGI("async context pool init success");83 DFXLOGI("async context pool init success");
@@ -85,14 +86,14 @@ bool DfxAsyncContextPool::Init()
85 86 
86void DfxAsyncContextPool::DeInit()87void DfxAsyncContextPool::DeInit()
87{88{
88- std::lock_guard<std::mutex> lock(mutex_);89+ std::lock_guard<std::shared_mutex> lock(sharedMutex_);
89 if (!initialized_.load()) {90 if (!initialized_.load()) {
90 return;91 return;
91 }92 }
92 initialized_.store(false);93 initialized_.store(false);
93 if (pool_ != nullptr) {94 if (pool_ != nullptr) {
94 size_t poolMemSize = static_cast<size_t>(poolSize_) * sizeof(DfxAsyncContext);95 size_t poolMemSize = static_cast<size_t>(poolSize_) * sizeof(DfxAsyncContext);
95- munmap(pool_, poolMemSize);96+ (void)syscall(SYS_munmap, pool_, poolMemSize);
96 pool_ = nullptr;97 pool_ = nullptr;
97 }98 }
98 poolSize_ = 0;99 poolSize_ = 0;
@@ -103,7 +104,7 @@ void DfxAsyncContextPool::DeInit()
103 104 
104DfxAsyncContext* DfxAsyncContextPool::AcquireAsyncContext()105DfxAsyncContext* DfxAsyncContextPool::AcquireAsyncContext()
105{106{
106- std::lock_guard<std::mutex> lock(mutex_);107+ std::lock_guard<std::shared_mutex> lock(sharedMutex_);
107 if (!initialized_.load()) {108 if (!initialized_.load()) {
108 return nullptr;109 return nullptr;
109 }110 }
@@ -113,7 +114,7 @@ DfxAsyncContext* DfxAsyncContextPool::AcquireAsyncContext()
113 }114 }
114 DfxAsyncContext* ctx = freeListHead_;115 DfxAsyncContext* ctx = freeListHead_;
115 freeListHead_ = freeListHead_->next;116 freeListHead_ = freeListHead_->next;
116- ctx->valid = true;117+ ctx->valid.store(true, std::memory_order_release);
117 return ctx;118 return ctx;
118}119}
119 120 
@@ -123,24 +124,26 @@ void DfxAsyncContextPool::ReleaseAsyncContext(DfxAsyncContext* ctx)
123 DFXLOGW("ReleaseAsyncContext ctx is nullptr");124 DFXLOGW("ReleaseAsyncContext ctx is nullptr");
124 return;125 return;
125 }126 }
126- std::lock_guard<std::mutex> lock(mutex_);127+ std::lock_guard<std::shared_mutex> lock(sharedMutex_);
127 if (!initialized_.load()) {128 if (!initialized_.load()) {
128 return;129 return;
129 }130 }
130- if (!ctx->valid) {131+ if (!ctx->valid.load(std::memory_order_acquire)) {
131 DFXLOGW("ReleaseAsyncContext ctx is invalid");132 DFXLOGW("ReleaseAsyncContext ctx is invalid");
132 return;133 return;
133 }134 }
135+ DFXLOGD("ReleaseAsyncContext tid:%{public}d, type %{public}llu",
136+ gettid(), static_cast<unsigned long long>(ctx->ctxs[0].type));
134 (void)memset_s(&ctx->ctxs[0], sizeof(ctx->ctxs), 0, sizeof(ctx->ctxs));137 (void)memset_s(&ctx->ctxs[0], sizeof(ctx->ctxs), 0, sizeof(ctx->ctxs));
135 freeListTail_->next = ctx;138 freeListTail_->next = ctx;
136 freeListTail_ = ctx;139 freeListTail_ = ctx;
137- ctx->valid = false;140+ ctx->valid.store(false, std::memory_order_release);
138 ctx->next = nullptr;141 ctx->next = nullptr;
139}142}
140 143 
141DfxThreadAsyncContext* DfxAsyncContextPool::AcquireThreadContext()144DfxThreadAsyncContext* DfxAsyncContextPool::AcquireThreadContext()
142{145{
143- std::lock_guard<std::mutex> lock(mutex_);146+ std::lock_guard<std::shared_mutex> lock(sharedMutex_);
144 if (!initialized_.load()) {147 if (!initialized_.load()) {
145 return nullptr;148 return nullptr;
146 }149 }
@@ -150,8 +153,9 @@ DfxThreadAsyncContext* DfxAsyncContextPool::AcquireThreadContext()
150 }153 }
151 DfxThreadAsyncContext* ctx = freeThreadList_;154 DfxThreadAsyncContext* ctx = freeThreadList_;
152 freeThreadList_ = freeThreadList_->next;155 freeThreadList_ = freeThreadList_->next;
153- ctx->valid = true;156+ ctx->valid.store(true, std::memory_order_release);
154 ctx->curAsyncContextsCnt = 0;157 ctx->curAsyncContextsCnt = 0;
158+ (void)memset_s(&(ctx->contexts), sizeof(ctx->contexts), 0, sizeof(ctx->contexts));
155 return ctx;159 return ctx;
156}160}
157 161 
@@ -161,11 +165,15 @@ void DfxAsyncContextPool::ReleaseThreadContext(DfxThreadAsyncContext* ctx)
161 DFXLOGW("ReleaseThreadContext ctx is nullptr");165 DFXLOGW("ReleaseThreadContext ctx is nullptr");
162 return;166 return;
163 }167 }
164- std::lock_guard<std::mutex> lock(mutex_);168+ std::lock_guard<std::shared_mutex> lock(sharedMutex_);
165 if (!initialized_.load()) {169 if (!initialized_.load()) {
166 return;170 return;
167 }171 }
168- ctx->valid = false;172+ if (!ctx->valid.load(std::memory_order_acquire)) {
173+ DFXLOGW("ReleaseThreadContext ctx is invalid");
174+ return;
175+ }
176+ ctx->valid.store(false, std::memory_order_release);
169 ctx->next = freeThreadList_;177 ctx->next = freeThreadList_;
170 ctx->curAsyncContextsCnt = 0;178 ctx->curAsyncContextsCnt = 0;
171 freeThreadList_ = ctx;179 freeThreadList_ = ctx;
@@ -195,6 +203,7 @@ void ThreadAsyncContextDestructor(void *arg)
195 203 
196bool DfxAsyncContextManager::Init()204bool DfxAsyncContextManager::Init()
197{205{
206+ std::lock_guard<std::mutex> lock(mutex_);
198 if (initialized_.load()) {207 if (initialized_.load()) {
199 return true;208 return true;
200 }209 }
@@ -203,6 +212,7 @@ bool DfxAsyncContextManager::Init()
203 return false;212 return false;
204 }213 }
205 if (pthread_key_create(&threadAsyncCtxKey_, ThreadAsyncContextDestructor) != 0) {214 if (pthread_key_create(&threadAsyncCtxKey_, ThreadAsyncContextDestructor) != 0) {
215+ DfxAsyncContextPool::Instance()->DeInit();
206 DFXLOGE("pthread_key_create failed");216 DFXLOGE("pthread_key_create failed");
207 return false;217 return false;
208 }218 }
@@ -213,12 +223,13 @@ bool DfxAsyncContextManager::Init()
213 223 
214void DfxAsyncContextManager::DeInit()224void DfxAsyncContextManager::DeInit()
215{225{
226+ std::lock_guard<std::mutex> lock(mutex_);
216 if (!initialized_.load()) {227 if (!initialized_.load()) {
217 return;228 return;
218 }229 }
230+ initialized_.store(false);
219 DfxAsyncContextPool::Instance()->DeInit();231 DfxAsyncContextPool::Instance()->DeInit();
220 pthread_key_delete(threadAsyncCtxKey_);232 pthread_key_delete(threadAsyncCtxKey_);
221- initialized_.store(false);
222 DFXLOGI("AsyncContextManager deinit success");233 DFXLOGI("AsyncContextManager deinit success");
223}234}
224 235 
@@ -233,7 +244,7 @@ DfxAsyncContext* DfxAsyncContextManager::GetCurrentContext()
233 return nullptr;244 return nullptr;
234 }245 }
235 if (threadCtx->curAsyncContextsCnt <= 0 || threadCtx->curAsyncContextsCnt > MAX_THREAD_ASYNC_CTX_DEPTH ||246 if (threadCtx->curAsyncContextsCnt <= 0 || threadCtx->curAsyncContextsCnt > MAX_THREAD_ASYNC_CTX_DEPTH ||
236- !threadCtx->valid) {247+ !threadCtx->valid.load(std::memory_order_acquire)) {
237 DFXLOGD("GetCurrentContext thread context count is invalid");248 DFXLOGD("GetCurrentContext thread context count is invalid");
238 return nullptr;249 return nullptr;
239 }250 }
@@ -248,7 +259,7 @@ void DfxAsyncContextManager::ClearThreadContext(DfxThreadAsyncContext* threadCtx
248 return;259 return;
249 }260 }
250 if (threadCtx->curAsyncContextsCnt < 0 || threadCtx->curAsyncContextsCnt > MAX_THREAD_ASYNC_CTX_DEPTH ||261 if (threadCtx->curAsyncContextsCnt < 0 || threadCtx->curAsyncContextsCnt > MAX_THREAD_ASYNC_CTX_DEPTH ||
251- !threadCtx->valid) {262+ !threadCtx->valid.load(std::memory_order_acquire)) {
252 DFXLOGW("ClearThreadContext invalid thread context");263 DFXLOGW("ClearThreadContext invalid thread context");
253 return;264 return;
254 }265 }
@@ -260,7 +271,20 @@ bool DfxAsyncContextPool::IsValidAsyncContextAddress(DfxAsyncContext* ctx)
260 if (ctx == nullptr) {271 if (ctx == nullptr) {
261 return false;272 return false;
262 }273 }
263- std::lock_guard<std::mutex> lock(mutex_);274+ std::shared_lock<std::shared_mutex> lock(sharedMutex_);
275+ return IsValidAsyncContextAddressLocked(ctx);
276+}
277+ 
278+std::shared_lock<std::shared_mutex> DfxAsyncContextPool::AcquireReadLock()
279+{
280+ return std::shared_lock<std::shared_mutex>(sharedMutex_);
281+}
282+ 
283+bool DfxAsyncContextPool::IsValidAsyncContextAddressLocked(DfxAsyncContext* ctx)
284+{
285+ if (ctx == nullptr) {
286+ return false;
287+ }
264 if (!initialized_.load() || pool_ == nullptr || poolSize_ == 0) {288 if (!initialized_.load() || pool_ == nullptr || poolSize_ == 0) {
265 return false;289 return false;
266 }290 }
@@ -282,8 +306,6 @@ bool DfxAsyncContextManager::RecycleAsyncContext(DfxAsyncContext* ctx)
282 DFXLOGW("RecycleAsyncContext ctx invalid");306 DFXLOGW("RecycleAsyncContext ctx invalid");
283 return false;307 return false;
284 }308 }
285- DFXLOGD("RecycleAsyncContext tid:%{public}d, type %{public}llu",
286- gettid(), static_cast<unsigned long long>(ctx->ctxs[0].type));
287 DfxAsyncContextPool::Instance()->ReleaseAsyncContext(ctx);309 DfxAsyncContextPool::Instance()->ReleaseAsyncContext(ctx);
288 return true;310 return true;
289}311}
@@ -301,6 +323,7 @@ void DfxAsyncContextManager::PushAsyncContext(DfxThreadAsyncContext* threadCtx,
301 threadCtx->curAsyncContextsCnt);323 threadCtx->curAsyncContextsCnt);
302 return;324 return;
303 }325 }
326+ auto readLock = DfxAsyncContextPool::Instance()->AcquireReadLock();
304 threadCtx->contexts[threadCtx->curAsyncContextsCnt++] = ctx;327 threadCtx->contexts[threadCtx->curAsyncContextsCnt++] = ctx;
305}328}
306 329 
@@ -338,6 +361,10 @@ void DfxAsyncContextManager::PopCurrentThreadContext(uint64_t stackId)
338 pthread_setspecific(threadAsyncCtxKey_, threadCtx);361 pthread_setspecific(threadAsyncCtxKey_, threadCtx);
339 }362 }
340 363 
364+ if (threadCtx->curAsyncContextsCnt <= 0) {
365+ DFXLOGW("PopCurrentThreadContext empty stack tid:%{public}d", gettid());
366+ return;
367+ }
341 if (ctx == threadCtx->contexts[threadCtx->curAsyncContextsCnt - 1]) {368 if (ctx == threadCtx->contexts[threadCtx->curAsyncContextsCnt - 1]) {
342 PopAsyncContext(threadCtx);369 PopAsyncContext(threadCtx);
343 }370 }
@@ -364,8 +391,13 @@ void DfxAsyncContextManager::SetCurrentThreadContext(uint64_t stackId)
364 if (ctx == nullptr) {391 if (ctx == nullptr) {
365 PopAsyncContext(threadCtx);392 PopAsyncContext(threadCtx);
366 return;393 return;
367- } else if (IsValidAsyncContext(ctx) && (ctx->ctxs[0].type & CLEAR_THREAD_CTX_TYPE)) {394+ }
368- ClearThreadContext(threadCtx);395+ {
396+ auto readLock = DfxAsyncContextPool::Instance()->AcquireReadLock();
397+ if (DfxAsyncContextPool::Instance()->IsValidAsyncContextAddressLocked(ctx) &&
398+ (ctx->ctxs[0].type & CLEAR_THREAD_CTX_TYPE)) {
399+ ClearThreadContext(threadCtx);
400+ }
369 }401 }
370 PushAsyncContext(threadCtx, ctx);402 PushAsyncContext(threadCtx, ctx);
371}403}
@@ -377,6 +409,7 @@ DfxAsyncContext* DfxAsyncContextManager::HandleCollectAsyncStack(uint64_t stackI
377 DFXLOGW("HandleCollectAsyncStack acquire async context failed");409 DFXLOGW("HandleCollectAsyncStack acquire async context failed");
378 return nullptr;410 return nullptr;
379 }411 }
412+ auto readLock = DfxAsyncContextPool::Instance()->AcquireReadLock();
380 ctx->ctxs[0].id = stackId;413 ctx->ctxs[0].id = stackId;
381 ctx->ctxs[0].type = asyncType;414 ctx->ctxs[0].type = asyncType;
382 auto curCtx = GetCurrentContext();415 auto curCtx = GetCurrentContext();
Minterfaces/innerkits/async_stack/async_stack.cpp+1-0
@@ -239,6 +239,7 @@ extern "C" int GetCurrentChainedAsyncContext(DfxAsyncCtx buffer[], size_t sz)
239 DFXLOGW("GetCurrentChainedAsyncContext sz is 0");239 DFXLOGW("GetCurrentChainedAsyncContext sz is 0");
240 return 0;240 return 0;
241 }241 }
242+ auto readLock = DfxAsyncContextPool::Instance()->AcquireReadLock();
C
CChenShiCoder10 天前

只保留这个,其他asyncstack可以去掉

likedislike
242 DfxAsyncContext* ctx = DfxAsyncContextManager::Instance()->GetCurrentContext();243 DfxAsyncContext* ctx = DfxAsyncContextManager::Instance()->GetCurrentContext();
243 if (ctx == nullptr) {244 if (ctx == nullptr) {
244 DFXLOGD("GetCurrentContext failed, ctx is nullptr");245 DFXLOGD("GetCurrentContext failed, ctx is nullptr");
Minterfaces/innerkits/async_stack/include/async_context_manager.h+8-4
@@ -18,6 +18,7 @@
18#include <stdint.h>18#include <stdint.h>
19#include <pthread.h>19#include <pthread.h>
20#include <mutex>20#include <mutex>
21+#include <shared_mutex>
21#include <atomic>22#include <atomic>
22#include "async_stack.h"23#include "async_stack.h"
23 24 
@@ -36,14 +37,14 @@ constexpr uint32_t PRINT_CHAIN_INTERVAL = 10;
36 37 
37typedef struct DfxAsyncContext {38typedef struct DfxAsyncContext {
38 DfxAsyncContext* next;39 DfxAsyncContext* next;
39- bool valid;40+ std::atomic<bool> valid;
40 DfxAsyncCtx ctxs[MAX_ASYNC_CHAIN_LAYERS_LIMIT];41 DfxAsyncCtx ctxs[MAX_ASYNC_CHAIN_LAYERS_LIMIT];
41} DfxAsyncContext;42} DfxAsyncContext;
42 43 
43typedef struct DfxThreadAsyncContext {44typedef struct DfxThreadAsyncContext {
44 DfxAsyncContext* contexts[MAX_THREAD_ASYNC_CTX_DEPTH];45 DfxAsyncContext* contexts[MAX_THREAD_ASYNC_CTX_DEPTH];
45 DfxThreadAsyncContext* next;46 DfxThreadAsyncContext* next;
46- bool valid;47+ std::atomic<bool> valid;
47 int32_t curAsyncContextsCnt;48 int32_t curAsyncContextsCnt;
48} DfxThreadAsyncContext;49} DfxThreadAsyncContext;
49 50 
@@ -60,6 +61,8 @@ public:
60 DfxThreadAsyncContext* AcquireThreadContext();61 DfxThreadAsyncContext* AcquireThreadContext();
61 void ReleaseThreadContext(DfxThreadAsyncContext* ctx);62 void ReleaseThreadContext(DfxThreadAsyncContext* ctx);
62 bool IsValidAsyncContextAddress(DfxAsyncContext* ctx);63 bool IsValidAsyncContextAddress(DfxAsyncContext* ctx);
64+ std::shared_lock<std::shared_mutex> AcquireReadLock();
65+ bool IsValidAsyncContextAddressLocked(DfxAsyncContext* ctx);
63private:66private:
64 DfxAsyncContextPool() = default;67 DfxAsyncContextPool() = default;
65 ~DfxAsyncContextPool() = default;68 ~DfxAsyncContextPool() = default;
@@ -71,7 +74,7 @@ private:
71 DfxAsyncContext* freeListHead_{nullptr};74 DfxAsyncContext* freeListHead_{nullptr};
72 DfxAsyncContext* freeListTail_{nullptr};75 DfxAsyncContext* freeListTail_{nullptr};
73 DfxThreadAsyncContext* freeThreadList_{nullptr};76 DfxThreadAsyncContext* freeThreadList_{nullptr};
74- std::mutex mutex_;77+ std::shared_mutex sharedMutex_;
75 std::atomic<bool> initialized_{false};78 std::atomic<bool> initialized_{false};
76};79};
77 80 
@@ -95,7 +98,8 @@ private:
95 void PushAsyncContext(DfxThreadAsyncContext* threadCtx, DfxAsyncContext* ctx);98 void PushAsyncContext(DfxThreadAsyncContext* threadCtx, DfxAsyncContext* ctx);
96 void PopAsyncContext(DfxThreadAsyncContext* threadCtx);99 void PopAsyncContext(DfxThreadAsyncContext* threadCtx);
97 pthread_key_t threadAsyncCtxKey_;100 pthread_key_t threadAsyncCtxKey_;
98- std::atomic<bool> initialized_;101+ std::atomic<bool> initialized_{false};
102+ std::mutex mutex_;
99};103};
100 104 
101} // namespace HiviewDFX105} // namespace HiviewDFX
Mtest/unittest/async_stack/async_stack_test.cpp+48-0
@@ -677,5 +677,53 @@ HWTEST_F(AsyncStackTest, AsyncStackTest015, TestSize.Level2)
677#endif677#endif
678 GTEST_LOG_(INFO) << "AsyncStackTest015: end.";678 GTEST_LOG_(INFO) << "AsyncStackTest015: end.";
679}679}
680+ 
681+/**
682+ * @tc.name: AsyncStackTest016
683+ * @tc.desc: test concurrent GetCurrentChainedAsyncContext with SetAsyncStackMode DeInit/munmap
684+ * @tc.type: FUNC
685+ */
686+HWTEST_F(AsyncStackTest, AsyncStackTest016, TestSize.Level2)
687+{
688+#if defined(__aarch64__)
689+ GTEST_LOG_(INFO) << "AsyncStackTest016: start.";
690+ ASSERT_TRUE(DfxInitAsyncStack());
691+ constexpr int ROUND_COUNT = 30;
692+ for (int round = 0; round < ROUND_COUNT; round++) {
693+ SetAsyncStackMode(MODE_CHAINED_STACKTRACE);
694+ DfxSetAsyncStackType(DEFAULT_ASYNC_TYPE);
695+ std::atomic<bool> stopFlag{false};
696+ std::atomic<bool> started{false};
697+ auto reader = [&stopFlag, &started]() {
698+ uint64_t sid = DfxCollectAsyncStack(ASYNC_TYPE_LIBUV_QUEUE);
699+ DfxSetSubmitterStackId(sid);
700+ started.store(true, std::memory_order_release);
701+ DfxAsyncCtx buffer[5];
702+ while (!stopFlag.load(std::memory_order_relaxed)) {
703+ (void)memset_s(buffer, sizeof(buffer), 0, sizeof(buffer));
704+ GetCurrentChainedAsyncContext(buffer, 5);
705+ }
706+ DfxSetSubmitterStackId(0);
707+ };
708+ auto toggler = [&stopFlag, &started]() {
709+ while (!started.load(std::memory_order_acquire)) {
710+ std::this_thread::yield();
711+ }
712+ std::this_thread::yield();
713+ SetAsyncStackMode(MODE_LAST_STACKTRACE);
714+ SetAsyncStackMode(MODE_CHAINED_STACKTRACE);
715+ stopFlag.store(true, std::memory_order_relaxed);
716+ };
717+ std::thread t0(reader);
718+ std::thread t1(toggler);
719+ t0.join();
720+ t1.join();
721+ SetAsyncStackMode(MODE_LAST_STACKTRACE);
722+ }
723+ GTEST_LOG_(INFO) << "AsyncStackTest016: survived " << ROUND_COUNT << " rounds.";
724+ SUCCEED();
725+ GTEST_LOG_(INFO) << "AsyncStackTest016: end.";
726+#endif
727+}
680} // namespace HiviewDFX728} // namespace HiviewDFX
681} // namespace OHOS729} // namespace OHOS