]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | //=-- lsan_thread.cc ------------------------------------------------------===// |
2 | // | |
3 | // The LLVM Compiler Infrastructure | |
4 | // | |
5 | // This file is distributed under the University of Illinois Open Source | |
6 | // License. See LICENSE.TXT for details. | |
7 | // | |
8 | //===----------------------------------------------------------------------===// | |
9 | // | |
10 | // This file is a part of LeakSanitizer. | |
11 | // See lsan_thread.h for details. | |
12 | // | |
13 | //===----------------------------------------------------------------------===// | |
14 | ||
15 | #include "lsan_thread.h" | |
16 | ||
17 | #include "sanitizer_common/sanitizer_common.h" | |
18 | #include "sanitizer_common/sanitizer_placement_new.h" | |
19 | #include "sanitizer_common/sanitizer_thread_registry.h" | |
5bcae85e | 20 | #include "sanitizer_common/sanitizer_tls_get_addr.h" |
1a4d82fc JJ |
21 | #include "lsan_allocator.h" |
22 | ||
23 | namespace __lsan { | |
24 | ||
25 | const u32 kInvalidTid = (u32) -1; | |
26 | ||
27 | static ThreadRegistry *thread_registry; | |
28 | static THREADLOCAL u32 current_thread_tid = kInvalidTid; | |
29 | ||
30 | static ThreadContextBase *CreateThreadContext(u32 tid) { | |
31 | void *mem = MmapOrDie(sizeof(ThreadContext), "ThreadContext"); | |
32 | return new(mem) ThreadContext(tid); | |
33 | } | |
34 | ||
35 | static const uptr kMaxThreads = 1 << 13; | |
36 | static const uptr kThreadQuarantineSize = 64; | |
37 | ||
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); | |
42 | } | |
43 | ||
44 | u32 GetCurrentThread() { | |
45 | return current_thread_tid; | |
46 | } | |
47 | ||
48 | void SetCurrentThread(u32 tid) { | |
49 | current_thread_tid = tid; | |
50 | } | |
51 | ||
52 | ThreadContext::ThreadContext(int tid) | |
5bcae85e SL |
53 | : ThreadContextBase(tid), |
54 | stack_begin_(0), | |
55 | stack_end_(0), | |
56 | cache_begin_(0), | |
57 | cache_end_(0), | |
58 | tls_begin_(0), | |
59 | tls_end_(0), | |
60 | dtls_(nullptr) {} | |
1a4d82fc JJ |
61 | |
62 | struct OnStartedArgs { | |
63 | uptr stack_begin, stack_end, | |
64 | cache_begin, cache_end, | |
65 | tls_begin, tls_end; | |
5bcae85e | 66 | DTLS *dtls; |
1a4d82fc JJ |
67 | }; |
68 | ||
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; | |
5bcae85e | 77 | dtls_ = args->dtls; |
1a4d82fc JJ |
78 | } |
79 | ||
80 | void ThreadContext::OnFinished() { | |
81 | AllocatorThreadFinish(); | |
5bcae85e | 82 | DTLS_Destroy(); |
1a4d82fc JJ |
83 | } |
84 | ||
85 | u32 ThreadCreate(u32 parent_tid, uptr user_id, bool detached) { | |
86 | return thread_registry->CreateThread(user_id, detached, parent_tid, | |
92a42be0 | 87 | /* arg */ nullptr); |
1a4d82fc JJ |
88 | } |
89 | ||
90 | void ThreadStart(u32 tid, uptr os_id) { | |
91 | OnStartedArgs args; | |
92 | uptr stack_size = 0; | |
93 | uptr tls_size = 0; | |
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); | |
5bcae85e | 99 | args.dtls = DTLS_Get(); |
1a4d82fc JJ |
100 | thread_registry->StartThread(tid, os_id, &args); |
101 | } | |
102 | ||
103 | void ThreadFinish() { | |
104 | thread_registry->FinishThread(GetCurrentThread()); | |
105 | } | |
106 | ||
107 | ThreadContext *CurrentThreadContext() { | |
92a42be0 | 108 | if (!thread_registry) return nullptr; |
1a4d82fc | 109 | if (GetCurrentThread() == kInvalidTid) |
92a42be0 | 110 | return nullptr; |
1a4d82fc JJ |
111 | // No lock needed when getting current thread. |
112 | return (ThreadContext *)thread_registry->GetThreadLocked(GetCurrentThread()); | |
113 | } | |
114 | ||
115 | static bool FindThreadByUid(ThreadContextBase *tctx, void *arg) { | |
116 | uptr uid = (uptr)arg; | |
117 | if (tctx->user_id == uid && tctx->status != ThreadStatusInvalid) { | |
118 | return true; | |
119 | } | |
120 | return false; | |
121 | } | |
122 | ||
123 | u32 ThreadTid(uptr uid) { | |
124 | return thread_registry->FindThread(FindThreadByUid, (void*)uid); | |
125 | } | |
126 | ||
127 | void ThreadJoin(u32 tid) { | |
128 | CHECK_NE(tid, kInvalidTid); | |
92a42be0 | 129 | thread_registry->JoinThread(tid, /* arg */nullptr); |
1a4d82fc JJ |
130 | } |
131 | ||
132 | void EnsureMainThreadIDIsCorrect() { | |
133 | if (GetCurrentThread() == 0) | |
134 | CurrentThreadContext()->os_id = GetTid(); | |
135 | } | |
136 | ||
137 | ///// Interface to the common LSan module. ///// | |
138 | ||
139 | bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end, | |
5bcae85e SL |
140 | uptr *tls_begin, uptr *tls_end, uptr *cache_begin, |
141 | uptr *cache_end, DTLS **dtls) { | |
1a4d82fc JJ |
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(); | |
5bcae85e | 151 | *dtls = context->dtls(); |
1a4d82fc JJ |
152 | return true; |
153 | } | |
154 | ||
155 | void ForEachExtraStackRange(uptr os_id, RangeIteratorCallback callback, | |
156 | void *arg) { | |
157 | } | |
158 | ||
159 | void LockThreadRegistry() { | |
160 | thread_registry->Lock(); | |
161 | } | |
162 | ||
163 | void UnlockThreadRegistry() { | |
164 | thread_registry->Unlock(); | |
165 | } | |
166 | ||
92a42be0 | 167 | } // namespace __lsan |