xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
168d75effSDimitry Andric //===-- tsan_rtl_thread.cpp -----------------------------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // This file is a part of ThreadSanitizer (TSan), a race detector.
1068d75effSDimitry Andric //
1168d75effSDimitry Andric //===----------------------------------------------------------------------===//
1268d75effSDimitry Andric 
1368d75effSDimitry Andric #include "sanitizer_common/sanitizer_placement_new.h"
1468d75effSDimitry Andric #include "tsan_rtl.h"
1568d75effSDimitry Andric #include "tsan_mman.h"
1668d75effSDimitry Andric #include "tsan_platform.h"
1768d75effSDimitry Andric #include "tsan_report.h"
1868d75effSDimitry Andric #include "tsan_sync.h"
1968d75effSDimitry Andric 
2068d75effSDimitry Andric namespace __tsan {
2168d75effSDimitry Andric 
2268d75effSDimitry Andric // ThreadContext implementation.
2368d75effSDimitry Andric 
240eae32dcSDimitry Andric ThreadContext::ThreadContext(Tid tid) : ThreadContextBase(tid), thr(), sync() {}
2568d75effSDimitry Andric 
2668d75effSDimitry Andric #if !SANITIZER_GO
2768d75effSDimitry Andric ThreadContext::~ThreadContext() {
2868d75effSDimitry Andric }
2968d75effSDimitry Andric #endif
3068d75effSDimitry Andric 
310eae32dcSDimitry Andric void ThreadContext::OnReset() { CHECK(!sync); }
3268d75effSDimitry Andric 
3368d75effSDimitry Andric #if !SANITIZER_GO
3468d75effSDimitry Andric struct ThreadLeak {
3568d75effSDimitry Andric   ThreadContext *tctx;
3668d75effSDimitry Andric   int count;
3768d75effSDimitry Andric };
3868d75effSDimitry Andric 
39349cc55cSDimitry Andric static void CollectThreadLeaks(ThreadContextBase *tctx_base, void *arg) {
40349cc55cSDimitry Andric   auto &leaks = *static_cast<Vector<ThreadLeak> *>(arg);
41349cc55cSDimitry Andric   auto *tctx = static_cast<ThreadContext *>(tctx_base);
4268d75effSDimitry Andric   if (tctx->detached || tctx->status != ThreadStatusFinished)
4368d75effSDimitry Andric     return;
4468d75effSDimitry Andric   for (uptr i = 0; i < leaks.Size(); i++) {
4568d75effSDimitry Andric     if (leaks[i].tctx->creation_stack_id == tctx->creation_stack_id) {
4668d75effSDimitry Andric       leaks[i].count++;
4768d75effSDimitry Andric       return;
4868d75effSDimitry Andric     }
4968d75effSDimitry Andric   }
50349cc55cSDimitry Andric   leaks.PushBack({tctx, 1});
5168d75effSDimitry Andric }
5268d75effSDimitry Andric #endif
5368d75effSDimitry Andric 
540eae32dcSDimitry Andric // Disabled on Mac because lldb test TestTsanBasic fails:
550eae32dcSDimitry Andric // https://reviews.llvm.org/D112603#3163158
5681ad6265SDimitry Andric #if !SANITIZER_GO && !SANITIZER_APPLE
5768d75effSDimitry Andric static void ReportIgnoresEnabled(ThreadContext *tctx, IgnoreSet *set) {
58fe6060f1SDimitry Andric   if (tctx->tid == kMainTid) {
5968d75effSDimitry Andric     Printf("ThreadSanitizer: main thread finished with ignores enabled\n");
6068d75effSDimitry Andric   } else {
6168d75effSDimitry Andric     Printf("ThreadSanitizer: thread T%d %s finished with ignores enabled,"
6268d75effSDimitry Andric       " created at:\n", tctx->tid, tctx->name);
6368d75effSDimitry Andric     PrintStack(SymbolizeStackId(tctx->creation_stack_id));
6468d75effSDimitry Andric   }
6568d75effSDimitry Andric   Printf("  One of the following ignores was not ended"
6668d75effSDimitry Andric       " (in order of probability)\n");
6768d75effSDimitry Andric   for (uptr i = 0; i < set->Size(); i++) {
6868d75effSDimitry Andric     Printf("  Ignore was enabled at:\n");
6968d75effSDimitry Andric     PrintStack(SymbolizeStackId(set->At(i)));
7068d75effSDimitry Andric   }
7168d75effSDimitry Andric   Die();
7268d75effSDimitry Andric }
7368d75effSDimitry Andric 
7468d75effSDimitry Andric static void ThreadCheckIgnore(ThreadState *thr) {
7568d75effSDimitry Andric   if (ctx->after_multithreaded_fork)
7668d75effSDimitry Andric     return;
7768d75effSDimitry Andric   if (thr->ignore_reads_and_writes)
7868d75effSDimitry Andric     ReportIgnoresEnabled(thr->tctx, &thr->mop_ignore_set);
7968d75effSDimitry Andric   if (thr->ignore_sync)
8068d75effSDimitry Andric     ReportIgnoresEnabled(thr->tctx, &thr->sync_ignore_set);
8168d75effSDimitry Andric }
8268d75effSDimitry Andric #else
8368d75effSDimitry Andric static void ThreadCheckIgnore(ThreadState *thr) {}
8468d75effSDimitry Andric #endif
8568d75effSDimitry Andric 
8668d75effSDimitry Andric void ThreadFinalize(ThreadState *thr) {
8768d75effSDimitry Andric   ThreadCheckIgnore(thr);
8868d75effSDimitry Andric #if !SANITIZER_GO
89fe6060f1SDimitry Andric   if (!ShouldReport(thr, ReportTypeThreadLeak))
9068d75effSDimitry Andric     return;
91349cc55cSDimitry Andric   ThreadRegistryLock l(&ctx->thread_registry);
9268d75effSDimitry Andric   Vector<ThreadLeak> leaks;
93349cc55cSDimitry Andric   ctx->thread_registry.RunCallbackForEachThreadLocked(CollectThreadLeaks,
94349cc55cSDimitry Andric                                                       &leaks);
9568d75effSDimitry Andric   for (uptr i = 0; i < leaks.Size(); i++) {
9668d75effSDimitry Andric     ScopedReport rep(ReportTypeThreadLeak);
9768d75effSDimitry Andric     rep.AddThread(leaks[i].tctx, true);
9868d75effSDimitry Andric     rep.SetCount(leaks[i].count);
9968d75effSDimitry Andric     OutputReport(thr, rep);
10068d75effSDimitry Andric   }
10168d75effSDimitry Andric #endif
10268d75effSDimitry Andric }
10368d75effSDimitry Andric 
10468d75effSDimitry Andric int ThreadCount(ThreadState *thr) {
10568d75effSDimitry Andric   uptr result;
106349cc55cSDimitry Andric   ctx->thread_registry.GetNumberOfThreads(0, 0, &result);
10768d75effSDimitry Andric   return (int)result;
10868d75effSDimitry Andric }
10968d75effSDimitry Andric 
110349cc55cSDimitry Andric struct OnCreatedArgs {
1110eae32dcSDimitry Andric   VectorClock *sync;
1120eae32dcSDimitry Andric   uptr sync_epoch;
1130eae32dcSDimitry Andric   StackID stack;
114349cc55cSDimitry Andric };
115349cc55cSDimitry Andric 
116349cc55cSDimitry Andric Tid ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached) {
1170eae32dcSDimitry Andric   // The main thread and GCD workers don't have a parent thread.
1180eae32dcSDimitry Andric   Tid parent = kInvalidTid;
1190eae32dcSDimitry Andric   OnCreatedArgs arg = {nullptr, 0, kInvalidStackID};
1200eae32dcSDimitry Andric   if (thr) {
1210eae32dcSDimitry Andric     parent = thr->tid;
1220eae32dcSDimitry Andric     arg.stack = CurrentStackId(thr, pc);
1230eae32dcSDimitry Andric     if (!thr->ignore_sync) {
1240eae32dcSDimitry Andric       SlotLocker locker(thr);
1250eae32dcSDimitry Andric       thr->clock.ReleaseStore(&arg.sync);
1260eae32dcSDimitry Andric       arg.sync_epoch = ctx->global_epoch;
1270eae32dcSDimitry Andric       IncrementEpoch(thr);
1280eae32dcSDimitry Andric     }
1290eae32dcSDimitry Andric   }
1300eae32dcSDimitry Andric   Tid tid = ctx->thread_registry.CreateThread(uid, detached, parent, &arg);
1310eae32dcSDimitry Andric   DPrintf("#%d: ThreadCreate tid=%d uid=%zu\n", parent, tid, uid);
13268d75effSDimitry Andric   return tid;
13368d75effSDimitry Andric }
13468d75effSDimitry Andric 
135349cc55cSDimitry Andric void ThreadContext::OnCreated(void *arg) {
136349cc55cSDimitry Andric   OnCreatedArgs *args = static_cast<OnCreatedArgs *>(arg);
1370eae32dcSDimitry Andric   sync = args->sync;
1380eae32dcSDimitry Andric   sync_epoch = args->sync_epoch;
1390eae32dcSDimitry Andric   creation_stack_id = args->stack;
140349cc55cSDimitry Andric }
141349cc55cSDimitry Andric 
142349cc55cSDimitry Andric extern "C" void __tsan_stack_initialization() {}
143349cc55cSDimitry Andric 
144349cc55cSDimitry Andric struct OnStartedArgs {
145349cc55cSDimitry Andric   ThreadState *thr;
146349cc55cSDimitry Andric   uptr stk_addr;
147349cc55cSDimitry Andric   uptr stk_size;
148349cc55cSDimitry Andric   uptr tls_addr;
149349cc55cSDimitry Andric   uptr tls_size;
150349cc55cSDimitry Andric };
151349cc55cSDimitry Andric 
152349cc55cSDimitry Andric void ThreadStart(ThreadState *thr, Tid tid, tid_t os_id,
15368d75effSDimitry Andric                  ThreadType thread_type) {
1540eae32dcSDimitry Andric   ctx->thread_registry.StartThread(tid, os_id, thread_type, thr);
1550eae32dcSDimitry Andric   if (!thr->ignore_sync) {
1560eae32dcSDimitry Andric     SlotAttachAndLock(thr);
1570eae32dcSDimitry Andric     if (thr->tctx->sync_epoch == ctx->global_epoch)
1580eae32dcSDimitry Andric       thr->clock.Acquire(thr->tctx->sync);
1590eae32dcSDimitry Andric     SlotUnlock(thr);
1600eae32dcSDimitry Andric   }
1610eae32dcSDimitry Andric   Free(thr->tctx->sync);
1620eae32dcSDimitry Andric 
163*0fca6ea1SDimitry Andric #if !SANITIZER_GO
164*0fca6ea1SDimitry Andric   thr->is_inited = true;
165*0fca6ea1SDimitry Andric #endif
166*0fca6ea1SDimitry Andric 
16768d75effSDimitry Andric   uptr stk_addr = 0;
16868d75effSDimitry Andric   uptr stk_size = 0;
16968d75effSDimitry Andric   uptr tls_addr = 0;
17068d75effSDimitry Andric   uptr tls_size = 0;
17168d75effSDimitry Andric #if !SANITIZER_GO
17268d75effSDimitry Andric   if (thread_type != ThreadType::Fiber)
173fe6060f1SDimitry Andric     GetThreadStackAndTls(tid == kMainTid, &stk_addr, &stk_size, &tls_addr,
174fe6060f1SDimitry Andric                          &tls_size);
17568d75effSDimitry Andric #endif
1760eae32dcSDimitry Andric   thr->stk_addr = stk_addr;
1770eae32dcSDimitry Andric   thr->stk_size = stk_size;
1780eae32dcSDimitry Andric   thr->tls_addr = tls_addr;
1790eae32dcSDimitry Andric   thr->tls_size = tls_size;
18068d75effSDimitry Andric 
18168d75effSDimitry Andric #if !SANITIZER_GO
18268d75effSDimitry Andric   if (ctx->after_multithreaded_fork) {
18368d75effSDimitry Andric     thr->ignore_interceptors++;
18468d75effSDimitry Andric     ThreadIgnoreBegin(thr, 0);
18568d75effSDimitry Andric     ThreadIgnoreSyncBegin(thr, 0);
18668d75effSDimitry Andric   }
18768d75effSDimitry Andric #endif
188349cc55cSDimitry Andric 
189349cc55cSDimitry Andric #if !SANITIZER_GO
190349cc55cSDimitry Andric   // Don't imitate stack/TLS writes for the main thread,
191349cc55cSDimitry Andric   // because its initialization is synchronized with all
192349cc55cSDimitry Andric   // subsequent threads anyway.
193349cc55cSDimitry Andric   if (tid != kMainTid) {
194349cc55cSDimitry Andric     if (stk_addr && stk_size) {
195349cc55cSDimitry Andric       const uptr pc = StackTrace::GetNextInstructionPc(
196349cc55cSDimitry Andric           reinterpret_cast<uptr>(__tsan_stack_initialization));
197349cc55cSDimitry Andric       MemoryRangeImitateWrite(thr, pc, stk_addr, stk_size);
198349cc55cSDimitry Andric     }
199349cc55cSDimitry Andric 
200349cc55cSDimitry Andric     if (tls_addr && tls_size)
201349cc55cSDimitry Andric       ImitateTlsWrite(thr, tls_addr, tls_size);
202349cc55cSDimitry Andric   }
203349cc55cSDimitry Andric #endif
204349cc55cSDimitry Andric }
205349cc55cSDimitry Andric 
206349cc55cSDimitry Andric void ThreadContext::OnStarted(void *arg) {
2070eae32dcSDimitry Andric   DPrintf("#%d: ThreadStart\n", tid);
208*0fca6ea1SDimitry Andric   thr = new (arg) ThreadState(tid);
209349cc55cSDimitry Andric   if (common_flags()->detect_deadlocks)
2100eae32dcSDimitry Andric     thr->dd_lt = ctx->dd->CreateLogicalThread(tid);
211349cc55cSDimitry Andric   thr->tctx = this;
21268d75effSDimitry Andric }
21368d75effSDimitry Andric 
21468d75effSDimitry Andric void ThreadFinish(ThreadState *thr) {
2150eae32dcSDimitry Andric   DPrintf("#%d: ThreadFinish\n", thr->tid);
21668d75effSDimitry Andric   ThreadCheckIgnore(thr);
21768d75effSDimitry Andric   if (thr->stk_addr && thr->stk_size)
21868d75effSDimitry Andric     DontNeedShadowFor(thr->stk_addr, thr->stk_size);
21968d75effSDimitry Andric   if (thr->tls_addr && thr->tls_size)
22068d75effSDimitry Andric     DontNeedShadowFor(thr->tls_addr, thr->tls_size);
22168d75effSDimitry Andric   thr->is_dead = true;
222349cc55cSDimitry Andric #if !SANITIZER_GO
2230eae32dcSDimitry Andric   thr->is_inited = false;
224349cc55cSDimitry Andric   thr->ignore_interceptors++;
2250eae32dcSDimitry Andric   PlatformCleanUpThreadState(thr);
226349cc55cSDimitry Andric #endif
2270eae32dcSDimitry Andric   if (!thr->ignore_sync) {
2280eae32dcSDimitry Andric     SlotLocker locker(thr);
2290eae32dcSDimitry Andric     ThreadRegistryLock lock(&ctx->thread_registry);
2300eae32dcSDimitry Andric     // Note: detached is protected by the thread registry mutex,
2310eae32dcSDimitry Andric     // the thread may be detaching concurrently in another thread.
2320eae32dcSDimitry Andric     if (!thr->tctx->detached) {
2330eae32dcSDimitry Andric       thr->clock.ReleaseStore(&thr->tctx->sync);
2340eae32dcSDimitry Andric       thr->tctx->sync_epoch = ctx->global_epoch;
2350eae32dcSDimitry Andric       IncrementEpoch(thr);
236349cc55cSDimitry Andric     }
237349cc55cSDimitry Andric   }
238349cc55cSDimitry Andric #if !SANITIZER_GO
239349cc55cSDimitry Andric   UnmapOrDie(thr->shadow_stack, kShadowStackSize * sizeof(uptr));
240349cc55cSDimitry Andric #else
241349cc55cSDimitry Andric   Free(thr->shadow_stack);
242349cc55cSDimitry Andric #endif
243349cc55cSDimitry Andric   thr->shadow_stack = nullptr;
244349cc55cSDimitry Andric   thr->shadow_stack_pos = nullptr;
245349cc55cSDimitry Andric   thr->shadow_stack_end = nullptr;
246349cc55cSDimitry Andric   if (common_flags()->detect_deadlocks)
247349cc55cSDimitry Andric     ctx->dd->DestroyLogicalThread(thr->dd_lt);
2480eae32dcSDimitry Andric   SlotDetach(thr);
2490eae32dcSDimitry Andric   ctx->thread_registry.FinishThread(thr->tid);
250349cc55cSDimitry Andric   thr->~ThreadState();
2510eae32dcSDimitry Andric }
2520eae32dcSDimitry Andric 
2530eae32dcSDimitry Andric void ThreadContext::OnFinished() {
2540eae32dcSDimitry Andric   Lock lock(&ctx->slot_mtx);
2550eae32dcSDimitry Andric   Lock lock1(&trace.mtx);
2560eae32dcSDimitry Andric   // Queue all trace parts into the global recycle queue.
2570eae32dcSDimitry Andric   auto parts = &trace.parts;
2580eae32dcSDimitry Andric   while (trace.local_head) {
2590eae32dcSDimitry Andric     CHECK(parts->Queued(trace.local_head));
2600eae32dcSDimitry Andric     ctx->trace_part_recycle.PushBack(trace.local_head);
2610eae32dcSDimitry Andric     trace.local_head = parts->Next(trace.local_head);
2620eae32dcSDimitry Andric   }
2630eae32dcSDimitry Andric   ctx->trace_part_recycle_finished += parts->Size();
2640eae32dcSDimitry Andric   if (ctx->trace_part_recycle_finished > Trace::kFinishedThreadHi) {
2650eae32dcSDimitry Andric     ctx->trace_part_finished_excess += parts->Size();
2660eae32dcSDimitry Andric     trace.parts_allocated = 0;
2670eae32dcSDimitry Andric   } else if (ctx->trace_part_recycle_finished > Trace::kFinishedThreadLo &&
2680eae32dcSDimitry Andric              parts->Size() > 1) {
2690eae32dcSDimitry Andric     ctx->trace_part_finished_excess += parts->Size() - 1;
2700eae32dcSDimitry Andric     trace.parts_allocated = 1;
2710eae32dcSDimitry Andric   }
2720eae32dcSDimitry Andric   // From now on replay will use trace->final_pos.
2730eae32dcSDimitry Andric   trace.final_pos = (Event *)atomic_load_relaxed(&thr->trace_pos);
2740eae32dcSDimitry Andric   atomic_store_relaxed(&thr->trace_pos, 0);
2750eae32dcSDimitry Andric   thr->tctx = nullptr;
2760eae32dcSDimitry Andric   thr = nullptr;
27768d75effSDimitry Andric }
27868d75effSDimitry Andric 
2795ffd83dbSDimitry Andric struct ConsumeThreadContext {
2805ffd83dbSDimitry Andric   uptr uid;
2815ffd83dbSDimitry Andric   ThreadContextBase *tctx;
2825ffd83dbSDimitry Andric };
2835ffd83dbSDimitry Andric 
284349cc55cSDimitry Andric Tid ThreadConsumeTid(ThreadState *thr, uptr pc, uptr uid) {
285349cc55cSDimitry Andric   return ctx->thread_registry.ConsumeThreadUserId(uid);
28668d75effSDimitry Andric }
28768d75effSDimitry Andric 
2880eae32dcSDimitry Andric struct JoinArg {
2890eae32dcSDimitry Andric   VectorClock *sync;
2900eae32dcSDimitry Andric   uptr sync_epoch;
2910eae32dcSDimitry Andric };
2920eae32dcSDimitry Andric 
293349cc55cSDimitry Andric void ThreadJoin(ThreadState *thr, uptr pc, Tid tid) {
29468d75effSDimitry Andric   CHECK_GT(tid, 0);
29568d75effSDimitry Andric   DPrintf("#%d: ThreadJoin tid=%d\n", thr->tid, tid);
2960eae32dcSDimitry Andric   JoinArg arg = {};
2970eae32dcSDimitry Andric   ctx->thread_registry.JoinThread(tid, &arg);
2980eae32dcSDimitry Andric   if (!thr->ignore_sync) {
2990eae32dcSDimitry Andric     SlotLocker locker(thr);
3000eae32dcSDimitry Andric     if (arg.sync_epoch == ctx->global_epoch)
3010eae32dcSDimitry Andric       thr->clock.Acquire(arg.sync);
3020eae32dcSDimitry Andric   }
3030eae32dcSDimitry Andric   Free(arg.sync);
30468d75effSDimitry Andric }
30568d75effSDimitry Andric 
3060eae32dcSDimitry Andric void ThreadContext::OnJoined(void *ptr) {
3070eae32dcSDimitry Andric   auto arg = static_cast<JoinArg *>(ptr);
3080eae32dcSDimitry Andric   arg->sync = sync;
3090eae32dcSDimitry Andric   arg->sync_epoch = sync_epoch;
3100eae32dcSDimitry Andric   sync = nullptr;
3110eae32dcSDimitry Andric   sync_epoch = 0;
31268d75effSDimitry Andric }
31368d75effSDimitry Andric 
3140eae32dcSDimitry Andric void ThreadContext::OnDead() { CHECK_EQ(sync, nullptr); }
315349cc55cSDimitry Andric 
316349cc55cSDimitry Andric void ThreadDetach(ThreadState *thr, uptr pc, Tid tid) {
31768d75effSDimitry Andric   CHECK_GT(tid, 0);
318349cc55cSDimitry Andric   ctx->thread_registry.DetachThread(tid, thr);
319349cc55cSDimitry Andric }
320349cc55cSDimitry Andric 
3210eae32dcSDimitry Andric void ThreadContext::OnDetached(void *arg) { Free(sync); }
322349cc55cSDimitry Andric 
323349cc55cSDimitry Andric void ThreadNotJoined(ThreadState *thr, uptr pc, Tid tid, uptr uid) {
324349cc55cSDimitry Andric   CHECK_GT(tid, 0);
325349cc55cSDimitry Andric   ctx->thread_registry.SetThreadUserId(tid, uid);
32668d75effSDimitry Andric }
32768d75effSDimitry Andric 
32868d75effSDimitry Andric void ThreadSetName(ThreadState *thr, const char *name) {
329349cc55cSDimitry Andric   ctx->thread_registry.SetThreadName(thr->tid, name);
33068d75effSDimitry Andric }
33168d75effSDimitry Andric 
33268d75effSDimitry Andric #if !SANITIZER_GO
33368d75effSDimitry Andric void FiberSwitchImpl(ThreadState *from, ThreadState *to) {
33468d75effSDimitry Andric   Processor *proc = from->proc();
33568d75effSDimitry Andric   ProcUnwire(proc, from);
33668d75effSDimitry Andric   ProcWire(proc, to);
33768d75effSDimitry Andric   set_cur_thread(to);
33868d75effSDimitry Andric }
33968d75effSDimitry Andric 
34068d75effSDimitry Andric ThreadState *FiberCreate(ThreadState *thr, uptr pc, unsigned flags) {
341349cc55cSDimitry Andric   void *mem = Alloc(sizeof(ThreadState));
34268d75effSDimitry Andric   ThreadState *fiber = static_cast<ThreadState *>(mem);
34368d75effSDimitry Andric   internal_memset(fiber, 0, sizeof(*fiber));
344349cc55cSDimitry Andric   Tid tid = ThreadCreate(thr, pc, 0, true);
34568d75effSDimitry Andric   FiberSwitchImpl(thr, fiber);
34668d75effSDimitry Andric   ThreadStart(fiber, tid, 0, ThreadType::Fiber);
34768d75effSDimitry Andric   FiberSwitchImpl(fiber, thr);
34868d75effSDimitry Andric   return fiber;
34968d75effSDimitry Andric }
35068d75effSDimitry Andric 
35168d75effSDimitry Andric void FiberDestroy(ThreadState *thr, uptr pc, ThreadState *fiber) {
35268d75effSDimitry Andric   FiberSwitchImpl(thr, fiber);
35368d75effSDimitry Andric   ThreadFinish(fiber);
35468d75effSDimitry Andric   FiberSwitchImpl(fiber, thr);
355349cc55cSDimitry Andric   Free(fiber);
35668d75effSDimitry Andric }
35768d75effSDimitry Andric 
35868d75effSDimitry Andric void FiberSwitch(ThreadState *thr, uptr pc,
35968d75effSDimitry Andric                  ThreadState *fiber, unsigned flags) {
36068d75effSDimitry Andric   if (!(flags & FiberSwitchFlagNoSync))
36168d75effSDimitry Andric     Release(thr, pc, (uptr)fiber);
36268d75effSDimitry Andric   FiberSwitchImpl(thr, fiber);
36368d75effSDimitry Andric   if (!(flags & FiberSwitchFlagNoSync))
36468d75effSDimitry Andric     Acquire(fiber, pc, (uptr)fiber);
36568d75effSDimitry Andric }
36668d75effSDimitry Andric #endif
36768d75effSDimitry Andric 
36868d75effSDimitry Andric }  // namespace __tsan
369