sanitizer_thread_registry.cc revision 5cf2c460e96e593b1c772f1b02d3a217f4837fdc
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 17namespace __sanitizer { 18 19ThreadContextBase::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 25ThreadContextBase::~ThreadContextBase() { 26 // ThreadContextBase should never be deleted. 27 CHECK(0); 28} 29 30void ThreadContextBase::SetName(const char *new_name) { 31 name[0] = '\0'; 32 if (new_name) { 33 internal_strncpy(name, new_name, sizeof(name)); 34 name[sizeof(name) - 1] = '\0'; 35 } 36} 37 38void ThreadContextBase::SetDead() { 39 CHECK(status == ThreadStatusRunning || 40 status == ThreadStatusFinished); 41 status = ThreadStatusDead; 42 user_id = 0; 43 OnDead(); 44} 45 46void ThreadContextBase::SetJoined(void *arg) { 47 // FIXME(dvyukov): print message and continue (it's user error). 48 CHECK_EQ(false, detached); 49 CHECK_EQ(ThreadStatusFinished, status); 50 status = ThreadStatusDead; 51 user_id = 0; 52 OnJoined(arg); 53} 54 55void ThreadContextBase::SetFinished() { 56 if (!detached) 57 status = ThreadStatusFinished; 58 OnFinished(); 59} 60 61void ThreadContextBase::SetStarted(uptr _os_id, void *arg) { 62 status = ThreadStatusRunning; 63 os_id = _os_id; 64 OnStarted(arg); 65} 66 67void ThreadContextBase::SetCreated(uptr _user_id, u64 _unique_id, 68 bool _detached, u32 _parent_tid, void *arg) { 69 status = ThreadStatusCreated; 70 user_id = _user_id; 71 unique_id = _unique_id; 72 detached = _detached; 73 // Parent tid makes no sense for the main thread. 74 if (tid != 0) 75 parent_tid = _parent_tid; 76 OnCreated(arg); 77} 78 79void ThreadContextBase::Reset() { 80 status = ThreadStatusInvalid; 81 reuse_count++; 82 SetName(0); 83 OnReset(); 84} 85 86// ThreadRegistry implementation. 87 88const u32 ThreadRegistry::kUnknownTid = ~0U; 89 90ThreadRegistry::ThreadRegistry(ThreadContextFactory factory, u32 max_threads, 91 u32 thread_quarantine_size) 92 : context_factory_(factory), 93 max_threads_(max_threads), 94 thread_quarantine_size_(thread_quarantine_size), 95 mtx_(), 96 n_contexts_(0), 97 total_threads_(0), 98 alive_threads_(0), 99 max_alive_threads_(0), 100 running_threads_(0) { 101 threads_ = (ThreadContextBase **)MmapOrDie(max_threads_ * sizeof(threads_[0]), 102 "ThreadRegistry"); 103 dead_threads_.clear(); 104 invalid_threads_.clear(); 105} 106 107void 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 115uptr ThreadRegistry::GetMaxAliveThreads() { 116 BlockingMutexLock l(&mtx_); 117 return max_alive_threads_; 118} 119 120u32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid, 121 void *arg) { 122 BlockingMutexLock l(&mtx_); 123 u32 tid = kUnknownTid; 124 ThreadContextBase *tctx = QuarantinePop(); 125 if (tctx) { 126 tid = tctx->tid; 127 } else if (n_contexts_ < max_threads_) { 128 // Allocate new thread context and tid. 129 tid = n_contexts_++; 130 tctx = context_factory_(tid); 131 threads_[tid] = tctx; 132 } else { 133 Report("%s: Thread limit (%u threads) exceeded. Dying.\n", 134 SanitizerToolName, max_threads_); 135 Die(); 136 } 137 CHECK_NE(tctx, 0); 138 CHECK_NE(tid, kUnknownTid); 139 CHECK_LT(tid, max_threads_); 140 CHECK_EQ(tctx->status, ThreadStatusInvalid); 141 alive_threads_++; 142 if (max_alive_threads_ < alive_threads_) { 143 max_alive_threads_++; 144 CHECK_EQ(alive_threads_, max_alive_threads_); 145 } 146 tctx->SetCreated(user_id, total_threads_++, detached, 147 parent_tid, arg); 148 return tid; 149} 150 151void ThreadRegistry::RunCallbackForEachThreadLocked(ThreadCallback cb, 152 void *arg) { 153 CheckLocked(); 154 for (u32 tid = 0; tid < n_contexts_; tid++) { 155 ThreadContextBase *tctx = threads_[tid]; 156 if (tctx == 0) 157 continue; 158 cb(tctx, arg); 159 } 160} 161 162u32 ThreadRegistry::FindThread(FindThreadCallback cb, void *arg) { 163 BlockingMutexLock l(&mtx_); 164 for (u32 tid = 0; tid < n_contexts_; tid++) { 165 ThreadContextBase *tctx = threads_[tid]; 166 if (tctx != 0 && cb(tctx, arg)) 167 return tctx->tid; 168 } 169 return kUnknownTid; 170} 171 172ThreadContextBase * 173ThreadRegistry::FindThreadContextLocked(FindThreadCallback cb, void *arg) { 174 CheckLocked(); 175 for (u32 tid = 0; tid < n_contexts_; tid++) { 176 ThreadContextBase *tctx = threads_[tid]; 177 if (tctx != 0 && cb(tctx, arg)) 178 return tctx; 179 } 180 return 0; 181} 182 183static bool FindThreadContextByOsIdCallback(ThreadContextBase *tctx, 184 void *arg) { 185 return (tctx->os_id == (uptr)arg && tctx->status != ThreadStatusInvalid && 186 tctx->status != ThreadStatusDead); 187} 188 189ThreadContextBase *ThreadRegistry::FindThreadContextByOsIDLocked(uptr os_id) { 190 return FindThreadContextLocked(FindThreadContextByOsIdCallback, 191 (void *)os_id); 192} 193 194void ThreadRegistry::SetThreadName(u32 tid, const char *name) { 195 BlockingMutexLock l(&mtx_); 196 CHECK_LT(tid, n_contexts_); 197 ThreadContextBase *tctx = threads_[tid]; 198 CHECK_NE(tctx, 0); 199 CHECK_EQ(ThreadStatusRunning, tctx->status); 200 tctx->SetName(name); 201} 202 203void ThreadRegistry::SetThreadNameByUserId(uptr user_id, const char *name) { 204 BlockingMutexLock l(&mtx_); 205 for (u32 tid = 0; tid < n_contexts_; tid++) { 206 ThreadContextBase *tctx = threads_[tid]; 207 if (tctx != 0 && tctx->user_id == user_id && 208 tctx->status != ThreadStatusInvalid) { 209 tctx->SetName(name); 210 return; 211 } 212 } 213} 214 215void ThreadRegistry::DetachThread(u32 tid) { 216 BlockingMutexLock l(&mtx_); 217 CHECK_LT(tid, n_contexts_); 218 ThreadContextBase *tctx = threads_[tid]; 219 CHECK_NE(tctx, 0); 220 if (tctx->status == ThreadStatusInvalid) { 221 Report("%s: Detach of non-existent thread\n", SanitizerToolName); 222 return; 223 } 224 if (tctx->status == ThreadStatusFinished) { 225 tctx->SetDead(); 226 QuarantinePush(tctx); 227 } else { 228 tctx->detached = true; 229 } 230} 231 232void ThreadRegistry::JoinThread(u32 tid, void *arg) { 233 BlockingMutexLock l(&mtx_); 234 CHECK_LT(tid, n_contexts_); 235 ThreadContextBase *tctx = threads_[tid]; 236 CHECK_NE(tctx, 0); 237 if (tctx->status == ThreadStatusInvalid) { 238 Report("%s: Join of non-existent thread\n", SanitizerToolName); 239 return; 240 } 241 tctx->SetJoined(arg); 242 QuarantinePush(tctx); 243} 244 245void ThreadRegistry::FinishThread(u32 tid) { 246 BlockingMutexLock l(&mtx_); 247 CHECK_GT(alive_threads_, 0); 248 alive_threads_--; 249 CHECK_GT(running_threads_, 0); 250 running_threads_--; 251 CHECK_LT(tid, n_contexts_); 252 ThreadContextBase *tctx = threads_[tid]; 253 CHECK_NE(tctx, 0); 254 CHECK_EQ(ThreadStatusRunning, tctx->status); 255 tctx->SetFinished(); 256 if (tctx->detached) { 257 tctx->SetDead(); 258 QuarantinePush(tctx); 259 } 260} 261 262void ThreadRegistry::StartThread(u32 tid, uptr os_id, void *arg) { 263 BlockingMutexLock l(&mtx_); 264 running_threads_++; 265 CHECK_LT(tid, n_contexts_); 266 ThreadContextBase *tctx = threads_[tid]; 267 CHECK_NE(tctx, 0); 268 CHECK_EQ(ThreadStatusCreated, tctx->status); 269 tctx->SetStarted(os_id, arg); 270} 271 272void ThreadRegistry::QuarantinePush(ThreadContextBase *tctx) { 273 dead_threads_.push_back(tctx); 274 if (dead_threads_.size() <= thread_quarantine_size_) 275 return; 276 tctx = dead_threads_.front(); 277 dead_threads_.pop_front(); 278 CHECK_EQ(tctx->status, ThreadStatusDead); 279 tctx->Reset(); 280 invalid_threads_.push_back(tctx); 281} 282 283ThreadContextBase *ThreadRegistry::QuarantinePop() { 284 if (invalid_threads_.size() == 0) 285 return 0; 286 ThreadContextBase *tctx = invalid_threads_.front(); 287 invalid_threads_.pop_front(); 288 return tctx; 289} 290 291} // namespace __sanitizer 292