* stor-layout.c (place_field): Finalize non-constant offset for the
[official-gcc.git] / libsanitizer / sanitizer_common / sanitizer_thread_registry.cc
blob666955f6c9a9178da2b76da82b7ade89cfb49e93
1 //===-- sanitizer_thread_registry.cc --------------------------------------===//
2 //
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // This file is shared between sanitizer tools.
9 //
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) {
20 name[0] = '\0';
23 ThreadContextBase::~ThreadContextBase() {
24 // ThreadContextBase should never be deleted.
25 CHECK(0);
28 void ThreadContextBase::SetName(const char *new_name) {
29 name[0] = '\0';
30 if (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;
40 user_id = 0;
41 OnDead();
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;
49 user_id = 0;
50 OnJoined(arg);
53 void ThreadContextBase::SetFinished() {
54 if (!detached)
55 status = ThreadStatusFinished;
56 OnFinished();
59 void ThreadContextBase::SetStarted(uptr _os_id, void *arg) {
60 status = ThreadStatusRunning;
61 os_id = _os_id;
62 OnStarted(arg);
65 void ThreadContextBase::SetCreated(uptr _user_id, u64 _unique_id,
66 bool _detached, u32 _parent_tid, void *arg) {
67 status = ThreadStatusCreated;
68 user_id = _user_id;
69 unique_id = _unique_id;
70 detached = _detached;
71 // Parent tid makes no sense for the main thread.
72 if (tid != 0)
73 parent_tid = _parent_tid;
74 OnCreated(arg);
77 void ThreadContextBase::Reset() {
78 status = ThreadStatusInvalid;
79 reuse_count++;
80 SetName(0);
81 OnReset();
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),
93 mtx_(),
94 n_contexts_(0),
95 total_threads_(0),
96 alive_threads_(0),
97 max_alive_threads_(0),
98 running_threads_(0) {
99 threads_ = (ThreadContextBase **)MmapOrDie(max_threads_ * sizeof(threads_[0]),
100 "ThreadRegistry");
101 dead_threads_.clear();
102 invalid_threads_.clear();
105 void ThreadRegistry::GetNumberOfThreads(uptr *total, uptr *running,
106 uptr *alive) {
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,
119 void *arg) {
120 BlockingMutexLock l(&mtx_);
121 u32 tid = kUnknownTid;
122 ThreadContextBase *tctx = QuarantinePop();
123 if (tctx) {
124 tid = tctx->tid;
125 } else if (n_contexts_ < max_threads_) {
126 // Allocate new thread context and tid.
127 tid = n_contexts_++;
128 tctx = context_factory_(tid);
129 threads_[tid] = tctx;
130 } else {
131 Report("%s: Thread limit (%u threads) exceeded. Dying.\n",
132 SanitizerToolName, max_threads_);
133 Die();
135 CHECK_NE(tctx, 0);
136 CHECK_NE(tid, kUnknownTid);
137 CHECK_LT(tid, max_threads_);
138 CHECK_EQ(tctx->status, ThreadStatusInvalid);
139 alive_threads_++;
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,
145 parent_tid, arg);
146 return tid;
149 void ThreadRegistry::RunCallbackForEachThreadLocked(ThreadCallback cb,
150 void *arg) {
151 CheckLocked();
152 for (u32 tid = 0; tid < n_contexts_; tid++) {
153 ThreadContextBase *tctx = threads_[tid];
154 if (tctx == 0)
155 continue;
156 cb(tctx, arg);
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))
165 return tctx->tid;
167 return kUnknownTid;
170 ThreadContextBase *
171 ThreadRegistry::FindThreadContextLocked(FindThreadCallback cb, void *arg) {
172 CheckLocked();
173 for (u32 tid = 0; tid < n_contexts_; tid++) {
174 ThreadContextBase *tctx = threads_[tid];
175 if (tctx != 0 && cb(tctx, arg))
176 return tctx;
178 return 0;
181 static bool FindThreadContextByOsIdCallback(ThreadContextBase *tctx,
182 void *arg) {
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,
189 (void *)os_id);
192 void ThreadRegistry::SetThreadName(u32 tid, const char *name) {
193 BlockingMutexLock l(&mtx_);
194 CHECK_LT(tid, n_contexts_);
195 ThreadContextBase *tctx = threads_[tid];
196 CHECK_NE(tctx, 0);
197 CHECK_EQ(ThreadStatusRunning, tctx->status);
198 tctx->SetName(name);
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) {
207 tctx->SetName(name);
208 return;
213 void ThreadRegistry::DetachThread(u32 tid) {
214 BlockingMutexLock l(&mtx_);
215 CHECK_LT(tid, n_contexts_);
216 ThreadContextBase *tctx = threads_[tid];
217 CHECK_NE(tctx, 0);
218 if (tctx->status == ThreadStatusInvalid) {
219 Report("%s: Detach of non-existent thread\n", SanitizerToolName);
220 return;
222 if (tctx->status == ThreadStatusFinished) {
223 tctx->SetDead();
224 QuarantinePush(tctx);
225 } else {
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];
234 CHECK_NE(tctx, 0);
235 if (tctx->status == ThreadStatusInvalid) {
236 Report("%s: Join of non-existent thread\n", SanitizerToolName);
237 return;
239 tctx->SetJoined(arg);
240 QuarantinePush(tctx);
243 void ThreadRegistry::FinishThread(u32 tid) {
244 BlockingMutexLock l(&mtx_);
245 CHECK_GT(alive_threads_, 0);
246 alive_threads_--;
247 CHECK_GT(running_threads_, 0);
248 running_threads_--;
249 CHECK_LT(tid, n_contexts_);
250 ThreadContextBase *tctx = threads_[tid];
251 CHECK_NE(tctx, 0);
252 CHECK_EQ(ThreadStatusRunning, tctx->status);
253 tctx->SetFinished();
254 if (tctx->detached) {
255 tctx->SetDead();
256 QuarantinePush(tctx);
260 void ThreadRegistry::StartThread(u32 tid, uptr os_id, void *arg) {
261 BlockingMutexLock l(&mtx_);
262 running_threads_++;
263 CHECK_LT(tid, n_contexts_);
264 ThreadContextBase *tctx = threads_[tid];
265 CHECK_NE(tctx, 0);
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_)
273 return;
274 tctx = dead_threads_.front();
275 dead_threads_.pop_front();
276 CHECK_EQ(tctx->status, ThreadStatusDead);
277 tctx->Reset();
278 invalid_threads_.push_back(tctx);
281 ThreadContextBase *ThreadRegistry::QuarantinePop() {
282 if (invalid_threads_.size() == 0)
283 return 0;
284 ThreadContextBase *tctx = invalid_threads_.front();
285 invalid_threads_.pop_front();
286 return tctx;
289 } // namespace __sanitizer