1218885Sdim//=-- lsan_thread.cc ------------------------------------------------------===// 2218885Sdim// 3218885Sdim// The LLVM Compiler Infrastructure 4218885Sdim// 5218885Sdim// This file is distributed under the University of Illinois Open Source 6218885Sdim// License. See LICENSE.TXT for details. 7218885Sdim// 8218885Sdim//===----------------------------------------------------------------------===// 9218885Sdim// 10218885Sdim// This file is a part of LeakSanitizer. 11218885Sdim// See lsan_thread.h for details. 12218885Sdim// 13218885Sdim//===----------------------------------------------------------------------===// 14221345Sdim 15218885Sdim#include "lsan_thread.h" 16218885Sdim 17221345Sdim#include "sanitizer_common/sanitizer_common.h" 18223017Sdim#include "sanitizer_common/sanitizer_placement_new.h" 19221345Sdim#include "sanitizer_common/sanitizer_thread_registry.h" 20218885Sdim#include "lsan_allocator.h" 21218885Sdim 22218885Sdimnamespace __lsan { 23221345Sdim 24221345Sdimconst u32 kInvalidTid = (u32) -1; 25218885Sdim 26218885Sdimstatic ThreadRegistry *thread_registry; 27218885Sdimstatic THREADLOCAL u32 current_thread_tid = kInvalidTid; 28223017Sdim 29223017Sdimstatic ThreadContextBase *CreateThreadContext(u32 tid) { 30223017Sdim void *mem = MmapOrDie(sizeof(ThreadContext), "ThreadContext"); 31223017Sdim return new(mem) ThreadContext(tid); 32221345Sdim} 33221345Sdim 34221345Sdimstatic const uptr kMaxThreads = 1 << 13; 35221345Sdimstatic const uptr kThreadQuarantineSize = 64; 36221345Sdim 37221345Sdimvoid InitializeThreadRegistry() { 38221345Sdim static char thread_registry_placeholder[sizeof(ThreadRegistry)] ALIGNED(64); 39221345Sdim thread_registry = new(thread_registry_placeholder) 40221345Sdim ThreadRegistry(CreateThreadContext, kMaxThreads, kThreadQuarantineSize); 41221345Sdim} 42218885Sdim 43218885Sdimu32 GetCurrentThread() { 44221345Sdim return current_thread_tid; 45221345Sdim} 46221345Sdim 47221345Sdimvoid SetCurrentThread(u32 tid) { 48221345Sdim current_thread_tid = tid; 49221345Sdim} 50221345Sdim 51221345SdimThreadContext::ThreadContext(int tid) 52221345Sdim : ThreadContextBase(tid), 53221345Sdim stack_begin_(0), 54221345Sdim stack_end_(0), 55221345Sdim cache_begin_(0), 56218885Sdim cache_end_(0), 57218885Sdim tls_begin_(0), 58218885Sdim tls_end_(0) {} 59218885Sdim 60218885Sdimstruct OnStartedArgs { 61218885Sdim uptr stack_begin, stack_end, 62218885Sdim cache_begin, cache_end, 63218885Sdim tls_begin, tls_end; 64218885Sdim}; 65218885Sdim 66218885Sdimvoid ThreadContext::OnStarted(void *arg) { 67221345Sdim OnStartedArgs *args = reinterpret_cast<OnStartedArgs *>(arg); 68218885Sdim stack_begin_ = args->stack_begin; 69218885Sdim stack_end_ = args->stack_end; 70218885Sdim tls_begin_ = args->tls_begin; 71218885Sdim tls_end_ = args->tls_end; 72218885Sdim cache_begin_ = args->cache_begin; 73218885Sdim cache_end_ = args->cache_end; 74218885Sdim} 75218885Sdim 76218885Sdimvoid ThreadContext::OnFinished() { 77218885Sdim AllocatorThreadFinish(); 78218885Sdim} 79218885Sdim 80218885Sdimu32 ThreadCreate(u32 parent_tid, uptr user_id, bool detached) { 81218885Sdim return thread_registry->CreateThread(user_id, detached, parent_tid, 82218885Sdim /* arg */ nullptr); 83218885Sdim} 84218885Sdim 85218885Sdimvoid ThreadStart(u32 tid, uptr os_id) { 86218885Sdim OnStartedArgs args; 87218885Sdim uptr stack_size = 0; 88218885Sdim uptr tls_size = 0; 89218885Sdim GetThreadStackAndTls(tid == 0, &args.stack_begin, &stack_size, 90221345Sdim &args.tls_begin, &tls_size); 91218885Sdim args.stack_end = args.stack_begin + stack_size; 92218885Sdim args.tls_end = args.tls_begin + tls_size; 93218885Sdim GetAllocatorCacheRange(&args.cache_begin, &args.cache_end); 94218885Sdim thread_registry->StartThread(tid, os_id, &args); 95218885Sdim} 96221345Sdim 97221345Sdimvoid ThreadFinish() { 98221345Sdim thread_registry->FinishThread(GetCurrentThread()); 99221345Sdim} 100218885Sdim 101218885SdimThreadContext *CurrentThreadContext() { 102218885Sdim if (!thread_registry) return nullptr; 103218885Sdim if (GetCurrentThread() == kInvalidTid) 104218885Sdim return nullptr; 105218885Sdim // No lock needed when getting current thread. 106218885Sdim return (ThreadContext *)thread_registry->GetThreadLocked(GetCurrentThread()); 107218885Sdim} 108218885Sdim 109218885Sdimstatic bool FindThreadByUid(ThreadContextBase *tctx, void *arg) { 110218885Sdim uptr uid = (uptr)arg; 111218885Sdim if (tctx->user_id == uid && tctx->status != ThreadStatusInvalid) { 112218885Sdim return true; 113218885Sdim } 114218885Sdim return false; 115218885Sdim} 116218885Sdim 117218885Sdimu32 ThreadTid(uptr uid) { 118218885Sdim return thread_registry->FindThread(FindThreadByUid, (void*)uid); 119218885Sdim} 120218885Sdim 121221345Sdimvoid ThreadJoin(u32 tid) { 122221345Sdim CHECK_NE(tid, kInvalidTid); 123221345Sdim thread_registry->JoinThread(tid, /* arg */nullptr); 124221345Sdim} 125221345Sdim 126221345Sdimvoid EnsureMainThreadIDIsCorrect() { 127221345Sdim if (GetCurrentThread() == 0) 128221345Sdim CurrentThreadContext()->os_id = GetTid(); 129221345Sdim} 130218885Sdim 131218885Sdim///// Interface to the common LSan module. ///// 132218885Sdim 133218885Sdimbool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end, 134218885Sdim uptr *tls_begin, uptr *tls_end, 135218885Sdim uptr *cache_begin, uptr *cache_end) { 136221345Sdim ThreadContext *context = static_cast<ThreadContext *>( 137218885Sdim thread_registry->FindThreadContextByOsIDLocked(os_id)); 138218885Sdim if (!context) return false; 139218885Sdim *stack_begin = context->stack_begin(); 140218885Sdim *stack_end = context->stack_end(); 141218885Sdim *tls_begin = context->tls_begin(); 142218885Sdim *tls_end = context->tls_end(); 143218885Sdim *cache_begin = context->cache_begin(); 144218885Sdim *cache_end = context->cache_end(); 145218885Sdim return true; 146218885Sdim} 147218885Sdim 148221345Sdimvoid ForEachExtraStackRange(uptr os_id, RangeIteratorCallback callback, 149221345Sdim void *arg) { 150218885Sdim} 151218885Sdim 152218885Sdimvoid LockThreadRegistry() { 153221345Sdim thread_registry->Lock(); 154221345Sdim} 155218885Sdim 156218885Sdimvoid UnlockThreadRegistry() { 157221345Sdim thread_registry->Unlock(); 158221345Sdim} 159221345Sdim 160221345Sdim} // namespace __lsan 161221345Sdim