1 //=-- lsan_thread.cc ------------------------------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file is a part of LeakSanitizer. 11 // See lsan_thread.h for details. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "lsan_thread.h" 16 17 #include "sanitizer_common/sanitizer_common.h" 18 #include "sanitizer_common/sanitizer_placement_new.h" 19 #include "sanitizer_common/sanitizer_thread_registry.h" 20 #include "sanitizer_common/sanitizer_tls_get_addr.h" 21 #include "lsan_allocator.h" 22 #include "lsan_common.h" 23 24 namespace __lsan { 25 26 static ThreadRegistry *thread_registry; 27 28 static ThreadContextBase *CreateThreadContext(u32 tid) { 29 void *mem = MmapOrDie(sizeof(ThreadContext), "ThreadContext"); 30 return new(mem) ThreadContext(tid); 31 } 32 33 static const uptr kMaxThreads = 1 << 13; 34 static const uptr kThreadQuarantineSize = 64; 35 36 void InitializeThreadRegistry() { 37 static ALIGNED(64) char thread_registry_placeholder[sizeof(ThreadRegistry)]; 38 thread_registry = new(thread_registry_placeholder) 39 ThreadRegistry(CreateThreadContext, kMaxThreads, kThreadQuarantineSize); 40 } 41 42 ThreadContext::ThreadContext(int tid) 43 : ThreadContextBase(tid), 44 stack_begin_(0), 45 stack_end_(0), 46 cache_begin_(0), 47 cache_end_(0), 48 tls_begin_(0), 49 tls_end_(0), 50 dtls_(nullptr) {} 51 52 struct OnStartedArgs { 53 uptr stack_begin, stack_end, 54 cache_begin, cache_end, 55 tls_begin, tls_end; 56 DTLS *dtls; 57 }; 58 59 void ThreadContext::OnStarted(void *arg) { 60 OnStartedArgs *args = reinterpret_cast<OnStartedArgs *>(arg); 61 stack_begin_ = args->stack_begin; 62 stack_end_ = args->stack_end; 63 tls_begin_ = args->tls_begin; 64 tls_end_ = args->tls_end; 65 cache_begin_ = args->cache_begin; 66 cache_end_ = args->cache_end; 67 dtls_ = args->dtls; 68 } 69 70 void ThreadContext::OnFinished() { 71 AllocatorThreadFinish(); 72 DTLS_Destroy(); 73 } 74 75 u32 ThreadCreate(u32 parent_tid, uptr user_id, bool detached) { 76 return thread_registry->CreateThread(user_id, detached, parent_tid, 77 /* arg */ nullptr); 78 } 79 80 void ThreadStart(u32 tid, tid_t os_id, bool workerthread) { 81 OnStartedArgs args; 82 uptr stack_size = 0; 83 uptr tls_size = 0; 84 GetThreadStackAndTls(tid == 0, &args.stack_begin, &stack_size, 85 &args.tls_begin, &tls_size); 86 args.stack_end = args.stack_begin + stack_size; 87 args.tls_end = args.tls_begin + tls_size; 88 GetAllocatorCacheRange(&args.cache_begin, &args.cache_end); 89 args.dtls = DTLS_Get(); 90 thread_registry->StartThread(tid, os_id, workerthread, &args); 91 } 92 93 void ThreadFinish() { 94 thread_registry->FinishThread(GetCurrentThread()); 95 SetCurrentThread(kInvalidTid); 96 } 97 98 ThreadContext *CurrentThreadContext() { 99 if (!thread_registry) return nullptr; 100 if (GetCurrentThread() == kInvalidTid) 101 return nullptr; 102 // No lock needed when getting current thread. 103 return (ThreadContext *)thread_registry->GetThreadLocked(GetCurrentThread()); 104 } 105 106 static bool FindThreadByUid(ThreadContextBase *tctx, void *arg) { 107 uptr uid = (uptr)arg; 108 if (tctx->user_id == uid && tctx->status != ThreadStatusInvalid) { 109 return true; 110 } 111 return false; 112 } 113 114 u32 ThreadTid(uptr uid) { 115 return thread_registry->FindThread(FindThreadByUid, (void*)uid); 116 } 117 118 void ThreadJoin(u32 tid) { 119 CHECK_NE(tid, kInvalidTid); 120 thread_registry->JoinThread(tid, /* arg */nullptr); 121 } 122 123 void EnsureMainThreadIDIsCorrect() { 124 if (GetCurrentThread() == 0) 125 CurrentThreadContext()->os_id = GetTid(); 126 } 127 128 ///// Interface to the common LSan module. ///// 129 130 bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end, 131 uptr *tls_begin, uptr *tls_end, uptr *cache_begin, 132 uptr *cache_end, DTLS **dtls) { 133 ThreadContext *context = static_cast<ThreadContext *>( 134 thread_registry->FindThreadContextByOsIDLocked(os_id)); 135 if (!context) return false; 136 *stack_begin = context->stack_begin(); 137 *stack_end = context->stack_end(); 138 *tls_begin = context->tls_begin(); 139 *tls_end = context->tls_end(); 140 *cache_begin = context->cache_begin(); 141 *cache_end = context->cache_end(); 142 *dtls = context->dtls(); 143 return true; 144 } 145 146 void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback, 147 void *arg) { 148 } 149 150 void LockThreadRegistry() { 151 thread_registry->Lock(); 152 } 153 154 void UnlockThreadRegistry() { 155 thread_registry->Unlock(); 156 } 157 158 ThreadRegistry *GetThreadRegistryLocked() { 159 thread_registry->CheckLocked(); 160 return thread_registry; 161 } 162 163 } // namespace __lsan 164