1 //===-- sanitizer_thread_registry.cpp -------------------------------------===// 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 #include "sanitizer_thread_registry.h" 15 16 #include "sanitizer_placement_new.h" 17 18 namespace __sanitizer { 19 20 ThreadContextBase::ThreadContextBase(u32 tid) 21 : tid(tid), 22 unique_id(0), 23 reuse_count(), 24 os_id(0), 25 user_id(0), 26 status(ThreadStatusInvalid), 27 detached(false), 28 thread_type(ThreadType::Regular), 29 parent_tid(0), 30 stack_id(0), 31 next(0) { 32 name[0] = '\0'; 33 atomic_store(&thread_destroyed, 0, memory_order_release); 34 } 35 36 ThreadContextBase::~ThreadContextBase() { 37 // ThreadContextBase should never be deleted. 38 CHECK(0); 39 } 40 41 void ThreadContextBase::SetName(const char *new_name) { 42 name[0] = '\0'; 43 if (new_name) { 44 internal_strncpy(name, new_name, sizeof(name)); 45 name[sizeof(name) - 1] = '\0'; 46 } 47 } 48 49 void ThreadContextBase::SetDead() { 50 CHECK(status == ThreadStatusRunning || status == ThreadStatusFinished); 51 status = ThreadStatusDead; 52 user_id = 0; 53 OnDead(); 54 } 55 56 void ThreadContextBase::SetDestroyed() { 57 atomic_store(&thread_destroyed, 1, memory_order_release); 58 } 59 60 bool ThreadContextBase::GetDestroyed() { 61 return !!atomic_load(&thread_destroyed, memory_order_acquire); 62 } 63 64 void ThreadContextBase::SetJoined(void *arg) { 65 // FIXME(dvyukov): print message and continue (it's user error). 66 CHECK_EQ(false, detached); 67 CHECK_EQ(ThreadStatusFinished, status); 68 status = ThreadStatusDead; 69 user_id = 0; 70 OnJoined(arg); 71 } 72 73 void ThreadContextBase::SetFinished() { 74 // ThreadRegistry::FinishThread calls here in ThreadStatusCreated state 75 // for a thread that never actually started. In that case the thread 76 // should go to ThreadStatusFinished regardless of whether it was created 77 // as detached. 78 if (!detached || status == ThreadStatusCreated) 79 status = ThreadStatusFinished; 80 OnFinished(); 81 } 82 83 void ThreadContextBase::SetStarted(tid_t _os_id, ThreadType _thread_type, 84 void *arg) { 85 status = ThreadStatusRunning; 86 os_id = _os_id; 87 thread_type = _thread_type; 88 OnStarted(arg); 89 } 90 91 void ThreadContextBase::SetCreated(uptr _user_id, u64 _unique_id, 92 bool _detached, u32 _parent_tid, 93 u32 _stack_tid, void *arg) { 94 status = ThreadStatusCreated; 95 user_id = _user_id; 96 unique_id = _unique_id; 97 detached = _detached; 98 // Parent tid makes no sense for the main thread. 99 if (tid != kMainTid) { 100 parent_tid = _parent_tid; 101 stack_id = _stack_tid; 102 } 103 OnCreated(arg); 104 } 105 106 void ThreadContextBase::Reset() { 107 status = ThreadStatusInvalid; 108 SetName(0); 109 atomic_store(&thread_destroyed, 0, memory_order_release); 110 OnReset(); 111 } 112 113 // ThreadRegistry implementation. 114 115 ThreadRegistry::ThreadRegistry(ThreadContextFactory factory) 116 : ThreadRegistry(factory, UINT32_MAX, UINT32_MAX, 0) {} 117 118 ThreadRegistry::ThreadRegistry(ThreadContextFactory factory, u32 max_threads, 119 u32 thread_quarantine_size, u32 max_reuse) 120 : context_factory_(factory), 121 max_threads_(max_threads), 122 thread_quarantine_size_(thread_quarantine_size), 123 max_reuse_(max_reuse), 124 mtx_(MutexThreadRegistry), 125 total_threads_(0), 126 alive_threads_(0), 127 max_alive_threads_(0), 128 running_threads_(0) { 129 dead_threads_.clear(); 130 invalid_threads_.clear(); 131 } 132 133 void ThreadRegistry::GetNumberOfThreads(uptr *total, uptr *running, 134 uptr *alive) { 135 ThreadRegistryLock l(this); 136 if (total) 137 *total = threads_.size(); 138 if (running) 139 *running = running_threads_; 140 if (alive) 141 *alive = alive_threads_; 142 } 143 144 uptr ThreadRegistry::GetMaxAliveThreads() { 145 ThreadRegistryLock l(this); 146 return max_alive_threads_; 147 } 148 149 u32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid, 150 u32 stack_tid, void *arg) { 151 ThreadRegistryLock l(this); 152 u32 tid = kInvalidTid; 153 ThreadContextBase *tctx = QuarantinePop(); 154 if (tctx) { 155 tid = tctx->tid; 156 } else if (threads_.size() < max_threads_) { 157 // Allocate new thread context and tid. 158 tid = threads_.size(); 159 tctx = context_factory_(tid); 160 threads_.push_back(tctx); 161 } else { 162 #if !SANITIZER_GO 163 Report("%s: Thread limit (%u threads) exceeded. Dying.\n", 164 SanitizerToolName, max_threads_); 165 #else 166 Printf( 167 "race: limit on %u simultaneously alive goroutines is exceeded," 168 " dying\n", 169 max_threads_); 170 #endif 171 Die(); 172 } 173 CHECK_NE(tctx, 0); 174 CHECK_NE(tid, kInvalidTid); 175 CHECK_LT(tid, max_threads_); 176 CHECK_EQ(tctx->status, ThreadStatusInvalid); 177 alive_threads_++; 178 if (max_alive_threads_ < alive_threads_) { 179 max_alive_threads_++; 180 CHECK_EQ(alive_threads_, max_alive_threads_); 181 } 182 if (user_id) { 183 // Ensure that user_id is unique. If it's not the case we are screwed. 184 // Ignoring this situation may lead to very hard to debug false 185 // positives later (e.g. if we join a wrong thread). 186 CHECK(live_.try_emplace(user_id, tid).second); 187 } 188 tctx->SetCreated(user_id, total_threads_++, detached, parent_tid, stack_tid, 189 arg); 190 return tid; 191 } 192 193 void ThreadRegistry::RunCallbackForEachThreadLocked(ThreadCallback cb, 194 void *arg) { 195 CheckLocked(); 196 for (u32 tid = 0; tid < threads_.size(); tid++) { 197 ThreadContextBase *tctx = threads_[tid]; 198 if (tctx == 0) 199 continue; 200 cb(tctx, arg); 201 } 202 } 203 204 u32 ThreadRegistry::FindThread(FindThreadCallback cb, void *arg) { 205 ThreadRegistryLock l(this); 206 for (u32 tid = 0; tid < threads_.size(); tid++) { 207 ThreadContextBase *tctx = threads_[tid]; 208 if (tctx != 0 && cb(tctx, arg)) 209 return tctx->tid; 210 } 211 return kInvalidTid; 212 } 213 214 ThreadContextBase *ThreadRegistry::FindThreadContextLocked( 215 FindThreadCallback cb, void *arg) { 216 CheckLocked(); 217 for (u32 tid = 0; tid < threads_.size(); tid++) { 218 ThreadContextBase *tctx = threads_[tid]; 219 if (tctx != 0 && cb(tctx, arg)) 220 return tctx; 221 } 222 return 0; 223 } 224 225 static bool FindThreadContextByOsIdCallback(ThreadContextBase *tctx, 226 void *arg) { 227 return (tctx->os_id == (uptr)arg && tctx->status != ThreadStatusInvalid && 228 tctx->status != ThreadStatusDead); 229 } 230 231 ThreadContextBase *ThreadRegistry::FindThreadContextByOsIDLocked(tid_t os_id) { 232 return FindThreadContextLocked(FindThreadContextByOsIdCallback, 233 (void *)os_id); 234 } 235 236 void ThreadRegistry::SetThreadName(u32 tid, const char *name) { 237 ThreadRegistryLock l(this); 238 ThreadContextBase *tctx = threads_[tid]; 239 CHECK_NE(tctx, 0); 240 CHECK_EQ(SANITIZER_FUCHSIA ? ThreadStatusCreated : ThreadStatusRunning, 241 tctx->status); 242 tctx->SetName(name); 243 } 244 245 void ThreadRegistry::SetThreadNameByUserId(uptr user_id, const char *name) { 246 ThreadRegistryLock l(this); 247 if (const auto *tid = live_.find(user_id)) 248 threads_[tid->second]->SetName(name); 249 } 250 251 void ThreadRegistry::DetachThread(u32 tid, void *arg) { 252 ThreadRegistryLock l(this); 253 ThreadContextBase *tctx = threads_[tid]; 254 CHECK_NE(tctx, 0); 255 if (tctx->status == ThreadStatusInvalid) { 256 Report("%s: Detach of non-existent thread\n", SanitizerToolName); 257 return; 258 } 259 tctx->OnDetached(arg); 260 if (tctx->status == ThreadStatusFinished) { 261 if (tctx->user_id) 262 live_.erase(tctx->user_id); 263 tctx->SetDead(); 264 QuarantinePush(tctx); 265 } else { 266 tctx->detached = true; 267 } 268 } 269 270 void ThreadRegistry::JoinThread(u32 tid, void *arg) { 271 bool destroyed = false; 272 do { 273 { 274 ThreadRegistryLock l(this); 275 ThreadContextBase *tctx = threads_[tid]; 276 CHECK_NE(tctx, 0); 277 if (tctx->status == ThreadStatusInvalid) { 278 Report("%s: Join of non-existent thread\n", SanitizerToolName); 279 return; 280 } 281 if ((destroyed = tctx->GetDestroyed())) { 282 if (tctx->user_id) 283 live_.erase(tctx->user_id); 284 tctx->SetJoined(arg); 285 QuarantinePush(tctx); 286 } 287 } 288 if (!destroyed) 289 internal_sched_yield(); 290 } while (!destroyed); 291 } 292 293 // Normally this is called when the thread is about to exit. If 294 // called in ThreadStatusCreated state, then this thread was never 295 // really started. We just did CreateThread for a prospective new 296 // thread before trying to create it, and then failed to actually 297 // create it, and so never called StartThread. 298 ThreadStatus ThreadRegistry::FinishThread(u32 tid) { 299 ThreadRegistryLock l(this); 300 CHECK_GT(alive_threads_, 0); 301 alive_threads_--; 302 ThreadContextBase *tctx = threads_[tid]; 303 CHECK_NE(tctx, 0); 304 bool dead = tctx->detached; 305 ThreadStatus prev_status = tctx->status; 306 if (tctx->status == ThreadStatusRunning) { 307 CHECK_GT(running_threads_, 0); 308 running_threads_--; 309 } else { 310 // The thread never really existed. 311 CHECK_EQ(tctx->status, ThreadStatusCreated); 312 dead = true; 313 } 314 tctx->SetFinished(); 315 if (dead) { 316 if (tctx->user_id) 317 live_.erase(tctx->user_id); 318 tctx->SetDead(); 319 QuarantinePush(tctx); 320 } 321 tctx->SetDestroyed(); 322 return prev_status; 323 } 324 325 void ThreadRegistry::StartThread(u32 tid, tid_t os_id, ThreadType thread_type, 326 void *arg) { 327 ThreadRegistryLock l(this); 328 running_threads_++; 329 ThreadContextBase *tctx = threads_[tid]; 330 CHECK_NE(tctx, 0); 331 CHECK_EQ(ThreadStatusCreated, tctx->status); 332 tctx->SetStarted(os_id, thread_type, arg); 333 } 334 335 void ThreadRegistry::QuarantinePush(ThreadContextBase *tctx) { 336 if (tctx->tid == 0) 337 return; // Don't reuse the main thread. It's a special snowflake. 338 dead_threads_.push_back(tctx); 339 if (dead_threads_.size() <= thread_quarantine_size_) 340 return; 341 tctx = dead_threads_.front(); 342 dead_threads_.pop_front(); 343 CHECK_EQ(tctx->status, ThreadStatusDead); 344 tctx->Reset(); 345 tctx->reuse_count++; 346 if (max_reuse_ > 0 && tctx->reuse_count >= max_reuse_) 347 return; 348 invalid_threads_.push_back(tctx); 349 } 350 351 ThreadContextBase *ThreadRegistry::QuarantinePop() { 352 if (invalid_threads_.size() == 0) 353 return nullptr; 354 ThreadContextBase *tctx = invalid_threads_.front(); 355 invalid_threads_.pop_front(); 356 return tctx; 357 } 358 359 u32 ThreadRegistry::ConsumeThreadUserId(uptr user_id) { 360 ThreadRegistryLock l(this); 361 u32 tid; 362 auto *t = live_.find(user_id); 363 CHECK(t); 364 tid = t->second; 365 live_.erase(t); 366 auto *tctx = threads_[tid]; 367 CHECK_EQ(tctx->user_id, user_id); 368 tctx->user_id = 0; 369 return tid; 370 } 371 372 void ThreadRegistry::SetThreadUserId(u32 tid, uptr user_id) { 373 ThreadRegistryLock l(this); 374 ThreadContextBase *tctx = threads_[tid]; 375 CHECK_NE(tctx, 0); 376 CHECK_NE(tctx->status, ThreadStatusInvalid); 377 CHECK_NE(tctx->status, ThreadStatusDead); 378 CHECK_EQ(tctx->user_id, 0); 379 tctx->user_id = user_id; 380 CHECK(live_.try_emplace(user_id, tctx->tid).second); 381 } 382 383 u32 ThreadRegistry::OnFork(u32 tid) { 384 ThreadRegistryLock l(this); 385 // We only purge user_id (pthread_t) of live threads because 386 // they cause CHECK failures if new threads with matching pthread_t 387 // created after fork. 388 // Potentially we could purge more info (ThreadContextBase themselves), 389 // but it's hard to test and easy to introduce new issues by doing this. 390 for (auto *tctx : threads_) { 391 if (tctx->tid == tid || !tctx->user_id) 392 continue; 393 CHECK(live_.erase(tctx->user_id)); 394 tctx->user_id = 0; 395 } 396 return alive_threads_; 397 } 398 399 } // namespace __sanitizer 400