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  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
87typedef ThreadContextBase* (*ThreadContextFactory)(u32 tid);
88
89class 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
164typedef GenericScopedLock<ThreadRegistry> ThreadRegistryLock;
165
166} // namespace __sanitizer
167
168#endif // SANITIZER_THREAD_REGISTRY_H
169