1 //=-- lsan_thread.cc ------------------------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // This file is a part of LeakSanitizer.
9 // See lsan_thread.h for details.
11 //===----------------------------------------------------------------------===//
13 #include "lsan_thread.h"
15 #include "sanitizer_common/sanitizer_common.h"
16 #include "sanitizer_common/sanitizer_placement_new.h"
17 #include "sanitizer_common/sanitizer_thread_registry.h"
18 #include "lsan_allocator.h"
22 const u32 kInvalidTid
= (u32
) -1;
24 static ThreadRegistry
*thread_registry
;
25 static THREADLOCAL u32 current_thread_tid
= kInvalidTid
;
27 static ThreadContextBase
*CreateThreadContext(u32 tid
) {
28 void *mem
= MmapOrDie(sizeof(ThreadContext
), "ThreadContext");
29 return new(mem
) ThreadContext(tid
);
32 static const uptr kMaxThreads
= 1 << 13;
33 static const uptr kThreadQuarantineSize
= 64;
35 void InitializeThreadRegistry() {
36 static char thread_registry_placeholder
[sizeof(ThreadRegistry
)] ALIGNED(64);
37 thread_registry
= new(thread_registry_placeholder
)
38 ThreadRegistry(CreateThreadContext
, kMaxThreads
, kThreadQuarantineSize
);
41 u32
GetCurrentThread() {
42 return current_thread_tid
;
45 void SetCurrentThread(u32 tid
) {
46 current_thread_tid
= tid
;
49 ThreadContext::ThreadContext(int tid
)
50 : ThreadContextBase(tid
),
58 struct OnStartedArgs
{
59 uptr stack_begin
, stack_end
,
60 cache_begin
, cache_end
,
64 void ThreadContext::OnStarted(void *arg
) {
65 OnStartedArgs
*args
= reinterpret_cast<OnStartedArgs
*>(arg
);
66 stack_begin_
= args
->stack_begin
;
67 stack_end_
= args
->stack_end
;
68 tls_begin_
= args
->tls_begin
;
69 tls_end_
= args
->tls_end
;
70 cache_begin_
= args
->cache_begin
;
71 cache_end_
= args
->cache_end
;
74 void ThreadContext::OnFinished() {
75 AllocatorThreadFinish();
78 u32
ThreadCreate(u32 parent_tid
, uptr user_id
, bool detached
) {
79 return thread_registry
->CreateThread(user_id
, detached
, parent_tid
,
83 void ThreadStart(u32 tid
, uptr os_id
) {
87 GetThreadStackAndTls(tid
== 0, &args
.stack_begin
, &stack_size
,
88 &args
.tls_begin
, &tls_size
);
89 args
.stack_end
= args
.stack_begin
+ stack_size
;
90 args
.tls_end
= args
.tls_begin
+ tls_size
;
91 GetAllocatorCacheRange(&args
.cache_begin
, &args
.cache_end
);
92 thread_registry
->StartThread(tid
, os_id
, &args
);
96 thread_registry
->FinishThread(GetCurrentThread());
99 ThreadContext
*CurrentThreadContext() {
100 if (!thread_registry
) return nullptr;
101 if (GetCurrentThread() == kInvalidTid
)
103 // No lock needed when getting current thread.
104 return (ThreadContext
*)thread_registry
->GetThreadLocked(GetCurrentThread());
107 static bool FindThreadByUid(ThreadContextBase
*tctx
, void *arg
) {
108 uptr uid
= (uptr
)arg
;
109 if (tctx
->user_id
== uid
&& tctx
->status
!= ThreadStatusInvalid
) {
115 u32
ThreadTid(uptr uid
) {
116 return thread_registry
->FindThread(FindThreadByUid
, (void*)uid
);
119 void ThreadJoin(u32 tid
) {
120 CHECK_NE(tid
, kInvalidTid
);
121 thread_registry
->JoinThread(tid
, /* arg */nullptr);
124 void EnsureMainThreadIDIsCorrect() {
125 if (GetCurrentThread() == 0)
126 CurrentThreadContext()->os_id
= GetTid();
129 ///// Interface to the common LSan module. /////
131 bool GetThreadRangesLocked(uptr os_id
, uptr
*stack_begin
, uptr
*stack_end
,
132 uptr
*tls_begin
, uptr
*tls_end
,
133 uptr
*cache_begin
, uptr
*cache_end
) {
134 ThreadContext
*context
= static_cast<ThreadContext
*>(
135 thread_registry
->FindThreadContextByOsIDLocked(os_id
));
136 if (!context
) return false;
137 *stack_begin
= context
->stack_begin();
138 *stack_end
= context
->stack_end();
139 *tls_begin
= context
->tls_begin();
140 *tls_end
= context
->tls_end();
141 *cache_begin
= context
->cache_begin();
142 *cache_end
= context
->cache_end();
146 void ForEachExtraStackRange(uptr os_id
, RangeIteratorCallback callback
,
150 void LockThreadRegistry() {
151 thread_registry
->Lock();
154 void UnlockThreadRegistry() {
155 thread_registry
->Unlock();
158 } // namespace __lsan