1 //===-- sanitizer_thread_registry.cc --------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // This file is shared between sanitizer tools.
10 // General thread bookkeeping functionality.
11 //===----------------------------------------------------------------------===//
13 #include "sanitizer_thread_registry.h"
15 namespace __sanitizer
{
17 ThreadContextBase::ThreadContextBase(u32 tid
)
18 : tid(tid
), unique_id(0), os_id(0), user_id(0), status(ThreadStatusInvalid
),
19 detached(false), reuse_count(0), parent_tid(0), next(0) {
23 ThreadContextBase::~ThreadContextBase() {
24 // ThreadContextBase should never be deleted.
28 void ThreadContextBase::SetName(const char *new_name
) {
31 internal_strncpy(name
, new_name
, sizeof(name
));
32 name
[sizeof(name
) - 1] = '\0';
36 void ThreadContextBase::SetDead() {
37 CHECK(status
== ThreadStatusRunning
||
38 status
== ThreadStatusFinished
);
39 status
= ThreadStatusDead
;
44 void ThreadContextBase::SetJoined(void *arg
) {
45 // FIXME(dvyukov): print message and continue (it's user error).
46 CHECK_EQ(false, detached
);
47 CHECK_EQ(ThreadStatusFinished
, status
);
48 status
= ThreadStatusDead
;
53 void ThreadContextBase::SetFinished() {
55 status
= ThreadStatusFinished
;
59 void ThreadContextBase::SetStarted(uptr _os_id
, void *arg
) {
60 status
= ThreadStatusRunning
;
65 void ThreadContextBase::SetCreated(uptr _user_id
, u64 _unique_id
,
66 bool _detached
, u32 _parent_tid
, void *arg
) {
67 status
= ThreadStatusCreated
;
69 unique_id
= _unique_id
;
71 // Parent tid makes no sense for the main thread.
73 parent_tid
= _parent_tid
;
77 void ThreadContextBase::Reset() {
78 status
= ThreadStatusInvalid
;
84 // ThreadRegistry implementation.
86 const u32
ThreadRegistry::kUnknownTid
= ~0U;
88 ThreadRegistry::ThreadRegistry(ThreadContextFactory factory
, u32 max_threads
,
89 u32 thread_quarantine_size
)
90 : context_factory_(factory
),
91 max_threads_(max_threads
),
92 thread_quarantine_size_(thread_quarantine_size
),
97 max_alive_threads_(0),
99 threads_
= (ThreadContextBase
**)MmapOrDie(max_threads_
* sizeof(threads_
[0]),
101 dead_threads_
.clear();
102 invalid_threads_
.clear();
105 void ThreadRegistry::GetNumberOfThreads(uptr
*total
, uptr
*running
,
107 BlockingMutexLock
l(&mtx_
);
108 if (total
) *total
= n_contexts_
;
109 if (running
) *running
= running_threads_
;
110 if (alive
) *alive
= alive_threads_
;
113 uptr
ThreadRegistry::GetMaxAliveThreads() {
114 BlockingMutexLock
l(&mtx_
);
115 return max_alive_threads_
;
118 u32
ThreadRegistry::CreateThread(uptr user_id
, bool detached
, u32 parent_tid
,
120 BlockingMutexLock
l(&mtx_
);
121 u32 tid
= kUnknownTid
;
122 ThreadContextBase
*tctx
= QuarantinePop();
125 } else if (n_contexts_
< max_threads_
) {
126 // Allocate new thread context and tid.
128 tctx
= context_factory_(tid
);
129 threads_
[tid
] = tctx
;
131 Report("%s: Thread limit (%u threads) exceeded. Dying.\n",
132 SanitizerToolName
, max_threads_
);
136 CHECK_NE(tid
, kUnknownTid
);
137 CHECK_LT(tid
, max_threads_
);
138 CHECK_EQ(tctx
->status
, ThreadStatusInvalid
);
140 if (max_alive_threads_
< alive_threads_
) {
141 max_alive_threads_
++;
142 CHECK_EQ(alive_threads_
, max_alive_threads_
);
144 tctx
->SetCreated(user_id
, total_threads_
++, detached
,
149 void ThreadRegistry::RunCallbackForEachThreadLocked(ThreadCallback cb
,
152 for (u32 tid
= 0; tid
< n_contexts_
; tid
++) {
153 ThreadContextBase
*tctx
= threads_
[tid
];
160 u32
ThreadRegistry::FindThread(FindThreadCallback cb
, void *arg
) {
161 BlockingMutexLock
l(&mtx_
);
162 for (u32 tid
= 0; tid
< n_contexts_
; tid
++) {
163 ThreadContextBase
*tctx
= threads_
[tid
];
164 if (tctx
!= 0 && cb(tctx
, arg
))
171 ThreadRegistry::FindThreadContextLocked(FindThreadCallback cb
, void *arg
) {
173 for (u32 tid
= 0; tid
< n_contexts_
; tid
++) {
174 ThreadContextBase
*tctx
= threads_
[tid
];
175 if (tctx
!= 0 && cb(tctx
, arg
))
181 static bool FindThreadContextByOsIdCallback(ThreadContextBase
*tctx
,
183 return (tctx
->os_id
== (uptr
)arg
&& tctx
->status
!= ThreadStatusInvalid
&&
184 tctx
->status
!= ThreadStatusDead
);
187 ThreadContextBase
*ThreadRegistry::FindThreadContextByOsIDLocked(uptr os_id
) {
188 return FindThreadContextLocked(FindThreadContextByOsIdCallback
,
192 void ThreadRegistry::SetThreadName(u32 tid
, const char *name
) {
193 BlockingMutexLock
l(&mtx_
);
194 CHECK_LT(tid
, n_contexts_
);
195 ThreadContextBase
*tctx
= threads_
[tid
];
197 CHECK_EQ(ThreadStatusRunning
, tctx
->status
);
201 void ThreadRegistry::SetThreadNameByUserId(uptr user_id
, const char *name
) {
202 BlockingMutexLock
l(&mtx_
);
203 for (u32 tid
= 0; tid
< n_contexts_
; tid
++) {
204 ThreadContextBase
*tctx
= threads_
[tid
];
205 if (tctx
!= 0 && tctx
->user_id
== user_id
&&
206 tctx
->status
!= ThreadStatusInvalid
) {
213 void ThreadRegistry::DetachThread(u32 tid
) {
214 BlockingMutexLock
l(&mtx_
);
215 CHECK_LT(tid
, n_contexts_
);
216 ThreadContextBase
*tctx
= threads_
[tid
];
218 if (tctx
->status
== ThreadStatusInvalid
) {
219 Report("%s: Detach of non-existent thread\n", SanitizerToolName
);
222 if (tctx
->status
== ThreadStatusFinished
) {
224 QuarantinePush(tctx
);
226 tctx
->detached
= true;
230 void ThreadRegistry::JoinThread(u32 tid
, void *arg
) {
231 BlockingMutexLock
l(&mtx_
);
232 CHECK_LT(tid
, n_contexts_
);
233 ThreadContextBase
*tctx
= threads_
[tid
];
235 if (tctx
->status
== ThreadStatusInvalid
) {
236 Report("%s: Join of non-existent thread\n", SanitizerToolName
);
239 tctx
->SetJoined(arg
);
240 QuarantinePush(tctx
);
243 void ThreadRegistry::FinishThread(u32 tid
) {
244 BlockingMutexLock
l(&mtx_
);
245 CHECK_GT(alive_threads_
, 0);
247 CHECK_GT(running_threads_
, 0);
249 CHECK_LT(tid
, n_contexts_
);
250 ThreadContextBase
*tctx
= threads_
[tid
];
252 CHECK_EQ(ThreadStatusRunning
, tctx
->status
);
254 if (tctx
->detached
) {
256 QuarantinePush(tctx
);
260 void ThreadRegistry::StartThread(u32 tid
, uptr os_id
, void *arg
) {
261 BlockingMutexLock
l(&mtx_
);
263 CHECK_LT(tid
, n_contexts_
);
264 ThreadContextBase
*tctx
= threads_
[tid
];
266 CHECK_EQ(ThreadStatusCreated
, tctx
->status
);
267 tctx
->SetStarted(os_id
, arg
);
270 void ThreadRegistry::QuarantinePush(ThreadContextBase
*tctx
) {
271 dead_threads_
.push_back(tctx
);
272 if (dead_threads_
.size() <= thread_quarantine_size_
)
274 tctx
= dead_threads_
.front();
275 dead_threads_
.pop_front();
276 CHECK_EQ(tctx
->status
, ThreadStatusDead
);
278 invalid_threads_
.push_back(tctx
);
281 ThreadContextBase
*ThreadRegistry::QuarantinePop() {
282 if (invalid_threads_
.size() == 0)
284 ThreadContextBase
*tctx
= invalid_threads_
.front();
285 invalid_threads_
.pop_front();
289 } // namespace __sanitizer