sanitizer_thread_registry.cc revision e174cd1ee373c3b77f3ce8e7fc62f70d0668d03d
16d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov//===-- sanitizer_thread_registry.cc --------------------------------------===//
26d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov//
36d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov//                     The LLVM Compiler Infrastructure
46d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov//
56d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov// This file is distributed under the University of Illinois Open Source
66d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov// License. See LICENSE.TXT for details.
76d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov//
86d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov//===----------------------------------------------------------------------===//
96d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov//
106d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov// This file is shared between sanitizer tools.
116d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov//
126d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov// General thread bookkeeping functionality.
136d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov//===----------------------------------------------------------------------===//
146d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
156d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov#include "sanitizer_thread_registry.h"
166d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
176d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovnamespace __sanitizer {
186d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
196d429cda69b7ccc007ee368a73a6040c6b125afbAlexey SamsonovThreadContextBase::ThreadContextBase(u32 tid)
206d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    : tid(tid), unique_id(0), os_id(0), user_id(0), status(ThreadStatusInvalid),
216d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov      detached(false), reuse_count(0), parent_tid(0), next(0) {
226d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  name[0] = '\0';
236d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
246d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
256af642eaf764434ac6f28f242e7f081156bce9e3Dmitry VyukovThreadContextBase::~ThreadContextBase() {
26e374e4ece521692173aad355420d03e1b2cd819aAlexey Samsonov  // ThreadContextBase should never be deleted.
276af642eaf764434ac6f28f242e7f081156bce9e3Dmitry Vyukov  CHECK(0);
286af642eaf764434ac6f28f242e7f081156bce9e3Dmitry Vyukov}
29c7bc60cd4bfe21868aacd8a87b13590b314ed330Eric Christopher
306d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovvoid ThreadContextBase::SetName(const char *new_name) {
316d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  name[0] = '\0';
326d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  if (new_name) {
336d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    internal_strncpy(name, new_name, sizeof(name));
346d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    name[sizeof(name) - 1] = '\0';
356d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
366d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
376d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
386d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovvoid ThreadContextBase::SetDead() {
396d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK(status == ThreadStatusRunning ||
406d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov        status == ThreadStatusFinished);
416d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  status = ThreadStatusDead;
426d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  user_id = 0;
436d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  OnDead();
446d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
456d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
466d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovvoid ThreadContextBase::SetJoined(void *arg) {
476d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  // FIXME(dvyukov): print message and continue (it's user error).
486d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_EQ(false, detached);
496d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_EQ(ThreadStatusFinished, status);
506d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  status = ThreadStatusDead;
516d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  user_id = 0;
526d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  OnJoined(arg);
536d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
546d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
556d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovvoid ThreadContextBase::SetFinished() {
566d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  if (!detached)
576d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    status = ThreadStatusFinished;
586d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  OnFinished();
596d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
606d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
616d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovvoid ThreadContextBase::SetStarted(uptr _os_id, void *arg) {
626d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  status = ThreadStatusRunning;
636d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  os_id = _os_id;
646d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  OnStarted(arg);
656d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
666d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
676d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovvoid ThreadContextBase::SetCreated(uptr _user_id, u64 _unique_id,
686d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov                                   bool _detached, u32 _parent_tid, void *arg) {
696d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  status = ThreadStatusCreated;
706d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  user_id = _user_id;
716d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  unique_id = _unique_id;
726d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  detached = _detached;
736d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  // Parent tid makes no sense for the main thread.
746d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  if (tid != 0)
756d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    parent_tid = _parent_tid;
766d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  OnCreated(arg);
776d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
786d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
79ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukovvoid ThreadContextBase::Reset() {
806d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  status = ThreadStatusInvalid;
816d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  reuse_count++;
826d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  SetName(0);
83ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  OnReset();
846d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
856d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
866d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov// ThreadRegistry implementation.
876d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
88e174cd1ee373c3b77f3ce8e7fc62f70d0668d03dTimur Iskhodzhanovconst u32 ThreadRegistry::kUnknownTid = ~0U;
89827d4ef8b76760ef8c58612d916b8f53081bf368Alexey Samsonov
906d429cda69b7ccc007ee368a73a6040c6b125afbAlexey SamsonovThreadRegistry::ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
916d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov                               u32 thread_quarantine_size)
926d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    : context_factory_(factory),
936d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov      max_threads_(max_threads),
946d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov      thread_quarantine_size_(thread_quarantine_size),
956d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov      mtx_(),
966d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov      n_contexts_(0),
976d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov      total_threads_(0),
986d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov      alive_threads_(0),
996d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov      max_alive_threads_(0),
1006d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov      running_threads_(0) {
1016d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  threads_ = (ThreadContextBase **)MmapOrDie(max_threads_ * sizeof(threads_[0]),
1026d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov                                             "ThreadRegistry");
1036d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  dead_threads_.clear();
104ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  invalid_threads_.clear();
1056d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
1066d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
1076d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovvoid ThreadRegistry::GetNumberOfThreads(uptr *total, uptr *running,
1086d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov                                        uptr *alive) {
1096d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  BlockingMutexLock l(&mtx_);
1106d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  if (total) *total = n_contexts_;
1116d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  if (running) *running = running_threads_;
1126d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  if (alive) *alive = alive_threads_;
1136d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
1146d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
1156d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovuptr ThreadRegistry::GetMaxAliveThreads() {
1166d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  BlockingMutexLock l(&mtx_);
1176d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  return max_alive_threads_;
1186d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
1196d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
1206d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovu32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid,
1216d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov                                 void *arg) {
1226d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  BlockingMutexLock l(&mtx_);
1236d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  u32 tid = kUnknownTid;
124ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  ThreadContextBase *tctx = QuarantinePop();
125ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  if (tctx) {
1266d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    tid = tctx->tid;
127ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  } else if (n_contexts_ < max_threads_) {
1286d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    // Allocate new thread context and tid.
1296d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    tid = n_contexts_++;
1306d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    tctx = context_factory_(tid);
1316d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    threads_[tid] = tctx;
132ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  } else {
133ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov    Report("%s: Thread limit (%u threads) exceeded. Dying.\n",
134ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov           SanitizerToolName, max_threads_);
135ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov    Die();
1366d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
1376d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_NE(tctx, 0);
1386d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_NE(tid, kUnknownTid);
1396d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_LT(tid, max_threads_);
1406d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_EQ(tctx->status, ThreadStatusInvalid);
1416d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  alive_threads_++;
1426d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  if (max_alive_threads_ < alive_threads_) {
1436d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    max_alive_threads_++;
1446d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    CHECK_EQ(alive_threads_, max_alive_threads_);
1456d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
1466d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  tctx->SetCreated(user_id, total_threads_++, detached,
1476d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov                   parent_tid, arg);
1486d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  return tid;
1496d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
1506d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
1516d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovvoid ThreadRegistry::RunCallbackForEachThreadLocked(ThreadCallback cb,
1526d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov                                                    void *arg) {
1536d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CheckLocked();
1546d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  for (u32 tid = 0; tid < n_contexts_; tid++) {
1556d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    ThreadContextBase *tctx = threads_[tid];
1566d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    if (tctx == 0)
1576d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov      continue;
1586d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    cb(tctx, arg);
1596d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
1606d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
1616d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
1626d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovu32 ThreadRegistry::FindThread(FindThreadCallback cb, void *arg) {
1636d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  BlockingMutexLock l(&mtx_);
1646d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  for (u32 tid = 0; tid < n_contexts_; tid++) {
1656d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    ThreadContextBase *tctx = threads_[tid];
1666d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    if (tctx != 0 && cb(tctx, arg))
1676d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov      return tctx->tid;
1686d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
1696d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  return kUnknownTid;
1706d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
1716d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
1726d429cda69b7ccc007ee368a73a6040c6b125afbAlexey SamsonovThreadContextBase *
1736d429cda69b7ccc007ee368a73a6040c6b125afbAlexey SamsonovThreadRegistry::FindThreadContextLocked(FindThreadCallback cb, void *arg) {
1746d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CheckLocked();
1756d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  for (u32 tid = 0; tid < n_contexts_; tid++) {
1766d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    ThreadContextBase *tctx = threads_[tid];
1776d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    if (tctx != 0 && cb(tctx, arg))
1786d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov      return tctx;
1796d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
1806d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  return 0;
1816d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
1826d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
18398d3b40ec5cf06e46397492c21acc9d18e8c54abSergey Matveevstatic bool FindThreadContextByOsIdCallback(ThreadContextBase *tctx,
18498d3b40ec5cf06e46397492c21acc9d18e8c54abSergey Matveev                                            void *arg) {
18598d3b40ec5cf06e46397492c21acc9d18e8c54abSergey Matveev  return (tctx->os_id == (uptr)arg && tctx->status != ThreadStatusInvalid &&
18698d3b40ec5cf06e46397492c21acc9d18e8c54abSergey Matveev      tctx->status != ThreadStatusDead);
18798d3b40ec5cf06e46397492c21acc9d18e8c54abSergey Matveev}
18898d3b40ec5cf06e46397492c21acc9d18e8c54abSergey Matveev
18998d3b40ec5cf06e46397492c21acc9d18e8c54abSergey MatveevThreadContextBase *ThreadRegistry::FindThreadContextByOsIDLocked(uptr os_id) {
19098d3b40ec5cf06e46397492c21acc9d18e8c54abSergey Matveev  return FindThreadContextLocked(FindThreadContextByOsIdCallback,
19198d3b40ec5cf06e46397492c21acc9d18e8c54abSergey Matveev                                 (void *)os_id);
19298d3b40ec5cf06e46397492c21acc9d18e8c54abSergey Matveev}
19398d3b40ec5cf06e46397492c21acc9d18e8c54abSergey Matveev
1946d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovvoid ThreadRegistry::SetThreadName(u32 tid, const char *name) {
1956d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  BlockingMutexLock l(&mtx_);
1966d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_LT(tid, n_contexts_);
1976d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  ThreadContextBase *tctx = threads_[tid];
1986d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_NE(tctx, 0);
1996d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_EQ(ThreadStatusRunning, tctx->status);
2006d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  tctx->SetName(name);
2016d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
2026d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
2036d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovvoid ThreadRegistry::DetachThread(u32 tid) {
2046d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  BlockingMutexLock l(&mtx_);
2056d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_LT(tid, n_contexts_);
2066d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  ThreadContextBase *tctx = threads_[tid];
2076d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_NE(tctx, 0);
2086d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  if (tctx->status == ThreadStatusInvalid) {
2096d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    Report("%s: Detach of non-existent thread\n", SanitizerToolName);
2106d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    return;
2116d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
2126d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  if (tctx->status == ThreadStatusFinished) {
2136d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    tctx->SetDead();
214ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov    QuarantinePush(tctx);
2156d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  } else {
2166d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    tctx->detached = true;
2176d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
2186d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
2196d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
2206d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovvoid ThreadRegistry::JoinThread(u32 tid, void *arg) {
2216d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  BlockingMutexLock l(&mtx_);
2226d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_LT(tid, n_contexts_);
2236d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  ThreadContextBase *tctx = threads_[tid];
2246d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_NE(tctx, 0);
2256d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  if (tctx->status == ThreadStatusInvalid) {
2266d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    Report("%s: Join of non-existent thread\n", SanitizerToolName);
2276d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    return;
2286d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
2296d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  tctx->SetJoined(arg);
230ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  QuarantinePush(tctx);
2316d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
2326d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
2336d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovvoid ThreadRegistry::FinishThread(u32 tid) {
2346d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  BlockingMutexLock l(&mtx_);
2356d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_GT(alive_threads_, 0);
2366d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  alive_threads_--;
2376d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_GT(running_threads_, 0);
2386d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  running_threads_--;
2396d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_LT(tid, n_contexts_);
2406d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  ThreadContextBase *tctx = threads_[tid];
2416d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_NE(tctx, 0);
2426d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_EQ(ThreadStatusRunning, tctx->status);
2436d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  tctx->SetFinished();
2446d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  if (tctx->detached) {
2456d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    tctx->SetDead();
246ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov    QuarantinePush(tctx);
2476d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
2486d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
2496d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
2506d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovvoid ThreadRegistry::StartThread(u32 tid, uptr os_id, void *arg) {
2516d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  BlockingMutexLock l(&mtx_);
2526d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  running_threads_++;
2536d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_LT(tid, n_contexts_);
2546d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  ThreadContextBase *tctx = threads_[tid];
2556d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_NE(tctx, 0);
2566d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_EQ(ThreadStatusCreated, tctx->status);
2576d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  tctx->SetStarted(os_id, arg);
2586d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
2596d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
260ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukovvoid ThreadRegistry::QuarantinePush(ThreadContextBase *tctx) {
261ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  dead_threads_.push_back(tctx);
262ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  if (dead_threads_.size() <= thread_quarantine_size_)
263ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov    return;
264ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  tctx = dead_threads_.front();
265ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  dead_threads_.pop_front();
266ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  CHECK_EQ(tctx->status, ThreadStatusDead);
267ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  tctx->Reset();
268ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  invalid_threads_.push_back(tctx);
269ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov}
270ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov
271ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry VyukovThreadContextBase *ThreadRegistry::QuarantinePop() {
272ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  if (invalid_threads_.size() == 0)
273ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov    return 0;
274ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  ThreadContextBase *tctx = invalid_threads_.front();
275ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  invalid_threads_.pop_front();
276ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  return tctx;
277ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov}
278ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov
2796d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}  // namespace __sanitizer
280