15a3bb1a4SNico Weber //===-- tsan_rtl_thread.cpp -----------------------------------------------===// 25a3bb1a4SNico Weber // 35a3bb1a4SNico Weber // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45a3bb1a4SNico Weber // See https://llvm.org/LICENSE.txt for license information. 55a3bb1a4SNico Weber // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65a3bb1a4SNico Weber // 75a3bb1a4SNico Weber //===----------------------------------------------------------------------===// 85a3bb1a4SNico Weber // 95a3bb1a4SNico Weber // This file is a part of ThreadSanitizer (TSan), a race detector. 105a3bb1a4SNico Weber // 115a3bb1a4SNico Weber //===----------------------------------------------------------------------===// 125a3bb1a4SNico Weber 135a3bb1a4SNico Weber #include "sanitizer_common/sanitizer_placement_new.h" 145a3bb1a4SNico Weber #include "tsan_rtl.h" 155a3bb1a4SNico Weber #include "tsan_mman.h" 165a3bb1a4SNico Weber #include "tsan_platform.h" 175a3bb1a4SNico Weber #include "tsan_report.h" 185a3bb1a4SNico Weber #include "tsan_sync.h" 195a3bb1a4SNico Weber 205a3bb1a4SNico Weber namespace __tsan { 215a3bb1a4SNico Weber 225a3bb1a4SNico Weber // ThreadContext implementation. 235a3bb1a4SNico Weber 24b3321349SDmitry Vyukov ThreadContext::ThreadContext(Tid tid) : ThreadContextBase(tid), thr(), sync() {} 255a3bb1a4SNico Weber 265a3bb1a4SNico Weber #if !SANITIZER_GO 275a3bb1a4SNico Weber ThreadContext::~ThreadContext() { 285a3bb1a4SNico Weber } 295a3bb1a4SNico Weber #endif 305a3bb1a4SNico Weber 31b3321349SDmitry Vyukov void ThreadContext::OnReset() { CHECK(!sync); } 325a3bb1a4SNico Weber 335a3bb1a4SNico Weber #if !SANITIZER_GO 345a3bb1a4SNico Weber struct ThreadLeak { 355a3bb1a4SNico Weber ThreadContext *tctx; 365a3bb1a4SNico Weber int count; 375a3bb1a4SNico Weber }; 385a3bb1a4SNico Weber 3915eb4315SDmitry Vyukov static void CollectThreadLeaks(ThreadContextBase *tctx_base, void *arg) { 4015eb4315SDmitry Vyukov auto &leaks = *static_cast<Vector<ThreadLeak> *>(arg); 4115eb4315SDmitry Vyukov auto *tctx = static_cast<ThreadContext *>(tctx_base); 425a3bb1a4SNico Weber if (tctx->detached || tctx->status != ThreadStatusFinished) 435a3bb1a4SNico Weber return; 445a3bb1a4SNico Weber for (uptr i = 0; i < leaks.Size(); i++) { 455a3bb1a4SNico Weber if (leaks[i].tctx->creation_stack_id == tctx->creation_stack_id) { 465a3bb1a4SNico Weber leaks[i].count++; 475a3bb1a4SNico Weber return; 485a3bb1a4SNico Weber } 495a3bb1a4SNico Weber } 5015eb4315SDmitry Vyukov leaks.PushBack({tctx, 1}); 515a3bb1a4SNico Weber } 525a3bb1a4SNico Weber #endif 535a3bb1a4SNico Weber 54b3321349SDmitry Vyukov // Disabled on Mac because lldb test TestTsanBasic fails: 55b3321349SDmitry Vyukov // https://reviews.llvm.org/D112603#3163158 568246b2e1SMariusz Borsa #if !SANITIZER_GO && !SANITIZER_APPLE 575a3bb1a4SNico Weber static void ReportIgnoresEnabled(ThreadContext *tctx, IgnoreSet *set) { 5892a3a2dcSDmitry Vyukov if (tctx->tid == kMainTid) { 595a3bb1a4SNico Weber Printf("ThreadSanitizer: main thread finished with ignores enabled\n"); 605a3bb1a4SNico Weber } else { 615a3bb1a4SNico Weber Printf("ThreadSanitizer: thread T%d %s finished with ignores enabled," 625a3bb1a4SNico Weber " created at:\n", tctx->tid, tctx->name); 635a3bb1a4SNico Weber PrintStack(SymbolizeStackId(tctx->creation_stack_id)); 645a3bb1a4SNico Weber } 655a3bb1a4SNico Weber Printf(" One of the following ignores was not ended" 665a3bb1a4SNico Weber " (in order of probability)\n"); 675a3bb1a4SNico Weber for (uptr i = 0; i < set->Size(); i++) { 685a3bb1a4SNico Weber Printf(" Ignore was enabled at:\n"); 695a3bb1a4SNico Weber PrintStack(SymbolizeStackId(set->At(i))); 705a3bb1a4SNico Weber } 715a3bb1a4SNico Weber Die(); 725a3bb1a4SNico Weber } 735a3bb1a4SNico Weber 745a3bb1a4SNico Weber static void ThreadCheckIgnore(ThreadState *thr) { 755a3bb1a4SNico Weber if (ctx->after_multithreaded_fork) 765a3bb1a4SNico Weber return; 775a3bb1a4SNico Weber if (thr->ignore_reads_and_writes) 785a3bb1a4SNico Weber ReportIgnoresEnabled(thr->tctx, &thr->mop_ignore_set); 795a3bb1a4SNico Weber if (thr->ignore_sync) 805a3bb1a4SNico Weber ReportIgnoresEnabled(thr->tctx, &thr->sync_ignore_set); 815a3bb1a4SNico Weber } 825a3bb1a4SNico Weber #else 835a3bb1a4SNico Weber static void ThreadCheckIgnore(ThreadState *thr) {} 845a3bb1a4SNico Weber #endif 855a3bb1a4SNico Weber 865a3bb1a4SNico Weber void ThreadFinalize(ThreadState *thr) { 875a3bb1a4SNico Weber ThreadCheckIgnore(thr); 885a3bb1a4SNico Weber #if !SANITIZER_GO 89ed7bf7d7SDmitry Vyukov if (!ShouldReport(thr, ReportTypeThreadLeak)) 905a3bb1a4SNico Weber return; 910d68cfc9SDmitry Vyukov ThreadRegistryLock l(&ctx->thread_registry); 925a3bb1a4SNico Weber Vector<ThreadLeak> leaks; 9315eb4315SDmitry Vyukov ctx->thread_registry.RunCallbackForEachThreadLocked(CollectThreadLeaks, 940d68cfc9SDmitry Vyukov &leaks); 955a3bb1a4SNico Weber for (uptr i = 0; i < leaks.Size(); i++) { 965a3bb1a4SNico Weber ScopedReport rep(ReportTypeThreadLeak); 975a3bb1a4SNico Weber rep.AddThread(leaks[i].tctx, true); 985a3bb1a4SNico Weber rep.SetCount(leaks[i].count); 995a3bb1a4SNico Weber OutputReport(thr, rep); 1005a3bb1a4SNico Weber } 1015a3bb1a4SNico Weber #endif 1025a3bb1a4SNico Weber } 1035a3bb1a4SNico Weber 1045a3bb1a4SNico Weber int ThreadCount(ThreadState *thr) { 1055a3bb1a4SNico Weber uptr result; 1060d68cfc9SDmitry Vyukov ctx->thread_registry.GetNumberOfThreads(0, 0, &result); 1075a3bb1a4SNico Weber return (int)result; 1085a3bb1a4SNico Weber } 1095a3bb1a4SNico Weber 110908256b0SDmitry Vyukov struct OnCreatedArgs { 111b3321349SDmitry Vyukov VectorClock *sync; 112b3321349SDmitry Vyukov uptr sync_epoch; 113b3321349SDmitry Vyukov StackID stack; 114908256b0SDmitry Vyukov }; 115908256b0SDmitry Vyukov 116103d075bSDmitry Vyukov Tid ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached) { 117b3321349SDmitry Vyukov // The main thread and GCD workers don't have a parent thread. 118b3321349SDmitry Vyukov Tid parent = kInvalidTid; 119b3321349SDmitry Vyukov OnCreatedArgs arg = {nullptr, 0, kInvalidStackID}; 120b3321349SDmitry Vyukov if (thr) { 121b3321349SDmitry Vyukov parent = thr->tid; 122b3321349SDmitry Vyukov arg.stack = CurrentStackId(thr, pc); 123b3321349SDmitry Vyukov if (!thr->ignore_sync) { 124b3321349SDmitry Vyukov SlotLocker locker(thr); 125b3321349SDmitry Vyukov thr->clock.ReleaseStore(&arg.sync); 126b3321349SDmitry Vyukov arg.sync_epoch = ctx->global_epoch; 127b3321349SDmitry Vyukov IncrementEpoch(thr); 128b3321349SDmitry Vyukov } 129b3321349SDmitry Vyukov } 130b3321349SDmitry Vyukov Tid tid = ctx->thread_registry.CreateThread(uid, detached, parent, &arg); 131b3321349SDmitry Vyukov DPrintf("#%d: ThreadCreate tid=%d uid=%zu\n", parent, tid, uid); 1325a3bb1a4SNico Weber return tid; 1335a3bb1a4SNico Weber } 1345a3bb1a4SNico Weber 135908256b0SDmitry Vyukov void ThreadContext::OnCreated(void *arg) { 136908256b0SDmitry Vyukov OnCreatedArgs *args = static_cast<OnCreatedArgs *>(arg); 137b3321349SDmitry Vyukov sync = args->sync; 138b3321349SDmitry Vyukov sync_epoch = args->sync_epoch; 139b3321349SDmitry Vyukov creation_stack_id = args->stack; 140908256b0SDmitry Vyukov } 141908256b0SDmitry Vyukov 142c483140fSDmitry Vyukov extern "C" void __tsan_stack_initialization() {} 143c483140fSDmitry Vyukov 144908256b0SDmitry Vyukov struct OnStartedArgs { 145908256b0SDmitry Vyukov ThreadState *thr; 146908256b0SDmitry Vyukov uptr stk_addr; 147908256b0SDmitry Vyukov uptr stk_size; 148908256b0SDmitry Vyukov uptr tls_addr; 149908256b0SDmitry Vyukov uptr tls_size; 150908256b0SDmitry Vyukov }; 151908256b0SDmitry Vyukov 152103d075bSDmitry Vyukov void ThreadStart(ThreadState *thr, Tid tid, tid_t os_id, 1535a3bb1a4SNico Weber ThreadType thread_type) { 154b3321349SDmitry Vyukov ctx->thread_registry.StartThread(tid, os_id, thread_type, thr); 155b3321349SDmitry Vyukov if (!thr->ignore_sync) { 156b3321349SDmitry Vyukov SlotAttachAndLock(thr); 157b3321349SDmitry Vyukov if (thr->tctx->sync_epoch == ctx->global_epoch) 158b3321349SDmitry Vyukov thr->clock.Acquire(thr->tctx->sync); 159b3321349SDmitry Vyukov SlotUnlock(thr); 160b3321349SDmitry Vyukov } 161b3321349SDmitry Vyukov Free(thr->tctx->sync); 162b3321349SDmitry Vyukov 1630ba678a5SVitaly Buka #if !SANITIZER_GO 1640ba678a5SVitaly Buka thr->is_inited = true; 1650ba678a5SVitaly Buka #endif 1660ba678a5SVitaly Buka 1675a3bb1a4SNico Weber uptr stk_addr = 0; 168*f13b7d0bSVitaly Buka uptr stk_end = 0; 1695a3bb1a4SNico Weber uptr tls_addr = 0; 170*f13b7d0bSVitaly Buka uptr tls_end = 0; 1715a3bb1a4SNico Weber #if !SANITIZER_GO 1725a3bb1a4SNico Weber if (thread_type != ThreadType::Fiber) 173*f13b7d0bSVitaly Buka GetThreadStackAndTls(tid == kMainTid, &stk_addr, &stk_end, &tls_addr, 174*f13b7d0bSVitaly Buka &tls_end); 1755a3bb1a4SNico Weber #endif 176*f13b7d0bSVitaly Buka uptr stk_size = stk_end - stk_addr; 177*f13b7d0bSVitaly Buka uptr tls_size = tls_end - tls_addr; 178b3321349SDmitry Vyukov thr->stk_addr = stk_addr; 179b3321349SDmitry Vyukov thr->stk_size = stk_size; 180b3321349SDmitry Vyukov thr->tls_addr = tls_addr; 181b3321349SDmitry Vyukov thr->tls_size = tls_size; 182c9731899SDmitry Vyukov 1835a3bb1a4SNico Weber #if !SANITIZER_GO 1845a3bb1a4SNico Weber if (ctx->after_multithreaded_fork) { 1855a3bb1a4SNico Weber thr->ignore_interceptors++; 1865a3bb1a4SNico Weber ThreadIgnoreBegin(thr, 0); 1875a3bb1a4SNico Weber ThreadIgnoreSyncBegin(thr, 0); 1885a3bb1a4SNico Weber } 1895a3bb1a4SNico Weber #endif 190c483140fSDmitry Vyukov 191c483140fSDmitry Vyukov #if !SANITIZER_GO 192c483140fSDmitry Vyukov // Don't imitate stack/TLS writes for the main thread, 193c483140fSDmitry Vyukov // because its initialization is synchronized with all 194c483140fSDmitry Vyukov // subsequent threads anyway. 195c483140fSDmitry Vyukov if (tid != kMainTid) { 196c483140fSDmitry Vyukov if (stk_addr && stk_size) { 197c483140fSDmitry Vyukov const uptr pc = StackTrace::GetNextInstructionPc( 198c483140fSDmitry Vyukov reinterpret_cast<uptr>(__tsan_stack_initialization)); 199c483140fSDmitry Vyukov MemoryRangeImitateWrite(thr, pc, stk_addr, stk_size); 200c483140fSDmitry Vyukov } 201c483140fSDmitry Vyukov 202c483140fSDmitry Vyukov if (tls_addr && tls_size) 203c483140fSDmitry Vyukov ImitateTlsWrite(thr, tls_addr, tls_size); 204c483140fSDmitry Vyukov } 205c483140fSDmitry Vyukov #endif 2065a3bb1a4SNico Weber } 2075a3bb1a4SNico Weber 208908256b0SDmitry Vyukov void ThreadContext::OnStarted(void *arg) { 209b3321349SDmitry Vyukov DPrintf("#%d: ThreadStart\n", tid); 210913e2996SVitaly Buka thr = new (arg) ThreadState(tid); 211908256b0SDmitry Vyukov if (common_flags()->detect_deadlocks) 212b3321349SDmitry Vyukov thr->dd_lt = ctx->dd->CreateLogicalThread(tid); 2139d7b7350SDmitry Vyukov thr->tctx = this; 214908256b0SDmitry Vyukov } 215908256b0SDmitry Vyukov 2165a3bb1a4SNico Weber void ThreadFinish(ThreadState *thr) { 217b3321349SDmitry Vyukov DPrintf("#%d: ThreadFinish\n", thr->tid); 2185a3bb1a4SNico Weber ThreadCheckIgnore(thr); 2195a3bb1a4SNico Weber if (thr->stk_addr && thr->stk_size) 2205a3bb1a4SNico Weber DontNeedShadowFor(thr->stk_addr, thr->stk_size); 2215a3bb1a4SNico Weber if (thr->tls_addr && thr->tls_size) 2225a3bb1a4SNico Weber DontNeedShadowFor(thr->tls_addr, thr->tls_size); 2235a3bb1a4SNico Weber thr->is_dead = true; 224396113c1SJonas Devlieghere #if !SANITIZER_GO 225b3321349SDmitry Vyukov thr->is_inited = false; 226c7081b5bSDmitry Vyukov thr->ignore_interceptors++; 227b3321349SDmitry Vyukov PlatformCleanUpThreadState(thr); 228c7081b5bSDmitry Vyukov #endif 229b3321349SDmitry Vyukov if (!thr->ignore_sync) { 230b3321349SDmitry Vyukov SlotLocker locker(thr); 231b3321349SDmitry Vyukov ThreadRegistryLock lock(&ctx->thread_registry); 232b3321349SDmitry Vyukov // Note: detached is protected by the thread registry mutex, 233b3321349SDmitry Vyukov // the thread may be detaching concurrently in another thread. 234b3321349SDmitry Vyukov if (!thr->tctx->detached) { 235b3321349SDmitry Vyukov thr->clock.ReleaseStore(&thr->tctx->sync); 236b3321349SDmitry Vyukov thr->tctx->sync_epoch = ctx->global_epoch; 237b3321349SDmitry Vyukov IncrementEpoch(thr); 23879fbba9bSDmitry Vyukov } 239908256b0SDmitry Vyukov } 240b5ff187bSDmitry Vyukov #if !SANITIZER_GO 241b5ff187bSDmitry Vyukov UnmapOrDie(thr->shadow_stack, kShadowStackSize * sizeof(uptr)); 242b5ff187bSDmitry Vyukov #else 243b5ff187bSDmitry Vyukov Free(thr->shadow_stack); 244b5ff187bSDmitry Vyukov #endif 245b5ff187bSDmitry Vyukov thr->shadow_stack = nullptr; 246b5ff187bSDmitry Vyukov thr->shadow_stack_pos = nullptr; 247b5ff187bSDmitry Vyukov thr->shadow_stack_end = nullptr; 248908256b0SDmitry Vyukov if (common_flags()->detect_deadlocks) 249908256b0SDmitry Vyukov ctx->dd->DestroyLogicalThread(thr->dd_lt); 250b3321349SDmitry Vyukov SlotDetach(thr); 251b3321349SDmitry Vyukov ctx->thread_registry.FinishThread(thr->tid); 252908256b0SDmitry Vyukov thr->~ThreadState(); 253b3321349SDmitry Vyukov } 254b3321349SDmitry Vyukov 255b3321349SDmitry Vyukov void ThreadContext::OnFinished() { 256b3321349SDmitry Vyukov Lock lock(&ctx->slot_mtx); 257b3321349SDmitry Vyukov Lock lock1(&trace.mtx); 258b3321349SDmitry Vyukov // Queue all trace parts into the global recycle queue. 259b3321349SDmitry Vyukov auto parts = &trace.parts; 260b3321349SDmitry Vyukov while (trace.local_head) { 261b3321349SDmitry Vyukov CHECK(parts->Queued(trace.local_head)); 262b3321349SDmitry Vyukov ctx->trace_part_recycle.PushBack(trace.local_head); 263b3321349SDmitry Vyukov trace.local_head = parts->Next(trace.local_head); 264b3321349SDmitry Vyukov } 265b3321349SDmitry Vyukov ctx->trace_part_recycle_finished += parts->Size(); 266b3321349SDmitry Vyukov if (ctx->trace_part_recycle_finished > Trace::kFinishedThreadHi) { 267b3321349SDmitry Vyukov ctx->trace_part_finished_excess += parts->Size(); 268b3321349SDmitry Vyukov trace.parts_allocated = 0; 269b3321349SDmitry Vyukov } else if (ctx->trace_part_recycle_finished > Trace::kFinishedThreadLo && 270b3321349SDmitry Vyukov parts->Size() > 1) { 271b3321349SDmitry Vyukov ctx->trace_part_finished_excess += parts->Size() - 1; 272b3321349SDmitry Vyukov trace.parts_allocated = 1; 273b3321349SDmitry Vyukov } 274b3321349SDmitry Vyukov // From now on replay will use trace->final_pos. 275b3321349SDmitry Vyukov trace.final_pos = (Event *)atomic_load_relaxed(&thr->trace_pos); 276b3321349SDmitry Vyukov atomic_store_relaxed(&thr->trace_pos, 0); 277b3321349SDmitry Vyukov thr->tctx = nullptr; 278b3321349SDmitry Vyukov thr = nullptr; 279908256b0SDmitry Vyukov } 280908256b0SDmitry Vyukov 2812dcbdba8SDmitry Vyukov struct ConsumeThreadContext { 2822dcbdba8SDmitry Vyukov uptr uid; 2832dcbdba8SDmitry Vyukov ThreadContextBase *tctx; 2842dcbdba8SDmitry Vyukov }; 2852dcbdba8SDmitry Vyukov 286103d075bSDmitry Vyukov Tid ThreadConsumeTid(ThreadState *thr, uptr pc, uptr uid) { 287111d8f78SDmitry Vyukov return ctx->thread_registry.ConsumeThreadUserId(uid); 2885a3bb1a4SNico Weber } 2895a3bb1a4SNico Weber 290b3321349SDmitry Vyukov struct JoinArg { 291b3321349SDmitry Vyukov VectorClock *sync; 292b3321349SDmitry Vyukov uptr sync_epoch; 293b3321349SDmitry Vyukov }; 294b3321349SDmitry Vyukov 295103d075bSDmitry Vyukov void ThreadJoin(ThreadState *thr, uptr pc, Tid tid) { 2965a3bb1a4SNico Weber CHECK_GT(tid, 0); 2975a3bb1a4SNico Weber DPrintf("#%d: ThreadJoin tid=%d\n", thr->tid, tid); 298b3321349SDmitry Vyukov JoinArg arg = {}; 299b3321349SDmitry Vyukov ctx->thread_registry.JoinThread(tid, &arg); 300b3321349SDmitry Vyukov if (!thr->ignore_sync) { 301b3321349SDmitry Vyukov SlotLocker locker(thr); 302b3321349SDmitry Vyukov if (arg.sync_epoch == ctx->global_epoch) 303b3321349SDmitry Vyukov thr->clock.Acquire(arg.sync); 304b3321349SDmitry Vyukov } 305b3321349SDmitry Vyukov Free(arg.sync); 3065a3bb1a4SNico Weber } 3075a3bb1a4SNico Weber 308b3321349SDmitry Vyukov void ThreadContext::OnJoined(void *ptr) { 309b3321349SDmitry Vyukov auto arg = static_cast<JoinArg *>(ptr); 310b3321349SDmitry Vyukov arg->sync = sync; 311b3321349SDmitry Vyukov arg->sync_epoch = sync_epoch; 312b3321349SDmitry Vyukov sync = nullptr; 313b3321349SDmitry Vyukov sync_epoch = 0; 314908256b0SDmitry Vyukov } 315908256b0SDmitry Vyukov 316b3321349SDmitry Vyukov void ThreadContext::OnDead() { CHECK_EQ(sync, nullptr); } 317908256b0SDmitry Vyukov 318103d075bSDmitry Vyukov void ThreadDetach(ThreadState *thr, uptr pc, Tid tid) { 3195a3bb1a4SNico Weber CHECK_GT(tid, 0); 3200d68cfc9SDmitry Vyukov ctx->thread_registry.DetachThread(tid, thr); 3215a3bb1a4SNico Weber } 3225a3bb1a4SNico Weber 323b3321349SDmitry Vyukov void ThreadContext::OnDetached(void *arg) { Free(sync); } 324908256b0SDmitry Vyukov 325103d075bSDmitry Vyukov void ThreadNotJoined(ThreadState *thr, uptr pc, Tid tid, uptr uid) { 3265a3bb1a4SNico Weber CHECK_GT(tid, 0); 3270d68cfc9SDmitry Vyukov ctx->thread_registry.SetThreadUserId(tid, uid); 3285a3bb1a4SNico Weber } 3295a3bb1a4SNico Weber 3305a3bb1a4SNico Weber void ThreadSetName(ThreadState *thr, const char *name) { 3310d68cfc9SDmitry Vyukov ctx->thread_registry.SetThreadName(thr->tid, name); 3325a3bb1a4SNico Weber } 3335a3bb1a4SNico Weber 3345a3bb1a4SNico Weber #if !SANITIZER_GO 3355a3bb1a4SNico Weber void FiberSwitchImpl(ThreadState *from, ThreadState *to) { 3365a3bb1a4SNico Weber Processor *proc = from->proc(); 3375a3bb1a4SNico Weber ProcUnwire(proc, from); 3385a3bb1a4SNico Weber ProcWire(proc, to); 3395a3bb1a4SNico Weber set_cur_thread(to); 3405a3bb1a4SNico Weber } 3415a3bb1a4SNico Weber 3425a3bb1a4SNico Weber ThreadState *FiberCreate(ThreadState *thr, uptr pc, unsigned flags) { 343817f942aSDmitry Vyukov void *mem = Alloc(sizeof(ThreadState)); 3445a3bb1a4SNico Weber ThreadState *fiber = static_cast<ThreadState *>(mem); 3455a3bb1a4SNico Weber internal_memset(fiber, 0, sizeof(*fiber)); 346103d075bSDmitry Vyukov Tid tid = ThreadCreate(thr, pc, 0, true); 3475a3bb1a4SNico Weber FiberSwitchImpl(thr, fiber); 3485a3bb1a4SNico Weber ThreadStart(fiber, tid, 0, ThreadType::Fiber); 3495a3bb1a4SNico Weber FiberSwitchImpl(fiber, thr); 3505a3bb1a4SNico Weber return fiber; 3515a3bb1a4SNico Weber } 3525a3bb1a4SNico Weber 3535a3bb1a4SNico Weber void FiberDestroy(ThreadState *thr, uptr pc, ThreadState *fiber) { 3545a3bb1a4SNico Weber FiberSwitchImpl(thr, fiber); 3555a3bb1a4SNico Weber ThreadFinish(fiber); 3565a3bb1a4SNico Weber FiberSwitchImpl(fiber, thr); 357817f942aSDmitry Vyukov Free(fiber); 3585a3bb1a4SNico Weber } 3595a3bb1a4SNico Weber 3605a3bb1a4SNico Weber void FiberSwitch(ThreadState *thr, uptr pc, 3615a3bb1a4SNico Weber ThreadState *fiber, unsigned flags) { 3625a3bb1a4SNico Weber if (!(flags & FiberSwitchFlagNoSync)) 3635a3bb1a4SNico Weber Release(thr, pc, (uptr)fiber); 3645a3bb1a4SNico Weber FiberSwitchImpl(thr, fiber); 3655a3bb1a4SNico Weber if (!(flags & FiberSwitchFlagNoSync)) 3665a3bb1a4SNico Weber Acquire(fiber, pc, (uptr)fiber); 3675a3bb1a4SNico Weber } 3685a3bb1a4SNico Weber #endif 3695a3bb1a4SNico Weber 3705a3bb1a4SNico Weber } // namespace __tsan 371