1 //=-- lsan_thread.cc ------------------------------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file is a part of LeakSanitizer.
11 // See lsan_thread.h for details.
13 //===----------------------------------------------------------------------===//
15 #include "lsan_thread.h"
17 #include "sanitizer_common/sanitizer_common.h"
18 #include "sanitizer_common/sanitizer_placement_new.h"
19 #include "sanitizer_common/sanitizer_thread_registry.h"
20 #include "sanitizer_common/sanitizer_tls_get_addr.h"
21 #include "lsan_allocator.h"
25 const u32 kInvalidTid
= (u32
) -1;
27 static ThreadRegistry
*thread_registry
;
28 static THREADLOCAL u32 current_thread_tid
= kInvalidTid
;
30 static ThreadContextBase
*CreateThreadContext(u32 tid
) {
31 void *mem
= MmapOrDie(sizeof(ThreadContext
), "ThreadContext");
32 return new(mem
) ThreadContext(tid
);
35 static const uptr kMaxThreads
= 1 << 13;
36 static const uptr kThreadQuarantineSize
= 64;
38 void InitializeThreadRegistry() {
39 static char thread_registry_placeholder
[sizeof(ThreadRegistry
)] ALIGNED(64);
40 thread_registry
= new(thread_registry_placeholder
)
41 ThreadRegistry(CreateThreadContext
, kMaxThreads
, kThreadQuarantineSize
);
44 u32
GetCurrentThread() {
45 return current_thread_tid
;
48 void SetCurrentThread(u32 tid
) {
49 current_thread_tid
= tid
;
52 ThreadContext::ThreadContext(int tid
)
53 : ThreadContextBase(tid
),
62 struct OnStartedArgs
{
63 uptr stack_begin
, stack_end
,
64 cache_begin
, cache_end
,
69 void ThreadContext::OnStarted(void *arg
) {
70 OnStartedArgs
*args
= reinterpret_cast<OnStartedArgs
*>(arg
);
71 stack_begin_
= args
->stack_begin
;
72 stack_end_
= args
->stack_end
;
73 tls_begin_
= args
->tls_begin
;
74 tls_end_
= args
->tls_end
;
75 cache_begin_
= args
->cache_begin
;
76 cache_end_
= args
->cache_end
;
80 void ThreadContext::OnFinished() {
81 AllocatorThreadFinish();
85 u32
ThreadCreate(u32 parent_tid
, uptr user_id
, bool detached
) {
86 return thread_registry
->CreateThread(user_id
, detached
, parent_tid
,
90 void ThreadStart(u32 tid
, uptr os_id
) {
94 GetThreadStackAndTls(tid
== 0, &args
.stack_begin
, &stack_size
,
95 &args
.tls_begin
, &tls_size
);
96 args
.stack_end
= args
.stack_begin
+ stack_size
;
97 args
.tls_end
= args
.tls_begin
+ tls_size
;
98 GetAllocatorCacheRange(&args
.cache_begin
, &args
.cache_end
);
99 args
.dtls
= DTLS_Get();
100 thread_registry
->StartThread(tid
, os_id
, &args
);
103 void ThreadFinish() {
104 thread_registry
->FinishThread(GetCurrentThread());
107 ThreadContext
*CurrentThreadContext() {
108 if (!thread_registry
) return nullptr;
109 if (GetCurrentThread() == kInvalidTid
)
111 // No lock needed when getting current thread.
112 return (ThreadContext
*)thread_registry
->GetThreadLocked(GetCurrentThread());
115 static bool FindThreadByUid(ThreadContextBase
*tctx
, void *arg
) {
116 uptr uid
= (uptr
)arg
;
117 if (tctx
->user_id
== uid
&& tctx
->status
!= ThreadStatusInvalid
) {
123 u32
ThreadTid(uptr uid
) {
124 return thread_registry
->FindThread(FindThreadByUid
, (void*)uid
);
127 void ThreadJoin(u32 tid
) {
128 CHECK_NE(tid
, kInvalidTid
);
129 thread_registry
->JoinThread(tid
, /* arg */nullptr);
132 void EnsureMainThreadIDIsCorrect() {
133 if (GetCurrentThread() == 0)
134 CurrentThreadContext()->os_id
= GetTid();
137 ///// Interface to the common LSan module. /////
139 bool GetThreadRangesLocked(uptr os_id
, uptr
*stack_begin
, uptr
*stack_end
,
140 uptr
*tls_begin
, uptr
*tls_end
, uptr
*cache_begin
,
141 uptr
*cache_end
, DTLS
**dtls
) {
142 ThreadContext
*context
= static_cast<ThreadContext
*>(
143 thread_registry
->FindThreadContextByOsIDLocked(os_id
));
144 if (!context
) return false;
145 *stack_begin
= context
->stack_begin();
146 *stack_end
= context
->stack_end();
147 *tls_begin
= context
->tls_begin();
148 *tls_end
= context
->tls_end();
149 *cache_begin
= context
->cache_begin();
150 *cache_end
= context
->cache_end();
151 *dtls
= context
->dtls();
155 void ForEachExtraStackRange(uptr os_id
, RangeIteratorCallback callback
,
159 void LockThreadRegistry() {
160 thread_registry
->Lock();
163 void UnlockThreadRegistry() {
164 thread_registry
->Unlock();
167 } // namespace __lsan