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