1 //===-- sanitizer_thread_registry.cpp -------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file is shared between sanitizer tools.
11 // General thread bookkeeping functionality.
12 //===----------------------------------------------------------------------===//
14 #include "sanitizer_thread_registry.h"
16 #include "sanitizer_placement_new.h"
18 namespace __sanitizer
{
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) {
25 atomic_store(&thread_destroyed
, 0, memory_order_release
);
28 ThreadContextBase::~ThreadContextBase() {
29 // ThreadContextBase should never be deleted.
33 void ThreadContextBase::SetName(const char *new_name
) {
36 internal_strncpy(name
, new_name
, sizeof(name
));
37 name
[sizeof(name
) - 1] = '\0';
41 void ThreadContextBase::SetDead() {
42 CHECK(status
== ThreadStatusRunning
||
43 status
== ThreadStatusFinished
);
44 status
= ThreadStatusDead
;
49 void ThreadContextBase::SetDestroyed() {
50 atomic_store(&thread_destroyed
, 1, memory_order_release
);
53 bool ThreadContextBase::GetDestroyed() {
54 return !!atomic_load(&thread_destroyed
, memory_order_acquire
);
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
;
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
71 if (!detached
|| status
== ThreadStatusCreated
) status
= ThreadStatusFinished
;
75 void ThreadContextBase::SetStarted(tid_t _os_id
, ThreadType _thread_type
,
77 status
= ThreadStatusRunning
;
79 thread_type
= _thread_type
;
83 void ThreadContextBase::SetCreated(uptr _user_id
, u64 _unique_id
,
84 bool _detached
, u32 _parent_tid
, void *arg
) {
85 status
= ThreadStatusCreated
;
87 unique_id
= _unique_id
;
89 // Parent tid makes no sense for the main thread.
91 parent_tid
= _parent_tid
;
95 void ThreadContextBase::Reset() {
96 status
= ThreadStatusInvalid
;
98 atomic_store(&thread_destroyed
, 0, memory_order_release
);
102 // ThreadRegistry implementation.
104 ThreadRegistry::ThreadRegistry(ThreadContextFactory factory
)
105 : ThreadRegistry(factory
, UINT32_MAX
, UINT32_MAX
, 0) {}
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
),
116 max_alive_threads_(0),
117 running_threads_(0) {
118 dead_threads_
.clear();
119 invalid_threads_
.clear();
122 void ThreadRegistry::GetNumberOfThreads(uptr
*total
, uptr
*running
,
124 ThreadRegistryLock
l(this);
126 *total
= threads_
.size();
127 if (running
) *running
= running_threads_
;
128 if (alive
) *alive
= alive_threads_
;
131 uptr
ThreadRegistry::GetMaxAliveThreads() {
132 ThreadRegistryLock
l(this);
133 return max_alive_threads_
;
136 u32
ThreadRegistry::CreateThread(uptr user_id
, bool detached
, u32 parent_tid
,
138 ThreadRegistryLock
l(this);
139 u32 tid
= kInvalidTid
;
140 ThreadContextBase
*tctx
= QuarantinePop();
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
);
150 Report("%s: Thread limit (%u threads) exceeded. Dying.\n",
151 SanitizerToolName
, max_threads_
);
153 Printf("race: limit on %u simultaneously alive goroutines is exceeded,"
154 " dying\n", max_threads_
);
159 CHECK_NE(tid
, kInvalidTid
);
160 CHECK_LT(tid
, max_threads_
);
161 CHECK_EQ(tctx
->status
, ThreadStatusInvalid
);
163 if (max_alive_threads_
< alive_threads_
) {
164 max_alive_threads_
++;
165 CHECK_EQ(alive_threads_
, max_alive_threads_
);
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
);
173 tctx
->SetCreated(user_id
, total_threads_
++, detached
,
178 void ThreadRegistry::RunCallbackForEachThreadLocked(ThreadCallback cb
,
181 for (u32 tid
= 0; tid
< threads_
.size(); tid
++) {
182 ThreadContextBase
*tctx
= threads_
[tid
];
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
))
200 ThreadRegistry::FindThreadContextLocked(FindThreadCallback cb
, void *arg
) {
202 for (u32 tid
= 0; tid
< threads_
.size(); tid
++) {
203 ThreadContextBase
*tctx
= threads_
[tid
];
204 if (tctx
!= 0 && cb(tctx
, arg
))
210 static bool FindThreadContextByOsIdCallback(ThreadContextBase
*tctx
,
212 return (tctx
->os_id
== (uptr
)arg
&& tctx
->status
!= ThreadStatusInvalid
&&
213 tctx
->status
!= ThreadStatusDead
);
216 ThreadContextBase
*ThreadRegistry::FindThreadContextByOsIDLocked(tid_t os_id
) {
217 return FindThreadContextLocked(FindThreadContextByOsIdCallback
,
221 void ThreadRegistry::SetThreadName(u32 tid
, const char *name
) {
222 ThreadRegistryLock
l(this);
223 ThreadContextBase
*tctx
= threads_
[tid
];
225 CHECK_EQ(SANITIZER_FUCHSIA
? ThreadStatusCreated
: ThreadStatusRunning
,
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
);
236 void ThreadRegistry::DetachThread(u32 tid
, void *arg
) {
237 ThreadRegistryLock
l(this);
238 ThreadContextBase
*tctx
= threads_
[tid
];
240 if (tctx
->status
== ThreadStatusInvalid
) {
241 Report("%s: Detach of non-existent thread\n", SanitizerToolName
);
244 tctx
->OnDetached(arg
);
245 if (tctx
->status
== ThreadStatusFinished
) {
247 live_
.erase(tctx
->user_id
);
249 QuarantinePush(tctx
);
251 tctx
->detached
= true;
255 void ThreadRegistry::JoinThread(u32 tid
, void *arg
) {
256 bool destroyed
= false;
259 ThreadRegistryLock
l(this);
260 ThreadContextBase
*tctx
= threads_
[tid
];
262 if (tctx
->status
== ThreadStatusInvalid
) {
263 Report("%s: Join of non-existent thread\n", SanitizerToolName
);
266 if ((destroyed
= tctx
->GetDestroyed())) {
268 live_
.erase(tctx
->user_id
);
269 tctx
->SetJoined(arg
);
270 QuarantinePush(tctx
);
274 internal_sched_yield();
275 } while (!destroyed
);
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.
283 ThreadStatus
ThreadRegistry::FinishThread(u32 tid
) {
284 ThreadRegistryLock
l(this);
285 CHECK_GT(alive_threads_
, 0);
287 ThreadContextBase
*tctx
= threads_
[tid
];
289 bool dead
= tctx
->detached
;
290 ThreadStatus prev_status
= tctx
->status
;
291 if (tctx
->status
== ThreadStatusRunning
) {
292 CHECK_GT(running_threads_
, 0);
295 // The thread never really existed.
296 CHECK_EQ(tctx
->status
, ThreadStatusCreated
);
302 live_
.erase(tctx
->user_id
);
304 QuarantinePush(tctx
);
306 tctx
->SetDestroyed();
310 void ThreadRegistry::StartThread(u32 tid
, tid_t os_id
, ThreadType thread_type
,
312 ThreadRegistryLock
l(this);
314 ThreadContextBase
*tctx
= threads_
[tid
];
316 CHECK_EQ(ThreadStatusCreated
, tctx
->status
);
317 tctx
->SetStarted(os_id
, thread_type
, arg
);
320 void ThreadRegistry::QuarantinePush(ThreadContextBase
*tctx
) {
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_
)
326 tctx
= dead_threads_
.front();
327 dead_threads_
.pop_front();
328 CHECK_EQ(tctx
->status
, ThreadStatusDead
);
331 if (max_reuse_
> 0 && tctx
->reuse_count
>= max_reuse_
)
333 invalid_threads_
.push_back(tctx
);
336 ThreadContextBase
*ThreadRegistry::QuarantinePop() {
337 if (invalid_threads_
.size() == 0)
339 ThreadContextBase
*tctx
= invalid_threads_
.front();
340 invalid_threads_
.pop_front();
344 u32
ThreadRegistry::ConsumeThreadUserId(uptr user_id
) {
345 ThreadRegistryLock
l(this);
347 auto *t
= live_
.find(user_id
);
351 auto *tctx
= threads_
[tid
];
352 CHECK_EQ(tctx
->user_id
, user_id
);
357 void ThreadRegistry::SetThreadUserId(u32 tid
, uptr user_id
) {
358 ThreadRegistryLock
l(this);
359 ThreadContextBase
*tctx
= threads_
[tid
];
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
);
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
)
378 CHECK(live_
.erase(tctx
->user_id
));
381 return alive_threads_
;
384 } // namespace __sanitizer