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 "sanitizer_common/sanitizer_tls_get_addr.h"
19 #include "lsan_allocator.h"
23 const u32 kInvalidTid
= (u32
) -1;
25 static ThreadRegistry
*thread_registry
;
26 static THREADLOCAL u32 current_thread_tid
= kInvalidTid
;
28 static ThreadContextBase
*CreateThreadContext(u32 tid
) {
29 void *mem
= MmapOrDie(sizeof(ThreadContext
), "ThreadContext");
30 return new(mem
) ThreadContext(tid
);
33 static const uptr kMaxThreads
= 1 << 13;
34 static const uptr kThreadQuarantineSize
= 64;
36 void InitializeThreadRegistry() {
37 static ALIGNED(64) char thread_registry_placeholder
[sizeof(ThreadRegistry
)];
38 thread_registry
= new(thread_registry_placeholder
)
39 ThreadRegistry(CreateThreadContext
, kMaxThreads
, kThreadQuarantineSize
);
42 u32
GetCurrentThread() {
43 return current_thread_tid
;
46 void SetCurrentThread(u32 tid
) {
47 current_thread_tid
= tid
;
50 ThreadContext::ThreadContext(int tid
)
51 : ThreadContextBase(tid
),
60 struct OnStartedArgs
{
61 uptr stack_begin
, stack_end
,
62 cache_begin
, cache_end
,
67 void ThreadContext::OnStarted(void *arg
) {
68 OnStartedArgs
*args
= reinterpret_cast<OnStartedArgs
*>(arg
);
69 stack_begin_
= args
->stack_begin
;
70 stack_end_
= args
->stack_end
;
71 tls_begin_
= args
->tls_begin
;
72 tls_end_
= args
->tls_end
;
73 cache_begin_
= args
->cache_begin
;
74 cache_end_
= args
->cache_end
;
78 void ThreadContext::OnFinished() {
79 AllocatorThreadFinish();
83 u32
ThreadCreate(u32 parent_tid
, uptr user_id
, bool detached
) {
84 return thread_registry
->CreateThread(user_id
, detached
, parent_tid
,
88 void ThreadStart(u32 tid
, uptr os_id
) {
92 GetThreadStackAndTls(tid
== 0, &args
.stack_begin
, &stack_size
,
93 &args
.tls_begin
, &tls_size
);
94 args
.stack_end
= args
.stack_begin
+ stack_size
;
95 args
.tls_end
= args
.tls_begin
+ tls_size
;
96 GetAllocatorCacheRange(&args
.cache_begin
, &args
.cache_end
);
97 args
.dtls
= DTLS_Get();
98 thread_registry
->StartThread(tid
, os_id
, &args
);
101 void ThreadFinish() {
102 thread_registry
->FinishThread(GetCurrentThread());
105 ThreadContext
*CurrentThreadContext() {
106 if (!thread_registry
) return nullptr;
107 if (GetCurrentThread() == kInvalidTid
)
109 // No lock needed when getting current thread.
110 return (ThreadContext
*)thread_registry
->GetThreadLocked(GetCurrentThread());
113 static bool FindThreadByUid(ThreadContextBase
*tctx
, void *arg
) {
114 uptr uid
= (uptr
)arg
;
115 if (tctx
->user_id
== uid
&& tctx
->status
!= ThreadStatusInvalid
) {
121 u32
ThreadTid(uptr uid
) {
122 return thread_registry
->FindThread(FindThreadByUid
, (void*)uid
);
125 void ThreadJoin(u32 tid
) {
126 CHECK_NE(tid
, kInvalidTid
);
127 thread_registry
->JoinThread(tid
, /* arg */nullptr);
130 void EnsureMainThreadIDIsCorrect() {
131 if (GetCurrentThread() == 0)
132 CurrentThreadContext()->os_id
= GetTid();
135 ///// Interface to the common LSan module. /////
137 bool GetThreadRangesLocked(uptr os_id
, uptr
*stack_begin
, uptr
*stack_end
,
138 uptr
*tls_begin
, uptr
*tls_end
, uptr
*cache_begin
,
139 uptr
*cache_end
, DTLS
**dtls
) {
140 ThreadContext
*context
= static_cast<ThreadContext
*>(
141 thread_registry
->FindThreadContextByOsIDLocked(os_id
));
142 if (!context
) return false;
143 *stack_begin
= context
->stack_begin();
144 *stack_end
= context
->stack_end();
145 *tls_begin
= context
->tls_begin();
146 *tls_end
= context
->tls_end();
147 *cache_begin
= context
->cache_begin();
148 *cache_end
= context
->cache_end();
149 *dtls
= context
->dtls();
153 void ForEachExtraStackRange(uptr os_id
, RangeIteratorCallback callback
,
157 void LockThreadRegistry() {
158 thread_registry
->Lock();
161 void UnlockThreadRegistry() {
162 thread_registry
->Unlock();
165 } // namespace __lsan