diff options
author | Dmitry Vyukov <dvyukov@google.com> | 2013-03-19 12:25:48 +0000 |
---|---|---|
committer | Dmitry Vyukov <dvyukov@google.com> | 2013-03-19 12:25:48 +0000 |
commit | ce85e03620f64ce7e4cd0598f2e93090f52a9e99 (patch) | |
tree | 16b43363033c32c949b7b187e5d6cbe23219e1b0 | |
parent | 8e1c769ed84f4d5cf23904dee1abeec6f125f1ac (diff) | |
download | compiler-rt-ce85e03620f64ce7e4cd0598f2e93090f52a9e99.tar.gz compiler-rt-ce85e03620f64ce7e4cd0598f2e93090f52a9e99.tar.bz2 compiler-rt-ce85e03620f64ce7e4cd0598f2e93090f52a9e99.tar.xz |
tsan: flush dead thread info earlier (when another thread is finished rather than new thread is created)
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@177394 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/sanitizer_common/sanitizer_thread_registry.cc | 51 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_thread_registry.h | 8 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_rtl.h | 2 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_rtl_thread.cc | 7 |
4 files changed, 42 insertions, 26 deletions
diff --git a/lib/sanitizer_common/sanitizer_thread_registry.cc b/lib/sanitizer_common/sanitizer_thread_registry.cc index 3d246fee..5b3dacc5 100644 --- a/lib/sanitizer_common/sanitizer_thread_registry.cc +++ b/lib/sanitizer_common/sanitizer_thread_registry.cc @@ -77,11 +77,11 @@ void ThreadContextBase::SetCreated(uptr _user_id, u64 _unique_id, OnCreated(arg); } -void ThreadContextBase::Reset(void *arg) { +void ThreadContextBase::Reset() { status = ThreadStatusInvalid; reuse_count++; SetName(0); - OnReset(arg); + OnReset(); } // ThreadRegistry implementation. @@ -102,6 +102,7 @@ ThreadRegistry::ThreadRegistry(ThreadContextFactory factory, u32 max_threads, threads_ = (ThreadContextBase **)MmapOrDie(max_threads_ * sizeof(threads_[0]), "ThreadRegistry"); dead_threads_.clear(); + invalid_threads_.clear(); } void ThreadRegistry::GetNumberOfThreads(uptr *total, uptr *running, @@ -121,25 +122,18 @@ u32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid, void *arg) { BlockingMutexLock l(&mtx_); u32 tid = kUnknownTid; - ThreadContextBase *tctx = 0; - if (dead_threads_.size() > thread_quarantine_size_ || - n_contexts_ >= max_threads_) { - // Reusing old thread descriptor and tid. - if (dead_threads_.size() == 0) { - Report("%s: Thread limit (%u threads) exceeded. Dying.\n", - SanitizerToolName, max_threads_); - Die(); - } - tctx = dead_threads_.front(); - dead_threads_.pop_front(); - CHECK_EQ(ThreadStatusDead, tctx->status); - tctx->Reset(arg); + ThreadContextBase *tctx = QuarantinePop(); + if (tctx) { tid = tctx->tid; - } else { + } else if (n_contexts_ < max_threads_) { // Allocate new thread context and tid. tid = n_contexts_++; tctx = context_factory_(tid); threads_[tid] = tctx; + } else { + Report("%s: Thread limit (%u threads) exceeded. Dying.\n", + SanitizerToolName, max_threads_); + Die(); } CHECK_NE(tctx, 0); CHECK_NE(tid, kUnknownTid); @@ -207,7 +201,7 @@ void ThreadRegistry::DetachThread(u32 tid) { } if (tctx->status == ThreadStatusFinished) { tctx->SetDead(); - dead_threads_.push_back(tctx); + QuarantinePush(tctx); } else { tctx->detached = true; } @@ -223,7 +217,7 @@ void ThreadRegistry::JoinThread(u32 tid, void *arg) { return; } tctx->SetJoined(arg); - dead_threads_.push_back(tctx); + QuarantinePush(tctx); } void ThreadRegistry::FinishThread(u32 tid) { @@ -239,7 +233,7 @@ void ThreadRegistry::FinishThread(u32 tid) { tctx->SetFinished(); if (tctx->detached) { tctx->SetDead(); - dead_threads_.push_back(tctx); + QuarantinePush(tctx); } } @@ -253,4 +247,23 @@ void ThreadRegistry::StartThread(u32 tid, uptr os_id, void *arg) { tctx->SetStarted(os_id, arg); } +void ThreadRegistry::QuarantinePush(ThreadContextBase *tctx) { + dead_threads_.push_back(tctx); + if (dead_threads_.size() <= thread_quarantine_size_) + return; + tctx = dead_threads_.front(); + dead_threads_.pop_front(); + CHECK_EQ(tctx->status, ThreadStatusDead); + tctx->Reset(); + invalid_threads_.push_back(tctx); +} + +ThreadContextBase *ThreadRegistry::QuarantinePop() { + if (invalid_threads_.size() == 0) + return 0; + ThreadContextBase *tctx = invalid_threads_.front(); + invalid_threads_.pop_front(); + return tctx; +} + } // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_thread_registry.h b/lib/sanitizer_common/sanitizer_thread_registry.h index e2ee8f82..66eb4ca1 100644 --- a/lib/sanitizer_common/sanitizer_thread_registry.h +++ b/lib/sanitizer_common/sanitizer_thread_registry.h @@ -60,7 +60,7 @@ class ThreadContextBase { void SetStarted(uptr _os_id, void *arg); void SetCreated(uptr _user_id, u64 _unique_id, bool _detached, u32 _parent_tid, void *arg); - void Reset(void *arg); + void Reset(); // The following methods may be overriden by subclasses. // Some of them take opaque arg that may be optionally be used @@ -70,7 +70,7 @@ class ThreadContextBase { virtual void OnFinished() {} virtual void OnStarted(void *arg) {} virtual void OnCreated(void *arg) {} - virtual void OnReset(void *arg) {} + virtual void OnReset() {} }; typedef ThreadContextBase* (*ThreadContextFactory)(u32 tid); @@ -133,6 +133,10 @@ class ThreadRegistry { ThreadContextBase **threads_; // Array of thread contexts is leaked. IntrusiveList<ThreadContextBase> dead_threads_; + IntrusiveList<ThreadContextBase> invalid_threads_; + + void QuarantinePush(ThreadContextBase *tctx); + ThreadContextBase *QuarantinePop(); }; typedef GenericScopedLock<ThreadRegistry> ThreadRegistryLock; diff --git a/lib/tsan/rtl/tsan_rtl.h b/lib/tsan/rtl/tsan_rtl.h index 053f24aa..19929def 100644 --- a/lib/tsan/rtl/tsan_rtl.h +++ b/lib/tsan/rtl/tsan_rtl.h @@ -487,7 +487,7 @@ class ThreadContext : public ThreadContextBase { void OnFinished(); void OnStarted(void *arg); void OnCreated(void *arg); - void OnReset(void *arg); + void OnReset(); }; struct RacyStacks { diff --git a/lib/tsan/rtl/tsan_rtl_thread.cc b/lib/tsan/rtl/tsan_rtl_thread.cc index bcb5498c..476b670b 100644 --- a/lib/tsan/rtl/tsan_rtl_thread.cc +++ b/lib/tsan/rtl/tsan_rtl_thread.cc @@ -73,11 +73,10 @@ void ThreadContext::OnCreated(void *arg) { StatInc(args->thr, StatThreadMaxTid); } -void ThreadContext::OnReset(void *arg) { - OnCreatedArgs *args = static_cast<OnCreatedArgs *>(arg); - StatInc(args->thr, StatThreadReuse); +void ThreadContext::OnReset() { sync.Reset(); - DestroyAndFree(dead_info); + if (dead_info) + DestroyAndFree(dead_info); } struct OnStartedArgs { |