sanitizer_thread_registry.h revision 1.1.1.6
1//===-- sanitizer_thread_registry.h -----------------------------*- C++ -*-===// 2// 3// This file is distributed under the University of Illinois Open Source 4// License. See LICENSE.TXT for details. 5// 6//===----------------------------------------------------------------------===// 7// 8// This file is shared between sanitizer tools. 9// 10// General thread bookkeeping functionality. 11//===----------------------------------------------------------------------===// 12 13#ifndef SANITIZER_THREAD_REGISTRY_H 14#define SANITIZER_THREAD_REGISTRY_H 15 16#include "sanitizer_common.h" 17#include "sanitizer_list.h" 18#include "sanitizer_mutex.h" 19 20namespace __sanitizer { 21 22enum ThreadStatus { 23 ThreadStatusInvalid, // Non-existent thread, data is invalid. 24 ThreadStatusCreated, // Created but not yet running. 25 ThreadStatusRunning, // The thread is currently running. 26 ThreadStatusFinished, // Joinable thread is finished but not yet joined. 27 ThreadStatusDead // Joined, but some info is still available. 28}; 29 30// Generic thread context. Specific sanitizer tools may inherit from it. 31// If thread is dead, context may optionally be reused for a new thread. 32class ThreadContextBase { 33 public: 34 explicit ThreadContextBase(u32 tid); 35 ~ThreadContextBase(); // Should never be called. 36 37 const u32 tid; // Thread ID. Main thread should have tid = 0. 38 u64 unique_id; // Unique thread ID. 39 u32 reuse_count; // Number of times this tid was reused. 40 tid_t os_id; // PID (used for reporting). 41 uptr user_id; // Some opaque user thread id (e.g. pthread_t). 42 char name[64]; // As annotated by user. 43 44 ThreadStatus status; 45 bool detached; 46 bool workerthread; 47 48 u32 parent_tid; 49 ThreadContextBase *next; // For storing thread contexts in a list. 50 51 atomic_uint32_t thread_destroyed; // To address race of Joined vs Finished 52 53 void SetName(const char *new_name); 54 55 void SetDead(); 56 void SetJoined(void *arg); 57 void SetFinished(); 58 void SetStarted(tid_t _os_id, bool _workerthread, void *arg); 59 void SetCreated(uptr _user_id, u64 _unique_id, bool _detached, 60 u32 _parent_tid, void *arg); 61 void Reset(); 62 63 void SetDestroyed(); 64 bool GetDestroyed(); 65 66 // The following methods may be overriden by subclasses. 67 // Some of them take opaque arg that may be optionally be used 68 // by subclasses. 69 virtual void OnDead() {} 70 virtual void OnJoined(void *arg) {} 71 virtual void OnFinished() {} 72 virtual void OnStarted(void *arg) {} 73 virtual void OnCreated(void *arg) {} 74 virtual void OnReset() {} 75 virtual void OnDetached(void *arg) {} 76}; 77 78typedef ThreadContextBase* (*ThreadContextFactory)(u32 tid); 79 80class ThreadRegistry { 81 public: 82 static const u32 kUnknownTid; 83 84 ThreadRegistry(ThreadContextFactory factory, u32 max_threads, 85 u32 thread_quarantine_size, u32 max_reuse = 0); 86 void GetNumberOfThreads(uptr *total = nullptr, uptr *running = nullptr, 87 uptr *alive = nullptr); 88 uptr GetMaxAliveThreads(); 89 90 void Lock() { mtx_.Lock(); } 91 void CheckLocked() { mtx_.CheckLocked(); } 92 void Unlock() { mtx_.Unlock(); } 93 94 // Should be guarded by ThreadRegistryLock. 95 ThreadContextBase *GetThreadLocked(u32 tid) { 96 DCHECK_LT(tid, n_contexts_); 97 return threads_[tid]; 98 } 99 100 u32 CreateThread(uptr user_id, bool detached, u32 parent_tid, void *arg); 101 102 typedef void (*ThreadCallback)(ThreadContextBase *tctx, void *arg); 103 // Invokes callback with a specified arg for each thread context. 104 // Should be guarded by ThreadRegistryLock. 105 void RunCallbackForEachThreadLocked(ThreadCallback cb, void *arg); 106 107 typedef bool (*FindThreadCallback)(ThreadContextBase *tctx, void *arg); 108 // Finds a thread using the provided callback. Returns kUnknownTid if no 109 // thread is found. 110 u32 FindThread(FindThreadCallback cb, void *arg); 111 // Should be guarded by ThreadRegistryLock. Return 0 if no thread 112 // is found. 113 ThreadContextBase *FindThreadContextLocked(FindThreadCallback cb, 114 void *arg); 115 ThreadContextBase *FindThreadContextByOsIDLocked(tid_t os_id); 116 117 void SetThreadName(u32 tid, const char *name); 118 void SetThreadNameByUserId(uptr user_id, const char *name); 119 void DetachThread(u32 tid, void *arg); 120 void JoinThread(u32 tid, void *arg); 121 void FinishThread(u32 tid); 122 void StartThread(u32 tid, tid_t os_id, bool workerthread, void *arg); 123 124 private: 125 const ThreadContextFactory context_factory_; 126 const u32 max_threads_; 127 const u32 thread_quarantine_size_; 128 const u32 max_reuse_; 129 130 BlockingMutex mtx_; 131 132 u32 n_contexts_; // Number of created thread contexts, 133 // at most max_threads_. 134 u64 total_threads_; // Total number of created threads. May be greater than 135 // max_threads_ if contexts were reused. 136 uptr alive_threads_; // Created or running. 137 uptr max_alive_threads_; 138 uptr running_threads_; 139 140 ThreadContextBase **threads_; // Array of thread contexts is leaked. 141 IntrusiveList<ThreadContextBase> dead_threads_; 142 IntrusiveList<ThreadContextBase> invalid_threads_; 143 144 void QuarantinePush(ThreadContextBase *tctx); 145 ThreadContextBase *QuarantinePop(); 146}; 147 148typedef GenericScopedLock<ThreadRegistry> ThreadRegistryLock; 149 150} // namespace __sanitizer 151 152#endif // SANITIZER_THREAD_REGISTRY_H 153