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-exception 6 // 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 20 namespace __tsan { 21 22 // ThreadContext implementation. 23 24 ThreadContext::ThreadContext(Tid tid) 25 : ThreadContextBase(tid), thr(), sync(), epoch0(), epoch1() {} 26 27 #if !SANITIZER_GO 28 ThreadContext::~ThreadContext() { 29 } 30 #endif 31 32 void ThreadContext::OnReset() { 33 CHECK_EQ(sync.size(), 0); 34 uptr trace_p = GetThreadTrace(tid); 35 ReleaseMemoryPagesToOS(trace_p, trace_p + TraceSize() * sizeof(Event)); 36 //!!! ReleaseMemoryToOS(GetThreadTraceHeader(tid), sizeof(Trace)); 37 } 38 39 #if !SANITIZER_GO 40 struct ThreadLeak { 41 ThreadContext *tctx; 42 int count; 43 }; 44 45 static void CollectThreadLeaks(ThreadContextBase *tctx_base, void *arg) { 46 auto &leaks = *static_cast<Vector<ThreadLeak> *>(arg); 47 auto *tctx = static_cast<ThreadContext *>(tctx_base); 48 if (tctx->detached || tctx->status != ThreadStatusFinished) 49 return; 50 for (uptr i = 0; i < leaks.Size(); i++) { 51 if (leaks[i].tctx->creation_stack_id == tctx->creation_stack_id) { 52 leaks[i].count++; 53 return; 54 } 55 } 56 leaks.PushBack({tctx, 1}); 57 } 58 #endif 59 60 #if !SANITIZER_GO 61 static void ReportIgnoresEnabled(ThreadContext *tctx, IgnoreSet *set) { 62 if (tctx->tid == kMainTid) { 63 Printf("ThreadSanitizer: main thread finished with ignores enabled\n"); 64 } else { 65 Printf("ThreadSanitizer: thread T%d %s finished with ignores enabled," 66 " created at:\n", tctx->tid, tctx->name); 67 PrintStack(SymbolizeStackId(tctx->creation_stack_id)); 68 } 69 Printf(" One of the following ignores was not ended" 70 " (in order of probability)\n"); 71 for (uptr i = 0; i < set->Size(); i++) { 72 Printf(" Ignore was enabled at:\n"); 73 PrintStack(SymbolizeStackId(set->At(i))); 74 } 75 Die(); 76 } 77 78 static void ThreadCheckIgnore(ThreadState *thr) { 79 if (ctx->after_multithreaded_fork) 80 return; 81 if (thr->ignore_reads_and_writes) 82 ReportIgnoresEnabled(thr->tctx, &thr->mop_ignore_set); 83 if (thr->ignore_sync) 84 ReportIgnoresEnabled(thr->tctx, &thr->sync_ignore_set); 85 } 86 #else 87 static void ThreadCheckIgnore(ThreadState *thr) {} 88 #endif 89 90 void ThreadFinalize(ThreadState *thr) { 91 ThreadCheckIgnore(thr); 92 #if !SANITIZER_GO 93 if (!ShouldReport(thr, ReportTypeThreadLeak)) 94 return; 95 ThreadRegistryLock l(&ctx->thread_registry); 96 Vector<ThreadLeak> leaks; 97 ctx->thread_registry.RunCallbackForEachThreadLocked(CollectThreadLeaks, 98 &leaks); 99 for (uptr i = 0; i < leaks.Size(); i++) { 100 ScopedReport rep(ReportTypeThreadLeak); 101 rep.AddThread(leaks[i].tctx, true); 102 rep.SetCount(leaks[i].count); 103 OutputReport(thr, rep); 104 } 105 #endif 106 } 107 108 int ThreadCount(ThreadState *thr) { 109 uptr result; 110 ctx->thread_registry.GetNumberOfThreads(0, 0, &result); 111 return (int)result; 112 } 113 114 struct OnCreatedArgs { 115 ThreadState *thr; 116 uptr pc; 117 }; 118 119 Tid ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached) { 120 OnCreatedArgs args = { thr, pc }; 121 u32 parent_tid = thr ? thr->tid : kInvalidTid; // No parent for GCD workers. 122 Tid tid = ctx->thread_registry.CreateThread(uid, detached, parent_tid, &args); 123 DPrintf("#%d: ThreadCreate tid=%d uid=%zu\n", parent_tid, tid, uid); 124 return tid; 125 } 126 127 void ThreadContext::OnCreated(void *arg) { 128 thr = 0; 129 if (tid == kMainTid) 130 return; 131 OnCreatedArgs *args = static_cast<OnCreatedArgs *>(arg); 132 if (!args->thr) // GCD workers don't have a parent thread. 133 return; 134 args->thr->fast_state.IncrementEpoch(); 135 // Can't increment epoch w/o writing to the trace as well. 136 TraceAddEvent(args->thr, args->thr->fast_state, EventTypeMop, 0); 137 ReleaseImpl(args->thr, 0, &sync); 138 creation_stack_id = CurrentStackId(args->thr, args->pc); 139 } 140 141 extern "C" void __tsan_stack_initialization() {} 142 143 struct OnStartedArgs { 144 ThreadState *thr; 145 uptr stk_addr; 146 uptr stk_size; 147 uptr tls_addr; 148 uptr tls_size; 149 }; 150 151 void ThreadStart(ThreadState *thr, Tid tid, tid_t os_id, 152 ThreadType thread_type) { 153 uptr stk_addr = 0; 154 uptr stk_size = 0; 155 uptr tls_addr = 0; 156 uptr tls_size = 0; 157 #if !SANITIZER_GO 158 if (thread_type != ThreadType::Fiber) 159 GetThreadStackAndTls(tid == kMainTid, &stk_addr, &stk_size, &tls_addr, 160 &tls_size); 161 #endif 162 163 ThreadRegistry *tr = &ctx->thread_registry; 164 OnStartedArgs args = { thr, stk_addr, stk_size, tls_addr, tls_size }; 165 tr->StartThread(tid, os_id, thread_type, &args); 166 167 while (!thr->tctx->trace.parts.Empty()) thr->tctx->trace.parts.PopBack(); 168 169 #if !SANITIZER_GO 170 if (ctx->after_multithreaded_fork) { 171 thr->ignore_interceptors++; 172 ThreadIgnoreBegin(thr, 0); 173 ThreadIgnoreSyncBegin(thr, 0); 174 } 175 #endif 176 177 #if !SANITIZER_GO 178 // Don't imitate stack/TLS writes for the main thread, 179 // because its initialization is synchronized with all 180 // subsequent threads anyway. 181 if (tid != kMainTid) { 182 if (stk_addr && stk_size) { 183 const uptr pc = StackTrace::GetNextInstructionPc( 184 reinterpret_cast<uptr>(__tsan_stack_initialization)); 185 MemoryRangeImitateWrite(thr, pc, stk_addr, stk_size); 186 } 187 188 if (tls_addr && tls_size) 189 ImitateTlsWrite(thr, tls_addr, tls_size); 190 } 191 #endif 192 } 193 194 void ThreadContext::OnStarted(void *arg) { 195 OnStartedArgs *args = static_cast<OnStartedArgs *>(arg); 196 thr = args->thr; 197 // RoundUp so that one trace part does not contain events 198 // from different threads. 199 epoch0 = RoundUp(epoch1 + 1, kTracePartSize); 200 epoch1 = (u64)-1; 201 new (thr) 202 ThreadState(ctx, tid, unique_id, epoch0, reuse_count, args->stk_addr, 203 args->stk_size, args->tls_addr, args->tls_size); 204 if (common_flags()->detect_deadlocks) 205 thr->dd_lt = ctx->dd->CreateLogicalThread(unique_id); 206 thr->fast_state.SetHistorySize(flags()->history_size); 207 // Commit switch to the new part of the trace. 208 // TraceAddEvent will reset stack0/mset0 in the new part for us. 209 TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0); 210 211 thr->fast_synch_epoch = epoch0; 212 AcquireImpl(thr, 0, &sync); 213 sync.Reset(&thr->proc()->clock_cache); 214 thr->tctx = this; 215 thr->is_inited = true; 216 DPrintf( 217 "#%d: ThreadStart epoch=%zu stk_addr=%zx stk_size=%zx " 218 "tls_addr=%zx tls_size=%zx\n", 219 tid, (uptr)epoch0, args->stk_addr, args->stk_size, args->tls_addr, 220 args->tls_size); 221 } 222 223 void ThreadFinish(ThreadState *thr) { 224 ThreadCheckIgnore(thr); 225 if (thr->stk_addr && thr->stk_size) 226 DontNeedShadowFor(thr->stk_addr, thr->stk_size); 227 if (thr->tls_addr && thr->tls_size) 228 DontNeedShadowFor(thr->tls_addr, thr->tls_size); 229 thr->is_dead = true; 230 thr->is_inited = false; 231 #if !SANITIZER_GO 232 thr->ignore_interceptors++; 233 #endif 234 ctx->thread_registry.FinishThread(thr->tid); 235 } 236 237 void ThreadContext::OnFinished() { 238 if (!detached) { 239 thr->fast_state.IncrementEpoch(); 240 // Can't increment epoch w/o writing to the trace as well. 241 TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0); 242 ReleaseImpl(thr, 0, &sync); 243 } 244 epoch1 = thr->fast_state.epoch(); 245 246 #if !SANITIZER_GO 247 UnmapOrDie(thr->shadow_stack, kShadowStackSize * sizeof(uptr)); 248 #else 249 Free(thr->shadow_stack); 250 #endif 251 thr->shadow_stack = nullptr; 252 thr->shadow_stack_pos = nullptr; 253 thr->shadow_stack_end = nullptr; 254 255 if (common_flags()->detect_deadlocks) 256 ctx->dd->DestroyLogicalThread(thr->dd_lt); 257 thr->clock.ResetCached(&thr->proc()->clock_cache); 258 #if !SANITIZER_GO 259 thr->last_sleep_clock.ResetCached(&thr->proc()->clock_cache); 260 #endif 261 #if !SANITIZER_GO 262 PlatformCleanUpThreadState(thr); 263 #endif 264 thr->~ThreadState(); 265 thr = 0; 266 } 267 268 struct ConsumeThreadContext { 269 uptr uid; 270 ThreadContextBase *tctx; 271 }; 272 273 Tid ThreadConsumeTid(ThreadState *thr, uptr pc, uptr uid) { 274 return ctx->thread_registry.ConsumeThreadUserId(uid); 275 } 276 277 void ThreadJoin(ThreadState *thr, uptr pc, Tid tid) { 278 CHECK_GT(tid, 0); 279 CHECK_LT(tid, kMaxTid); 280 DPrintf("#%d: ThreadJoin tid=%d\n", thr->tid, tid); 281 ctx->thread_registry.JoinThread(tid, thr); 282 } 283 284 void ThreadContext::OnJoined(void *arg) { 285 ThreadState *caller_thr = static_cast<ThreadState *>(arg); 286 AcquireImpl(caller_thr, 0, &sync); 287 sync.Reset(&caller_thr->proc()->clock_cache); 288 } 289 290 void ThreadContext::OnDead() { CHECK_EQ(sync.size(), 0); } 291 292 void ThreadDetach(ThreadState *thr, uptr pc, Tid tid) { 293 CHECK_GT(tid, 0); 294 CHECK_LT(tid, kMaxTid); 295 ctx->thread_registry.DetachThread(tid, thr); 296 } 297 298 void ThreadContext::OnDetached(void *arg) { 299 ThreadState *thr1 = static_cast<ThreadState *>(arg); 300 sync.Reset(&thr1->proc()->clock_cache); 301 } 302 303 void ThreadNotJoined(ThreadState *thr, uptr pc, Tid tid, uptr uid) { 304 CHECK_GT(tid, 0); 305 CHECK_LT(tid, kMaxTid); 306 ctx->thread_registry.SetThreadUserId(tid, uid); 307 } 308 309 void ThreadSetName(ThreadState *thr, const char *name) { 310 ctx->thread_registry.SetThreadName(thr->tid, name); 311 } 312 313 #if !SANITIZER_GO 314 void FiberSwitchImpl(ThreadState *from, ThreadState *to) { 315 Processor *proc = from->proc(); 316 ProcUnwire(proc, from); 317 ProcWire(proc, to); 318 set_cur_thread(to); 319 } 320 321 ThreadState *FiberCreate(ThreadState *thr, uptr pc, unsigned flags) { 322 void *mem = Alloc(sizeof(ThreadState)); 323 ThreadState *fiber = static_cast<ThreadState *>(mem); 324 internal_memset(fiber, 0, sizeof(*fiber)); 325 Tid tid = ThreadCreate(thr, pc, 0, true); 326 FiberSwitchImpl(thr, fiber); 327 ThreadStart(fiber, tid, 0, ThreadType::Fiber); 328 FiberSwitchImpl(fiber, thr); 329 return fiber; 330 } 331 332 void FiberDestroy(ThreadState *thr, uptr pc, ThreadState *fiber) { 333 FiberSwitchImpl(thr, fiber); 334 ThreadFinish(fiber); 335 FiberSwitchImpl(fiber, thr); 336 Free(fiber); 337 } 338 339 void FiberSwitch(ThreadState *thr, uptr pc, 340 ThreadState *fiber, unsigned flags) { 341 if (!(flags & FiberSwitchFlagNoSync)) 342 Release(thr, pc, (uptr)fiber); 343 FiberSwitchImpl(thr, fiber); 344 if (!(flags & FiberSwitchFlagNoSync)) 345 Acquire(fiber, pc, (uptr)fiber); 346 } 347 #endif 348 349 } // namespace __tsan 350