Home | History | Annotate | Line # | Download | only in sanitizer_common
      1 //===-- sanitizer_thread_registry.h -----------------------------*- C++ -*-===//
      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 #ifndef SANITIZER_THREAD_REGISTRY_H
     15 #define SANITIZER_THREAD_REGISTRY_H
     16 
     17 #include "sanitizer_common.h"
     18 #include "sanitizer_dense_map.h"
     19 #include "sanitizer_list.h"
     20 #include "sanitizer_mutex.h"
     21 
     22 namespace __sanitizer {
     23 
     24 enum ThreadStatus {
     25   ThreadStatusInvalid,   // Non-existent thread, data is invalid.
     26   ThreadStatusCreated,   // Created but not yet running.
     27   ThreadStatusRunning,   // The thread is currently running.
     28   ThreadStatusFinished,  // Joinable thread is finished but not yet joined.
     29   ThreadStatusDead       // Joined, but some info is still available.
     30 };
     31 
     32 enum class ThreadType {
     33   Regular, // Normal thread
     34   Worker,  // macOS Grand Central Dispatch (GCD) worker thread
     35   Fiber,   // Fiber
     36 };
     37 
     38 // Generic thread context. Specific sanitizer tools may inherit from it.
     39 // If thread is dead, context may optionally be reused for a new thread.
     40 class ThreadContextBase {
     41  public:
     42   explicit ThreadContextBase(u32 tid);
     43   const u32 tid;  // Thread ID. Main thread should have tid = 0.
     44   u64 unique_id;  // Unique thread ID.
     45   u32 reuse_count;  // Number of times this tid was reused.
     46   tid_t os_id;     // PID (used for reporting).
     47   uptr user_id;   // Some opaque user thread id (e.g. pthread_t).
     48   char name[64];  // As annotated by user.
     49 
     50   ThreadStatus status;
     51   bool detached;
     52   ThreadType thread_type;
     53 
     54   u32 parent_tid;
     55   ThreadContextBase *next;  // For storing thread contexts in a list.
     56 
     57   atomic_uint32_t thread_destroyed; // To address race of Joined vs Finished
     58 
     59   void SetName(const char *new_name);
     60 
     61   void SetDead();
     62   void SetJoined(void *arg);
     63   void SetFinished();
     64   void SetStarted(tid_t _os_id, ThreadType _thread_type, void *arg);
     65   void SetCreated(uptr _user_id, u64 _unique_id, bool _detached,
     66                   u32 _parent_tid, void *arg);
     67   void Reset();
     68 
     69   void SetDestroyed();
     70   bool GetDestroyed();
     71 
     72   // The following methods may be overriden by subclasses.
     73   // Some of them take opaque arg that may be optionally be used
     74   // by subclasses.
     75   virtual void OnDead() {}
     76   virtual void OnJoined(void *arg) {}
     77   virtual void OnFinished() {}
     78   virtual void OnStarted(void *arg) {}
     79   virtual void OnCreated(void *arg) {}
     80   virtual void OnReset() {}
     81   virtual void OnDetached(void *arg) {}
     82 
     83  protected:
     84   ~ThreadContextBase();
     85 };
     86 
     87 typedef ThreadContextBase* (*ThreadContextFactory)(u32 tid);
     88 
     89 class SANITIZER_MUTEX ThreadRegistry {
     90  public:
     91   ThreadRegistry(ThreadContextFactory factory);
     92   ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
     93                  u32 thread_quarantine_size, u32 max_reuse);
     94   void GetNumberOfThreads(uptr *total = nullptr, uptr *running = nullptr,
     95                           uptr *alive = nullptr);
     96   uptr GetMaxAliveThreads();
     97 
     98   void Lock() SANITIZER_ACQUIRE() { mtx_.Lock(); }
     99   void CheckLocked() const SANITIZER_CHECK_LOCKED() { mtx_.CheckLocked(); }
    100   void Unlock() SANITIZER_RELEASE() { mtx_.Unlock(); }
    101 
    102   // Should be guarded by ThreadRegistryLock.
    103   ThreadContextBase *GetThreadLocked(u32 tid) {
    104     return threads_.empty() ? nullptr : threads_[tid];
    105   }
    106 
    107   u32 NumThreadsLocked() const { return threads_.size(); }
    108 
    109   u32 CreateThread(uptr user_id, bool detached, u32 parent_tid, void *arg);
    110 
    111   typedef void (*ThreadCallback)(ThreadContextBase *tctx, void *arg);
    112   // Invokes callback with a specified arg for each thread context.
    113   // Should be guarded by ThreadRegistryLock.
    114   void RunCallbackForEachThreadLocked(ThreadCallback cb, void *arg);
    115 
    116   typedef bool (*FindThreadCallback)(ThreadContextBase *tctx, void *arg);
    117   // Finds a thread using the provided callback. Returns kInvalidTid if no
    118   // thread is found.
    119   u32 FindThread(FindThreadCallback cb, void *arg);
    120   // Should be guarded by ThreadRegistryLock. Return 0 if no thread
    121   // is found.
    122   ThreadContextBase *FindThreadContextLocked(FindThreadCallback cb,
    123                                              void *arg);
    124   ThreadContextBase *FindThreadContextByOsIDLocked(tid_t os_id);
    125 
    126   void SetThreadName(u32 tid, const char *name);
    127   void SetThreadNameByUserId(uptr user_id, const char *name);
    128   void DetachThread(u32 tid, void *arg);
    129   void JoinThread(u32 tid, void *arg);
    130   // Finishes thread and returns previous status.
    131   ThreadStatus FinishThread(u32 tid);
    132   void StartThread(u32 tid, tid_t os_id, ThreadType thread_type, void *arg);
    133   u32 ConsumeThreadUserId(uptr user_id);
    134   void SetThreadUserId(u32 tid, uptr user_id);
    135 
    136   // OnFork must be called in the child process after fork to purge old
    137   // threads that don't exist anymore (except for the current thread tid).
    138   // Returns number of alive threads before fork.
    139   u32 OnFork(u32 tid);
    140 
    141  private:
    142   const ThreadContextFactory context_factory_;
    143   const u32 max_threads_;
    144   const u32 thread_quarantine_size_;
    145   const u32 max_reuse_;
    146 
    147   Mutex mtx_;
    148 
    149   u64 total_threads_;   // Total number of created threads. May be greater than
    150                         // max_threads_ if contexts were reused.
    151   uptr alive_threads_;  // Created or running.
    152   uptr max_alive_threads_;
    153   uptr running_threads_;
    154 
    155   InternalMmapVector<ThreadContextBase *> threads_;
    156   IntrusiveList<ThreadContextBase> dead_threads_;
    157   IntrusiveList<ThreadContextBase> invalid_threads_;
    158   DenseMap<uptr, Tid> live_;
    159 
    160   void QuarantinePush(ThreadContextBase *tctx);
    161   ThreadContextBase *QuarantinePop();
    162 };
    163 
    164 typedef GenericScopedLock<ThreadRegistry> ThreadRegistryLock;
    165 
    166 } // namespace __sanitizer
    167 
    168 #endif // SANITIZER_THREAD_REGISTRY_H
    169