1238901Sandrew//===-- tsan_rtl_thread.cc ------------------------------------------------===//
2238901Sandrew//
3238901Sandrew//                     The LLVM Compiler Infrastructure
4238901Sandrew//
5238901Sandrew// This file is distributed under the University of Illinois Open Source
6238901Sandrew// License. See LICENSE.TXT for details.
7238901Sandrew//
8238901Sandrew//===----------------------------------------------------------------------===//
9238901Sandrew//
10238901Sandrew// This file is a part of ThreadSanitizer (TSan), a race detector.
11238901Sandrew//
12238901Sandrew//===----------------------------------------------------------------------===//
13238901Sandrew
14238901Sandrew#include "sanitizer_common/sanitizer_placement_new.h"
15238901Sandrew#include "tsan_rtl.h"
16238901Sandrew#include "tsan_mman.h"
17238901Sandrew#include "tsan_platform.h"
18238901Sandrew#include "tsan_report.h"
19238901Sandrew#include "tsan_sync.h"
20238901Sandrew
21238901Sandrewnamespace __tsan {
22238901Sandrew
23251034Sed// ThreadContext implementation.
24251034Sed
25251034SedThreadContext::ThreadContext(int tid)
26251034Sed  : ThreadContextBase(tid)
27251034Sed  , thr()
28251034Sed  , sync()
29251034Sed  , epoch0()
30251034Sed  , epoch1() {
31251034Sed}
32251034Sed
33276789Sdim#ifndef SANITIZER_GO
34251034SedThreadContext::~ThreadContext() {
35251034Sed}
36251034Sed#endif
37251034Sed
38251034Sedvoid ThreadContext::OnDead() {
39276789Sdim  CHECK_EQ(sync.size(), 0);
40251034Sed}
41251034Sed
42251034Sedvoid ThreadContext::OnJoined(void *arg) {
43251034Sed  ThreadState *caller_thr = static_cast<ThreadState *>(arg);
44274201Sdim  AcquireImpl(caller_thr, 0, &sync);
45276789Sdim  sync.Reset(&caller_thr->clock_cache);
46251034Sed}
47251034Sed
48251034Sedstruct OnCreatedArgs {
49251034Sed  ThreadState *thr;
50251034Sed  uptr pc;
51251034Sed};
52251034Sed
53251034Sedvoid ThreadContext::OnCreated(void *arg) {
54251034Sed  thr = 0;
55251034Sed  if (tid == 0)
56251034Sed    return;
57251034Sed  OnCreatedArgs *args = static_cast<OnCreatedArgs *>(arg);
58296417Sdim  if (!args->thr)  // GCD workers don't have a parent thread.
59296417Sdim    return;
60251034Sed  args->thr->fast_state.IncrementEpoch();
61251034Sed  // Can't increment epoch w/o writing to the trace as well.
62251034Sed  TraceAddEvent(args->thr, args->thr->fast_state, EventTypeMop, 0);
63274201Sdim  ReleaseImpl(args->thr, 0, &sync);
64251034Sed  creation_stack_id = CurrentStackId(args->thr, args->pc);
65251034Sed  if (reuse_count == 0)
66251034Sed    StatInc(args->thr, StatThreadMaxTid);
67251034Sed}
68238901Sandrew
69251034Sedvoid ThreadContext::OnReset() {
70276789Sdim  CHECK_EQ(sync.size(), 0);
71251034Sed  FlushUnneededShadowMemory(GetThreadTrace(tid), TraceSize() * sizeof(Event));
72251034Sed  //!!! FlushUnneededShadowMemory(GetThreadTraceHeader(tid), sizeof(Trace));
73251034Sed}
74251034Sed
75276789Sdimvoid ThreadContext::OnDetached(void *arg) {
76276789Sdim  ThreadState *thr1 = static_cast<ThreadState*>(arg);
77276789Sdim  sync.Reset(&thr1->clock_cache);
78276789Sdim}
79276789Sdim
80251034Sedstruct OnStartedArgs {
81251034Sed  ThreadState *thr;
82251034Sed  uptr stk_addr;
83251034Sed  uptr stk_size;
84251034Sed  uptr tls_addr;
85251034Sed  uptr tls_size;
86251034Sed};
87251034Sed
88251034Sedvoid ThreadContext::OnStarted(void *arg) {
89251034Sed  OnStartedArgs *args = static_cast<OnStartedArgs*>(arg);
90251034Sed  thr = args->thr;
91251034Sed  // RoundUp so that one trace part does not contain events
92251034Sed  // from different threads.
93251034Sed  epoch0 = RoundUp(epoch1 + 1, kTracePartSize);
94251034Sed  epoch1 = (u64)-1;
95276789Sdim  new(thr) ThreadState(ctx, tid, unique_id, epoch0, reuse_count,
96276789Sdim      args->stk_addr, args->stk_size, args->tls_addr, args->tls_size);
97276789Sdim#ifndef SANITIZER_GO
98274201Sdim  thr->shadow_stack = &ThreadTrace(thr->tid)->shadow_stack[0];
99274201Sdim  thr->shadow_stack_pos = thr->shadow_stack;
100274201Sdim  thr->shadow_stack_end = thr->shadow_stack + kShadowStackSize;
101274201Sdim#else
102251034Sed  // Setup dynamic shadow stack.
103251034Sed  const int kInitStackSize = 8;
104274201Sdim  thr->shadow_stack = (uptr*)internal_alloc(MBlockShadowStack,
105251034Sed      kInitStackSize * sizeof(uptr));
106274201Sdim  thr->shadow_stack_pos = thr->shadow_stack;
107274201Sdim  thr->shadow_stack_end = thr->shadow_stack + kInitStackSize;
108251034Sed#endif
109276789Sdim#ifndef SANITIZER_GO
110274201Sdim  AllocatorThreadStart(thr);
111251034Sed#endif
112276789Sdim  if (common_flags()->detect_deadlocks) {
113276789Sdim    thr->dd_pt = ctx->dd->CreatePhysicalThread();
114276789Sdim    thr->dd_lt = ctx->dd->CreateLogicalThread(unique_id);
115276789Sdim  }
116280031Sdim  thr->fast_state.SetHistorySize(flags()->history_size);
117280031Sdim  // Commit switch to the new part of the trace.
118280031Sdim  // TraceAddEvent will reset stack0/mset0 in the new part for us.
119280031Sdim  TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
120280031Sdim
121251034Sed  thr->fast_synch_epoch = epoch0;
122274201Sdim  AcquireImpl(thr, 0, &sync);
123251034Sed  StatInc(thr, StatSyncAcquire);
124276789Sdim  sync.Reset(&thr->clock_cache);
125288943Sdim  thr->is_inited = true;
126251034Sed  DPrintf("#%d: ThreadStart epoch=%zu stk_addr=%zx stk_size=%zx "
127251034Sed          "tls_addr=%zx tls_size=%zx\n",
128251034Sed          tid, (uptr)epoch0, args->stk_addr, args->stk_size,
129251034Sed          args->tls_addr, args->tls_size);
130251034Sed}
131251034Sed
132251034Sedvoid ThreadContext::OnFinished() {
133251034Sed  if (!detached) {
134251034Sed    thr->fast_state.IncrementEpoch();
135251034Sed    // Can't increment epoch w/o writing to the trace as well.
136251034Sed    TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
137274201Sdim    ReleaseImpl(thr, 0, &sync);
138251034Sed  }
139251034Sed  epoch1 = thr->fast_state.epoch();
140251034Sed
141276789Sdim  if (common_flags()->detect_deadlocks) {
142276789Sdim    ctx->dd->DestroyPhysicalThread(thr->dd_pt);
143276789Sdim    ctx->dd->DestroyLogicalThread(thr->dd_lt);
144276789Sdim  }
145276789Sdim  ctx->clock_alloc.FlushCache(&thr->clock_cache);
146276789Sdim  ctx->metamap.OnThreadIdle(thr);
147276789Sdim#ifndef SANITIZER_GO
148251034Sed  AllocatorThreadFinish(thr);
149251034Sed#endif
150251034Sed  thr->~ThreadState();
151280031Sdim#if TSAN_COLLECT_STATS
152276789Sdim  StatAggregate(ctx->stat, thr->stat);
153280031Sdim#endif
154251034Sed  thr = 0;
155251034Sed}
156251034Sed
157276789Sdim#ifndef SANITIZER_GO
158251034Sedstruct ThreadLeak {
159251034Sed  ThreadContext *tctx;
160251034Sed  int count;
161251034Sed};
162251034Sed
163251034Sedstatic void MaybeReportThreadLeak(ThreadContextBase *tctx_base, void *arg) {
164251034Sed  Vector<ThreadLeak> &leaks = *(Vector<ThreadLeak>*)arg;
165251034Sed  ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base);
166251034Sed  if (tctx->detached || tctx->status != ThreadStatusFinished)
167238901Sandrew    return;
168251034Sed  for (uptr i = 0; i < leaks.Size(); i++) {
169251034Sed    if (leaks[i].tctx->creation_stack_id == tctx->creation_stack_id) {
170251034Sed      leaks[i].count++;
171251034Sed      return;
172251034Sed    }
173251034Sed  }
174251034Sed  ThreadLeak leak = {tctx, 1};
175251034Sed  leaks.PushBack(leak);
176238901Sandrew}
177251034Sed#endif
178238901Sandrew
179276789Sdim#ifndef SANITIZER_GO
180276789Sdimstatic void ReportIgnoresEnabled(ThreadContext *tctx, IgnoreSet *set) {
181276789Sdim  if (tctx->tid == 0) {
182276789Sdim    Printf("ThreadSanitizer: main thread finished with ignores enabled\n");
183276789Sdim  } else {
184276789Sdim    Printf("ThreadSanitizer: thread T%d %s finished with ignores enabled,"
185276789Sdim      " created at:\n", tctx->tid, tctx->name);
186276789Sdim    PrintStack(SymbolizeStackId(tctx->creation_stack_id));
187251034Sed  }
188276789Sdim  Printf("  One of the following ignores was not ended"
189276789Sdim      " (in order of probability)\n");
190276789Sdim  for (uptr i = 0; i < set->Size(); i++) {
191276789Sdim    Printf("  Ignore was enabled at:\n");
192276789Sdim    PrintStack(SymbolizeStackId(set->At(i)));
193274201Sdim  }
194276789Sdim  Die();
195251034Sed}
196251034Sed
197276789Sdimstatic void ThreadCheckIgnore(ThreadState *thr) {
198276789Sdim  if (ctx->after_multithreaded_fork)
199276789Sdim    return;
200276789Sdim  if (thr->ignore_reads_and_writes)
201276789Sdim    ReportIgnoresEnabled(thr->tctx, &thr->mop_ignore_set);
202276789Sdim  if (thr->ignore_sync)
203276789Sdim    ReportIgnoresEnabled(thr->tctx, &thr->sync_ignore_set);
204276789Sdim}
205276789Sdim#else
206276789Sdimstatic void ThreadCheckIgnore(ThreadState *thr) {}
207276789Sdim#endif
208276789Sdim
209238901Sandrewvoid ThreadFinalize(ThreadState *thr) {
210251034Sed  ThreadCheckIgnore(thr);
211276789Sdim#ifndef SANITIZER_GO
212238901Sandrew  if (!flags()->report_thread_leaks)
213238901Sandrew    return;
214276789Sdim  ThreadRegistryLock l(ctx->thread_registry);
215251034Sed  Vector<ThreadLeak> leaks(MBlockScopedBuf);
216276789Sdim  ctx->thread_registry->RunCallbackForEachThreadLocked(
217251034Sed      MaybeReportThreadLeak, &leaks);
218251034Sed  for (uptr i = 0; i < leaks.Size(); i++) {
219251034Sed    ScopedReport rep(ReportTypeThreadLeak);
220276789Sdim    rep.AddThread(leaks[i].tctx, true);
221251034Sed    rep.SetCount(leaks[i].count);
222276789Sdim    OutputReport(thr, rep);
223238901Sandrew  }
224251034Sed#endif
225238901Sandrew}
226238901Sandrew
227245614Sandrewint ThreadCount(ThreadState *thr) {
228251034Sed  uptr result;
229251034Sed  ctx->thread_registry->GetNumberOfThreads(0, 0, &result);
230251034Sed  return (int)result;
231245614Sandrew}
232245614Sandrew
233238901Sandrewint ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached) {
234251034Sed  StatInc(thr, StatThreadCreate);
235251034Sed  OnCreatedArgs args = { thr, pc };
236296417Sdim  u32 parent_tid = thr ? thr->tid : kInvalidTid;  // No parent for GCD workers.
237296417Sdim  int tid =
238296417Sdim      ctx->thread_registry->CreateThread(uid, detached, parent_tid, &args);
239296417Sdim  DPrintf("#%d: ThreadCreate tid=%d uid=%zu\n", parent_tid, tid, uid);
240251034Sed  StatSet(thr, StatThreadMaxAlive, ctx->thread_registry->GetMaxAliveThreads());
241238901Sandrew  return tid;
242238901Sandrew}
243238901Sandrew
244245614Sandrewvoid ThreadStart(ThreadState *thr, int tid, uptr os_id) {
245238901Sandrew  uptr stk_addr = 0;
246238901Sandrew  uptr stk_size = 0;
247238901Sandrew  uptr tls_addr = 0;
248238901Sandrew  uptr tls_size = 0;
249280031Sdim#ifndef SANITIZER_GO
250238901Sandrew  GetThreadStackAndTls(tid == 0, &stk_addr, &stk_size, &tls_addr, &tls_size);
251238901Sandrew
252238901Sandrew  if (tid) {
253251034Sed    if (stk_addr && stk_size)
254251034Sed      MemoryRangeImitateWrite(thr, /*pc=*/ 1, stk_addr, stk_size);
255238901Sandrew
256238901Sandrew    if (tls_addr && tls_size) {
257238901Sandrew      // Check that the thr object is in tls;
258238901Sandrew      const uptr thr_beg = (uptr)thr;
259238901Sandrew      const uptr thr_end = (uptr)thr + sizeof(*thr);
260238901Sandrew      CHECK_GE(thr_beg, tls_addr);
261238901Sandrew      CHECK_LE(thr_beg, tls_addr + tls_size);
262238901Sandrew      CHECK_GE(thr_end, tls_addr);
263238901Sandrew      CHECK_LE(thr_end, tls_addr + tls_size);
264238901Sandrew      // Since the thr object is huge, skip it.
265251034Sed      MemoryRangeImitateWrite(thr, /*pc=*/ 2, tls_addr, thr_beg - tls_addr);
266251034Sed      MemoryRangeImitateWrite(thr, /*pc=*/ 2,
267251034Sed          thr_end, tls_addr + tls_size - thr_end);
268238901Sandrew    }
269238901Sandrew  }
270280031Sdim#endif
271238901Sandrew
272276789Sdim  ThreadRegistry *tr = ctx->thread_registry;
273251034Sed  OnStartedArgs args = { thr, stk_addr, stk_size, tls_addr, tls_size };
274276789Sdim  tr->StartThread(tid, os_id, &args);
275276789Sdim
276276789Sdim  tr->Lock();
277276789Sdim  thr->tctx = (ThreadContext*)tr->GetThreadLocked(tid);
278276789Sdim  tr->Unlock();
279276789Sdim
280276789Sdim#ifndef SANITIZER_GO
281276789Sdim  if (ctx->after_multithreaded_fork) {
282276789Sdim    thr->ignore_interceptors++;
283276789Sdim    ThreadIgnoreBegin(thr, 0);
284276789Sdim    ThreadIgnoreSyncBegin(thr, 0);
285276789Sdim  }
286276789Sdim#endif
287238901Sandrew}
288238901Sandrew
289238901Sandrewvoid ThreadFinish(ThreadState *thr) {
290251034Sed  ThreadCheckIgnore(thr);
291238901Sandrew  StatInc(thr, StatThreadFinish);
292238901Sandrew  if (thr->stk_addr && thr->stk_size)
293251034Sed    DontNeedShadowFor(thr->stk_addr, thr->stk_size);
294251034Sed  if (thr->tls_addr && thr->tls_size)
295251034Sed    DontNeedShadowFor(thr->tls_addr, thr->tls_size);
296276789Sdim  thr->is_dead = true;
297251034Sed  ctx->thread_registry->FinishThread(thr->tid);
298251034Sed}
299238901Sandrew
300251034Sedstatic bool FindThreadByUid(ThreadContextBase *tctx, void *arg) {
301251034Sed  uptr uid = (uptr)arg;
302251034Sed  if (tctx->user_id == uid && tctx->status != ThreadStatusInvalid) {
303251034Sed    tctx->user_id = 0;
304251034Sed    return true;
305238901Sandrew  }
306251034Sed  return false;
307238901Sandrew}
308238901Sandrew
309238901Sandrewint ThreadTid(ThreadState *thr, uptr pc, uptr uid) {
310251034Sed  int res = ctx->thread_registry->FindThread(FindThreadByUid, (void*)uid);
311238901Sandrew  DPrintf("#%d: ThreadTid uid=%zu tid=%d\n", thr->tid, uid, res);
312238901Sandrew  return res;
313238901Sandrew}
314238901Sandrew
315238901Sandrewvoid ThreadJoin(ThreadState *thr, uptr pc, int tid) {
316238901Sandrew  CHECK_GT(tid, 0);
317238901Sandrew  CHECK_LT(tid, kMaxTid);
318238901Sandrew  DPrintf("#%d: ThreadJoin tid=%d\n", thr->tid, tid);
319251034Sed  ctx->thread_registry->JoinThread(tid, thr);
320238901Sandrew}
321238901Sandrew
322238901Sandrewvoid ThreadDetach(ThreadState *thr, uptr pc, int tid) {
323238901Sandrew  CHECK_GT(tid, 0);
324238901Sandrew  CHECK_LT(tid, kMaxTid);
325276789Sdim  ctx->thread_registry->DetachThread(tid, thr);
326238901Sandrew}
327238901Sandrew
328245614Sandrewvoid ThreadSetName(ThreadState *thr, const char *name) {
329276789Sdim  ctx->thread_registry->SetThreadName(thr->tid, name);
330238901Sandrew}
331238901Sandrew
332238901Sandrewvoid MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr,
333238901Sandrew                       uptr size, bool is_write) {
334238901Sandrew  if (size == 0)
335238901Sandrew    return;
336238901Sandrew
337238901Sandrew  u64 *shadow_mem = (u64*)MemToShadow(addr);
338238901Sandrew  DPrintf2("#%d: MemoryAccessRange: @%p %p size=%d is_write=%d\n",
339238901Sandrew      thr->tid, (void*)pc, (void*)addr,
340238901Sandrew      (int)size, is_write);
341238901Sandrew
342280031Sdim#if SANITIZER_DEBUG
343238901Sandrew  if (!IsAppMem(addr)) {
344245614Sandrew    Printf("Access to non app mem %zx\n", addr);
345238901Sandrew    DCHECK(IsAppMem(addr));
346238901Sandrew  }
347238901Sandrew  if (!IsAppMem(addr + size - 1)) {
348245614Sandrew    Printf("Access to non app mem %zx\n", addr + size - 1);
349238901Sandrew    DCHECK(IsAppMem(addr + size - 1));
350238901Sandrew  }
351238901Sandrew  if (!IsShadowMem((uptr)shadow_mem)) {
352245614Sandrew    Printf("Bad shadow addr %p (%zx)\n", shadow_mem, addr);
353238901Sandrew    DCHECK(IsShadowMem((uptr)shadow_mem));
354238901Sandrew  }
355238901Sandrew  if (!IsShadowMem((uptr)(shadow_mem + size * kShadowCnt / 8 - 1))) {
356245614Sandrew    Printf("Bad shadow addr %p (%zx)\n",
357238901Sandrew               shadow_mem + size * kShadowCnt / 8 - 1, addr + size - 1);
358238901Sandrew    DCHECK(IsShadowMem((uptr)(shadow_mem + size * kShadowCnt / 8 - 1)));
359238901Sandrew  }
360238901Sandrew#endif
361238901Sandrew
362238901Sandrew  StatInc(thr, StatMopRange);
363238901Sandrew
364251034Sed  if (*shadow_mem == kShadowRodata) {
365251034Sed    // Access to .rodata section, no races here.
366251034Sed    // Measurements show that it can be 10-20% of all memory accesses.
367251034Sed    StatInc(thr, StatMopRangeRodata);
368251034Sed    return;
369251034Sed  }
370251034Sed
371238901Sandrew  FastState fast_state = thr->fast_state;
372238901Sandrew  if (fast_state.GetIgnoreBit())
373238901Sandrew    return;
374238901Sandrew
375238901Sandrew  fast_state.IncrementEpoch();
376238901Sandrew  thr->fast_state = fast_state;
377245614Sandrew  TraceAddEvent(thr, fast_state, EventTypeMop, pc);
378238901Sandrew
379238901Sandrew  bool unaligned = (addr % kShadowCell) != 0;
380238901Sandrew
381238901Sandrew  // Handle unaligned beginning, if any.
382238901Sandrew  for (; addr % kShadowCell && size; addr++, size--) {
383238901Sandrew    int const kAccessSizeLog = 0;
384238901Sandrew    Shadow cur(fast_state);
385238901Sandrew    cur.SetWrite(is_write);
386238901Sandrew    cur.SetAddr0AndSizeLog(addr & (kShadowCell - 1), kAccessSizeLog);
387251034Sed    MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false,
388238901Sandrew        shadow_mem, cur);
389238901Sandrew  }
390238901Sandrew  if (unaligned)
391238901Sandrew    shadow_mem += kShadowCnt;
392238901Sandrew  // Handle middle part, if any.
393238901Sandrew  for (; size >= kShadowCell; addr += kShadowCell, size -= kShadowCell) {
394238901Sandrew    int const kAccessSizeLog = 3;
395238901Sandrew    Shadow cur(fast_state);
396238901Sandrew    cur.SetWrite(is_write);
397238901Sandrew    cur.SetAddr0AndSizeLog(0, kAccessSizeLog);
398251034Sed    MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false,
399238901Sandrew        shadow_mem, cur);
400238901Sandrew    shadow_mem += kShadowCnt;
401238901Sandrew  }
402238901Sandrew  // Handle ending, if any.
403238901Sandrew  for (; size; addr++, size--) {
404238901Sandrew    int const kAccessSizeLog = 0;
405238901Sandrew    Shadow cur(fast_state);
406238901Sandrew    cur.SetWrite(is_write);
407238901Sandrew    cur.SetAddr0AndSizeLog(addr & (kShadowCell - 1), kAccessSizeLog);
408251034Sed    MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false,
409238901Sandrew        shadow_mem, cur);
410238901Sandrew  }
411238901Sandrew}
412238901Sandrew
413238901Sandrew}  // namespace __tsan
414