168d75effSDimitry Andric //===-- sanitizer_thread_registry.cpp -------------------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // This file is shared between sanitizer tools.
1068d75effSDimitry Andric //
1168d75effSDimitry Andric // General thread bookkeeping functionality.
1268d75effSDimitry Andric //===----------------------------------------------------------------------===//
1368d75effSDimitry Andric 
1468d75effSDimitry Andric #include "sanitizer_thread_registry.h"
1568d75effSDimitry Andric 
16349cc55cSDimitry Andric #include "sanitizer_placement_new.h"
17349cc55cSDimitry Andric 
1868d75effSDimitry Andric namespace __sanitizer {
1968d75effSDimitry Andric 
ThreadContextBase(u32 tid)2068d75effSDimitry Andric ThreadContextBase::ThreadContextBase(u32 tid)
2168d75effSDimitry Andric     : tid(tid), unique_id(0), reuse_count(), os_id(0), user_id(0),
2268d75effSDimitry Andric       status(ThreadStatusInvalid), detached(false),
2368d75effSDimitry Andric       thread_type(ThreadType::Regular), parent_tid(0), next(0) {
2468d75effSDimitry Andric   name[0] = '\0';
2568d75effSDimitry Andric   atomic_store(&thread_destroyed, 0, memory_order_release);
2668d75effSDimitry Andric }
2768d75effSDimitry Andric 
~ThreadContextBase()2868d75effSDimitry Andric ThreadContextBase::~ThreadContextBase() {
2968d75effSDimitry Andric   // ThreadContextBase should never be deleted.
3068d75effSDimitry Andric   CHECK(0);
3168d75effSDimitry Andric }
3268d75effSDimitry Andric 
SetName(const char * new_name)3368d75effSDimitry Andric void ThreadContextBase::SetName(const char *new_name) {
3468d75effSDimitry Andric   name[0] = '\0';
3568d75effSDimitry Andric   if (new_name) {
3668d75effSDimitry Andric     internal_strncpy(name, new_name, sizeof(name));
3768d75effSDimitry Andric     name[sizeof(name) - 1] = '\0';
3868d75effSDimitry Andric   }
3968d75effSDimitry Andric }
4068d75effSDimitry Andric 
SetDead()4168d75effSDimitry Andric void ThreadContextBase::SetDead() {
4268d75effSDimitry Andric   CHECK(status == ThreadStatusRunning ||
4368d75effSDimitry Andric         status == ThreadStatusFinished);
4468d75effSDimitry Andric   status = ThreadStatusDead;
4568d75effSDimitry Andric   user_id = 0;
4668d75effSDimitry Andric   OnDead();
4768d75effSDimitry Andric }
4868d75effSDimitry Andric 
SetDestroyed()4968d75effSDimitry Andric void ThreadContextBase::SetDestroyed() {
5068d75effSDimitry Andric   atomic_store(&thread_destroyed, 1, memory_order_release);
5168d75effSDimitry Andric }
5268d75effSDimitry Andric 
GetDestroyed()5368d75effSDimitry Andric bool ThreadContextBase::GetDestroyed() {
5468d75effSDimitry Andric   return !!atomic_load(&thread_destroyed, memory_order_acquire);
5568d75effSDimitry Andric }
5668d75effSDimitry Andric 
SetJoined(void * arg)5768d75effSDimitry Andric void ThreadContextBase::SetJoined(void *arg) {
5868d75effSDimitry Andric   // FIXME(dvyukov): print message and continue (it's user error).
5968d75effSDimitry Andric   CHECK_EQ(false, detached);
6068d75effSDimitry Andric   CHECK_EQ(ThreadStatusFinished, status);
6168d75effSDimitry Andric   status = ThreadStatusDead;
6268d75effSDimitry Andric   user_id = 0;
6368d75effSDimitry Andric   OnJoined(arg);
6468d75effSDimitry Andric }
6568d75effSDimitry Andric 
SetFinished()6668d75effSDimitry Andric void ThreadContextBase::SetFinished() {
6768d75effSDimitry Andric   // ThreadRegistry::FinishThread calls here in ThreadStatusCreated state
6868d75effSDimitry Andric   // for a thread that never actually started.  In that case the thread
6968d75effSDimitry Andric   // should go to ThreadStatusFinished regardless of whether it was created
7068d75effSDimitry Andric   // as detached.
7168d75effSDimitry Andric   if (!detached || status == ThreadStatusCreated) status = ThreadStatusFinished;
7268d75effSDimitry Andric   OnFinished();
7368d75effSDimitry Andric }
7468d75effSDimitry Andric 
SetStarted(tid_t _os_id,ThreadType _thread_type,void * arg)7568d75effSDimitry Andric void ThreadContextBase::SetStarted(tid_t _os_id, ThreadType _thread_type,
7668d75effSDimitry Andric                                    void *arg) {
7768d75effSDimitry Andric   status = ThreadStatusRunning;
7868d75effSDimitry Andric   os_id = _os_id;
7968d75effSDimitry Andric   thread_type = _thread_type;
8068d75effSDimitry Andric   OnStarted(arg);
8168d75effSDimitry Andric }
8268d75effSDimitry Andric 
SetCreated(uptr _user_id,u64 _unique_id,bool _detached,u32 _parent_tid,void * arg)8368d75effSDimitry Andric void ThreadContextBase::SetCreated(uptr _user_id, u64 _unique_id,
8468d75effSDimitry Andric                                    bool _detached, u32 _parent_tid, void *arg) {
8568d75effSDimitry Andric   status = ThreadStatusCreated;
8668d75effSDimitry Andric   user_id = _user_id;
8768d75effSDimitry Andric   unique_id = _unique_id;
8868d75effSDimitry Andric   detached = _detached;
8968d75effSDimitry Andric   // Parent tid makes no sense for the main thread.
90fe6060f1SDimitry Andric   if (tid != kMainTid)
9168d75effSDimitry Andric     parent_tid = _parent_tid;
9268d75effSDimitry Andric   OnCreated(arg);
9368d75effSDimitry Andric }
9468d75effSDimitry Andric 
Reset()9568d75effSDimitry Andric void ThreadContextBase::Reset() {
9668d75effSDimitry Andric   status = ThreadStatusInvalid;
9768d75effSDimitry Andric   SetName(0);
9868d75effSDimitry Andric   atomic_store(&thread_destroyed, 0, memory_order_release);
9968d75effSDimitry Andric   OnReset();
10068d75effSDimitry Andric }
10168d75effSDimitry Andric 
10268d75effSDimitry Andric // ThreadRegistry implementation.
10368d75effSDimitry Andric 
ThreadRegistry(ThreadContextFactory factory)104fe6060f1SDimitry Andric ThreadRegistry::ThreadRegistry(ThreadContextFactory factory)
105fe6060f1SDimitry Andric     : ThreadRegistry(factory, UINT32_MAX, UINT32_MAX, 0) {}
10668d75effSDimitry Andric 
ThreadRegistry(ThreadContextFactory factory,u32 max_threads,u32 thread_quarantine_size,u32 max_reuse)10768d75effSDimitry Andric ThreadRegistry::ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
10868d75effSDimitry Andric                                u32 thread_quarantine_size, u32 max_reuse)
10968d75effSDimitry Andric     : context_factory_(factory),
11068d75effSDimitry Andric       max_threads_(max_threads),
11168d75effSDimitry Andric       thread_quarantine_size_(thread_quarantine_size),
11268d75effSDimitry Andric       max_reuse_(max_reuse),
1130eae32dcSDimitry Andric       mtx_(MutexThreadRegistry),
11468d75effSDimitry Andric       total_threads_(0),
11568d75effSDimitry Andric       alive_threads_(0),
11668d75effSDimitry Andric       max_alive_threads_(0),
11768d75effSDimitry Andric       running_threads_(0) {
11868d75effSDimitry Andric   dead_threads_.clear();
11968d75effSDimitry Andric   invalid_threads_.clear();
12068d75effSDimitry Andric }
12168d75effSDimitry Andric 
GetNumberOfThreads(uptr * total,uptr * running,uptr * alive)12268d75effSDimitry Andric void ThreadRegistry::GetNumberOfThreads(uptr *total, uptr *running,
12368d75effSDimitry Andric                                         uptr *alive) {
124349cc55cSDimitry Andric   ThreadRegistryLock l(this);
125fe6060f1SDimitry Andric   if (total)
126fe6060f1SDimitry Andric     *total = threads_.size();
12768d75effSDimitry Andric   if (running) *running = running_threads_;
12868d75effSDimitry Andric   if (alive) *alive = alive_threads_;
12968d75effSDimitry Andric }
13068d75effSDimitry Andric 
GetMaxAliveThreads()13168d75effSDimitry Andric uptr ThreadRegistry::GetMaxAliveThreads() {
132349cc55cSDimitry Andric   ThreadRegistryLock l(this);
13368d75effSDimitry Andric   return max_alive_threads_;
13468d75effSDimitry Andric }
13568d75effSDimitry Andric 
CreateThread(uptr user_id,bool detached,u32 parent_tid,void * arg)13668d75effSDimitry Andric u32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid,
13768d75effSDimitry Andric                                  void *arg) {
138349cc55cSDimitry Andric   ThreadRegistryLock l(this);
139fe6060f1SDimitry Andric   u32 tid = kInvalidTid;
14068d75effSDimitry Andric   ThreadContextBase *tctx = QuarantinePop();
14168d75effSDimitry Andric   if (tctx) {
14268d75effSDimitry Andric     tid = tctx->tid;
143fe6060f1SDimitry Andric   } else if (threads_.size() < max_threads_) {
14468d75effSDimitry Andric     // Allocate new thread context and tid.
145fe6060f1SDimitry Andric     tid = threads_.size();
14668d75effSDimitry Andric     tctx = context_factory_(tid);
147fe6060f1SDimitry Andric     threads_.push_back(tctx);
14868d75effSDimitry Andric   } else {
14968d75effSDimitry Andric #if !SANITIZER_GO
15068d75effSDimitry Andric     Report("%s: Thread limit (%u threads) exceeded. Dying.\n",
15168d75effSDimitry Andric            SanitizerToolName, max_threads_);
15268d75effSDimitry Andric #else
15368d75effSDimitry Andric     Printf("race: limit on %u simultaneously alive goroutines is exceeded,"
15468d75effSDimitry Andric         " dying\n", max_threads_);
15568d75effSDimitry Andric #endif
15668d75effSDimitry Andric     Die();
15768d75effSDimitry Andric   }
15868d75effSDimitry Andric   CHECK_NE(tctx, 0);
159fe6060f1SDimitry Andric   CHECK_NE(tid, kInvalidTid);
16068d75effSDimitry Andric   CHECK_LT(tid, max_threads_);
16168d75effSDimitry Andric   CHECK_EQ(tctx->status, ThreadStatusInvalid);
16268d75effSDimitry Andric   alive_threads_++;
16368d75effSDimitry Andric   if (max_alive_threads_ < alive_threads_) {
16468d75effSDimitry Andric     max_alive_threads_++;
16568d75effSDimitry Andric     CHECK_EQ(alive_threads_, max_alive_threads_);
16668d75effSDimitry Andric   }
167349cc55cSDimitry Andric   if (user_id) {
168349cc55cSDimitry Andric     // Ensure that user_id is unique. If it's not the case we are screwed.
169349cc55cSDimitry Andric     // Ignoring this situation may lead to very hard to debug false
170349cc55cSDimitry Andric     // positives later (e.g. if we join a wrong thread).
171349cc55cSDimitry Andric     CHECK(live_.try_emplace(user_id, tid).second);
172349cc55cSDimitry Andric   }
17368d75effSDimitry Andric   tctx->SetCreated(user_id, total_threads_++, detached,
17468d75effSDimitry Andric                    parent_tid, arg);
17568d75effSDimitry Andric   return tid;
17668d75effSDimitry Andric }
17768d75effSDimitry Andric 
RunCallbackForEachThreadLocked(ThreadCallback cb,void * arg)17868d75effSDimitry Andric void ThreadRegistry::RunCallbackForEachThreadLocked(ThreadCallback cb,
17968d75effSDimitry Andric                                                     void *arg) {
18068d75effSDimitry Andric   CheckLocked();
181fe6060f1SDimitry Andric   for (u32 tid = 0; tid < threads_.size(); tid++) {
18268d75effSDimitry Andric     ThreadContextBase *tctx = threads_[tid];
18368d75effSDimitry Andric     if (tctx == 0)
18468d75effSDimitry Andric       continue;
18568d75effSDimitry Andric     cb(tctx, arg);
18668d75effSDimitry Andric   }
18768d75effSDimitry Andric }
18868d75effSDimitry Andric 
FindThread(FindThreadCallback cb,void * arg)18968d75effSDimitry Andric u32 ThreadRegistry::FindThread(FindThreadCallback cb, void *arg) {
190349cc55cSDimitry Andric   ThreadRegistryLock l(this);
191fe6060f1SDimitry Andric   for (u32 tid = 0; tid < threads_.size(); tid++) {
19268d75effSDimitry Andric     ThreadContextBase *tctx = threads_[tid];
19368d75effSDimitry Andric     if (tctx != 0 && cb(tctx, arg))
19468d75effSDimitry Andric       return tctx->tid;
19568d75effSDimitry Andric   }
196fe6060f1SDimitry Andric   return kInvalidTid;
19768d75effSDimitry Andric }
19868d75effSDimitry Andric 
19968d75effSDimitry Andric ThreadContextBase *
FindThreadContextLocked(FindThreadCallback cb,void * arg)20068d75effSDimitry Andric ThreadRegistry::FindThreadContextLocked(FindThreadCallback cb, void *arg) {
20168d75effSDimitry Andric   CheckLocked();
202fe6060f1SDimitry Andric   for (u32 tid = 0; tid < threads_.size(); tid++) {
20368d75effSDimitry Andric     ThreadContextBase *tctx = threads_[tid];
20468d75effSDimitry Andric     if (tctx != 0 && cb(tctx, arg))
20568d75effSDimitry Andric       return tctx;
20668d75effSDimitry Andric   }
20768d75effSDimitry Andric   return 0;
20868d75effSDimitry Andric }
20968d75effSDimitry Andric 
FindThreadContextByOsIdCallback(ThreadContextBase * tctx,void * arg)21068d75effSDimitry Andric static bool FindThreadContextByOsIdCallback(ThreadContextBase *tctx,
21168d75effSDimitry Andric                                             void *arg) {
21268d75effSDimitry Andric   return (tctx->os_id == (uptr)arg && tctx->status != ThreadStatusInvalid &&
21368d75effSDimitry Andric       tctx->status != ThreadStatusDead);
21468d75effSDimitry Andric }
21568d75effSDimitry Andric 
FindThreadContextByOsIDLocked(tid_t os_id)21668d75effSDimitry Andric ThreadContextBase *ThreadRegistry::FindThreadContextByOsIDLocked(tid_t os_id) {
21768d75effSDimitry Andric   return FindThreadContextLocked(FindThreadContextByOsIdCallback,
21868d75effSDimitry Andric                                  (void *)os_id);
21968d75effSDimitry Andric }
22068d75effSDimitry Andric 
SetThreadName(u32 tid,const char * name)22168d75effSDimitry Andric void ThreadRegistry::SetThreadName(u32 tid, const char *name) {
222349cc55cSDimitry Andric   ThreadRegistryLock l(this);
22368d75effSDimitry Andric   ThreadContextBase *tctx = threads_[tid];
22468d75effSDimitry Andric   CHECK_NE(tctx, 0);
22568d75effSDimitry Andric   CHECK_EQ(SANITIZER_FUCHSIA ? ThreadStatusCreated : ThreadStatusRunning,
22668d75effSDimitry Andric            tctx->status);
22768d75effSDimitry Andric   tctx->SetName(name);
22868d75effSDimitry Andric }
22968d75effSDimitry Andric 
SetThreadNameByUserId(uptr user_id,const char * name)23068d75effSDimitry Andric void ThreadRegistry::SetThreadNameByUserId(uptr user_id, const char *name) {
231349cc55cSDimitry Andric   ThreadRegistryLock l(this);
232349cc55cSDimitry Andric   if (const auto *tid = live_.find(user_id))
233349cc55cSDimitry Andric     threads_[tid->second]->SetName(name);
23468d75effSDimitry Andric }
23568d75effSDimitry Andric 
DetachThread(u32 tid,void * arg)23668d75effSDimitry Andric void ThreadRegistry::DetachThread(u32 tid, void *arg) {
237349cc55cSDimitry Andric   ThreadRegistryLock l(this);
23868d75effSDimitry Andric   ThreadContextBase *tctx = threads_[tid];
23968d75effSDimitry Andric   CHECK_NE(tctx, 0);
24068d75effSDimitry Andric   if (tctx->status == ThreadStatusInvalid) {
24168d75effSDimitry Andric     Report("%s: Detach of non-existent thread\n", SanitizerToolName);
24268d75effSDimitry Andric     return;
24368d75effSDimitry Andric   }
24468d75effSDimitry Andric   tctx->OnDetached(arg);
24568d75effSDimitry Andric   if (tctx->status == ThreadStatusFinished) {
246349cc55cSDimitry Andric     if (tctx->user_id)
247349cc55cSDimitry Andric       live_.erase(tctx->user_id);
24868d75effSDimitry Andric     tctx->SetDead();
24968d75effSDimitry Andric     QuarantinePush(tctx);
25068d75effSDimitry Andric   } else {
25168d75effSDimitry Andric     tctx->detached = true;
25268d75effSDimitry Andric   }
25368d75effSDimitry Andric }
25468d75effSDimitry Andric 
JoinThread(u32 tid,void * arg)25568d75effSDimitry Andric void ThreadRegistry::JoinThread(u32 tid, void *arg) {
25668d75effSDimitry Andric   bool destroyed = false;
25768d75effSDimitry Andric   do {
25868d75effSDimitry Andric     {
259349cc55cSDimitry Andric       ThreadRegistryLock l(this);
26068d75effSDimitry Andric       ThreadContextBase *tctx = threads_[tid];
26168d75effSDimitry Andric       CHECK_NE(tctx, 0);
26268d75effSDimitry Andric       if (tctx->status == ThreadStatusInvalid) {
26368d75effSDimitry Andric         Report("%s: Join of non-existent thread\n", SanitizerToolName);
26468d75effSDimitry Andric         return;
26568d75effSDimitry Andric       }
26668d75effSDimitry Andric       if ((destroyed = tctx->GetDestroyed())) {
267349cc55cSDimitry Andric         if (tctx->user_id)
268349cc55cSDimitry Andric           live_.erase(tctx->user_id);
26968d75effSDimitry Andric         tctx->SetJoined(arg);
27068d75effSDimitry Andric         QuarantinePush(tctx);
27168d75effSDimitry Andric       }
27268d75effSDimitry Andric     }
27368d75effSDimitry Andric     if (!destroyed)
27468d75effSDimitry Andric       internal_sched_yield();
27568d75effSDimitry Andric   } while (!destroyed);
27668d75effSDimitry Andric }
27768d75effSDimitry Andric 
27868d75effSDimitry Andric // Normally this is called when the thread is about to exit.  If
27968d75effSDimitry Andric // called in ThreadStatusCreated state, then this thread was never
28068d75effSDimitry Andric // really started.  We just did CreateThread for a prospective new
28168d75effSDimitry Andric // thread before trying to create it, and then failed to actually
28268d75effSDimitry Andric // create it, and so never called StartThread.
FinishThread(u32 tid)283fe6060f1SDimitry Andric ThreadStatus ThreadRegistry::FinishThread(u32 tid) {
284349cc55cSDimitry Andric   ThreadRegistryLock l(this);
28568d75effSDimitry Andric   CHECK_GT(alive_threads_, 0);
28668d75effSDimitry Andric   alive_threads_--;
28768d75effSDimitry Andric   ThreadContextBase *tctx = threads_[tid];
28868d75effSDimitry Andric   CHECK_NE(tctx, 0);
28968d75effSDimitry Andric   bool dead = tctx->detached;
290fe6060f1SDimitry Andric   ThreadStatus prev_status = tctx->status;
29168d75effSDimitry Andric   if (tctx->status == ThreadStatusRunning) {
29268d75effSDimitry Andric     CHECK_GT(running_threads_, 0);
29368d75effSDimitry Andric     running_threads_--;
29468d75effSDimitry Andric   } else {
29568d75effSDimitry Andric     // The thread never really existed.
29668d75effSDimitry Andric     CHECK_EQ(tctx->status, ThreadStatusCreated);
29768d75effSDimitry Andric     dead = true;
29868d75effSDimitry Andric   }
29968d75effSDimitry Andric   tctx->SetFinished();
30068d75effSDimitry Andric   if (dead) {
301349cc55cSDimitry Andric     if (tctx->user_id)
302349cc55cSDimitry Andric       live_.erase(tctx->user_id);
30368d75effSDimitry Andric     tctx->SetDead();
30468d75effSDimitry Andric     QuarantinePush(tctx);
30568d75effSDimitry Andric   }
30668d75effSDimitry Andric   tctx->SetDestroyed();
307fe6060f1SDimitry Andric   return prev_status;
30868d75effSDimitry Andric }
30968d75effSDimitry Andric 
StartThread(u32 tid,tid_t os_id,ThreadType thread_type,void * arg)31068d75effSDimitry Andric void ThreadRegistry::StartThread(u32 tid, tid_t os_id, ThreadType thread_type,
31168d75effSDimitry Andric                                  void *arg) {
312349cc55cSDimitry Andric   ThreadRegistryLock l(this);
31368d75effSDimitry Andric   running_threads_++;
31468d75effSDimitry Andric   ThreadContextBase *tctx = threads_[tid];
31568d75effSDimitry Andric   CHECK_NE(tctx, 0);
31668d75effSDimitry Andric   CHECK_EQ(ThreadStatusCreated, tctx->status);
31768d75effSDimitry Andric   tctx->SetStarted(os_id, thread_type, arg);
31868d75effSDimitry Andric }
31968d75effSDimitry Andric 
QuarantinePush(ThreadContextBase * tctx)32068d75effSDimitry Andric void ThreadRegistry::QuarantinePush(ThreadContextBase *tctx) {
32168d75effSDimitry Andric   if (tctx->tid == 0)
32268d75effSDimitry Andric     return;  // Don't reuse the main thread.  It's a special snowflake.
32368d75effSDimitry Andric   dead_threads_.push_back(tctx);
32468d75effSDimitry Andric   if (dead_threads_.size() <= thread_quarantine_size_)
32568d75effSDimitry Andric     return;
32668d75effSDimitry Andric   tctx = dead_threads_.front();
32768d75effSDimitry Andric   dead_threads_.pop_front();
32868d75effSDimitry Andric   CHECK_EQ(tctx->status, ThreadStatusDead);
32968d75effSDimitry Andric   tctx->Reset();
33068d75effSDimitry Andric   tctx->reuse_count++;
33168d75effSDimitry Andric   if (max_reuse_ > 0 && tctx->reuse_count >= max_reuse_)
33268d75effSDimitry Andric     return;
33368d75effSDimitry Andric   invalid_threads_.push_back(tctx);
33468d75effSDimitry Andric }
33568d75effSDimitry Andric 
QuarantinePop()33668d75effSDimitry Andric ThreadContextBase *ThreadRegistry::QuarantinePop() {
33768d75effSDimitry Andric   if (invalid_threads_.size() == 0)
338*06c3fb27SDimitry Andric     return nullptr;
33968d75effSDimitry Andric   ThreadContextBase *tctx = invalid_threads_.front();
34068d75effSDimitry Andric   invalid_threads_.pop_front();
34168d75effSDimitry Andric   return tctx;
34268d75effSDimitry Andric }
34368d75effSDimitry Andric 
ConsumeThreadUserId(uptr user_id)344349cc55cSDimitry Andric u32 ThreadRegistry::ConsumeThreadUserId(uptr user_id) {
345349cc55cSDimitry Andric   ThreadRegistryLock l(this);
346349cc55cSDimitry Andric   u32 tid;
347349cc55cSDimitry Andric   auto *t = live_.find(user_id);
348349cc55cSDimitry Andric   CHECK(t);
349349cc55cSDimitry Andric   tid = t->second;
350349cc55cSDimitry Andric   live_.erase(t);
351349cc55cSDimitry Andric   auto *tctx = threads_[tid];
352349cc55cSDimitry Andric   CHECK_EQ(tctx->user_id, user_id);
353349cc55cSDimitry Andric   tctx->user_id = 0;
354349cc55cSDimitry Andric   return tid;
355349cc55cSDimitry Andric }
356349cc55cSDimitry Andric 
SetThreadUserId(u32 tid,uptr user_id)35768d75effSDimitry Andric void ThreadRegistry::SetThreadUserId(u32 tid, uptr user_id) {
358349cc55cSDimitry Andric   ThreadRegistryLock l(this);
35968d75effSDimitry Andric   ThreadContextBase *tctx = threads_[tid];
36068d75effSDimitry Andric   CHECK_NE(tctx, 0);
36168d75effSDimitry Andric   CHECK_NE(tctx->status, ThreadStatusInvalid);
36268d75effSDimitry Andric   CHECK_NE(tctx->status, ThreadStatusDead);
36368d75effSDimitry Andric   CHECK_EQ(tctx->user_id, 0);
36468d75effSDimitry Andric   tctx->user_id = user_id;
365349cc55cSDimitry Andric   CHECK(live_.try_emplace(user_id, tctx->tid).second);
36668d75effSDimitry Andric }
36768d75effSDimitry Andric 
OnFork(u32 tid)3680eae32dcSDimitry Andric u32 ThreadRegistry::OnFork(u32 tid) {
3690eae32dcSDimitry Andric   ThreadRegistryLock l(this);
3700eae32dcSDimitry Andric   // We only purge user_id (pthread_t) of live threads because
3710eae32dcSDimitry Andric   // they cause CHECK failures if new threads with matching pthread_t
3720eae32dcSDimitry Andric   // created after fork.
3730eae32dcSDimitry Andric   // Potentially we could purge more info (ThreadContextBase themselves),
3740eae32dcSDimitry Andric   // but it's hard to test and easy to introduce new issues by doing this.
3750eae32dcSDimitry Andric   for (auto *tctx : threads_) {
3760eae32dcSDimitry Andric     if (tctx->tid == tid || !tctx->user_id)
3770eae32dcSDimitry Andric       continue;
3780eae32dcSDimitry Andric     CHECK(live_.erase(tctx->user_id));
3790eae32dcSDimitry Andric     tctx->user_id = 0;
3800eae32dcSDimitry Andric   }
3810eae32dcSDimitry Andric   return alive_threads_;
3820eae32dcSDimitry Andric }
3830eae32dcSDimitry Andric 
38468d75effSDimitry Andric }  // namespace __sanitizer
385