1 //===-- sanitizer_thread_registry.cc --------------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file is shared between sanitizer tools.
12 // General thread bookkeeping functionality.
13 //===----------------------------------------------------------------------===//
15 #include "sanitizer_thread_registry.h"
17 namespace __sanitizer
{
19 ThreadContextBase::ThreadContextBase(u32 tid
)
20 : tid(tid
), unique_id(0), reuse_count(), os_id(0), user_id(0),
21 status(ThreadStatusInvalid
),
22 detached(false), parent_tid(0), next(0) {
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::SetJoined(void *arg
) {
48 // FIXME(dvyukov): print message and continue (it's user error).
49 CHECK_EQ(false, detached
);
50 CHECK_EQ(ThreadStatusFinished
, status
);
51 status
= ThreadStatusDead
;
56 void ThreadContextBase::SetFinished() {
58 status
= ThreadStatusFinished
;
62 void ThreadContextBase::SetStarted(uptr _os_id
, void *arg
) {
63 status
= ThreadStatusRunning
;
68 void ThreadContextBase::SetCreated(uptr _user_id
, u64 _unique_id
,
69 bool _detached
, u32 _parent_tid
, void *arg
) {
70 status
= ThreadStatusCreated
;
72 unique_id
= _unique_id
;
74 // Parent tid makes no sense for the main thread.
76 parent_tid
= _parent_tid
;
80 void ThreadContextBase::Reset() {
81 status
= ThreadStatusInvalid
;
86 // ThreadRegistry implementation.
88 const u32
ThreadRegistry::kUnknownTid
= ~0U;
90 ThreadRegistry::ThreadRegistry(ThreadContextFactory factory
, u32 max_threads
,
91 u32 thread_quarantine_size
, u32 max_reuse
)
92 : context_factory_(factory
),
93 max_threads_(max_threads
),
94 thread_quarantine_size_(thread_quarantine_size
),
95 max_reuse_(max_reuse
),
100 max_alive_threads_(0),
101 running_threads_(0) {
102 threads_
= (ThreadContextBase
**)MmapOrDie(max_threads_
* sizeof(threads_
[0]),
104 dead_threads_
.clear();
105 invalid_threads_
.clear();
108 void ThreadRegistry::GetNumberOfThreads(uptr
*total
, uptr
*running
,
110 BlockingMutexLock
l(&mtx_
);
111 if (total
) *total
= n_contexts_
;
112 if (running
) *running
= running_threads_
;
113 if (alive
) *alive
= alive_threads_
;
116 uptr
ThreadRegistry::GetMaxAliveThreads() {
117 BlockingMutexLock
l(&mtx_
);
118 return max_alive_threads_
;
121 u32
ThreadRegistry::CreateThread(uptr user_id
, bool detached
, u32 parent_tid
,
123 BlockingMutexLock
l(&mtx_
);
124 u32 tid
= kUnknownTid
;
125 ThreadContextBase
*tctx
= QuarantinePop();
128 } else if (n_contexts_
< max_threads_
) {
129 // Allocate new thread context and tid.
131 tctx
= context_factory_(tid
);
132 threads_
[tid
] = tctx
;
135 Report("%s: Thread limit (%u threads) exceeded. Dying.\n",
136 SanitizerToolName
, max_threads_
);
138 Printf("race: limit on %u simultaneously alive goroutines is exceeded,"
139 " dying\n", max_threads_
);
144 CHECK_NE(tid
, kUnknownTid
);
145 CHECK_LT(tid
, max_threads_
);
146 CHECK_EQ(tctx
->status
, ThreadStatusInvalid
);
148 if (max_alive_threads_
< alive_threads_
) {
149 max_alive_threads_
++;
150 CHECK_EQ(alive_threads_
, max_alive_threads_
);
152 tctx
->SetCreated(user_id
, total_threads_
++, detached
,
157 void ThreadRegistry::RunCallbackForEachThreadLocked(ThreadCallback cb
,
160 for (u32 tid
= 0; tid
< n_contexts_
; tid
++) {
161 ThreadContextBase
*tctx
= threads_
[tid
];
168 u32
ThreadRegistry::FindThread(FindThreadCallback cb
, void *arg
) {
169 BlockingMutexLock
l(&mtx_
);
170 for (u32 tid
= 0; tid
< n_contexts_
; tid
++) {
171 ThreadContextBase
*tctx
= threads_
[tid
];
172 if (tctx
!= 0 && cb(tctx
, arg
))
179 ThreadRegistry::FindThreadContextLocked(FindThreadCallback cb
, void *arg
) {
181 for (u32 tid
= 0; tid
< n_contexts_
; tid
++) {
182 ThreadContextBase
*tctx
= threads_
[tid
];
183 if (tctx
!= 0 && cb(tctx
, arg
))
189 static bool FindThreadContextByOsIdCallback(ThreadContextBase
*tctx
,
191 return (tctx
->os_id
== (uptr
)arg
&& tctx
->status
!= ThreadStatusInvalid
&&
192 tctx
->status
!= ThreadStatusDead
);
195 ThreadContextBase
*ThreadRegistry::FindThreadContextByOsIDLocked(uptr os_id
) {
196 return FindThreadContextLocked(FindThreadContextByOsIdCallback
,
200 void ThreadRegistry::SetThreadName(u32 tid
, const char *name
) {
201 BlockingMutexLock
l(&mtx_
);
202 CHECK_LT(tid
, n_contexts_
);
203 ThreadContextBase
*tctx
= threads_
[tid
];
205 CHECK_EQ(ThreadStatusRunning
, tctx
->status
);
209 void ThreadRegistry::SetThreadNameByUserId(uptr user_id
, const char *name
) {
210 BlockingMutexLock
l(&mtx_
);
211 for (u32 tid
= 0; tid
< n_contexts_
; tid
++) {
212 ThreadContextBase
*tctx
= threads_
[tid
];
213 if (tctx
!= 0 && tctx
->user_id
== user_id
&&
214 tctx
->status
!= ThreadStatusInvalid
) {
221 void ThreadRegistry::DetachThread(u32 tid
, void *arg
) {
222 BlockingMutexLock
l(&mtx_
);
223 CHECK_LT(tid
, n_contexts_
);
224 ThreadContextBase
*tctx
= threads_
[tid
];
226 if (tctx
->status
== ThreadStatusInvalid
) {
227 Report("%s: Detach of non-existent thread\n", SanitizerToolName
);
230 tctx
->OnDetached(arg
);
231 if (tctx
->status
== ThreadStatusFinished
) {
233 QuarantinePush(tctx
);
235 tctx
->detached
= true;
239 void ThreadRegistry::JoinThread(u32 tid
, void *arg
) {
240 BlockingMutexLock
l(&mtx_
);
241 CHECK_LT(tid
, n_contexts_
);
242 ThreadContextBase
*tctx
= threads_
[tid
];
244 if (tctx
->status
== ThreadStatusInvalid
) {
245 Report("%s: Join of non-existent thread\n", SanitizerToolName
);
248 tctx
->SetJoined(arg
);
249 QuarantinePush(tctx
);
252 void ThreadRegistry::FinishThread(u32 tid
) {
253 BlockingMutexLock
l(&mtx_
);
254 CHECK_GT(alive_threads_
, 0);
256 CHECK_GT(running_threads_
, 0);
258 CHECK_LT(tid
, n_contexts_
);
259 ThreadContextBase
*tctx
= threads_
[tid
];
261 CHECK_EQ(ThreadStatusRunning
, tctx
->status
);
263 if (tctx
->detached
) {
265 QuarantinePush(tctx
);
269 void ThreadRegistry::StartThread(u32 tid
, uptr os_id
, void *arg
) {
270 BlockingMutexLock
l(&mtx_
);
272 CHECK_LT(tid
, n_contexts_
);
273 ThreadContextBase
*tctx
= threads_
[tid
];
275 CHECK_EQ(ThreadStatusCreated
, tctx
->status
);
276 tctx
->SetStarted(os_id
, arg
);
279 void ThreadRegistry::QuarantinePush(ThreadContextBase
*tctx
) {
281 return; // Don't reuse the main thread. It's a special snowflake.
282 dead_threads_
.push_back(tctx
);
283 if (dead_threads_
.size() <= thread_quarantine_size_
)
285 tctx
= dead_threads_
.front();
286 dead_threads_
.pop_front();
287 CHECK_EQ(tctx
->status
, ThreadStatusDead
);
290 if (max_reuse_
> 0 && tctx
->reuse_count
>= max_reuse_
)
292 invalid_threads_
.push_back(tctx
);
295 ThreadContextBase
*ThreadRegistry::QuarantinePop() {
296 if (invalid_threads_
.size() == 0)
298 ThreadContextBase
*tctx
= invalid_threads_
.front();
299 invalid_threads_
.pop_front();
303 } // namespace __sanitizer