master
  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
 22namespace __sanitizer {
 23
 24enum 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
 32enum 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.
 40class 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  u32 stack_id;
 56  ThreadContextBase *next;  // For storing thread contexts in a list.
 57
 58  atomic_uint32_t thread_destroyed; // To address race of Joined vs Finished
 59
 60  void SetName(const char *new_name);
 61
 62  void SetDead();
 63  void SetJoined(void *arg);
 64  void SetFinished();
 65  void SetStarted(tid_t _os_id, ThreadType _thread_type, void *arg);
 66  void SetCreated(uptr _user_id, u64 _unique_id, bool _detached,
 67                  u32 _parent_tid, u32 _stack_tid, void *arg);
 68  void Reset();
 69
 70  void SetDestroyed();
 71  bool GetDestroyed();
 72
 73  // The following methods may be overriden by subclasses.
 74  // Some of them take opaque arg that may be optionally be used
 75  // by subclasses.
 76  virtual void OnDead() {}
 77  virtual void OnJoined(void *arg) {}
 78  virtual void OnFinished() {}
 79  virtual void OnStarted(void *arg) {}
 80  virtual void OnCreated(void *arg) {}
 81  virtual void OnReset() {}
 82  virtual void OnDetached(void *arg) {}
 83
 84 protected:
 85  ~ThreadContextBase();
 86};
 87
 88typedef ThreadContextBase* (*ThreadContextFactory)(u32 tid);
 89
 90class SANITIZER_MUTEX ThreadRegistry {
 91 public:
 92  ThreadRegistry(ThreadContextFactory factory);
 93  ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
 94                 u32 thread_quarantine_size, u32 max_reuse);
 95  void GetNumberOfThreads(uptr *total = nullptr, uptr *running = nullptr,
 96                          uptr *alive = nullptr);
 97  uptr GetMaxAliveThreads();
 98
 99  void Lock() SANITIZER_ACQUIRE() { mtx_.Lock(); }
100  void CheckLocked() const SANITIZER_CHECK_LOCKED() { mtx_.CheckLocked(); }
101  void Unlock() SANITIZER_RELEASE() { mtx_.Unlock(); }
102
103  // Should be guarded by ThreadRegistryLock.
104  ThreadContextBase *GetThreadLocked(u32 tid) {
105    return tid < threads_.size() ? threads_[tid] : nullptr;
106  }
107
108  u32 NumThreadsLocked() const { return threads_.size(); }
109
110  u32 CreateThread(uptr user_id, bool detached, u32 parent_tid, u32 stack_tid,
111                   void *arg);
112  u32 CreateThread(uptr user_id, bool detached, u32 parent_tid, void *arg) {
113    return CreateThread(user_id, detached, parent_tid, 0, arg);
114  }
115
116  typedef void (*ThreadCallback)(ThreadContextBase *tctx, void *arg);
117  // Invokes callback with a specified arg for each thread context.
118  // Should be guarded by ThreadRegistryLock.
119  void RunCallbackForEachThreadLocked(ThreadCallback cb, void *arg);
120
121  typedef bool (*FindThreadCallback)(ThreadContextBase *tctx, void *arg);
122  // Finds a thread using the provided callback. Returns kInvalidTid if no
123  // thread is found.
124  u32 FindThread(FindThreadCallback cb, void *arg);
125  // Should be guarded by ThreadRegistryLock. Return 0 if no thread
126  // is found.
127  ThreadContextBase *FindThreadContextLocked(FindThreadCallback cb,
128                                             void *arg);
129  ThreadContextBase *FindThreadContextByOsIDLocked(tid_t os_id);
130
131  void SetThreadName(u32 tid, const char *name);
132  void SetThreadNameByUserId(uptr user_id, const char *name);
133  void DetachThread(u32 tid, void *arg);
134  void JoinThread(u32 tid, void *arg);
135  // Finishes thread and returns previous status.
136  ThreadStatus FinishThread(u32 tid);
137  void StartThread(u32 tid, tid_t os_id, ThreadType thread_type, void *arg);
138  u32 ConsumeThreadUserId(uptr user_id);
139  void SetThreadUserId(u32 tid, uptr user_id);
140
141  // OnFork must be called in the child process after fork to purge old
142  // threads that don't exist anymore (except for the current thread tid).
143  // Returns number of alive threads before fork.
144  u32 OnFork(u32 tid);
145
146 private:
147  const ThreadContextFactory context_factory_;
148  const u32 max_threads_;
149  const u32 thread_quarantine_size_;
150  const u32 max_reuse_;
151
152  Mutex mtx_;
153
154  u64 total_threads_;   // Total number of created threads. May be greater than
155                        // max_threads_ if contexts were reused.
156  uptr alive_threads_;  // Created or running.
157  uptr max_alive_threads_;
158  uptr running_threads_;
159
160  InternalMmapVector<ThreadContextBase *> threads_;
161  IntrusiveList<ThreadContextBase> dead_threads_;
162  IntrusiveList<ThreadContextBase> invalid_threads_;
163  DenseMap<uptr, Tid> live_;
164
165  void QuarantinePush(ThreadContextBase *tctx);
166  ThreadContextBase *QuarantinePop();
167};
168
169typedef GenericScopedLock<ThreadRegistry> ThreadRegistryLock;
170
171} // namespace __sanitizer
172
173#endif // SANITIZER_THREAD_REGISTRY_H