(root)/
gcc-13.2.0/
libsanitizer/
sanitizer_common/
sanitizer_thread_registry.h
       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