xref: /openbsd-src/gnu/llvm/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.cpp (revision 810390e339a5425391477d5d41c78d7cab2424ac)
13cab2bb3Spatrick //===-- sanitizer_thread_registry.cpp -------------------------------------===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick //
93cab2bb3Spatrick // This file is shared between sanitizer tools.
103cab2bb3Spatrick //
113cab2bb3Spatrick // General thread bookkeeping functionality.
123cab2bb3Spatrick //===----------------------------------------------------------------------===//
133cab2bb3Spatrick 
143cab2bb3Spatrick #include "sanitizer_thread_registry.h"
153cab2bb3Spatrick 
16*810390e3Srobert #include "sanitizer_placement_new.h"
17*810390e3Srobert 
183cab2bb3Spatrick namespace __sanitizer {
193cab2bb3Spatrick 
ThreadContextBase(u32 tid)203cab2bb3Spatrick ThreadContextBase::ThreadContextBase(u32 tid)
213cab2bb3Spatrick     : tid(tid), unique_id(0), reuse_count(), os_id(0), user_id(0),
223cab2bb3Spatrick       status(ThreadStatusInvalid), detached(false),
233cab2bb3Spatrick       thread_type(ThreadType::Regular), parent_tid(0), next(0) {
243cab2bb3Spatrick   name[0] = '\0';
253cab2bb3Spatrick   atomic_store(&thread_destroyed, 0, memory_order_release);
263cab2bb3Spatrick }
273cab2bb3Spatrick 
~ThreadContextBase()283cab2bb3Spatrick ThreadContextBase::~ThreadContextBase() {
293cab2bb3Spatrick   // ThreadContextBase should never be deleted.
303cab2bb3Spatrick   CHECK(0);
313cab2bb3Spatrick }
323cab2bb3Spatrick 
SetName(const char * new_name)333cab2bb3Spatrick void ThreadContextBase::SetName(const char *new_name) {
343cab2bb3Spatrick   name[0] = '\0';
353cab2bb3Spatrick   if (new_name) {
363cab2bb3Spatrick     internal_strncpy(name, new_name, sizeof(name));
373cab2bb3Spatrick     name[sizeof(name) - 1] = '\0';
383cab2bb3Spatrick   }
393cab2bb3Spatrick }
403cab2bb3Spatrick 
SetDead()413cab2bb3Spatrick void ThreadContextBase::SetDead() {
423cab2bb3Spatrick   CHECK(status == ThreadStatusRunning ||
433cab2bb3Spatrick         status == ThreadStatusFinished);
443cab2bb3Spatrick   status = ThreadStatusDead;
453cab2bb3Spatrick   user_id = 0;
463cab2bb3Spatrick   OnDead();
473cab2bb3Spatrick }
483cab2bb3Spatrick 
SetDestroyed()493cab2bb3Spatrick void ThreadContextBase::SetDestroyed() {
503cab2bb3Spatrick   atomic_store(&thread_destroyed, 1, memory_order_release);
513cab2bb3Spatrick }
523cab2bb3Spatrick 
GetDestroyed()533cab2bb3Spatrick bool ThreadContextBase::GetDestroyed() {
543cab2bb3Spatrick   return !!atomic_load(&thread_destroyed, memory_order_acquire);
553cab2bb3Spatrick }
563cab2bb3Spatrick 
SetJoined(void * arg)573cab2bb3Spatrick void ThreadContextBase::SetJoined(void *arg) {
583cab2bb3Spatrick   // FIXME(dvyukov): print message and continue (it's user error).
593cab2bb3Spatrick   CHECK_EQ(false, detached);
603cab2bb3Spatrick   CHECK_EQ(ThreadStatusFinished, status);
613cab2bb3Spatrick   status = ThreadStatusDead;
623cab2bb3Spatrick   user_id = 0;
633cab2bb3Spatrick   OnJoined(arg);
643cab2bb3Spatrick }
653cab2bb3Spatrick 
SetFinished()663cab2bb3Spatrick void ThreadContextBase::SetFinished() {
673cab2bb3Spatrick   // ThreadRegistry::FinishThread calls here in ThreadStatusCreated state
683cab2bb3Spatrick   // for a thread that never actually started.  In that case the thread
693cab2bb3Spatrick   // should go to ThreadStatusFinished regardless of whether it was created
703cab2bb3Spatrick   // as detached.
713cab2bb3Spatrick   if (!detached || status == ThreadStatusCreated) status = ThreadStatusFinished;
723cab2bb3Spatrick   OnFinished();
733cab2bb3Spatrick }
743cab2bb3Spatrick 
SetStarted(tid_t _os_id,ThreadType _thread_type,void * arg)753cab2bb3Spatrick void ThreadContextBase::SetStarted(tid_t _os_id, ThreadType _thread_type,
763cab2bb3Spatrick                                    void *arg) {
773cab2bb3Spatrick   status = ThreadStatusRunning;
783cab2bb3Spatrick   os_id = _os_id;
793cab2bb3Spatrick   thread_type = _thread_type;
803cab2bb3Spatrick   OnStarted(arg);
813cab2bb3Spatrick }
823cab2bb3Spatrick 
SetCreated(uptr _user_id,u64 _unique_id,bool _detached,u32 _parent_tid,void * arg)833cab2bb3Spatrick void ThreadContextBase::SetCreated(uptr _user_id, u64 _unique_id,
843cab2bb3Spatrick                                    bool _detached, u32 _parent_tid, void *arg) {
853cab2bb3Spatrick   status = ThreadStatusCreated;
863cab2bb3Spatrick   user_id = _user_id;
873cab2bb3Spatrick   unique_id = _unique_id;
883cab2bb3Spatrick   detached = _detached;
893cab2bb3Spatrick   // Parent tid makes no sense for the main thread.
90d89ec533Spatrick   if (tid != kMainTid)
913cab2bb3Spatrick     parent_tid = _parent_tid;
923cab2bb3Spatrick   OnCreated(arg);
933cab2bb3Spatrick }
943cab2bb3Spatrick 
Reset()953cab2bb3Spatrick void ThreadContextBase::Reset() {
963cab2bb3Spatrick   status = ThreadStatusInvalid;
973cab2bb3Spatrick   SetName(0);
983cab2bb3Spatrick   atomic_store(&thread_destroyed, 0, memory_order_release);
993cab2bb3Spatrick   OnReset();
1003cab2bb3Spatrick }
1013cab2bb3Spatrick 
1023cab2bb3Spatrick // ThreadRegistry implementation.
1033cab2bb3Spatrick 
ThreadRegistry(ThreadContextFactory factory)104d89ec533Spatrick ThreadRegistry::ThreadRegistry(ThreadContextFactory factory)
105d89ec533Spatrick     : ThreadRegistry(factory, UINT32_MAX, UINT32_MAX, 0) {}
1063cab2bb3Spatrick 
ThreadRegistry(ThreadContextFactory factory,u32 max_threads,u32 thread_quarantine_size,u32 max_reuse)1073cab2bb3Spatrick ThreadRegistry::ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
1083cab2bb3Spatrick                                u32 thread_quarantine_size, u32 max_reuse)
1093cab2bb3Spatrick     : context_factory_(factory),
1103cab2bb3Spatrick       max_threads_(max_threads),
1113cab2bb3Spatrick       thread_quarantine_size_(thread_quarantine_size),
1123cab2bb3Spatrick       max_reuse_(max_reuse),
113*810390e3Srobert       mtx_(MutexThreadRegistry),
1143cab2bb3Spatrick       total_threads_(0),
1153cab2bb3Spatrick       alive_threads_(0),
1163cab2bb3Spatrick       max_alive_threads_(0),
1173cab2bb3Spatrick       running_threads_(0) {
1183cab2bb3Spatrick   dead_threads_.clear();
1193cab2bb3Spatrick   invalid_threads_.clear();
1203cab2bb3Spatrick }
1213cab2bb3Spatrick 
GetNumberOfThreads(uptr * total,uptr * running,uptr * alive)1223cab2bb3Spatrick void ThreadRegistry::GetNumberOfThreads(uptr *total, uptr *running,
1233cab2bb3Spatrick                                         uptr *alive) {
124*810390e3Srobert   ThreadRegistryLock l(this);
125d89ec533Spatrick   if (total)
126d89ec533Spatrick     *total = threads_.size();
1273cab2bb3Spatrick   if (running) *running = running_threads_;
1283cab2bb3Spatrick   if (alive) *alive = alive_threads_;
1293cab2bb3Spatrick }
1303cab2bb3Spatrick 
GetMaxAliveThreads()1313cab2bb3Spatrick uptr ThreadRegistry::GetMaxAliveThreads() {
132*810390e3Srobert   ThreadRegistryLock l(this);
1333cab2bb3Spatrick   return max_alive_threads_;
1343cab2bb3Spatrick }
1353cab2bb3Spatrick 
CreateThread(uptr user_id,bool detached,u32 parent_tid,void * arg)1363cab2bb3Spatrick u32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid,
1373cab2bb3Spatrick                                  void *arg) {
138*810390e3Srobert   ThreadRegistryLock l(this);
139d89ec533Spatrick   u32 tid = kInvalidTid;
1403cab2bb3Spatrick   ThreadContextBase *tctx = QuarantinePop();
1413cab2bb3Spatrick   if (tctx) {
1423cab2bb3Spatrick     tid = tctx->tid;
143d89ec533Spatrick   } else if (threads_.size() < max_threads_) {
1443cab2bb3Spatrick     // Allocate new thread context and tid.
145d89ec533Spatrick     tid = threads_.size();
1463cab2bb3Spatrick     tctx = context_factory_(tid);
147d89ec533Spatrick     threads_.push_back(tctx);
1483cab2bb3Spatrick   } else {
1493cab2bb3Spatrick #if !SANITIZER_GO
1503cab2bb3Spatrick     Report("%s: Thread limit (%u threads) exceeded. Dying.\n",
1513cab2bb3Spatrick            SanitizerToolName, max_threads_);
1523cab2bb3Spatrick #else
1533cab2bb3Spatrick     Printf("race: limit on %u simultaneously alive goroutines is exceeded,"
1543cab2bb3Spatrick         " dying\n", max_threads_);
1553cab2bb3Spatrick #endif
1563cab2bb3Spatrick     Die();
1573cab2bb3Spatrick   }
1583cab2bb3Spatrick   CHECK_NE(tctx, 0);
159d89ec533Spatrick   CHECK_NE(tid, kInvalidTid);
1603cab2bb3Spatrick   CHECK_LT(tid, max_threads_);
1613cab2bb3Spatrick   CHECK_EQ(tctx->status, ThreadStatusInvalid);
1623cab2bb3Spatrick   alive_threads_++;
1633cab2bb3Spatrick   if (max_alive_threads_ < alive_threads_) {
1643cab2bb3Spatrick     max_alive_threads_++;
1653cab2bb3Spatrick     CHECK_EQ(alive_threads_, max_alive_threads_);
1663cab2bb3Spatrick   }
167*810390e3Srobert   if (user_id) {
168*810390e3Srobert     // Ensure that user_id is unique. If it's not the case we are screwed.
169*810390e3Srobert     // Ignoring this situation may lead to very hard to debug false
170*810390e3Srobert     // positives later (e.g. if we join a wrong thread).
171*810390e3Srobert     CHECK(live_.try_emplace(user_id, tid).second);
172*810390e3Srobert   }
1733cab2bb3Spatrick   tctx->SetCreated(user_id, total_threads_++, detached,
1743cab2bb3Spatrick                    parent_tid, arg);
1753cab2bb3Spatrick   return tid;
1763cab2bb3Spatrick }
1773cab2bb3Spatrick 
RunCallbackForEachThreadLocked(ThreadCallback cb,void * arg)1783cab2bb3Spatrick void ThreadRegistry::RunCallbackForEachThreadLocked(ThreadCallback cb,
1793cab2bb3Spatrick                                                     void *arg) {
1803cab2bb3Spatrick   CheckLocked();
181d89ec533Spatrick   for (u32 tid = 0; tid < threads_.size(); tid++) {
1823cab2bb3Spatrick     ThreadContextBase *tctx = threads_[tid];
1833cab2bb3Spatrick     if (tctx == 0)
1843cab2bb3Spatrick       continue;
1853cab2bb3Spatrick     cb(tctx, arg);
1863cab2bb3Spatrick   }
1873cab2bb3Spatrick }
1883cab2bb3Spatrick 
FindThread(FindThreadCallback cb,void * arg)1893cab2bb3Spatrick u32 ThreadRegistry::FindThread(FindThreadCallback cb, void *arg) {
190*810390e3Srobert   ThreadRegistryLock l(this);
191d89ec533Spatrick   for (u32 tid = 0; tid < threads_.size(); tid++) {
1923cab2bb3Spatrick     ThreadContextBase *tctx = threads_[tid];
1933cab2bb3Spatrick     if (tctx != 0 && cb(tctx, arg))
1943cab2bb3Spatrick       return tctx->tid;
1953cab2bb3Spatrick   }
196d89ec533Spatrick   return kInvalidTid;
1973cab2bb3Spatrick }
1983cab2bb3Spatrick 
1993cab2bb3Spatrick ThreadContextBase *
FindThreadContextLocked(FindThreadCallback cb,void * arg)2003cab2bb3Spatrick ThreadRegistry::FindThreadContextLocked(FindThreadCallback cb, void *arg) {
2013cab2bb3Spatrick   CheckLocked();
202d89ec533Spatrick   for (u32 tid = 0; tid < threads_.size(); tid++) {
2033cab2bb3Spatrick     ThreadContextBase *tctx = threads_[tid];
2043cab2bb3Spatrick     if (tctx != 0 && cb(tctx, arg))
2053cab2bb3Spatrick       return tctx;
2063cab2bb3Spatrick   }
2073cab2bb3Spatrick   return 0;
2083cab2bb3Spatrick }
2093cab2bb3Spatrick 
FindThreadContextByOsIdCallback(ThreadContextBase * tctx,void * arg)2103cab2bb3Spatrick static bool FindThreadContextByOsIdCallback(ThreadContextBase *tctx,
2113cab2bb3Spatrick                                             void *arg) {
2123cab2bb3Spatrick   return (tctx->os_id == (uptr)arg && tctx->status != ThreadStatusInvalid &&
2133cab2bb3Spatrick       tctx->status != ThreadStatusDead);
2143cab2bb3Spatrick }
2153cab2bb3Spatrick 
FindThreadContextByOsIDLocked(tid_t os_id)2163cab2bb3Spatrick ThreadContextBase *ThreadRegistry::FindThreadContextByOsIDLocked(tid_t os_id) {
2173cab2bb3Spatrick   return FindThreadContextLocked(FindThreadContextByOsIdCallback,
2183cab2bb3Spatrick                                  (void *)os_id);
2193cab2bb3Spatrick }
2203cab2bb3Spatrick 
SetThreadName(u32 tid,const char * name)2213cab2bb3Spatrick void ThreadRegistry::SetThreadName(u32 tid, const char *name) {
222*810390e3Srobert   ThreadRegistryLock l(this);
2233cab2bb3Spatrick   ThreadContextBase *tctx = threads_[tid];
2243cab2bb3Spatrick   CHECK_NE(tctx, 0);
2253cab2bb3Spatrick   CHECK_EQ(SANITIZER_FUCHSIA ? ThreadStatusCreated : ThreadStatusRunning,
2263cab2bb3Spatrick            tctx->status);
2273cab2bb3Spatrick   tctx->SetName(name);
2283cab2bb3Spatrick }
2293cab2bb3Spatrick 
SetThreadNameByUserId(uptr user_id,const char * name)2303cab2bb3Spatrick void ThreadRegistry::SetThreadNameByUserId(uptr user_id, const char *name) {
231*810390e3Srobert   ThreadRegistryLock l(this);
232*810390e3Srobert   if (const auto *tid = live_.find(user_id))
233*810390e3Srobert     threads_[tid->second]->SetName(name);
2343cab2bb3Spatrick }
2353cab2bb3Spatrick 
DetachThread(u32 tid,void * arg)2363cab2bb3Spatrick void ThreadRegistry::DetachThread(u32 tid, void *arg) {
237*810390e3Srobert   ThreadRegistryLock l(this);
2383cab2bb3Spatrick   ThreadContextBase *tctx = threads_[tid];
2393cab2bb3Spatrick   CHECK_NE(tctx, 0);
2403cab2bb3Spatrick   if (tctx->status == ThreadStatusInvalid) {
2413cab2bb3Spatrick     Report("%s: Detach of non-existent thread\n", SanitizerToolName);
2423cab2bb3Spatrick     return;
2433cab2bb3Spatrick   }
2443cab2bb3Spatrick   tctx->OnDetached(arg);
2453cab2bb3Spatrick   if (tctx->status == ThreadStatusFinished) {
246*810390e3Srobert     if (tctx->user_id)
247*810390e3Srobert       live_.erase(tctx->user_id);
2483cab2bb3Spatrick     tctx->SetDead();
2493cab2bb3Spatrick     QuarantinePush(tctx);
2503cab2bb3Spatrick   } else {
2513cab2bb3Spatrick     tctx->detached = true;
2523cab2bb3Spatrick   }
2533cab2bb3Spatrick }
2543cab2bb3Spatrick 
JoinThread(u32 tid,void * arg)2553cab2bb3Spatrick void ThreadRegistry::JoinThread(u32 tid, void *arg) {
2563cab2bb3Spatrick   bool destroyed = false;
2573cab2bb3Spatrick   do {
2583cab2bb3Spatrick     {
259*810390e3Srobert       ThreadRegistryLock l(this);
2603cab2bb3Spatrick       ThreadContextBase *tctx = threads_[tid];
2613cab2bb3Spatrick       CHECK_NE(tctx, 0);
2623cab2bb3Spatrick       if (tctx->status == ThreadStatusInvalid) {
2633cab2bb3Spatrick         Report("%s: Join of non-existent thread\n", SanitizerToolName);
2643cab2bb3Spatrick         return;
2653cab2bb3Spatrick       }
2663cab2bb3Spatrick       if ((destroyed = tctx->GetDestroyed())) {
267*810390e3Srobert         if (tctx->user_id)
268*810390e3Srobert           live_.erase(tctx->user_id);
2693cab2bb3Spatrick         tctx->SetJoined(arg);
2703cab2bb3Spatrick         QuarantinePush(tctx);
2713cab2bb3Spatrick       }
2723cab2bb3Spatrick     }
2733cab2bb3Spatrick     if (!destroyed)
2743cab2bb3Spatrick       internal_sched_yield();
2753cab2bb3Spatrick   } while (!destroyed);
2763cab2bb3Spatrick }
2773cab2bb3Spatrick 
2783cab2bb3Spatrick // Normally this is called when the thread is about to exit.  If
2793cab2bb3Spatrick // called in ThreadStatusCreated state, then this thread was never
2803cab2bb3Spatrick // really started.  We just did CreateThread for a prospective new
2813cab2bb3Spatrick // thread before trying to create it, and then failed to actually
2823cab2bb3Spatrick // create it, and so never called StartThread.
FinishThread(u32 tid)283d89ec533Spatrick ThreadStatus ThreadRegistry::FinishThread(u32 tid) {
284*810390e3Srobert   ThreadRegistryLock l(this);
2853cab2bb3Spatrick   CHECK_GT(alive_threads_, 0);
2863cab2bb3Spatrick   alive_threads_--;
2873cab2bb3Spatrick   ThreadContextBase *tctx = threads_[tid];
2883cab2bb3Spatrick   CHECK_NE(tctx, 0);
2893cab2bb3Spatrick   bool dead = tctx->detached;
290d89ec533Spatrick   ThreadStatus prev_status = tctx->status;
2913cab2bb3Spatrick   if (tctx->status == ThreadStatusRunning) {
2923cab2bb3Spatrick     CHECK_GT(running_threads_, 0);
2933cab2bb3Spatrick     running_threads_--;
2943cab2bb3Spatrick   } else {
2953cab2bb3Spatrick     // The thread never really existed.
2963cab2bb3Spatrick     CHECK_EQ(tctx->status, ThreadStatusCreated);
2973cab2bb3Spatrick     dead = true;
2983cab2bb3Spatrick   }
2993cab2bb3Spatrick   tctx->SetFinished();
3003cab2bb3Spatrick   if (dead) {
301*810390e3Srobert     if (tctx->user_id)
302*810390e3Srobert       live_.erase(tctx->user_id);
3033cab2bb3Spatrick     tctx->SetDead();
3043cab2bb3Spatrick     QuarantinePush(tctx);
3053cab2bb3Spatrick   }
3063cab2bb3Spatrick   tctx->SetDestroyed();
307d89ec533Spatrick   return prev_status;
3083cab2bb3Spatrick }
3093cab2bb3Spatrick 
StartThread(u32 tid,tid_t os_id,ThreadType thread_type,void * arg)3103cab2bb3Spatrick void ThreadRegistry::StartThread(u32 tid, tid_t os_id, ThreadType thread_type,
3113cab2bb3Spatrick                                  void *arg) {
312*810390e3Srobert   ThreadRegistryLock l(this);
3133cab2bb3Spatrick   running_threads_++;
3143cab2bb3Spatrick   ThreadContextBase *tctx = threads_[tid];
3153cab2bb3Spatrick   CHECK_NE(tctx, 0);
3163cab2bb3Spatrick   CHECK_EQ(ThreadStatusCreated, tctx->status);
3173cab2bb3Spatrick   tctx->SetStarted(os_id, thread_type, arg);
3183cab2bb3Spatrick }
3193cab2bb3Spatrick 
QuarantinePush(ThreadContextBase * tctx)3203cab2bb3Spatrick void ThreadRegistry::QuarantinePush(ThreadContextBase *tctx) {
3213cab2bb3Spatrick   if (tctx->tid == 0)
3223cab2bb3Spatrick     return;  // Don't reuse the main thread.  It's a special snowflake.
3233cab2bb3Spatrick   dead_threads_.push_back(tctx);
3243cab2bb3Spatrick   if (dead_threads_.size() <= thread_quarantine_size_)
3253cab2bb3Spatrick     return;
3263cab2bb3Spatrick   tctx = dead_threads_.front();
3273cab2bb3Spatrick   dead_threads_.pop_front();
3283cab2bb3Spatrick   CHECK_EQ(tctx->status, ThreadStatusDead);
3293cab2bb3Spatrick   tctx->Reset();
3303cab2bb3Spatrick   tctx->reuse_count++;
3313cab2bb3Spatrick   if (max_reuse_ > 0 && tctx->reuse_count >= max_reuse_)
3323cab2bb3Spatrick     return;
3333cab2bb3Spatrick   invalid_threads_.push_back(tctx);
3343cab2bb3Spatrick }
3353cab2bb3Spatrick 
QuarantinePop()3363cab2bb3Spatrick ThreadContextBase *ThreadRegistry::QuarantinePop() {
3373cab2bb3Spatrick   if (invalid_threads_.size() == 0)
3383cab2bb3Spatrick     return 0;
3393cab2bb3Spatrick   ThreadContextBase *tctx = invalid_threads_.front();
3403cab2bb3Spatrick   invalid_threads_.pop_front();
3413cab2bb3Spatrick   return tctx;
3423cab2bb3Spatrick }
3433cab2bb3Spatrick 
ConsumeThreadUserId(uptr user_id)344*810390e3Srobert u32 ThreadRegistry::ConsumeThreadUserId(uptr user_id) {
345*810390e3Srobert   ThreadRegistryLock l(this);
346*810390e3Srobert   u32 tid;
347*810390e3Srobert   auto *t = live_.find(user_id);
348*810390e3Srobert   CHECK(t);
349*810390e3Srobert   tid = t->second;
350*810390e3Srobert   live_.erase(t);
351*810390e3Srobert   auto *tctx = threads_[tid];
352*810390e3Srobert   CHECK_EQ(tctx->user_id, user_id);
353*810390e3Srobert   tctx->user_id = 0;
354*810390e3Srobert   return tid;
355*810390e3Srobert }
356*810390e3Srobert 
SetThreadUserId(u32 tid,uptr user_id)3573cab2bb3Spatrick void ThreadRegistry::SetThreadUserId(u32 tid, uptr user_id) {
358*810390e3Srobert   ThreadRegistryLock l(this);
3593cab2bb3Spatrick   ThreadContextBase *tctx = threads_[tid];
3603cab2bb3Spatrick   CHECK_NE(tctx, 0);
3613cab2bb3Spatrick   CHECK_NE(tctx->status, ThreadStatusInvalid);
3623cab2bb3Spatrick   CHECK_NE(tctx->status, ThreadStatusDead);
3633cab2bb3Spatrick   CHECK_EQ(tctx->user_id, 0);
3643cab2bb3Spatrick   tctx->user_id = user_id;
365*810390e3Srobert   CHECK(live_.try_emplace(user_id, tctx->tid).second);
366*810390e3Srobert }
367*810390e3Srobert 
OnFork(u32 tid)368*810390e3Srobert u32 ThreadRegistry::OnFork(u32 tid) {
369*810390e3Srobert   ThreadRegistryLock l(this);
370*810390e3Srobert   // We only purge user_id (pthread_t) of live threads because
371*810390e3Srobert   // they cause CHECK failures if new threads with matching pthread_t
372*810390e3Srobert   // created after fork.
373*810390e3Srobert   // Potentially we could purge more info (ThreadContextBase themselves),
374*810390e3Srobert   // but it's hard to test and easy to introduce new issues by doing this.
375*810390e3Srobert   for (auto *tctx : threads_) {
376*810390e3Srobert     if (tctx->tid == tid || !tctx->user_id)
377*810390e3Srobert       continue;
378*810390e3Srobert     CHECK(live_.erase(tctx->user_id));
379*810390e3Srobert     tctx->user_id = 0;
380*810390e3Srobert   }
381*810390e3Srobert   return alive_threads_;
3823cab2bb3Spatrick }
3833cab2bb3Spatrick 
3843cab2bb3Spatrick }  // namespace __sanitizer
385