brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.2 KiB · 978d853 Raw
393 lines · cpp
1//===-- tsan_rtl_thread.cpp -----------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file is a part of ThreadSanitizer (TSan), a race detector.10//11//===----------------------------------------------------------------------===//12 13#include "sanitizer_common/sanitizer_placement_new.h"14#include "tsan_rtl.h"15#include "tsan_mman.h"16#include "tsan_platform.h"17#include "tsan_report.h"18#include "tsan_sync.h"19 20namespace __tsan {21 22// ThreadContext implementation.23 24ThreadContext::ThreadContext(Tid tid) : ThreadContextBase(tid), thr(), sync() {}25 26#if !SANITIZER_GO27ThreadContext::~ThreadContext() {28}29#endif30 31void ThreadContext::OnReset() { CHECK(!sync); }32 33#if !SANITIZER_GO34struct ThreadLeak {35  ThreadContext *tctx;36  int count;37};38 39static void CollectThreadLeaks(ThreadContextBase *tctx_base, void *arg) {40  auto &leaks = *static_cast<Vector<ThreadLeak> *>(arg);41  auto *tctx = static_cast<ThreadContext *>(tctx_base);42  if (tctx->detached || tctx->status != ThreadStatusFinished)43    return;44  for (uptr i = 0; i < leaks.Size(); i++) {45    if (leaks[i].tctx->creation_stack_id == tctx->creation_stack_id) {46      leaks[i].count++;47      return;48    }49  }50  leaks.PushBack({tctx, 1});51}52#endif53 54// Disabled on Mac because lldb test TestTsanBasic fails:55// https://reviews.llvm.org/D112603#316315856#if !SANITIZER_GO && !SANITIZER_APPLE57static void ReportIgnoresEnabled(ThreadContext *tctx, IgnoreSet *set) {58  if (tctx->tid == kMainTid) {59    Printf("ThreadSanitizer: main thread finished with ignores enabled\n");60  } else {61    Printf("ThreadSanitizer: thread T%d %s finished with ignores enabled,"62      " created at:\n", tctx->tid, tctx->name);63    PrintStack(SymbolizeStackId(tctx->creation_stack_id));64  }65  Printf("  One of the following ignores was not ended"66      " (in order of probability)\n");67  for (uptr i = 0; i < set->Size(); i++) {68    Printf("  Ignore was enabled at:\n");69    PrintStack(SymbolizeStackId(set->At(i)));70  }71  Die();72}73 74static void ThreadCheckIgnore(ThreadState *thr) {75  if (ctx->after_multithreaded_fork)76    return;77  if (thr->ignore_reads_and_writes)78    ReportIgnoresEnabled(thr->tctx, &thr->mop_ignore_set);79  if (thr->ignore_sync)80    ReportIgnoresEnabled(thr->tctx, &thr->sync_ignore_set);81}82#else83static void ThreadCheckIgnore(ThreadState *thr) {}84#endif85 86void ThreadFinalize(ThreadState *thr) {87  ThreadCheckIgnore(thr);88#if !SANITIZER_GO89  if (!ShouldReport(thr, ReportTypeThreadLeak))90    return;91  Vector<ThreadLeak> leaks;92  {93    ThreadRegistryLock l(&ctx->thread_registry);94    ctx->thread_registry.RunCallbackForEachThreadLocked(CollectThreadLeaks,95                                                        &leaks);96  }97 98  for (uptr i = 0; i < leaks.Size(); i++) {99    // Use alloca, because malloc during signal handling deadlocks100    ScopedReport *rep = (ScopedReport *)__builtin_alloca(sizeof(ScopedReport));101    // Take a new scope as Apple platforms require the below locks released102    // before symbolizing in order to avoid a deadlock103    {104      ThreadRegistryLock l(&ctx->thread_registry);105      new (rep) ScopedReport(ReportTypeThreadLeak);106      rep->AddThread(leaks[i].tctx, true);107      rep->SetCount(leaks[i].count);108#  if SANITIZER_APPLE109    }  // Close this scope to release the locks110#  endif111      OutputReport(thr, *rep);112 113      // Need to manually destroy this because we used placement new to allocate114      rep->~ScopedReport();115#  if !SANITIZER_APPLE116    }117#  endif118  }119#endif120}121 122int ThreadCount(ThreadState *thr) {123  uptr result;124  ctx->thread_registry.GetNumberOfThreads(0, 0, &result);125  return (int)result;126}127 128struct OnCreatedArgs {129  VectorClock *sync;130  uptr sync_epoch;131  StackID stack;132};133 134Tid ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached) {135  // The main thread and GCD workers don't have a parent thread.136  Tid parent = kInvalidTid;137  OnCreatedArgs arg = {nullptr, 0, kInvalidStackID};138  if (thr) {139    parent = thr->tid;140    arg.stack = CurrentStackId(thr, pc);141    if (!thr->ignore_sync) {142      SlotLocker locker(thr);143      thr->clock.ReleaseStore(&arg.sync);144      arg.sync_epoch = ctx->global_epoch;145      IncrementEpoch(thr);146    }147  }148  Tid tid = ctx->thread_registry.CreateThread(uid, detached, parent, &arg);149  DPrintf("#%d: ThreadCreate tid=%d uid=%zu\n", parent, tid, uid);150  return tid;151}152 153void ThreadContext::OnCreated(void *arg) {154  OnCreatedArgs *args = static_cast<OnCreatedArgs *>(arg);155  sync = args->sync;156  sync_epoch = args->sync_epoch;157  creation_stack_id = args->stack;158}159 160extern "C" void __tsan_stack_initialization() {}161 162struct OnStartedArgs {163  ThreadState *thr;164  uptr stk_addr;165  uptr stk_size;166  uptr tls_addr;167  uptr tls_size;168};169 170void ThreadStart(ThreadState *thr, Tid tid, ThreadID os_id,171                 ThreadType thread_type) {172  ctx->thread_registry.StartThread(tid, os_id, thread_type, thr);173  if (!thr->ignore_sync) {174    SlotAttachAndLock(thr);175    if (thr->tctx->sync_epoch == ctx->global_epoch)176      thr->clock.Acquire(thr->tctx->sync);177    SlotUnlock(thr);178  }179  Free(thr->tctx->sync);180 181#if !SANITIZER_GO182  thr->is_inited = true;183#endif184 185  uptr stk_addr = 0;186  uptr stk_end = 0;187  uptr tls_addr = 0;188  uptr tls_end = 0;189#if !SANITIZER_GO190  if (thread_type != ThreadType::Fiber)191    GetThreadStackAndTls(tid == kMainTid, &stk_addr, &stk_end, &tls_addr,192                         &tls_end);193#endif194  uptr stk_size = stk_end - stk_addr;195  uptr tls_size = tls_end - tls_addr;196  thr->stk_addr = stk_addr;197  thr->stk_size = stk_size;198  thr->tls_addr = tls_addr;199  thr->tls_size = tls_size;200 201#if !SANITIZER_GO202  if (ctx->after_multithreaded_fork) {203    thr->ignore_interceptors++;204    ThreadIgnoreBegin(thr, 0);205    ThreadIgnoreSyncBegin(thr, 0);206  }207#endif208 209#if !SANITIZER_GO && !SANITIZER_ANDROID210  // Don't imitate stack/TLS writes for the main thread,211  // because its initialization is synchronized with all212  // subsequent threads anyway.213  // Because thr is created by MmapOrDie, the thr object214  // is not in tls, the pointer to the thr object is in215  // TLS_SLOT_SANITIZER slot. So skip this check on216  // Android platform.217  if (tid != kMainTid) {218    if (stk_addr && stk_size) {219      const uptr pc = StackTrace::GetNextInstructionPc(220          reinterpret_cast<uptr>(__tsan_stack_initialization));221      MemoryRangeImitateWrite(thr, pc, stk_addr, stk_size);222    }223 224    if (tls_addr && tls_size)225      ImitateTlsWrite(thr, tls_addr, tls_size);226  }227#endif228}229 230void ThreadContext::OnStarted(void *arg) {231  DPrintf("#%d: ThreadStart\n", tid);232  thr = new (arg) ThreadState(tid);233  if (common_flags()->detect_deadlocks)234    thr->dd_lt = ctx->dd->CreateLogicalThread(tid);235  thr->tctx = this;236}237 238void ThreadFinish(ThreadState *thr) {239  DPrintf("#%d: ThreadFinish\n", thr->tid);240  ThreadCheckIgnore(thr);241  if (thr->stk_addr && thr->stk_size)242    DontNeedShadowFor(thr->stk_addr, thr->stk_size);243  if (thr->tls_addr && thr->tls_size)244    DontNeedShadowFor(thr->tls_addr, thr->tls_size);245  thr->is_dead = true;246#if !SANITIZER_GO247  thr->is_inited = false;248  thr->ignore_interceptors++;249  PlatformCleanUpThreadState(thr);250#endif251  if (!thr->ignore_sync) {252    SlotLocker locker(thr);253    ThreadRegistryLock lock(&ctx->thread_registry);254    // Note: detached is protected by the thread registry mutex,255    // the thread may be detaching concurrently in another thread.256    if (!thr->tctx->detached) {257      thr->clock.ReleaseStore(&thr->tctx->sync);258      thr->tctx->sync_epoch = ctx->global_epoch;259      IncrementEpoch(thr);260    }261  }262#if !SANITIZER_GO263  UnmapOrDie(thr->shadow_stack, kShadowStackSize * sizeof(uptr));264#else265  Free(thr->shadow_stack);266#endif267  thr->shadow_stack = nullptr;268  thr->shadow_stack_pos = nullptr;269  thr->shadow_stack_end = nullptr;270  if (common_flags()->detect_deadlocks)271    ctx->dd->DestroyLogicalThread(thr->dd_lt);272  SlotDetach(thr);273  ctx->thread_registry.FinishThread(thr->tid);274  thr->~ThreadState();275}276 277void ThreadContext::OnFinished() {278  Lock lock(&ctx->slot_mtx);279  Lock lock1(&trace.mtx);280  // Queue all trace parts into the global recycle queue.281  auto parts = &trace.parts;282  while (trace.local_head) {283    CHECK(parts->Queued(trace.local_head));284    ctx->trace_part_recycle.PushBack(trace.local_head);285    trace.local_head = parts->Next(trace.local_head);286  }287  ctx->trace_part_recycle_finished += parts->Size();288  if (ctx->trace_part_recycle_finished > Trace::kFinishedThreadHi) {289    ctx->trace_part_finished_excess += parts->Size();290    trace.parts_allocated = 0;291  } else if (ctx->trace_part_recycle_finished > Trace::kFinishedThreadLo &&292             parts->Size() > 1) {293    ctx->trace_part_finished_excess += parts->Size() - 1;294    trace.parts_allocated = 1;295  }296  // From now on replay will use trace->final_pos.297  trace.final_pos = (Event *)atomic_load_relaxed(&thr->trace_pos);298  atomic_store_relaxed(&thr->trace_pos, 0);299  thr->tctx = nullptr;300  thr = nullptr;301}302 303struct ConsumeThreadContext {304  uptr uid;305  ThreadContextBase *tctx;306};307 308Tid ThreadConsumeTid(ThreadState *thr, uptr pc, uptr uid) {309  return ctx->thread_registry.ConsumeThreadUserId(uid);310}311 312struct JoinArg {313  VectorClock *sync;314  uptr sync_epoch;315};316 317void ThreadJoin(ThreadState *thr, uptr pc, Tid tid) {318  CHECK_GT(tid, 0);319  DPrintf("#%d: ThreadJoin tid=%d\n", thr->tid, tid);320  JoinArg arg = {};321  ctx->thread_registry.JoinThread(tid, &arg);322  if (!thr->ignore_sync) {323    SlotLocker locker(thr);324    if (arg.sync_epoch == ctx->global_epoch)325      thr->clock.Acquire(arg.sync);326  }327  Free(arg.sync);328}329 330void ThreadContext::OnJoined(void *ptr) {331  auto arg = static_cast<JoinArg *>(ptr);332  arg->sync = sync;333  arg->sync_epoch = sync_epoch;334  sync = nullptr;335  sync_epoch = 0;336}337 338void ThreadContext::OnDead() { CHECK_EQ(sync, nullptr); }339 340void ThreadDetach(ThreadState *thr, uptr pc, Tid tid) {341  CHECK_GT(tid, 0);342  ctx->thread_registry.DetachThread(tid, thr);343}344 345void ThreadContext::OnDetached(void *arg) { Free(sync); }346 347void ThreadNotJoined(ThreadState *thr, uptr pc, Tid tid, uptr uid) {348  CHECK_GT(tid, 0);349  ctx->thread_registry.SetThreadUserId(tid, uid);350}351 352void ThreadSetName(ThreadState *thr, const char *name) {353  ctx->thread_registry.SetThreadName(thr->tid, name);354}355 356#if !SANITIZER_GO357void FiberSwitchImpl(ThreadState *from, ThreadState *to) {358  Processor *proc = from->proc();359  ProcUnwire(proc, from);360  ProcWire(proc, to);361  set_cur_thread(to);362}363 364ThreadState *FiberCreate(ThreadState *thr, uptr pc, unsigned flags) {365  void *mem = Alloc(sizeof(ThreadState));366  ThreadState *fiber = static_cast<ThreadState *>(mem);367  internal_memset(fiber, 0, sizeof(*fiber));368  Tid tid = ThreadCreate(thr, pc, 0, true);369  FiberSwitchImpl(thr, fiber);370  ThreadStart(fiber, tid, 0, ThreadType::Fiber);371  FiberSwitchImpl(fiber, thr);372  return fiber;373}374 375void FiberDestroy(ThreadState *thr, uptr pc, ThreadState *fiber) {376  FiberSwitchImpl(thr, fiber);377  ThreadFinish(fiber);378  FiberSwitchImpl(fiber, thr);379  Free(fiber);380}381 382void FiberSwitch(ThreadState *thr, uptr pc,383                 ThreadState *fiber, unsigned flags) {384  if (!(flags & FiberSwitchFlagNoSync))385    Release(thr, pc, (uptr)fiber);386  FiberSwitchImpl(thr, fiber);387  if (!(flags & FiberSwitchFlagNoSync))388    Acquire(fiber, pc, (uptr)fiber);389}390#endif391 392}  // namespace __tsan393