Index: lib/asan/asan_interceptors.cc =================================================================== --- lib/asan/asan_interceptors.cc +++ lib/asan/asan_interceptors.cc @@ -293,7 +293,7 @@ atomic_load(¶m->t, memory_order_acquire))) == nullptr) internal_sched_yield(); SetCurrentThread(t); - return t->ThreadStart(GetTid(), ¶m->is_registered); + return t->ThreadStart(internal_gettid(), ¶m->is_registered); } INTERCEPTOR(int, pthread_create, void *thread, Index: lib/asan/asan_mac.cc =================================================================== --- lib/asan/asan_mac.cc +++ lib/asan/asan_mac.cc @@ -138,7 +138,7 @@ t = AsanThread::Create(/* start_routine */ nullptr, /* arg */ nullptr, parent_tid, stack, /* detached */ true); t->Init(); - asanThreadRegistry().StartThread(t->tid(), GetTid(), + asanThreadRegistry().StartThread(t->tid(), internal_gettid(), /* workerthread */ true, 0); SetCurrentThread(t); } Index: lib/asan/asan_thread.cc =================================================================== --- lib/asan/asan_thread.cc +++ lib/asan/asan_thread.cc @@ -389,7 +389,7 @@ AsanThreadContext *context = reinterpret_cast(AsanTSDGet()); if (context && (context->tid == 0)) - context->os_id = GetTid(); + context->os_id = internal_gettid(); } __asan::AsanThread *GetAsanThreadByOsIDLocked(uptr os_id) { @@ -433,6 +433,14 @@ __asan::asanThreadRegistry().Unlock(); } +void LockThreadRegistryRead() { + __asan::asanThreadRegistry().ReadLock(); +} + +void UnlockThreadRegistryRead() { + __asan::asanThreadRegistry().ReadUnlock(); +} + void EnsureMainThreadIDIsCorrect() { __asan::EnsureMainThreadIDIsCorrect(); } Index: lib/asan/asan_win.cc =================================================================== --- lib/asan/asan_win.cc +++ lib/asan/asan_win.cc @@ -133,7 +133,8 @@ static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) { AsanThread *t = (AsanThread*)arg; SetCurrentThread(t); - return t->ThreadStart(GetTid(), /* signal_thread_is_registered */ nullptr); + return t->ThreadStart(internal_gettid(), + /* signal_thread_is_registered */ nullptr); } INTERCEPTOR_WINAPI(DWORD, CreateThread, Index: lib/lsan/lsan.cc =================================================================== --- lib/lsan/lsan.cc +++ lib/lsan/lsan.cc @@ -81,7 +81,7 @@ InitializeThreadRegistry(); u32 tid = ThreadCreate(0, 0, true); CHECK_EQ(tid, 0); - ThreadStart(tid, GetTid()); + ThreadStart(tid, internal_gettid()); SetCurrentThread(tid); if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) Index: lib/lsan/lsan_common.h =================================================================== --- lib/lsan/lsan_common.h +++ lib/lsan/lsan_common.h @@ -161,6 +161,8 @@ // Wrappers for ThreadRegistry access. void LockThreadRegistry(); void UnlockThreadRegistry(); +void LockThreadRegistryRead(); +void UnlockThreadRegistryRead(); bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end, uptr *tls_begin, uptr *tls_end, uptr *cache_begin, uptr *cache_end, DTLS **dtls); Index: lib/lsan/lsan_common.cc =================================================================== --- lib/lsan/lsan_common.cc +++ lib/lsan/lsan_common.cc @@ -439,11 +439,11 @@ EnsureMainThreadIDIsCorrect(); CheckForLeaksParam param; param.success = false; - LockThreadRegistry(); + LockThreadRegistryRead(); LockAllocator(); DoStopTheWorld(CheckForLeaksCallback, ¶m); UnlockAllocator(); - UnlockThreadRegistry(); + UnlockThreadRegistryRead(); if (!param.success) { Report("LeakSanitizer has encountered a fatal error.\n"); Index: lib/lsan/lsan_interceptors.cc =================================================================== --- lib/lsan/lsan_interceptors.cc +++ lib/lsan/lsan_interceptors.cc @@ -248,7 +248,7 @@ while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0) internal_sched_yield(); SetCurrentThread(tid); - ThreadStart(tid, GetTid()); + ThreadStart(tid, internal_gettid()); atomic_store(&p->tid, 0, memory_order_release); return callback(param); } Index: lib/lsan/lsan_thread.cc =================================================================== --- lib/lsan/lsan_thread.cc +++ lib/lsan/lsan_thread.cc @@ -131,7 +131,7 @@ void EnsureMainThreadIDIsCorrect() { if (GetCurrentThread() == 0) - CurrentThreadContext()->os_id = GetTid(); + CurrentThreadContext()->os_id = internal_gettid(); } ///// Interface to the common LSan module. ///// @@ -164,4 +164,12 @@ thread_registry->Unlock(); } +void LockThreadRegistryRead() { + thread_registry->ReadLock(); +} + +void UnlockThreadRegistryRead() { + thread_registry->ReadUnlock(); +} + } // namespace __lsan Index: lib/sanitizer_common/sanitizer_common.h =================================================================== --- lib/sanitizer_common/sanitizer_common.h +++ lib/sanitizer_common/sanitizer_common.h @@ -72,7 +72,6 @@ uptr GetMmapGranularity(); uptr GetMaxVirtualAddress(); // Threads -uptr GetTid(); uptr GetThreadSelf(); void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, uptr *stack_bottom); Index: lib/sanitizer_common/sanitizer_libc.h =================================================================== --- lib/sanitizer_common/sanitizer_libc.h +++ lib/sanitizer_common/sanitizer_libc.h @@ -75,6 +75,7 @@ void NORETURN internal__exit(int exitcode); unsigned int internal_sleep(unsigned int seconds); +uptr internal_gettid(); uptr internal_getpid(); uptr internal_getppid(); Index: lib/sanitizer_common/sanitizer_linux.cc =================================================================== --- lib/sanitizer_common/sanitizer_linux.cc +++ lib/sanitizer_common/sanitizer_linux.cc @@ -370,7 +370,7 @@ return S_ISREG(st.st_mode); } -uptr GetTid() { +uptr internal_gettid() { #if SANITIZER_FREEBSD return (uptr)pthread_self(); #else @@ -520,20 +520,26 @@ } void BlockingMutex::Lock() { - CHECK_EQ(owner_, 0); + CHECK_NE(owner_, internal_gettid()); atomic_uint32_t *m = reinterpret_cast(&opaque_storage_); - if (atomic_exchange(m, MtxLocked, memory_order_acquire) == MtxUnlocked) - return; - while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked) { + if (atomic_exchange(m, MtxLocked, memory_order_acquire) != MtxUnlocked) { + while (atomic_exchange(m, MtxSleeping, memory_order_acquire) + != MtxUnlocked) { #if SANITIZER_FREEBSD - _umtx_op(m, UMTX_OP_WAIT_UINT, MtxSleeping, 0, 0); + _umtx_op(m, UMTX_OP_WAIT_UINT, MtxSleeping, 0, 0); #else - internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAIT, MtxSleeping, 0, 0, 0); + internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAIT, MtxSleeping, + 0, 0, 0); #endif + } } + CHECK_EQ(owner_, 0); + owner_ = internal_gettid(); } void BlockingMutex::Unlock() { + CHECK_EQ(owner_, internal_gettid()); + owner_ = 0; atomic_uint32_t *m = reinterpret_cast(&opaque_storage_); u32 v = atomic_exchange(m, MtxUnlocked, memory_order_relaxed); CHECK_NE(v, MtxUnlocked); @@ -547,6 +553,7 @@ } void BlockingMutex::CheckLocked() { + CHECK_EQ(owner_, internal_gettid()); atomic_uint32_t *m = reinterpret_cast(&opaque_storage_); CHECK_NE(MtxUnlocked, atomic_load(m, memory_order_relaxed)); } Index: lib/sanitizer_common/sanitizer_mac.cc =================================================================== --- lib/sanitizer_common/sanitizer_mac.cc +++ lib/sanitizer_common/sanitizer_mac.cc @@ -252,7 +252,7 @@ return S_ISREG(st.st_mode); } -uptr GetTid() { +uptr internal_gettid() { // FIXME: This can potentially get truncated on 32-bit, where uptr is 4 bytes. uint64_t tid; pthread_threadid_np(nullptr, &tid); Index: lib/sanitizer_common/sanitizer_mutex.h =================================================================== --- lib/sanitizer_common/sanitizer_mutex.h +++ lib/sanitizer_common/sanitizer_mutex.h @@ -86,13 +86,14 @@ void CheckLocked(); private: uptr opaque_storage_[10]; - uptr owner_; // for debugging + uptr owner_; // for debugging, unset for read-only locks }; // Reader-writer spin mutex. class RWMutex { public: RWMutex() { + owner_ = 0; atomic_store(&state_, kUnlocked, memory_order_relaxed); } @@ -101,14 +102,19 @@ } void Lock() { + CHECK_NE(owner_, internal_gettid()); u32 cmp = kUnlocked; - if (atomic_compare_exchange_strong(&state_, &cmp, kWriteLock, - memory_order_acquire)) - return; - LockSlow(); + if (!atomic_compare_exchange_strong(&state_, &cmp, kWriteLock, + memory_order_acquire)) { + LockSlow(); + } + CHECK_EQ(owner_, 0); + owner_ = internal_gettid(); } void Unlock() { + CHECK_EQ(owner_, internal_gettid()); + owner_ = 0; u32 prev = atomic_fetch_sub(&state_, kWriteLock, memory_order_release); DCHECK_NE(prev & kWriteLock, 0); (void)prev; @@ -116,9 +122,9 @@ void ReadLock() { u32 prev = atomic_fetch_add(&state_, kReadLock, memory_order_acquire); - if ((prev & kWriteLock) == 0) - return; - ReadLockSlow(); + if ((prev & kWriteLock) != 0) { + ReadLockSlow(); + } } void ReadUnlock() { @@ -129,11 +135,14 @@ } void CheckLocked() { - CHECK_NE(atomic_load(&state_, memory_order_relaxed), kUnlocked); + u32 state = atomic_load(&state_, memory_order_relaxed); + CHECK((owner_ == internal_gettid()) ? state != kUnlocked + : state == kReadLock); } private: atomic_uint32_t state_; + uptr owner_; // for debugging enum { kUnlocked = 0, Index: lib/sanitizer_common/sanitizer_thread_registry.h =================================================================== --- lib/sanitizer_common/sanitizer_thread_registry.h +++ lib/sanitizer_common/sanitizer_thread_registry.h @@ -87,6 +87,8 @@ void Lock() { mtx_.Lock(); } void CheckLocked() { mtx_.CheckLocked(); } void Unlock() { mtx_.Unlock(); } + void ReadLock() { mtx_.ReadLock(); } + void ReadUnlock() { mtx_.ReadUnlock(); } // Should be guarded by ThreadRegistryLock. ThreadContextBase *GetThreadLocked(u32 tid) { @@ -124,7 +126,7 @@ const u32 thread_quarantine_size_; const u32 max_reuse_; - BlockingMutex mtx_; + RWMutex mtx_; u32 n_contexts_; // Number of created thread contexts, // at most max_threads_. Index: lib/sanitizer_common/sanitizer_thread_registry.cc =================================================================== --- lib/sanitizer_common/sanitizer_thread_registry.cc +++ lib/sanitizer_common/sanitizer_thread_registry.cc @@ -108,20 +108,20 @@ void ThreadRegistry::GetNumberOfThreads(uptr *total, uptr *running, uptr *alive) { - BlockingMutexLock l(&mtx_); + RWMutexReadLock l(&mtx_); if (total) *total = n_contexts_; if (running) *running = running_threads_; if (alive) *alive = alive_threads_; } uptr ThreadRegistry::GetMaxAliveThreads() { - BlockingMutexLock l(&mtx_); + RWMutexReadLock l(&mtx_); return max_alive_threads_; } u32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid, void *arg) { - BlockingMutexLock l(&mtx_); + RWMutexLock l(&mtx_); u32 tid = kUnknownTid; ThreadContextBase *tctx = QuarantinePop(); if (tctx) { @@ -167,7 +167,7 @@ } u32 ThreadRegistry::FindThread(FindThreadCallback cb, void *arg) { - BlockingMutexLock l(&mtx_); + RWMutexLock l(&mtx_); for (u32 tid = 0; tid < n_contexts_; tid++) { ThreadContextBase *tctx = threads_[tid]; if (tctx != 0 && cb(tctx, arg)) @@ -199,7 +199,7 @@ } void ThreadRegistry::SetThreadName(u32 tid, const char *name) { - BlockingMutexLock l(&mtx_); + RWMutexLock l(&mtx_); CHECK_LT(tid, n_contexts_); ThreadContextBase *tctx = threads_[tid]; CHECK_NE(tctx, 0); @@ -208,7 +208,7 @@ } void ThreadRegistry::SetThreadNameByUserId(uptr user_id, const char *name) { - BlockingMutexLock l(&mtx_); + RWMutexLock l(&mtx_); for (u32 tid = 0; tid < n_contexts_; tid++) { ThreadContextBase *tctx = threads_[tid]; if (tctx != 0 && tctx->user_id == user_id && @@ -220,7 +220,7 @@ } void ThreadRegistry::DetachThread(u32 tid, void *arg) { - BlockingMutexLock l(&mtx_); + RWMutexLock l(&mtx_); CHECK_LT(tid, n_contexts_); ThreadContextBase *tctx = threads_[tid]; CHECK_NE(tctx, 0); @@ -238,7 +238,7 @@ } void ThreadRegistry::JoinThread(u32 tid, void *arg) { - BlockingMutexLock l(&mtx_); + RWMutexLock l(&mtx_); CHECK_LT(tid, n_contexts_); ThreadContextBase *tctx = threads_[tid]; CHECK_NE(tctx, 0); @@ -251,7 +251,7 @@ } void ThreadRegistry::FinishThread(u32 tid) { - BlockingMutexLock l(&mtx_); + RWMutexLock l(&mtx_); CHECK_GT(alive_threads_, 0); alive_threads_--; CHECK_GT(running_threads_, 0); @@ -269,7 +269,7 @@ void ThreadRegistry::StartThread(u32 tid, uptr os_id, bool workerthread, void *arg) { - BlockingMutexLock l(&mtx_); + RWMutexLock l(&mtx_); running_threads_++; CHECK_LT(tid, n_contexts_); ThreadContextBase *tctx = threads_[tid]; Index: lib/sanitizer_common/sanitizer_win.cc =================================================================== --- lib/sanitizer_common/sanitizer_win.cc +++ lib/sanitizer_common/sanitizer_win.cc @@ -80,12 +80,12 @@ // In contrast to POSIX, on Windows GetCurrentThreadId() // returns a system-unique identifier. -uptr GetTid() { +uptr internal_gettid() { return GetCurrentThreadId(); } uptr GetThreadSelf() { - return GetTid(); + return internal_gettid(); } #if !SANITIZER_GO Index: lib/sanitizer_common/tests/sanitizer_linux_test.cc =================================================================== --- lib/sanitizer_common/tests/sanitizer_linux_test.cc +++ lib/sanitizer_common/tests/sanitizer_linux_test.cc @@ -94,7 +94,7 @@ void *TidReporterThread(void *argument) { TidReporterArgument *arg = reinterpret_cast(argument); pthread_mutex_lock(&arg->tid_reported_mutex); - arg->reported_tid = GetTid(); + arg->reported_tid = internal_gettid(); pthread_cond_broadcast(&arg->tid_reported_cond); pthread_mutex_unlock(&arg->tid_reported_mutex); @@ -143,7 +143,7 @@ // ThreadLister's output should include the current thread's TID and the TID of // every thread we spawned. TEST_F(ThreadListerTest, ThreadListerSeesAllSpawnedThreads) { - pid_t self_tid = GetTid(); + pid_t self_tid = internal_gettid(); ThreadLister thread_lister(getpid()); std::vector listed_tids = ReadTidsToVector(&thread_lister); ASSERT_TRUE(HasElement(listed_tids, self_tid)); Index: lib/tsan/rtl/tsan_interceptors.cc =================================================================== --- lib/tsan/rtl/tsan_interceptors.cc +++ lib/tsan/rtl/tsan_interceptors.cc @@ -881,7 +881,7 @@ internal_sched_yield(); Processor *proc = ProcCreate(); ProcWire(proc, thr); - ThreadStart(thr, tid, GetTid(), /*workerthread*/ false); + ThreadStart(thr, tid, internal_gettid(), /*workerthread*/ false); atomic_store(&p->tid, 0, memory_order_release); } void *res = callback(param); Index: lib/tsan/rtl/tsan_platform_mac.cc =================================================================== --- lib/tsan/rtl/tsan_platform_mac.cc +++ lib/tsan/rtl/tsan_platform_mac.cc @@ -207,7 +207,7 @@ ThreadState *parent_thread_state = nullptr; // No parent. int tid = ThreadCreate(parent_thread_state, 0, (uptr)thread, true); CHECK_NE(tid, 0); - ThreadStart(thr, tid, GetTid(), /*workerthread*/ true); + ThreadStart(thr, tid, internal_gettid(), /*workerthread*/ true); } } else if (event == PTHREAD_INTROSPECTION_THREAD_TERMINATE) { if (thread == pthread_self()) { Index: lib/tsan/rtl/tsan_rtl.cc =================================================================== --- lib/tsan/rtl/tsan_rtl.cc +++ lib/tsan/rtl/tsan_rtl.cc @@ -381,7 +381,7 @@ // Initialize thread 0. int tid = ThreadCreate(thr, 0, 0, true); CHECK_EQ(tid, 0); - ThreadStart(thr, tid, GetTid(), /*workerthread*/ false); + ThreadStart(thr, tid, internal_gettid(), /*workerthread*/ false); #if TSAN_CONTAINS_UBSAN __ubsan::InitAsPlugin(); #endif @@ -455,18 +455,18 @@ #if !SANITIZER_GO void ForkBefore(ThreadState *thr, uptr pc) { - ctx->thread_registry->Lock(); + ctx->thread_registry->ReadLock(); ctx->report_mtx.Lock(); } void ForkParentAfter(ThreadState *thr, uptr pc) { ctx->report_mtx.Unlock(); - ctx->thread_registry->Unlock(); + ctx->thread_registry->ReadUnlock(); } void ForkChildAfter(ThreadState *thr, uptr pc) { ctx->report_mtx.Unlock(); - ctx->thread_registry->Unlock(); + ctx->thread_registry->ReadUnlock(); uptr nthread = 0; ctx->thread_registry->GetNumberOfThreads(0, 0, &nthread /* alive threads */);