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