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