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"
20 #include "lsan_common.h"
24 static ThreadRegistry
*thread_registry
;
26 static ThreadContextBase
*CreateThreadContext(u32 tid
) {
27 void *mem
= MmapOrDie(sizeof(ThreadContext
), "ThreadContext");
28 return new(mem
) ThreadContext(tid
);
31 static const uptr kMaxThreads
= 1 << 13;
32 static const uptr kThreadQuarantineSize
= 64;
34 void InitializeThreadRegistry() {
35 static ALIGNED(64) char thread_registry_placeholder
[sizeof(ThreadRegistry
)];
36 thread_registry
= new(thread_registry_placeholder
)
37 ThreadRegistry(CreateThreadContext
, kMaxThreads
, kThreadQuarantineSize
);
40 ThreadContext::ThreadContext(int tid
)
41 : ThreadContextBase(tid
),
50 struct OnStartedArgs
{
51 uptr stack_begin
, stack_end
,
52 cache_begin
, cache_end
,
57 void ThreadContext::OnStarted(void *arg
) {
58 OnStartedArgs
*args
= reinterpret_cast<OnStartedArgs
*>(arg
);
59 stack_begin_
= args
->stack_begin
;
60 stack_end_
= args
->stack_end
;
61 tls_begin_
= args
->tls_begin
;
62 tls_end_
= args
->tls_end
;
63 cache_begin_
= args
->cache_begin
;
64 cache_end_
= args
->cache_end
;
68 void ThreadContext::OnFinished() {
69 AllocatorThreadFinish();
73 u32
ThreadCreate(u32 parent_tid
, uptr user_id
, bool detached
) {
74 return thread_registry
->CreateThread(user_id
, detached
, parent_tid
,
78 void ThreadStart(u32 tid
, tid_t os_id
, bool workerthread
) {
82 GetThreadStackAndTls(tid
== 0, &args
.stack_begin
, &stack_size
,
83 &args
.tls_begin
, &tls_size
);
84 args
.stack_end
= args
.stack_begin
+ stack_size
;
85 args
.tls_end
= args
.tls_begin
+ tls_size
;
86 GetAllocatorCacheRange(&args
.cache_begin
, &args
.cache_end
);
87 args
.dtls
= DTLS_Get();
88 thread_registry
->StartThread(tid
, os_id
, workerthread
, &args
);
92 thread_registry
->FinishThread(GetCurrentThread());
93 SetCurrentThread(kInvalidTid
);
96 ThreadContext
*CurrentThreadContext() {
97 if (!thread_registry
) return nullptr;
98 if (GetCurrentThread() == kInvalidTid
)
100 // No lock needed when getting current thread.
101 return (ThreadContext
*)thread_registry
->GetThreadLocked(GetCurrentThread());
104 static bool FindThreadByUid(ThreadContextBase
*tctx
, void *arg
) {
105 uptr uid
= (uptr
)arg
;
106 if (tctx
->user_id
== uid
&& tctx
->status
!= ThreadStatusInvalid
) {
112 u32
ThreadTid(uptr uid
) {
113 return thread_registry
->FindThread(FindThreadByUid
, (void*)uid
);
116 void ThreadJoin(u32 tid
) {
117 CHECK_NE(tid
, kInvalidTid
);
118 thread_registry
->JoinThread(tid
, /* arg */nullptr);
121 void EnsureMainThreadIDIsCorrect() {
122 if (GetCurrentThread() == 0)
123 CurrentThreadContext()->os_id
= GetTid();
126 ///// Interface to the common LSan module. /////
128 bool GetThreadRangesLocked(tid_t os_id
, uptr
*stack_begin
, uptr
*stack_end
,
129 uptr
*tls_begin
, uptr
*tls_end
, uptr
*cache_begin
,
130 uptr
*cache_end
, DTLS
**dtls
) {
131 ThreadContext
*context
= static_cast<ThreadContext
*>(
132 thread_registry
->FindThreadContextByOsIDLocked(os_id
));
133 if (!context
) return false;
134 *stack_begin
= context
->stack_begin();
135 *stack_end
= context
->stack_end();
136 *tls_begin
= context
->tls_begin();
137 *tls_end
= context
->tls_end();
138 *cache_begin
= context
->cache_begin();
139 *cache_end
= context
->cache_end();
140 *dtls
= context
->dtls();
144 void ForEachExtraStackRange(tid_t os_id
, RangeIteratorCallback callback
,
148 void LockThreadRegistry() {
149 thread_registry
->Lock();
152 void UnlockThreadRegistry() {
153 thread_registry
->Unlock();
156 } // namespace __lsan