master
  1//===-- sanitizer_thread_registry.cpp -------------------------------------===//
  2//
  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
  6//
  7//===----------------------------------------------------------------------===//
  8//
  9// This file is shared between sanitizer tools.
 10//
 11// General thread bookkeeping functionality.
 12//===----------------------------------------------------------------------===//
 13
 14#include "sanitizer_thread_registry.h"
 15
 16#include "sanitizer_placement_new.h"
 17
 18namespace __sanitizer {
 19
 20ThreadContextBase::ThreadContextBase(u32 tid)
 21    : tid(tid),
 22      unique_id(0),
 23      reuse_count(),
 24      os_id(0),
 25      user_id(0),
 26      status(ThreadStatusInvalid),
 27      detached(false),
 28      thread_type(ThreadType::Regular),
 29      parent_tid(0),
 30      stack_id(0),
 31      next(0) {
 32  name[0] = '\0';
 33  atomic_store(&thread_destroyed, 0, memory_order_release);
 34}
 35
 36ThreadContextBase::~ThreadContextBase() {
 37  // ThreadContextBase should never be deleted.
 38  CHECK(0);
 39}
 40
 41void ThreadContextBase::SetName(const char *new_name) {
 42  name[0] = '\0';
 43  if (new_name) {
 44    internal_strncpy(name, new_name, sizeof(name));
 45    name[sizeof(name) - 1] = '\0';
 46  }
 47}
 48
 49void ThreadContextBase::SetDead() {
 50  CHECK(status == ThreadStatusRunning || status == ThreadStatusFinished);
 51  status = ThreadStatusDead;
 52  user_id = 0;
 53  OnDead();
 54}
 55
 56void ThreadContextBase::SetDestroyed() {
 57  atomic_store(&thread_destroyed, 1, memory_order_release);
 58}
 59
 60bool ThreadContextBase::GetDestroyed() {
 61  return !!atomic_load(&thread_destroyed, memory_order_acquire);
 62}
 63
 64void ThreadContextBase::SetJoined(void *arg) {
 65  // FIXME(dvyukov): print message and continue (it's user error).
 66  CHECK_EQ(false, detached);
 67  CHECK_EQ(ThreadStatusFinished, status);
 68  status = ThreadStatusDead;
 69  user_id = 0;
 70  OnJoined(arg);
 71}
 72
 73void ThreadContextBase::SetFinished() {
 74  // ThreadRegistry::FinishThread calls here in ThreadStatusCreated state
 75  // for a thread that never actually started.  In that case the thread
 76  // should go to ThreadStatusFinished regardless of whether it was created
 77  // as detached.
 78  if (!detached || status == ThreadStatusCreated)
 79    status = ThreadStatusFinished;
 80  OnFinished();
 81}
 82
 83void ThreadContextBase::SetStarted(tid_t _os_id, ThreadType _thread_type,
 84                                   void *arg) {
 85  status = ThreadStatusRunning;
 86  os_id = _os_id;
 87  thread_type = _thread_type;
 88  OnStarted(arg);
 89}
 90
 91void ThreadContextBase::SetCreated(uptr _user_id, u64 _unique_id,
 92                                   bool _detached, u32 _parent_tid,
 93                                   u32 _stack_tid, void *arg) {
 94  status = ThreadStatusCreated;
 95  user_id = _user_id;
 96  unique_id = _unique_id;
 97  detached = _detached;
 98  // Parent tid makes no sense for the main thread.
 99  if (tid != kMainTid) {
100    parent_tid = _parent_tid;
101    stack_id = _stack_tid;
102  }
103  OnCreated(arg);
104}
105
106void ThreadContextBase::Reset() {
107  status = ThreadStatusInvalid;
108  SetName(0);
109  atomic_store(&thread_destroyed, 0, memory_order_release);
110  OnReset();
111}
112
113// ThreadRegistry implementation.
114
115ThreadRegistry::ThreadRegistry(ThreadContextFactory factory)
116    : ThreadRegistry(factory, UINT32_MAX, UINT32_MAX, 0) {}
117
118ThreadRegistry::ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
119                               u32 thread_quarantine_size, u32 max_reuse)
120    : context_factory_(factory),
121      max_threads_(max_threads),
122      thread_quarantine_size_(thread_quarantine_size),
123      max_reuse_(max_reuse),
124      mtx_(MutexThreadRegistry),
125      total_threads_(0),
126      alive_threads_(0),
127      max_alive_threads_(0),
128      running_threads_(0) {
129  dead_threads_.clear();
130  invalid_threads_.clear();
131}
132
133void ThreadRegistry::GetNumberOfThreads(uptr *total, uptr *running,
134                                        uptr *alive) {
135  ThreadRegistryLock l(this);
136  if (total)
137    *total = threads_.size();
138  if (running)
139    *running = running_threads_;
140  if (alive)
141    *alive = alive_threads_;
142}
143
144uptr ThreadRegistry::GetMaxAliveThreads() {
145  ThreadRegistryLock l(this);
146  return max_alive_threads_;
147}
148
149u32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid,
150                                 u32 stack_tid, void *arg) {
151  ThreadRegistryLock l(this);
152  u32 tid = kInvalidTid;
153  ThreadContextBase *tctx = QuarantinePop();
154  if (tctx) {
155    tid = tctx->tid;
156  } else if (threads_.size() < max_threads_) {
157    // Allocate new thread context and tid.
158    tid = threads_.size();
159    tctx = context_factory_(tid);
160    threads_.push_back(tctx);
161  } else {
162#if !SANITIZER_GO
163    Report("%s: Thread limit (%u threads) exceeded. Dying.\n",
164           SanitizerToolName, max_threads_);
165#else
166    Printf(
167        "race: limit on %u simultaneously alive goroutines is exceeded,"
168        " dying\n",
169        max_threads_);
170#endif
171    Die();
172  }
173  CHECK_NE(tctx, 0);
174  CHECK_NE(tid, kInvalidTid);
175  CHECK_LT(tid, max_threads_);
176  CHECK_EQ(tctx->status, ThreadStatusInvalid);
177  alive_threads_++;
178  if (max_alive_threads_ < alive_threads_) {
179    max_alive_threads_++;
180    CHECK_EQ(alive_threads_, max_alive_threads_);
181  }
182  if (user_id) {
183    // Ensure that user_id is unique. If it's not the case we are screwed.
184    // Ignoring this situation may lead to very hard to debug false
185    // positives later (e.g. if we join a wrong thread).
186    CHECK(live_.try_emplace(user_id, tid).second);
187  }
188  tctx->SetCreated(user_id, total_threads_++, detached, parent_tid, stack_tid,
189                   arg);
190  return tid;
191}
192
193void ThreadRegistry::RunCallbackForEachThreadLocked(ThreadCallback cb,
194                                                    void *arg) {
195  CheckLocked();
196  for (u32 tid = 0; tid < threads_.size(); tid++) {
197    ThreadContextBase *tctx = threads_[tid];
198    if (tctx == 0)
199      continue;
200    cb(tctx, arg);
201  }
202}
203
204u32 ThreadRegistry::FindThread(FindThreadCallback cb, void *arg) {
205  ThreadRegistryLock l(this);
206  for (u32 tid = 0; tid < threads_.size(); tid++) {
207    ThreadContextBase *tctx = threads_[tid];
208    if (tctx != 0 && cb(tctx, arg))
209      return tctx->tid;
210  }
211  return kInvalidTid;
212}
213
214ThreadContextBase *ThreadRegistry::FindThreadContextLocked(
215    FindThreadCallback cb, void *arg) {
216  CheckLocked();
217  for (u32 tid = 0; tid < threads_.size(); tid++) {
218    ThreadContextBase *tctx = threads_[tid];
219    if (tctx != 0 && cb(tctx, arg))
220      return tctx;
221  }
222  return 0;
223}
224
225static bool FindThreadContextByOsIdCallback(ThreadContextBase *tctx,
226                                            void *arg) {
227  return (tctx->os_id == (uptr)arg && tctx->status != ThreadStatusInvalid &&
228          tctx->status != ThreadStatusDead);
229}
230
231ThreadContextBase *ThreadRegistry::FindThreadContextByOsIDLocked(tid_t os_id) {
232  return FindThreadContextLocked(FindThreadContextByOsIdCallback,
233                                 (void *)os_id);
234}
235
236void ThreadRegistry::SetThreadName(u32 tid, const char *name) {
237  ThreadRegistryLock l(this);
238  ThreadContextBase *tctx = threads_[tid];
239  CHECK_NE(tctx, 0);
240  CHECK_EQ(SANITIZER_FUCHSIA ? ThreadStatusCreated : ThreadStatusRunning,
241           tctx->status);
242  tctx->SetName(name);
243}
244
245void ThreadRegistry::SetThreadNameByUserId(uptr user_id, const char *name) {
246  ThreadRegistryLock l(this);
247  if (const auto *tid = live_.find(user_id))
248    threads_[tid->second]->SetName(name);
249}
250
251void ThreadRegistry::DetachThread(u32 tid, void *arg) {
252  ThreadRegistryLock l(this);
253  ThreadContextBase *tctx = threads_[tid];
254  CHECK_NE(tctx, 0);
255  if (tctx->status == ThreadStatusInvalid) {
256    Report("%s: Detach of non-existent thread\n", SanitizerToolName);
257    return;
258  }
259  tctx->OnDetached(arg);
260  if (tctx->status == ThreadStatusFinished) {
261    if (tctx->user_id)
262      live_.erase(tctx->user_id);
263    tctx->SetDead();
264    QuarantinePush(tctx);
265  } else {
266    tctx->detached = true;
267  }
268}
269
270void ThreadRegistry::JoinThread(u32 tid, void *arg) {
271  bool destroyed = false;
272  do {
273    {
274      ThreadRegistryLock l(this);
275      ThreadContextBase *tctx = threads_[tid];
276      CHECK_NE(tctx, 0);
277      if (tctx->status == ThreadStatusInvalid) {
278        Report("%s: Join of non-existent thread\n", SanitizerToolName);
279        return;
280      }
281      if ((destroyed = tctx->GetDestroyed())) {
282        if (tctx->user_id)
283          live_.erase(tctx->user_id);
284        tctx->SetJoined(arg);
285        QuarantinePush(tctx);
286      }
287    }
288    if (!destroyed)
289      internal_sched_yield();
290  } while (!destroyed);
291}
292
293// Normally this is called when the thread is about to exit.  If
294// called in ThreadStatusCreated state, then this thread was never
295// really started.  We just did CreateThread for a prospective new
296// thread before trying to create it, and then failed to actually
297// create it, and so never called StartThread.
298ThreadStatus ThreadRegistry::FinishThread(u32 tid) {
299  ThreadRegistryLock l(this);
300  CHECK_GT(alive_threads_, 0);
301  alive_threads_--;
302  ThreadContextBase *tctx = threads_[tid];
303  CHECK_NE(tctx, 0);
304  bool dead = tctx->detached;
305  ThreadStatus prev_status = tctx->status;
306  if (tctx->status == ThreadStatusRunning) {
307    CHECK_GT(running_threads_, 0);
308    running_threads_--;
309  } else {
310    // The thread never really existed.
311    CHECK_EQ(tctx->status, ThreadStatusCreated);
312    dead = true;
313  }
314  tctx->SetFinished();
315  if (dead) {
316    if (tctx->user_id)
317      live_.erase(tctx->user_id);
318    tctx->SetDead();
319    QuarantinePush(tctx);
320  }
321  tctx->SetDestroyed();
322  return prev_status;
323}
324
325void ThreadRegistry::StartThread(u32 tid, tid_t os_id, ThreadType thread_type,
326                                 void *arg) {
327  ThreadRegistryLock l(this);
328  running_threads_++;
329  ThreadContextBase *tctx = threads_[tid];
330  CHECK_NE(tctx, 0);
331  CHECK_EQ(ThreadStatusCreated, tctx->status);
332  tctx->SetStarted(os_id, thread_type, arg);
333}
334
335void ThreadRegistry::QuarantinePush(ThreadContextBase *tctx) {
336  if (tctx->tid == 0)
337    return;  // Don't reuse the main thread.  It's a special snowflake.
338  dead_threads_.push_back(tctx);
339  if (dead_threads_.size() <= thread_quarantine_size_)
340    return;
341  tctx = dead_threads_.front();
342  dead_threads_.pop_front();
343  CHECK_EQ(tctx->status, ThreadStatusDead);
344  tctx->Reset();
345  tctx->reuse_count++;
346  if (max_reuse_ > 0 && tctx->reuse_count >= max_reuse_)
347    return;
348  invalid_threads_.push_back(tctx);
349}
350
351ThreadContextBase *ThreadRegistry::QuarantinePop() {
352  if (invalid_threads_.size() == 0)
353    return nullptr;
354  ThreadContextBase *tctx = invalid_threads_.front();
355  invalid_threads_.pop_front();
356  return tctx;
357}
358
359u32 ThreadRegistry::ConsumeThreadUserId(uptr user_id) {
360  ThreadRegistryLock l(this);
361  u32 tid;
362  auto *t = live_.find(user_id);
363  CHECK(t);
364  tid = t->second;
365  live_.erase(t);
366  auto *tctx = threads_[tid];
367  CHECK_EQ(tctx->user_id, user_id);
368  tctx->user_id = 0;
369  return tid;
370}
371
372void ThreadRegistry::SetThreadUserId(u32 tid, uptr user_id) {
373  ThreadRegistryLock l(this);
374  ThreadContextBase *tctx = threads_[tid];
375  CHECK_NE(tctx, 0);
376  CHECK_NE(tctx->status, ThreadStatusInvalid);
377  CHECK_NE(tctx->status, ThreadStatusDead);
378  CHECK_EQ(tctx->user_id, 0);
379  tctx->user_id = user_id;
380  CHECK(live_.try_emplace(user_id, tctx->tid).second);
381}
382
383u32 ThreadRegistry::OnFork(u32 tid) {
384  ThreadRegistryLock l(this);
385  // We only purge user_id (pthread_t) of live threads because
386  // they cause CHECK failures if new threads with matching pthread_t
387  // created after fork.
388  // Potentially we could purge more info (ThreadContextBase themselves),
389  // but it's hard to test and easy to introduce new issues by doing this.
390  for (auto *tctx : threads_) {
391    if (tctx->tid == tid || !tctx->user_id)
392      continue;
393    CHECK(live_.erase(tctx->user_id));
394    tctx->user_id = 0;
395  }
396  return alive_threads_;
397}
398
399}  // namespace __sanitizer