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)
202d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    : tid(tid), unique_id(0), reuse_count(), os_id(0), user_id(0),
212d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      status(ThreadStatusInvalid),
222d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      detached(false), parent_tid(0), next(0) {
236d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  name[0] = '\0';
246d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
256d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
266af642eaf764434ac6f28f242e7f081156bce9e3Dmitry VyukovThreadContextBase::~ThreadContextBase() {
27e374e4ece521692173aad355420d03e1b2cd819aAlexey Samsonov  // ThreadContextBase should never be deleted.
286af642eaf764434ac6f28f242e7f081156bce9e3Dmitry Vyukov  CHECK(0);
296af642eaf764434ac6f28f242e7f081156bce9e3Dmitry Vyukov}
30c7bc60cd4bfe21868aacd8a87b13590b314ed330Eric Christopher
316d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovvoid ThreadContextBase::SetName(const char *new_name) {
326d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  name[0] = '\0';
336d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  if (new_name) {
346d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    internal_strncpy(name, new_name, sizeof(name));
356d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    name[sizeof(name) - 1] = '\0';
366d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
376d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
386d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
396d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovvoid ThreadContextBase::SetDead() {
406d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK(status == ThreadStatusRunning ||
416d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov        status == ThreadStatusFinished);
426d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  status = ThreadStatusDead;
436d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  user_id = 0;
446d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  OnDead();
456d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
466d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
476d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovvoid ThreadContextBase::SetJoined(void *arg) {
486d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  // FIXME(dvyukov): print message and continue (it's user error).
496d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_EQ(false, detached);
506d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_EQ(ThreadStatusFinished, status);
516d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  status = ThreadStatusDead;
526d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  user_id = 0;
536d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  OnJoined(arg);
546d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
556d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
566d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovvoid ThreadContextBase::SetFinished() {
576d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  if (!detached)
586d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    status = ThreadStatusFinished;
596d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  OnFinished();
606d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
616d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
626d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovvoid ThreadContextBase::SetStarted(uptr _os_id, void *arg) {
636d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  status = ThreadStatusRunning;
646d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  os_id = _os_id;
656d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  OnStarted(arg);
666d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
676d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
686d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovvoid ThreadContextBase::SetCreated(uptr _user_id, u64 _unique_id,
696d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov                                   bool _detached, u32 _parent_tid, void *arg) {
706d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  status = ThreadStatusCreated;
716d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  user_id = _user_id;
726d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  unique_id = _unique_id;
736d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  detached = _detached;
746d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  // Parent tid makes no sense for the main thread.
756d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  if (tid != 0)
766d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    parent_tid = _parent_tid;
776d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  OnCreated(arg);
786d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
796d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
80ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukovvoid ThreadContextBase::Reset() {
816d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  status = ThreadStatusInvalid;
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,
912d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines                               u32 thread_quarantine_size, u32 max_reuse)
926d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    : context_factory_(factory),
936d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov      max_threads_(max_threads),
946d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov      thread_quarantine_size_(thread_quarantine_size),
952d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      max_reuse_(max_reuse),
966d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov      mtx_(),
976d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov      n_contexts_(0),
986d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov      total_threads_(0),
996d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov      alive_threads_(0),
1006d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov      max_alive_threads_(0),
1016d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov      running_threads_(0) {
1026d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  threads_ = (ThreadContextBase **)MmapOrDie(max_threads_ * sizeof(threads_[0]),
1036d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov                                             "ThreadRegistry");
1046d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  dead_threads_.clear();
105ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  invalid_threads_.clear();
1066d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
1076d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
1086d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovvoid ThreadRegistry::GetNumberOfThreads(uptr *total, uptr *running,
1096d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov                                        uptr *alive) {
1106d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  BlockingMutexLock l(&mtx_);
1116d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  if (total) *total = n_contexts_;
1126d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  if (running) *running = running_threads_;
1136d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  if (alive) *alive = alive_threads_;
1146d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
1156d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
1166d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovuptr ThreadRegistry::GetMaxAliveThreads() {
1176d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  BlockingMutexLock l(&mtx_);
1186d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  return max_alive_threads_;
1196d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
1206d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
1216d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovu32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid,
1226d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov                                 void *arg) {
1236d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  BlockingMutexLock l(&mtx_);
1246d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  u32 tid = kUnknownTid;
125ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  ThreadContextBase *tctx = QuarantinePop();
126ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  if (tctx) {
1276d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    tid = tctx->tid;
128ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  } else if (n_contexts_ < max_threads_) {
1296d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    // Allocate new thread context and tid.
1306d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    tid = n_contexts_++;
1316d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    tctx = context_factory_(tid);
1326d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    threads_[tid] = tctx;
133ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  } else {
1342d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#ifndef SANITIZER_GO
135ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov    Report("%s: Thread limit (%u threads) exceeded. Dying.\n",
136ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov           SanitizerToolName, max_threads_);
1372d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#else
1382d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    Printf("race: limit on %u simultaneously alive goroutines is exceeded,"
1392d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines        " dying\n", max_threads_);
1402d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#endif
141ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov    Die();
1426d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
1436d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_NE(tctx, 0);
1446d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_NE(tid, kUnknownTid);
1456d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_LT(tid, max_threads_);
1466d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_EQ(tctx->status, ThreadStatusInvalid);
1476d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  alive_threads_++;
1486d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  if (max_alive_threads_ < alive_threads_) {
1496d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    max_alive_threads_++;
1506d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    CHECK_EQ(alive_threads_, max_alive_threads_);
1516d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
1526d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  tctx->SetCreated(user_id, total_threads_++, detached,
1536d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov                   parent_tid, arg);
1546d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  return tid;
1556d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
1566d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
1576d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovvoid ThreadRegistry::RunCallbackForEachThreadLocked(ThreadCallback cb,
1586d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov                                                    void *arg) {
1596d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CheckLocked();
1606d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  for (u32 tid = 0; tid < n_contexts_; tid++) {
1616d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    ThreadContextBase *tctx = threads_[tid];
1626d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    if (tctx == 0)
1636d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov      continue;
1646d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    cb(tctx, arg);
1656d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
1666d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
1676d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
1686d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovu32 ThreadRegistry::FindThread(FindThreadCallback cb, void *arg) {
1696d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  BlockingMutexLock l(&mtx_);
1706d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  for (u32 tid = 0; tid < n_contexts_; tid++) {
1716d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    ThreadContextBase *tctx = threads_[tid];
1726d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    if (tctx != 0 && cb(tctx, arg))
1736d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov      return tctx->tid;
1746d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
1756d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  return kUnknownTid;
1766d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
1776d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
1786d429cda69b7ccc007ee368a73a6040c6b125afbAlexey SamsonovThreadContextBase *
1796d429cda69b7ccc007ee368a73a6040c6b125afbAlexey SamsonovThreadRegistry::FindThreadContextLocked(FindThreadCallback cb, void *arg) {
1806d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CheckLocked();
1816d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  for (u32 tid = 0; tid < n_contexts_; tid++) {
1826d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    ThreadContextBase *tctx = threads_[tid];
1836d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    if (tctx != 0 && cb(tctx, arg))
1846d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov      return tctx;
1856d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
1866d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  return 0;
1876d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
1886d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
18998d3b40ec5cf06e46397492c21acc9d18e8c54abSergey Matveevstatic bool FindThreadContextByOsIdCallback(ThreadContextBase *tctx,
19098d3b40ec5cf06e46397492c21acc9d18e8c54abSergey Matveev                                            void *arg) {
19198d3b40ec5cf06e46397492c21acc9d18e8c54abSergey Matveev  return (tctx->os_id == (uptr)arg && tctx->status != ThreadStatusInvalid &&
19298d3b40ec5cf06e46397492c21acc9d18e8c54abSergey Matveev      tctx->status != ThreadStatusDead);
19398d3b40ec5cf06e46397492c21acc9d18e8c54abSergey Matveev}
19498d3b40ec5cf06e46397492c21acc9d18e8c54abSergey Matveev
19598d3b40ec5cf06e46397492c21acc9d18e8c54abSergey MatveevThreadContextBase *ThreadRegistry::FindThreadContextByOsIDLocked(uptr os_id) {
19698d3b40ec5cf06e46397492c21acc9d18e8c54abSergey Matveev  return FindThreadContextLocked(FindThreadContextByOsIdCallback,
19798d3b40ec5cf06e46397492c21acc9d18e8c54abSergey Matveev                                 (void *)os_id);
19898d3b40ec5cf06e46397492c21acc9d18e8c54abSergey Matveev}
19998d3b40ec5cf06e46397492c21acc9d18e8c54abSergey Matveev
2006d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovvoid ThreadRegistry::SetThreadName(u32 tid, const char *name) {
2016d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  BlockingMutexLock l(&mtx_);
2026d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_LT(tid, n_contexts_);
2036d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  ThreadContextBase *tctx = threads_[tid];
2046d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_NE(tctx, 0);
2056d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_EQ(ThreadStatusRunning, tctx->status);
2066d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  tctx->SetName(name);
2076d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
2086d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
2095cf2c460e96e593b1c772f1b02d3a217f4837fdcDmitry Vyukovvoid ThreadRegistry::SetThreadNameByUserId(uptr user_id, const char *name) {
2105cf2c460e96e593b1c772f1b02d3a217f4837fdcDmitry Vyukov  BlockingMutexLock l(&mtx_);
2115cf2c460e96e593b1c772f1b02d3a217f4837fdcDmitry Vyukov  for (u32 tid = 0; tid < n_contexts_; tid++) {
2125cf2c460e96e593b1c772f1b02d3a217f4837fdcDmitry Vyukov    ThreadContextBase *tctx = threads_[tid];
2135cf2c460e96e593b1c772f1b02d3a217f4837fdcDmitry Vyukov    if (tctx != 0 && tctx->user_id == user_id &&
2145cf2c460e96e593b1c772f1b02d3a217f4837fdcDmitry Vyukov        tctx->status != ThreadStatusInvalid) {
2155cf2c460e96e593b1c772f1b02d3a217f4837fdcDmitry Vyukov      tctx->SetName(name);
2165cf2c460e96e593b1c772f1b02d3a217f4837fdcDmitry Vyukov      return;
2175cf2c460e96e593b1c772f1b02d3a217f4837fdcDmitry Vyukov    }
2185cf2c460e96e593b1c772f1b02d3a217f4837fdcDmitry Vyukov  }
2195cf2c460e96e593b1c772f1b02d3a217f4837fdcDmitry Vyukov}
2205cf2c460e96e593b1c772f1b02d3a217f4837fdcDmitry Vyukov
2216d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovvoid ThreadRegistry::DetachThread(u32 tid) {
2226d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  BlockingMutexLock l(&mtx_);
2236d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_LT(tid, n_contexts_);
2246d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  ThreadContextBase *tctx = threads_[tid];
2256d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_NE(tctx, 0);
2266d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  if (tctx->status == ThreadStatusInvalid) {
2276d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    Report("%s: Detach of non-existent thread\n", SanitizerToolName);
2286d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    return;
2296d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
2306d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  if (tctx->status == ThreadStatusFinished) {
2316d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    tctx->SetDead();
232ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov    QuarantinePush(tctx);
2336d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  } else {
2346d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    tctx->detached = true;
2356d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
2366d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
2376d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
2386d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovvoid ThreadRegistry::JoinThread(u32 tid, void *arg) {
2396d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  BlockingMutexLock l(&mtx_);
2406d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_LT(tid, n_contexts_);
2416d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  ThreadContextBase *tctx = threads_[tid];
2426d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_NE(tctx, 0);
2436d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  if (tctx->status == ThreadStatusInvalid) {
2446d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    Report("%s: Join of non-existent thread\n", SanitizerToolName);
2456d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    return;
2466d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
2476d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  tctx->SetJoined(arg);
248ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  QuarantinePush(tctx);
2496d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
2506d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
2516d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovvoid ThreadRegistry::FinishThread(u32 tid) {
2526d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  BlockingMutexLock l(&mtx_);
2536d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_GT(alive_threads_, 0);
2546d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  alive_threads_--;
2556d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_GT(running_threads_, 0);
2566d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  running_threads_--;
2576d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_LT(tid, n_contexts_);
2586d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  ThreadContextBase *tctx = threads_[tid];
2596d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_NE(tctx, 0);
2606d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_EQ(ThreadStatusRunning, tctx->status);
2616d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  tctx->SetFinished();
2626d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  if (tctx->detached) {
2636d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    tctx->SetDead();
264ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov    QuarantinePush(tctx);
2656d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
2666d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
2676d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
2686d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovvoid ThreadRegistry::StartThread(u32 tid, uptr os_id, void *arg) {
2696d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  BlockingMutexLock l(&mtx_);
2706d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  running_threads_++;
2716d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_LT(tid, n_contexts_);
2726d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  ThreadContextBase *tctx = threads_[tid];
2736d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_NE(tctx, 0);
2746d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CHECK_EQ(ThreadStatusCreated, tctx->status);
2756d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  tctx->SetStarted(os_id, arg);
2766d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
2776d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
278ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukovvoid ThreadRegistry::QuarantinePush(ThreadContextBase *tctx) {
279ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  dead_threads_.push_back(tctx);
280ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  if (dead_threads_.size() <= thread_quarantine_size_)
281ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov    return;
282ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  tctx = dead_threads_.front();
283ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  dead_threads_.pop_front();
284ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  CHECK_EQ(tctx->status, ThreadStatusDead);
285ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  tctx->Reset();
2862d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  tctx->reuse_count++;
2872d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (max_reuse_ > 0 && tctx->reuse_count >= max_reuse_)
2882d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    return;
289ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  invalid_threads_.push_back(tctx);
290ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov}
291ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov
292ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry VyukovThreadContextBase *ThreadRegistry::QuarantinePop() {
293ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  if (invalid_threads_.size() == 0)
294ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov    return 0;
295ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  ThreadContextBase *tctx = invalid_threads_.front();
296ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  invalid_threads_.pop_front();
297ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov  return tctx;
298ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov}
299ce85e03620f64ce7e4cd0598f2e93090f52a9e99Dmitry Vyukov
3006d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}  // namespace __sanitizer
301