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