|  | //=-- lsan_thread.cpp -----------------------------------------------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // This file is a part of LeakSanitizer. | 
|  | // See lsan_thread.h for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "lsan_thread.h" | 
|  |  | 
|  | #include "lsan.h" | 
|  | #include "lsan_allocator.h" | 
|  | #include "lsan_common.h" | 
|  | #include "sanitizer_common/sanitizer_common.h" | 
|  | #include "sanitizer_common/sanitizer_placement_new.h" | 
|  | #include "sanitizer_common/sanitizer_thread_registry.h" | 
|  | #include "sanitizer_common/sanitizer_tls_get_addr.h" | 
|  |  | 
|  | namespace __lsan { | 
|  |  | 
|  | static ThreadRegistry *thread_registry; | 
|  |  | 
|  | static ThreadContextBase *CreateThreadContext(u32 tid) { | 
|  | void *mem = MmapOrDie(sizeof(ThreadContext), "ThreadContext"); | 
|  | return new (mem) ThreadContext(tid); | 
|  | } | 
|  |  | 
|  | void InitializeThreadRegistry() { | 
|  | static ALIGNED(64) char thread_registry_placeholder[sizeof(ThreadRegistry)]; | 
|  | thread_registry = | 
|  | new (thread_registry_placeholder) ThreadRegistry(CreateThreadContext); | 
|  | } | 
|  |  | 
|  | ThreadContextLsanBase::ThreadContextLsanBase(int tid) | 
|  | : ThreadContextBase(tid) {} | 
|  |  | 
|  | void ThreadContextLsanBase::OnFinished() { | 
|  | AllocatorThreadFinish(); | 
|  | DTLS_Destroy(); | 
|  | } | 
|  |  | 
|  | u32 ThreadCreate(u32 parent_tid, uptr user_id, bool detached, void *arg) { | 
|  | return thread_registry->CreateThread(user_id, detached, parent_tid, arg); | 
|  | } | 
|  |  | 
|  | void ThreadContextLsanBase::ThreadStart(u32 tid, tid_t os_id, | 
|  | ThreadType thread_type, void *arg) { | 
|  | thread_registry->StartThread(tid, os_id, thread_type, arg); | 
|  | SetCurrentThread(tid); | 
|  | } | 
|  |  | 
|  | void ThreadFinish() { | 
|  | thread_registry->FinishThread(GetCurrentThread()); | 
|  | SetCurrentThread(kInvalidTid); | 
|  | } | 
|  |  | 
|  | ThreadContext *CurrentThreadContext() { | 
|  | if (!thread_registry) | 
|  | return nullptr; | 
|  | if (GetCurrentThread() == kInvalidTid) | 
|  | return nullptr; | 
|  | // No lock needed when getting current thread. | 
|  | return (ThreadContext *)thread_registry->GetThreadLocked(GetCurrentThread()); | 
|  | } | 
|  |  | 
|  | static bool FindThreadByUid(ThreadContextBase *tctx, void *arg) { | 
|  | uptr uid = (uptr)arg; | 
|  | if (tctx->user_id == uid && tctx->status != ThreadStatusInvalid) { | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | u32 ThreadTid(uptr uid) { | 
|  | return thread_registry->FindThread(FindThreadByUid, (void *)uid); | 
|  | } | 
|  |  | 
|  | void ThreadDetach(u32 tid) { | 
|  | CHECK_NE(tid, kInvalidTid); | 
|  | thread_registry->DetachThread(tid, /* arg */ nullptr); | 
|  | } | 
|  |  | 
|  | void ThreadJoin(u32 tid) { | 
|  | CHECK_NE(tid, kInvalidTid); | 
|  | thread_registry->JoinThread(tid, /* arg */ nullptr); | 
|  | } | 
|  |  | 
|  | void EnsureMainThreadIDIsCorrect() { | 
|  | if (GetCurrentThread() == kMainTid) | 
|  | CurrentThreadContext()->os_id = GetTid(); | 
|  | } | 
|  |  | 
|  | ///// Interface to the common LSan module. ///// | 
|  |  | 
|  | void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback, | 
|  | void *arg) {} | 
|  |  | 
|  | void LockThreadRegistry() { thread_registry->Lock(); } | 
|  |  | 
|  | void UnlockThreadRegistry() { thread_registry->Unlock(); } | 
|  |  | 
|  | ThreadRegistry *GetThreadRegistryLocked() { | 
|  | thread_registry->CheckLocked(); | 
|  | return thread_registry; | 
|  | } | 
|  |  | 
|  | }  // namespace __lsan |