sanitizer_thread_registry.cc revision 5cf2c460e96e593b1c772f1b02d3a217f4837fdc
1//===-- sanitizer_thread_registry.cc --------------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file is shared between sanitizer tools.
11//
12// General thread bookkeeping functionality.
13//===----------------------------------------------------------------------===//
14
15#include "sanitizer_thread_registry.h"
16
17namespace __sanitizer {
18
19ThreadContextBase::ThreadContextBase(u32 tid)
20    : tid(tid), unique_id(0), os_id(0), user_id(0), status(ThreadStatusInvalid),
21      detached(false), reuse_count(0), parent_tid(0), next(0) {
22  name[0] = '\0';
23}
24
25ThreadContextBase::~ThreadContextBase() {
26  // ThreadContextBase should never be deleted.
27  CHECK(0);
28}
29
30void ThreadContextBase::SetName(const char *new_name) {
31  name[0] = '\0';
32  if (new_name) {
33    internal_strncpy(name, new_name, sizeof(name));
34    name[sizeof(name) - 1] = '\0';
35  }
36}
37
38void ThreadContextBase::SetDead() {
39  CHECK(status == ThreadStatusRunning ||
40        status == ThreadStatusFinished);
41  status = ThreadStatusDead;
42  user_id = 0;
43  OnDead();
44}
45
46void ThreadContextBase::SetJoined(void *arg) {
47  // FIXME(dvyukov): print message and continue (it's user error).
48  CHECK_EQ(false, detached);
49  CHECK_EQ(ThreadStatusFinished, status);
50  status = ThreadStatusDead;
51  user_id = 0;
52  OnJoined(arg);
53}
54
55void ThreadContextBase::SetFinished() {
56  if (!detached)
57    status = ThreadStatusFinished;
58  OnFinished();
59}
60
61void ThreadContextBase::SetStarted(uptr _os_id, void *arg) {
62  status = ThreadStatusRunning;
63  os_id = _os_id;
64  OnStarted(arg);
65}
66
67void ThreadContextBase::SetCreated(uptr _user_id, u64 _unique_id,
68                                   bool _detached, u32 _parent_tid, void *arg) {
69  status = ThreadStatusCreated;
70  user_id = _user_id;
71  unique_id = _unique_id;
72  detached = _detached;
73  // Parent tid makes no sense for the main thread.
74  if (tid != 0)
75    parent_tid = _parent_tid;
76  OnCreated(arg);
77}
78
79void ThreadContextBase::Reset() {
80  status = ThreadStatusInvalid;
81  reuse_count++;
82  SetName(0);
83  OnReset();
84}
85
86// ThreadRegistry implementation.
87
88const u32 ThreadRegistry::kUnknownTid = ~0U;
89
90ThreadRegistry::ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
91                               u32 thread_quarantine_size)
92    : context_factory_(factory),
93      max_threads_(max_threads),
94      thread_quarantine_size_(thread_quarantine_size),
95      mtx_(),
96      n_contexts_(0),
97      total_threads_(0),
98      alive_threads_(0),
99      max_alive_threads_(0),
100      running_threads_(0) {
101  threads_ = (ThreadContextBase **)MmapOrDie(max_threads_ * sizeof(threads_[0]),
102                                             "ThreadRegistry");
103  dead_threads_.clear();
104  invalid_threads_.clear();
105}
106
107void ThreadRegistry::GetNumberOfThreads(uptr *total, uptr *running,
108                                        uptr *alive) {
109  BlockingMutexLock l(&mtx_);
110  if (total) *total = n_contexts_;
111  if (running) *running = running_threads_;
112  if (alive) *alive = alive_threads_;
113}
114
115uptr ThreadRegistry::GetMaxAliveThreads() {
116  BlockingMutexLock l(&mtx_);
117  return max_alive_threads_;
118}
119
120u32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid,
121                                 void *arg) {
122  BlockingMutexLock l(&mtx_);
123  u32 tid = kUnknownTid;
124  ThreadContextBase *tctx = QuarantinePop();
125  if (tctx) {
126    tid = tctx->tid;
127  } else if (n_contexts_ < max_threads_) {
128    // Allocate new thread context and tid.
129    tid = n_contexts_++;
130    tctx = context_factory_(tid);
131    threads_[tid] = tctx;
132  } else {
133    Report("%s: Thread limit (%u threads) exceeded. Dying.\n",
134           SanitizerToolName, max_threads_);
135    Die();
136  }
137  CHECK_NE(tctx, 0);
138  CHECK_NE(tid, kUnknownTid);
139  CHECK_LT(tid, max_threads_);
140  CHECK_EQ(tctx->status, ThreadStatusInvalid);
141  alive_threads_++;
142  if (max_alive_threads_ < alive_threads_) {
143    max_alive_threads_++;
144    CHECK_EQ(alive_threads_, max_alive_threads_);
145  }
146  tctx->SetCreated(user_id, total_threads_++, detached,
147                   parent_tid, arg);
148  return tid;
149}
150
151void ThreadRegistry::RunCallbackForEachThreadLocked(ThreadCallback cb,
152                                                    void *arg) {
153  CheckLocked();
154  for (u32 tid = 0; tid < n_contexts_; tid++) {
155    ThreadContextBase *tctx = threads_[tid];
156    if (tctx == 0)
157      continue;
158    cb(tctx, arg);
159  }
160}
161
162u32 ThreadRegistry::FindThread(FindThreadCallback cb, void *arg) {
163  BlockingMutexLock l(&mtx_);
164  for (u32 tid = 0; tid < n_contexts_; tid++) {
165    ThreadContextBase *tctx = threads_[tid];
166    if (tctx != 0 && cb(tctx, arg))
167      return tctx->tid;
168  }
169  return kUnknownTid;
170}
171
172ThreadContextBase *
173ThreadRegistry::FindThreadContextLocked(FindThreadCallback cb, void *arg) {
174  CheckLocked();
175  for (u32 tid = 0; tid < n_contexts_; tid++) {
176    ThreadContextBase *tctx = threads_[tid];
177    if (tctx != 0 && cb(tctx, arg))
178      return tctx;
179  }
180  return 0;
181}
182
183static bool FindThreadContextByOsIdCallback(ThreadContextBase *tctx,
184                                            void *arg) {
185  return (tctx->os_id == (uptr)arg && tctx->status != ThreadStatusInvalid &&
186      tctx->status != ThreadStatusDead);
187}
188
189ThreadContextBase *ThreadRegistry::FindThreadContextByOsIDLocked(uptr os_id) {
190  return FindThreadContextLocked(FindThreadContextByOsIdCallback,
191                                 (void *)os_id);
192}
193
194void ThreadRegistry::SetThreadName(u32 tid, const char *name) {
195  BlockingMutexLock l(&mtx_);
196  CHECK_LT(tid, n_contexts_);
197  ThreadContextBase *tctx = threads_[tid];
198  CHECK_NE(tctx, 0);
199  CHECK_EQ(ThreadStatusRunning, tctx->status);
200  tctx->SetName(name);
201}
202
203void ThreadRegistry::SetThreadNameByUserId(uptr user_id, const char *name) {
204  BlockingMutexLock l(&mtx_);
205  for (u32 tid = 0; tid < n_contexts_; tid++) {
206    ThreadContextBase *tctx = threads_[tid];
207    if (tctx != 0 && tctx->user_id == user_id &&
208        tctx->status != ThreadStatusInvalid) {
209      tctx->SetName(name);
210      return;
211    }
212  }
213}
214
215void ThreadRegistry::DetachThread(u32 tid) {
216  BlockingMutexLock l(&mtx_);
217  CHECK_LT(tid, n_contexts_);
218  ThreadContextBase *tctx = threads_[tid];
219  CHECK_NE(tctx, 0);
220  if (tctx->status == ThreadStatusInvalid) {
221    Report("%s: Detach of non-existent thread\n", SanitizerToolName);
222    return;
223  }
224  if (tctx->status == ThreadStatusFinished) {
225    tctx->SetDead();
226    QuarantinePush(tctx);
227  } else {
228    tctx->detached = true;
229  }
230}
231
232void ThreadRegistry::JoinThread(u32 tid, void *arg) {
233  BlockingMutexLock l(&mtx_);
234  CHECK_LT(tid, n_contexts_);
235  ThreadContextBase *tctx = threads_[tid];
236  CHECK_NE(tctx, 0);
237  if (tctx->status == ThreadStatusInvalid) {
238    Report("%s: Join of non-existent thread\n", SanitizerToolName);
239    return;
240  }
241  tctx->SetJoined(arg);
242  QuarantinePush(tctx);
243}
244
245void ThreadRegistry::FinishThread(u32 tid) {
246  BlockingMutexLock l(&mtx_);
247  CHECK_GT(alive_threads_, 0);
248  alive_threads_--;
249  CHECK_GT(running_threads_, 0);
250  running_threads_--;
251  CHECK_LT(tid, n_contexts_);
252  ThreadContextBase *tctx = threads_[tid];
253  CHECK_NE(tctx, 0);
254  CHECK_EQ(ThreadStatusRunning, tctx->status);
255  tctx->SetFinished();
256  if (tctx->detached) {
257    tctx->SetDead();
258    QuarantinePush(tctx);
259  }
260}
261
262void ThreadRegistry::StartThread(u32 tid, uptr os_id, void *arg) {
263  BlockingMutexLock l(&mtx_);
264  running_threads_++;
265  CHECK_LT(tid, n_contexts_);
266  ThreadContextBase *tctx = threads_[tid];
267  CHECK_NE(tctx, 0);
268  CHECK_EQ(ThreadStatusCreated, tctx->status);
269  tctx->SetStarted(os_id, arg);
270}
271
272void ThreadRegistry::QuarantinePush(ThreadContextBase *tctx) {
273  dead_threads_.push_back(tctx);
274  if (dead_threads_.size() <= thread_quarantine_size_)
275    return;
276  tctx = dead_threads_.front();
277  dead_threads_.pop_front();
278  CHECK_EQ(tctx->status, ThreadStatusDead);
279  tctx->Reset();
280  invalid_threads_.push_back(tctx);
281}
282
283ThreadContextBase *ThreadRegistry::QuarantinePop() {
284  if (invalid_threads_.size() == 0)
285    return 0;
286  ThreadContextBase *tctx = invalid_threads_.front();
287  invalid_threads_.pop_front();
288  return tctx;
289}
290
291}  // namespace __sanitizer
292