1 //===-- sanitizer_thread_registry.cpp -------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file is shared between sanitizer tools.
10 //
11 // General thread bookkeeping functionality.
12 //===----------------------------------------------------------------------===//
13
14 #include "sanitizer_thread_registry.h"
15
16 #include "sanitizer_placement_new.h"
17
18 namespace __sanitizer {
19
ThreadContextBase(u32 tid)20 ThreadContextBase::ThreadContextBase(u32 tid)
21 : tid(tid), unique_id(0), reuse_count(), os_id(0), user_id(0),
22 status(ThreadStatusInvalid), detached(false),
23 thread_type(ThreadType::Regular), parent_tid(0), next(0) {
24 name[0] = '\0';
25 atomic_store(&thread_destroyed, 0, memory_order_release);
26 }
27
~ThreadContextBase()28 ThreadContextBase::~ThreadContextBase() {
29 // ThreadContextBase should never be deleted.
30 CHECK(0);
31 }
32
SetName(const char * new_name)33 void ThreadContextBase::SetName(const char *new_name) {
34 name[0] = '\0';
35 if (new_name) {
36 internal_strncpy(name, new_name, sizeof(name));
37 name[sizeof(name) - 1] = '\0';
38 }
39 }
40
SetDead()41 void ThreadContextBase::SetDead() {
42 CHECK(status == ThreadStatusRunning ||
43 status == ThreadStatusFinished);
44 status = ThreadStatusDead;
45 user_id = 0;
46 OnDead();
47 }
48
SetDestroyed()49 void ThreadContextBase::SetDestroyed() {
50 atomic_store(&thread_destroyed, 1, memory_order_release);
51 }
52
GetDestroyed()53 bool ThreadContextBase::GetDestroyed() {
54 return !!atomic_load(&thread_destroyed, memory_order_acquire);
55 }
56
SetJoined(void * arg)57 void ThreadContextBase::SetJoined(void *arg) {
58 // FIXME(dvyukov): print message and continue (it's user error).
59 CHECK_EQ(false, detached);
60 CHECK_EQ(ThreadStatusFinished, status);
61 status = ThreadStatusDead;
62 user_id = 0;
63 OnJoined(arg);
64 }
65
SetFinished()66 void ThreadContextBase::SetFinished() {
67 // ThreadRegistry::FinishThread calls here in ThreadStatusCreated state
68 // for a thread that never actually started. In that case the thread
69 // should go to ThreadStatusFinished regardless of whether it was created
70 // as detached.
71 if (!detached || status == ThreadStatusCreated) status = ThreadStatusFinished;
72 OnFinished();
73 }
74
SetStarted(tid_t _os_id,ThreadType _thread_type,void * arg)75 void ThreadContextBase::SetStarted(tid_t _os_id, ThreadType _thread_type,
76 void *arg) {
77 status = ThreadStatusRunning;
78 os_id = _os_id;
79 thread_type = _thread_type;
80 OnStarted(arg);
81 }
82
SetCreated(uptr _user_id,u64 _unique_id,bool _detached,u32 _parent_tid,void * arg)83 void ThreadContextBase::SetCreated(uptr _user_id, u64 _unique_id,
84 bool _detached, u32 _parent_tid, void *arg) {
85 status = ThreadStatusCreated;
86 user_id = _user_id;
87 unique_id = _unique_id;
88 detached = _detached;
89 // Parent tid makes no sense for the main thread.
90 if (tid != kMainTid)
91 parent_tid = _parent_tid;
92 OnCreated(arg);
93 }
94
Reset()95 void ThreadContextBase::Reset() {
96 status = ThreadStatusInvalid;
97 SetName(0);
98 atomic_store(&thread_destroyed, 0, memory_order_release);
99 OnReset();
100 }
101
102 // ThreadRegistry implementation.
103
ThreadRegistry(ThreadContextFactory factory)104 ThreadRegistry::ThreadRegistry(ThreadContextFactory factory)
105 : ThreadRegistry(factory, UINT32_MAX, UINT32_MAX, 0) {}
106
ThreadRegistry(ThreadContextFactory factory,u32 max_threads,u32 thread_quarantine_size,u32 max_reuse)107 ThreadRegistry::ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
108 u32 thread_quarantine_size, u32 max_reuse)
109 : context_factory_(factory),
110 max_threads_(max_threads),
111 thread_quarantine_size_(thread_quarantine_size),
112 max_reuse_(max_reuse),
113 mtx_(MutexThreadRegistry),
114 total_threads_(0),
115 alive_threads_(0),
116 max_alive_threads_(0),
117 running_threads_(0) {
118 dead_threads_.clear();
119 invalid_threads_.clear();
120 }
121
GetNumberOfThreads(uptr * total,uptr * running,uptr * alive)122 void ThreadRegistry::GetNumberOfThreads(uptr *total, uptr *running,
123 uptr *alive) {
124 ThreadRegistryLock l(this);
125 if (total)
126 *total = threads_.size();
127 if (running) *running = running_threads_;
128 if (alive) *alive = alive_threads_;
129 }
130
GetMaxAliveThreads()131 uptr ThreadRegistry::GetMaxAliveThreads() {
132 ThreadRegistryLock l(this);
133 return max_alive_threads_;
134 }
135
CreateThread(uptr user_id,bool detached,u32 parent_tid,void * arg)136 u32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid,
137 void *arg) {
138 ThreadRegistryLock l(this);
139 u32 tid = kInvalidTid;
140 ThreadContextBase *tctx = QuarantinePop();
141 if (tctx) {
142 tid = tctx->tid;
143 } else if (threads_.size() < max_threads_) {
144 // Allocate new thread context and tid.
145 tid = threads_.size();
146 tctx = context_factory_(tid);
147 threads_.push_back(tctx);
148 } else {
149 #if !SANITIZER_GO
150 Report("%s: Thread limit (%u threads) exceeded. Dying.\n",
151 SanitizerToolName, max_threads_);
152 #else
153 Printf("race: limit on %u simultaneously alive goroutines is exceeded,"
154 " dying\n", max_threads_);
155 #endif
156 Die();
157 }
158 CHECK_NE(tctx, 0);
159 CHECK_NE(tid, kInvalidTid);
160 CHECK_LT(tid, max_threads_);
161 CHECK_EQ(tctx->status, ThreadStatusInvalid);
162 alive_threads_++;
163 if (max_alive_threads_ < alive_threads_) {
164 max_alive_threads_++;
165 CHECK_EQ(alive_threads_, max_alive_threads_);
166 }
167 if (user_id) {
168 // Ensure that user_id is unique. If it's not the case we are screwed.
169 // Ignoring this situation may lead to very hard to debug false
170 // positives later (e.g. if we join a wrong thread).
171 CHECK(live_.try_emplace(user_id, tid).second);
172 }
173 tctx->SetCreated(user_id, total_threads_++, detached,
174 parent_tid, arg);
175 return tid;
176 }
177
RunCallbackForEachThreadLocked(ThreadCallback cb,void * arg)178 void ThreadRegistry::RunCallbackForEachThreadLocked(ThreadCallback cb,
179 void *arg) {
180 CheckLocked();
181 for (u32 tid = 0; tid < threads_.size(); tid++) {
182 ThreadContextBase *tctx = threads_[tid];
183 if (tctx == 0)
184 continue;
185 cb(tctx, arg);
186 }
187 }
188
FindThread(FindThreadCallback cb,void * arg)189 u32 ThreadRegistry::FindThread(FindThreadCallback cb, void *arg) {
190 ThreadRegistryLock l(this);
191 for (u32 tid = 0; tid < threads_.size(); tid++) {
192 ThreadContextBase *tctx = threads_[tid];
193 if (tctx != 0 && cb(tctx, arg))
194 return tctx->tid;
195 }
196 return kInvalidTid;
197 }
198
199 ThreadContextBase *
FindThreadContextLocked(FindThreadCallback cb,void * arg)200 ThreadRegistry::FindThreadContextLocked(FindThreadCallback cb, void *arg) {
201 CheckLocked();
202 for (u32 tid = 0; tid < threads_.size(); tid++) {
203 ThreadContextBase *tctx = threads_[tid];
204 if (tctx != 0 && cb(tctx, arg))
205 return tctx;
206 }
207 return 0;
208 }
209
FindThreadContextByOsIdCallback(ThreadContextBase * tctx,void * arg)210 static bool FindThreadContextByOsIdCallback(ThreadContextBase *tctx,
211 void *arg) {
212 return (tctx->os_id == (uptr)arg && tctx->status != ThreadStatusInvalid &&
213 tctx->status != ThreadStatusDead);
214 }
215
FindThreadContextByOsIDLocked(tid_t os_id)216 ThreadContextBase *ThreadRegistry::FindThreadContextByOsIDLocked(tid_t os_id) {
217 return FindThreadContextLocked(FindThreadContextByOsIdCallback,
218 (void *)os_id);
219 }
220
SetThreadName(u32 tid,const char * name)221 void ThreadRegistry::SetThreadName(u32 tid, const char *name) {
222 ThreadRegistryLock l(this);
223 ThreadContextBase *tctx = threads_[tid];
224 CHECK_NE(tctx, 0);
225 CHECK_EQ(SANITIZER_FUCHSIA ? ThreadStatusCreated : ThreadStatusRunning,
226 tctx->status);
227 tctx->SetName(name);
228 }
229
SetThreadNameByUserId(uptr user_id,const char * name)230 void ThreadRegistry::SetThreadNameByUserId(uptr user_id, const char *name) {
231 ThreadRegistryLock l(this);
232 if (const auto *tid = live_.find(user_id))
233 threads_[tid->second]->SetName(name);
234 }
235
DetachThread(u32 tid,void * arg)236 void ThreadRegistry::DetachThread(u32 tid, void *arg) {
237 ThreadRegistryLock l(this);
238 ThreadContextBase *tctx = threads_[tid];
239 CHECK_NE(tctx, 0);
240 if (tctx->status == ThreadStatusInvalid) {
241 Report("%s: Detach of non-existent thread\n", SanitizerToolName);
242 return;
243 }
244 tctx->OnDetached(arg);
245 if (tctx->status == ThreadStatusFinished) {
246 if (tctx->user_id)
247 live_.erase(tctx->user_id);
248 tctx->SetDead();
249 QuarantinePush(tctx);
250 } else {
251 tctx->detached = true;
252 }
253 }
254
JoinThread(u32 tid,void * arg)255 void ThreadRegistry::JoinThread(u32 tid, void *arg) {
256 bool destroyed = false;
257 do {
258 {
259 ThreadRegistryLock l(this);
260 ThreadContextBase *tctx = threads_[tid];
261 CHECK_NE(tctx, 0);
262 if (tctx->status == ThreadStatusInvalid) {
263 Report("%s: Join of non-existent thread\n", SanitizerToolName);
264 return;
265 }
266 if ((destroyed = tctx->GetDestroyed())) {
267 if (tctx->user_id)
268 live_.erase(tctx->user_id);
269 tctx->SetJoined(arg);
270 QuarantinePush(tctx);
271 }
272 }
273 if (!destroyed)
274 internal_sched_yield();
275 } while (!destroyed);
276 }
277
278 // Normally this is called when the thread is about to exit. If
279 // called in ThreadStatusCreated state, then this thread was never
280 // really started. We just did CreateThread for a prospective new
281 // thread before trying to create it, and then failed to actually
282 // create it, and so never called StartThread.
FinishThread(u32 tid)283 ThreadStatus ThreadRegistry::FinishThread(u32 tid) {
284 ThreadRegistryLock l(this);
285 CHECK_GT(alive_threads_, 0);
286 alive_threads_--;
287 ThreadContextBase *tctx = threads_[tid];
288 CHECK_NE(tctx, 0);
289 bool dead = tctx->detached;
290 ThreadStatus prev_status = tctx->status;
291 if (tctx->status == ThreadStatusRunning) {
292 CHECK_GT(running_threads_, 0);
293 running_threads_--;
294 } else {
295 // The thread never really existed.
296 CHECK_EQ(tctx->status, ThreadStatusCreated);
297 dead = true;
298 }
299 tctx->SetFinished();
300 if (dead) {
301 if (tctx->user_id)
302 live_.erase(tctx->user_id);
303 tctx->SetDead();
304 QuarantinePush(tctx);
305 }
306 tctx->SetDestroyed();
307 return prev_status;
308 }
309
StartThread(u32 tid,tid_t os_id,ThreadType thread_type,void * arg)310 void ThreadRegistry::StartThread(u32 tid, tid_t os_id, ThreadType thread_type,
311 void *arg) {
312 ThreadRegistryLock l(this);
313 running_threads_++;
314 ThreadContextBase *tctx = threads_[tid];
315 CHECK_NE(tctx, 0);
316 CHECK_EQ(ThreadStatusCreated, tctx->status);
317 tctx->SetStarted(os_id, thread_type, arg);
318 }
319
QuarantinePush(ThreadContextBase * tctx)320 void ThreadRegistry::QuarantinePush(ThreadContextBase *tctx) {
321 if (tctx->tid == 0)
322 return; // Don't reuse the main thread. It's a special snowflake.
323 dead_threads_.push_back(tctx);
324 if (dead_threads_.size() <= thread_quarantine_size_)
325 return;
326 tctx = dead_threads_.front();
327 dead_threads_.pop_front();
328 CHECK_EQ(tctx->status, ThreadStatusDead);
329 tctx->Reset();
330 tctx->reuse_count++;
331 if (max_reuse_ > 0 && tctx->reuse_count >= max_reuse_)
332 return;
333 invalid_threads_.push_back(tctx);
334 }
335
QuarantinePop()336 ThreadContextBase *ThreadRegistry::QuarantinePop() {
337 if (invalid_threads_.size() == 0)
338 return nullptr;
339 ThreadContextBase *tctx = invalid_threads_.front();
340 invalid_threads_.pop_front();
341 return tctx;
342 }
343
ConsumeThreadUserId(uptr user_id)344 u32 ThreadRegistry::ConsumeThreadUserId(uptr user_id) {
345 ThreadRegistryLock l(this);
346 u32 tid;
347 auto *t = live_.find(user_id);
348 CHECK(t);
349 tid = t->second;
350 live_.erase(t);
351 auto *tctx = threads_[tid];
352 CHECK_EQ(tctx->user_id, user_id);
353 tctx->user_id = 0;
354 return tid;
355 }
356
SetThreadUserId(u32 tid,uptr user_id)357 void ThreadRegistry::SetThreadUserId(u32 tid, uptr user_id) {
358 ThreadRegistryLock l(this);
359 ThreadContextBase *tctx = threads_[tid];
360 CHECK_NE(tctx, 0);
361 CHECK_NE(tctx->status, ThreadStatusInvalid);
362 CHECK_NE(tctx->status, ThreadStatusDead);
363 CHECK_EQ(tctx->user_id, 0);
364 tctx->user_id = user_id;
365 CHECK(live_.try_emplace(user_id, tctx->tid).second);
366 }
367
OnFork(u32 tid)368 u32 ThreadRegistry::OnFork(u32 tid) {
369 ThreadRegistryLock l(this);
370 // We only purge user_id (pthread_t) of live threads because
371 // they cause CHECK failures if new threads with matching pthread_t
372 // created after fork.
373 // Potentially we could purge more info (ThreadContextBase themselves),
374 // but it's hard to test and easy to introduce new issues by doing this.
375 for (auto *tctx : threads_) {
376 if (tctx->tid == tid || !tctx->user_id)
377 continue;
378 CHECK(live_.erase(tctx->user_id));
379 tctx->user_id = 0;
380 }
381 return alive_threads_;
382 }
383
384 } // namespace __sanitizer
385