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