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 namespace __sanitizer
{
18 ThreadContextBase::ThreadContextBase(u32 tid
)
19 : tid(tid
), unique_id(0), reuse_count(), os_id(0), user_id(0),
20 status(ThreadStatusInvalid
), detached(false),
21 thread_type(ThreadType::Regular
), parent_tid(0), next(0) {
23 atomic_store(&thread_destroyed
, 0, memory_order_release
);
26 ThreadContextBase::~ThreadContextBase() {
27 // ThreadContextBase should never be deleted.
31 void ThreadContextBase::SetName(const char *new_name
) {
34 internal_strncpy(name
, new_name
, sizeof(name
));
35 name
[sizeof(name
) - 1] = '\0';
39 void ThreadContextBase::SetDead() {
40 CHECK(status
== ThreadStatusRunning
||
41 status
== ThreadStatusFinished
);
42 status
= ThreadStatusDead
;
47 void ThreadContextBase::SetDestroyed() {
48 atomic_store(&thread_destroyed
, 1, memory_order_release
);
51 bool ThreadContextBase::GetDestroyed() {
52 return !!atomic_load(&thread_destroyed
, memory_order_acquire
);
55 void ThreadContextBase::SetJoined(void *arg
) {
56 // FIXME(dvyukov): print message and continue (it's user error).
57 CHECK_EQ(false, detached
);
58 CHECK_EQ(ThreadStatusFinished
, status
);
59 status
= ThreadStatusDead
;
64 void ThreadContextBase::SetFinished() {
65 // ThreadRegistry::FinishThread calls here in ThreadStatusCreated state
66 // for a thread that never actually started. In that case the thread
67 // should go to ThreadStatusFinished regardless of whether it was created
69 if (!detached
|| status
== ThreadStatusCreated
) status
= ThreadStatusFinished
;
73 void ThreadContextBase::SetStarted(tid_t _os_id
, ThreadType _thread_type
,
75 status
= ThreadStatusRunning
;
77 thread_type
= _thread_type
;
81 void ThreadContextBase::SetCreated(uptr _user_id
, u64 _unique_id
,
82 bool _detached
, u32 _parent_tid
, void *arg
) {
83 status
= ThreadStatusCreated
;
85 unique_id
= _unique_id
;
87 // Parent tid makes no sense for the main thread.
89 parent_tid
= _parent_tid
;
93 void ThreadContextBase::Reset() {
94 status
= ThreadStatusInvalid
;
96 atomic_store(&thread_destroyed
, 0, memory_order_release
);
100 // ThreadRegistry implementation.
102 const u32
ThreadRegistry::kUnknownTid
= ~0U;
104 ThreadRegistry::ThreadRegistry(ThreadContextFactory factory
, u32 max_threads
,
105 u32 thread_quarantine_size
, u32 max_reuse
)
106 : context_factory_(factory
),
107 max_threads_(max_threads
),
108 thread_quarantine_size_(thread_quarantine_size
),
109 max_reuse_(max_reuse
),
114 max_alive_threads_(0),
115 running_threads_(0) {
116 threads_
= (ThreadContextBase
**)MmapOrDie(max_threads_
* sizeof(threads_
[0]),
118 dead_threads_
.clear();
119 invalid_threads_
.clear();
122 void ThreadRegistry::GetNumberOfThreads(uptr
*total
, uptr
*running
,
124 BlockingMutexLock
l(&mtx_
);
125 if (total
) *total
= n_contexts_
;
126 if (running
) *running
= running_threads_
;
127 if (alive
) *alive
= alive_threads_
;
130 uptr
ThreadRegistry::GetMaxAliveThreads() {
131 BlockingMutexLock
l(&mtx_
);
132 return max_alive_threads_
;
135 u32
ThreadRegistry::CreateThread(uptr user_id
, bool detached
, u32 parent_tid
,
137 BlockingMutexLock
l(&mtx_
);
138 u32 tid
= kUnknownTid
;
139 ThreadContextBase
*tctx
= QuarantinePop();
142 } else if (n_contexts_
< max_threads_
) {
143 // Allocate new thread context and tid.
145 tctx
= context_factory_(tid
);
146 threads_
[tid
] = tctx
;
149 Report("%s: Thread limit (%u threads) exceeded. Dying.\n",
150 SanitizerToolName
, max_threads_
);
152 Printf("race: limit on %u simultaneously alive goroutines is exceeded,"
153 " dying\n", max_threads_
);
158 CHECK_NE(tid
, kUnknownTid
);
159 CHECK_LT(tid
, max_threads_
);
160 CHECK_EQ(tctx
->status
, ThreadStatusInvalid
);
162 if (max_alive_threads_
< alive_threads_
) {
163 max_alive_threads_
++;
164 CHECK_EQ(alive_threads_
, max_alive_threads_
);
166 tctx
->SetCreated(user_id
, total_threads_
++, detached
,
171 void ThreadRegistry::RunCallbackForEachThreadLocked(ThreadCallback cb
,
174 for (u32 tid
= 0; tid
< n_contexts_
; tid
++) {
175 ThreadContextBase
*tctx
= threads_
[tid
];
182 u32
ThreadRegistry::FindThread(FindThreadCallback cb
, void *arg
) {
183 BlockingMutexLock
l(&mtx_
);
184 for (u32 tid
= 0; tid
< n_contexts_
; tid
++) {
185 ThreadContextBase
*tctx
= threads_
[tid
];
186 if (tctx
!= 0 && cb(tctx
, arg
))
193 ThreadRegistry::FindThreadContextLocked(FindThreadCallback cb
, void *arg
) {
195 for (u32 tid
= 0; tid
< n_contexts_
; tid
++) {
196 ThreadContextBase
*tctx
= threads_
[tid
];
197 if (tctx
!= 0 && cb(tctx
, arg
))
203 static bool FindThreadContextByOsIdCallback(ThreadContextBase
*tctx
,
205 return (tctx
->os_id
== (uptr
)arg
&& tctx
->status
!= ThreadStatusInvalid
&&
206 tctx
->status
!= ThreadStatusDead
);
209 ThreadContextBase
*ThreadRegistry::FindThreadContextByOsIDLocked(tid_t os_id
) {
210 return FindThreadContextLocked(FindThreadContextByOsIdCallback
,
214 void ThreadRegistry::SetThreadName(u32 tid
, const char *name
) {
215 BlockingMutexLock
l(&mtx_
);
216 CHECK_LT(tid
, n_contexts_
);
217 ThreadContextBase
*tctx
= threads_
[tid
];
219 CHECK_EQ(SANITIZER_FUCHSIA
? ThreadStatusCreated
: ThreadStatusRunning
,
224 void ThreadRegistry::SetThreadNameByUserId(uptr user_id
, const char *name
) {
225 BlockingMutexLock
l(&mtx_
);
226 for (u32 tid
= 0; tid
< n_contexts_
; tid
++) {
227 ThreadContextBase
*tctx
= threads_
[tid
];
228 if (tctx
!= 0 && tctx
->user_id
== user_id
&&
229 tctx
->status
!= ThreadStatusInvalid
) {
236 void ThreadRegistry::DetachThread(u32 tid
, void *arg
) {
237 BlockingMutexLock
l(&mtx_
);
238 CHECK_LT(tid
, n_contexts_
);
239 ThreadContextBase
*tctx
= threads_
[tid
];
241 if (tctx
->status
== ThreadStatusInvalid
) {
242 Report("%s: Detach of non-existent thread\n", SanitizerToolName
);
245 tctx
->OnDetached(arg
);
246 if (tctx
->status
== ThreadStatusFinished
) {
248 QuarantinePush(tctx
);
250 tctx
->detached
= true;
254 void ThreadRegistry::JoinThread(u32 tid
, void *arg
) {
255 bool destroyed
= false;
258 BlockingMutexLock
l(&mtx_
);
259 CHECK_LT(tid
, n_contexts_
);
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())) {
267 tctx
->SetJoined(arg
);
268 QuarantinePush(tctx
);
272 internal_sched_yield();
273 } while (!destroyed
);
276 // Normally this is called when the thread is about to exit. If
277 // called in ThreadStatusCreated state, then this thread was never
278 // really started. We just did CreateThread for a prospective new
279 // thread before trying to create it, and then failed to actually
280 // create it, and so never called StartThread.
281 void ThreadRegistry::FinishThread(u32 tid
) {
282 BlockingMutexLock
l(&mtx_
);
283 CHECK_GT(alive_threads_
, 0);
285 CHECK_LT(tid
, n_contexts_
);
286 ThreadContextBase
*tctx
= threads_
[tid
];
288 bool dead
= tctx
->detached
;
289 if (tctx
->status
== ThreadStatusRunning
) {
290 CHECK_GT(running_threads_
, 0);
293 // The thread never really existed.
294 CHECK_EQ(tctx
->status
, ThreadStatusCreated
);
300 QuarantinePush(tctx
);
302 tctx
->SetDestroyed();
305 void ThreadRegistry::StartThread(u32 tid
, tid_t os_id
, ThreadType thread_type
,
307 BlockingMutexLock
l(&mtx_
);
309 CHECK_LT(tid
, n_contexts_
);
310 ThreadContextBase
*tctx
= threads_
[tid
];
312 CHECK_EQ(ThreadStatusCreated
, tctx
->status
);
313 tctx
->SetStarted(os_id
, thread_type
, arg
);
316 void ThreadRegistry::QuarantinePush(ThreadContextBase
*tctx
) {
318 return; // Don't reuse the main thread. It's a special snowflake.
319 dead_threads_
.push_back(tctx
);
320 if (dead_threads_
.size() <= thread_quarantine_size_
)
322 tctx
= dead_threads_
.front();
323 dead_threads_
.pop_front();
324 CHECK_EQ(tctx
->status
, ThreadStatusDead
);
327 if (max_reuse_
> 0 && tctx
->reuse_count
>= max_reuse_
)
329 invalid_threads_
.push_back(tctx
);
332 ThreadContextBase
*ThreadRegistry::QuarantinePop() {
333 if (invalid_threads_
.size() == 0)
335 ThreadContextBase
*tctx
= invalid_threads_
.front();
336 invalid_threads_
.pop_front();
340 void ThreadRegistry::SetThreadUserId(u32 tid
, uptr user_id
) {
341 BlockingMutexLock
l(&mtx_
);
342 CHECK_LT(tid
, n_contexts_
);
343 ThreadContextBase
*tctx
= threads_
[tid
];
345 CHECK_NE(tctx
->status
, ThreadStatusInvalid
);
346 CHECK_NE(tctx
->status
, ThreadStatusDead
);
347 CHECK_EQ(tctx
->user_id
, 0);
348 tctx
->user_id
= user_id
;
351 } // namespace __sanitizer