1 //===-- sanitizer_thread_registry.cc --------------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file is shared between sanitizer tools. 11 // 12 // General thread bookkeeping functionality. 13 //===----------------------------------------------------------------------===// 14 15 #include "sanitizer_thread_registry.h" 16 17 namespace __sanitizer { 18 19 ThreadContextBase::ThreadContextBase(u32 tid) 20 : tid(tid), unique_id(0), os_id(0), user_id(0), status(ThreadStatusInvalid), 21 detached(false), reuse_count(0), parent_tid(0), next(0) { 22 name[0] = '\0'; 23 } 24 25 #ifndef SANITIZER_GO 26 ThreadContextBase::~ThreadContextBase() { 27 CHECK(0); 28 } 29 #endif 30 31 void ThreadContextBase::SetName(const char *new_name) { 32 name[0] = '\0'; 33 if (new_name) { 34 internal_strncpy(name, new_name, sizeof(name)); 35 name[sizeof(name) - 1] = '\0'; 36 } 37 } 38 39 void ThreadContextBase::SetDead() { 40 CHECK(status == ThreadStatusRunning || 41 status == ThreadStatusFinished); 42 status = ThreadStatusDead; 43 user_id = 0; 44 OnDead(); 45 } 46 47 void ThreadContextBase::SetJoined(void *arg) { 48 // FIXME(dvyukov): print message and continue (it's user error). 49 CHECK_EQ(false, detached); 50 CHECK_EQ(ThreadStatusFinished, status); 51 status = ThreadStatusDead; 52 user_id = 0; 53 OnJoined(arg); 54 } 55 56 void ThreadContextBase::SetFinished() { 57 if (!detached) 58 status = ThreadStatusFinished; 59 OnFinished(); 60 } 61 62 void ThreadContextBase::SetStarted(uptr _os_id, void *arg) { 63 status = ThreadStatusRunning; 64 os_id = _os_id; 65 OnStarted(arg); 66 } 67 68 void ThreadContextBase::SetCreated(uptr _user_id, u64 _unique_id, 69 bool _detached, u32 _parent_tid, void *arg) { 70 status = ThreadStatusCreated; 71 user_id = _user_id; 72 unique_id = _unique_id; 73 detached = _detached; 74 // Parent tid makes no sense for the main thread. 75 if (tid != 0) 76 parent_tid = _parent_tid; 77 OnCreated(arg); 78 } 79 80 void ThreadContextBase::Reset(void *arg) { 81 status = ThreadStatusInvalid; 82 reuse_count++; 83 SetName(0); 84 OnReset(arg); 85 } 86 87 // ThreadRegistry implementation. 88 89 const u32 ThreadRegistry::kUnknownTid = -1U; 90 91 ThreadRegistry::ThreadRegistry(ThreadContextFactory factory, u32 max_threads, 92 u32 thread_quarantine_size) 93 : context_factory_(factory), 94 max_threads_(max_threads), 95 thread_quarantine_size_(thread_quarantine_size), 96 mtx_(), 97 n_contexts_(0), 98 total_threads_(0), 99 alive_threads_(0), 100 max_alive_threads_(0), 101 running_threads_(0) { 102 threads_ = (ThreadContextBase **)MmapOrDie(max_threads_ * sizeof(threads_[0]), 103 "ThreadRegistry"); 104 dead_threads_.clear(); 105 } 106 107 void ThreadRegistry::GetNumberOfThreads(uptr *total, uptr *running, 108 uptr *alive) { 109 BlockingMutexLock l(&mtx_); 110 if (total) *total = n_contexts_; 111 if (running) *running = running_threads_; 112 if (alive) *alive = alive_threads_; 113 } 114 115 uptr ThreadRegistry::GetMaxAliveThreads() { 116 BlockingMutexLock l(&mtx_); 117 return max_alive_threads_; 118 } 119 120 u32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid, 121 void *arg) { 122 BlockingMutexLock l(&mtx_); 123 u32 tid = kUnknownTid; 124 ThreadContextBase *tctx = 0; 125 if (dead_threads_.size() > thread_quarantine_size_ || 126 n_contexts_ >= max_threads_) { 127 // Reusing old thread descriptor and tid. 128 if (dead_threads_.size() == 0) { 129 Report("%s: Thread limit (%u threads) exceeded. Dying.\n", 130 SanitizerToolName, max_threads_); 131 Die(); 132 } 133 tctx = dead_threads_.front(); 134 dead_threads_.pop_front(); 135 CHECK_EQ(ThreadStatusDead, tctx->status); 136 tctx->Reset(arg); 137 tid = tctx->tid; 138 } else { 139 // Allocate new thread context and tid. 140 tid = n_contexts_++; 141 tctx = context_factory_(tid); 142 threads_[tid] = tctx; 143 } 144 CHECK_NE(tctx, 0); 145 CHECK_NE(tid, kUnknownTid); 146 CHECK_LT(tid, max_threads_); 147 CHECK_EQ(tctx->status, ThreadStatusInvalid); 148 alive_threads_++; 149 if (max_alive_threads_ < alive_threads_) { 150 max_alive_threads_++; 151 CHECK_EQ(alive_threads_, max_alive_threads_); 152 } 153 tctx->SetCreated(user_id, total_threads_++, detached, 154 parent_tid, arg); 155 return tid; 156 } 157 158 void ThreadRegistry::RunCallbackForEachThreadLocked(ThreadCallback cb, 159 void *arg) { 160 CheckLocked(); 161 for (u32 tid = 0; tid < n_contexts_; tid++) { 162 ThreadContextBase *tctx = threads_[tid]; 163 if (tctx == 0) 164 continue; 165 cb(tctx, arg); 166 } 167 } 168 169 u32 ThreadRegistry::FindThread(FindThreadCallback cb, void *arg) { 170 BlockingMutexLock l(&mtx_); 171 for (u32 tid = 0; tid < n_contexts_; tid++) { 172 ThreadContextBase *tctx = threads_[tid]; 173 if (tctx != 0 && cb(tctx, arg)) 174 return tctx->tid; 175 } 176 return kUnknownTid; 177 } 178 179 ThreadContextBase * 180 ThreadRegistry::FindThreadContextLocked(FindThreadCallback cb, void *arg) { 181 CheckLocked(); 182 for (u32 tid = 0; tid < n_contexts_; tid++) { 183 ThreadContextBase *tctx = threads_[tid]; 184 if (tctx != 0 && cb(tctx, arg)) 185 return tctx; 186 } 187 return 0; 188 } 189 190 void ThreadRegistry::SetThreadName(u32 tid, const char *name) { 191 BlockingMutexLock l(&mtx_); 192 CHECK_LT(tid, n_contexts_); 193 ThreadContextBase *tctx = threads_[tid]; 194 CHECK_NE(tctx, 0); 195 CHECK_EQ(ThreadStatusRunning, tctx->status); 196 tctx->SetName(name); 197 } 198 199 void ThreadRegistry::DetachThread(u32 tid) { 200 BlockingMutexLock l(&mtx_); 201 CHECK_LT(tid, n_contexts_); 202 ThreadContextBase *tctx = threads_[tid]; 203 CHECK_NE(tctx, 0); 204 if (tctx->status == ThreadStatusInvalid) { 205 Report("%s: Detach of non-existent thread\n", SanitizerToolName); 206 return; 207 } 208 if (tctx->status == ThreadStatusFinished) { 209 tctx->SetDead(); 210 dead_threads_.push_back(tctx); 211 } else { 212 tctx->detached = true; 213 } 214 } 215 216 void ThreadRegistry::JoinThread(u32 tid, void *arg) { 217 BlockingMutexLock l(&mtx_); 218 CHECK_LT(tid, n_contexts_); 219 ThreadContextBase *tctx = threads_[tid]; 220 CHECK_NE(tctx, 0); 221 if (tctx->status == ThreadStatusInvalid) { 222 Report("%s: Join of non-existent thread\n", SanitizerToolName); 223 return; 224 } 225 tctx->SetJoined(arg); 226 dead_threads_.push_back(tctx); 227 } 228 229 void ThreadRegistry::FinishThread(u32 tid) { 230 BlockingMutexLock l(&mtx_); 231 CHECK_GT(alive_threads_, 0); 232 alive_threads_--; 233 CHECK_GT(running_threads_, 0); 234 running_threads_--; 235 CHECK_LT(tid, n_contexts_); 236 ThreadContextBase *tctx = threads_[tid]; 237 CHECK_NE(tctx, 0); 238 CHECK_EQ(ThreadStatusRunning, tctx->status); 239 tctx->SetFinished(); 240 if (tctx->detached) { 241 tctx->SetDead(); 242 dead_threads_.push_back(tctx); 243 } 244 } 245 246 void ThreadRegistry::StartThread(u32 tid, uptr os_id, void *arg) { 247 BlockingMutexLock l(&mtx_); 248 running_threads_++; 249 CHECK_LT(tid, n_contexts_); 250 ThreadContextBase *tctx = threads_[tid]; 251 CHECK_NE(tctx, 0); 252 CHECK_EQ(ThreadStatusCreated, tctx->status); 253 tctx->SetStarted(os_id, arg); 254 } 255 256 } // namespace __sanitizer 257