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 "lsan_allocator.h"
24 const u32 kInvalidTid
= (u32
) -1;
26 static ThreadRegistry
*thread_registry
;
27 static THREADLOCAL u32 current_thread_tid
= kInvalidTid
;
29 static ThreadContextBase
*CreateThreadContext(u32 tid
) {
30 void *mem
= MmapOrDie(sizeof(ThreadContext
), "ThreadContext");
31 return new(mem
) ThreadContext(tid
);
34 static const uptr kMaxThreads
= 1 << 13;
35 static const uptr kThreadQuarantineSize
= 64;
37 void InitializeThreadRegistry() {
38 static char thread_registry_placeholder
[sizeof(ThreadRegistry
)] ALIGNED(64);
39 thread_registry
= new(thread_registry_placeholder
)
40 ThreadRegistry(CreateThreadContext
, kMaxThreads
, kThreadQuarantineSize
);
43 u32
GetCurrentThread() {
44 return current_thread_tid
;
47 void SetCurrentThread(u32 tid
) {
48 current_thread_tid
= tid
;
51 ThreadContext::ThreadContext(int tid
)
52 : ThreadContextBase(tid
),
60 struct OnStartedArgs
{
61 uptr stack_begin
, stack_end
,
62 cache_begin
, cache_end
,
66 void ThreadContext::OnStarted(void *arg
) {
67 OnStartedArgs
*args
= reinterpret_cast<OnStartedArgs
*>(arg
);
68 stack_begin_
= args
->stack_begin
;
69 stack_end_
= args
->stack_end
;
70 tls_begin_
= args
->tls_begin
;
71 tls_end_
= args
->tls_end
;
72 cache_begin_
= args
->cache_begin
;
73 cache_end_
= args
->cache_end
;
76 void ThreadContext::OnFinished() {
77 AllocatorThreadFinish();
80 u32
ThreadCreate(u32 parent_tid
, uptr user_id
, bool detached
) {
81 return thread_registry
->CreateThread(user_id
, detached
, parent_tid
,
85 void ThreadStart(u32 tid
, uptr os_id
) {
89 GetThreadStackAndTls(tid
== 0, &args
.stack_begin
, &stack_size
,
90 &args
.tls_begin
, &tls_size
);
91 args
.stack_end
= args
.stack_begin
+ stack_size
;
92 args
.tls_end
= args
.tls_begin
+ tls_size
;
93 GetAllocatorCacheRange(&args
.cache_begin
, &args
.cache_end
);
94 thread_registry
->StartThread(tid
, os_id
, &args
);
98 thread_registry
->FinishThread(GetCurrentThread());
101 ThreadContext
*CurrentThreadContext() {
102 if (!thread_registry
) return 0;
103 if (GetCurrentThread() == kInvalidTid
)
105 // No lock needed when getting current thread.
106 return (ThreadContext
*)thread_registry
->GetThreadLocked(GetCurrentThread());
109 static bool FindThreadByUid(ThreadContextBase
*tctx
, void *arg
) {
110 uptr uid
= (uptr
)arg
;
111 if (tctx
->user_id
== uid
&& tctx
->status
!= ThreadStatusInvalid
) {
117 u32
ThreadTid(uptr uid
) {
118 return thread_registry
->FindThread(FindThreadByUid
, (void*)uid
);
121 void ThreadJoin(u32 tid
) {
122 CHECK_NE(tid
, kInvalidTid
);
123 thread_registry
->JoinThread(tid
, /* arg */0);
126 void EnsureMainThreadIDIsCorrect() {
127 if (GetCurrentThread() == 0)
128 CurrentThreadContext()->os_id
= GetTid();
131 ///// Interface to the common LSan module. /////
133 bool GetThreadRangesLocked(uptr os_id
, uptr
*stack_begin
, uptr
*stack_end
,
134 uptr
*tls_begin
, uptr
*tls_end
,
135 uptr
*cache_begin
, uptr
*cache_end
) {
136 ThreadContext
*context
= static_cast<ThreadContext
*>(
137 thread_registry
->FindThreadContextByOsIDLocked(os_id
));
138 if (!context
) return false;
139 *stack_begin
= context
->stack_begin();
140 *stack_end
= context
->stack_end();
141 *tls_begin
= context
->tls_begin();
142 *tls_end
= context
->tls_end();
143 *cache_begin
= context
->cache_begin();
144 *cache_end
= context
->cache_end();
148 void ForEachExtraStackRange(uptr os_id
, RangeIteratorCallback callback
,
152 void LockThreadRegistry() {
153 thread_registry
->Lock();
156 void UnlockThreadRegistry() {
157 thread_registry
->Unlock();
160 } // namespace __lsan