| 342 | } |
| 343 | |
| 344 | void ThreadMgr::AddThread(const pthread_t& pthread_id, const string& name, |
| 345 | const string& category, int64_t tid) { |
| 346 | // These annotations cause TSAN to ignore the synchronization on lock_ |
| 347 | // without causing the subsequent mutations to be treated as data races |
| 348 | // in and of themselves (that's what IGNORE_READS_AND_WRITES does). |
| 349 | // |
| 350 | // Why do we need them here and in SuperviseThread()? TSAN operates by |
| 351 | // observing synchronization events and using them to establish "happens |
| 352 | // before" relationships between threads. Where these relationships are |
| 353 | // not built, shared state access constitutes a data race. The |
| 354 | // synchronization events here, in RemoveThread(), and in |
| 355 | // SuperviseThread() may cause TSAN to establish a "happens before" |
| 356 | // relationship between thread functors, ignoring potential data races. |
| 357 | // The annotations prevent this from happening. |
| 358 | ANNOTATE_IGNORE_SYNC_BEGIN(); |
| 359 | ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN(); |
| 360 | { |
| 361 | // NOTE: Not using EmplaceOrDie() here -- that's because in environments |
| 362 | // where fork() is called after some threads have been spawned, child |
| 363 | // processes will inadvertently inherit the contents of the thread |
| 364 | // registry (i.e. the entries in the thread_categories_ container). |
| 365 | // For some platforms, pthread_t handles for threads in different |
| 366 | // processes might be the same, so using EmplaceOrDie() would induce |
| 367 | // a crash when ThreadMgr::AddThread() is called for a new thread |
| 368 | // in the child process. |
| 369 | // |
| 370 | // TODO(aserbin): maybe, keep the thread_categories_ registry not in a |
| 371 | // global static container, but bind the container with the life cycle |
| 372 | // of some top-level object that uses the ThreadMgr as a singleton. |
| 373 | { |
| 374 | std::lock_guard<decltype(lock_)> l(lock_); |
| 375 | thread_categories_[category][pthread_id] = ThreadDescriptor(category, name, tid); |
| 376 | } |
| 377 | ++threads_running_metric_; |
| 378 | ++threads_started_metric_; |
| 379 | } |
| 380 | ANNOTATE_IGNORE_SYNC_END(); |
| 381 | ANNOTATE_IGNORE_READS_AND_WRITES_END(); |
| 382 | } |
| 383 | |
| 384 | void ThreadMgr::RemoveThread(const pthread_t& pthread_id, const string& category) { |
| 385 | ANNOTATE_IGNORE_SYNC_BEGIN(); |
no test coverage detected