// Copyright 2017 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/threading/scoped_blocking_call.h" #include "base/lazy_instance.h" #include "base/threading/thread_local.h" namespace base { namespace { LazyInstance<ThreadLocalPointer<internal::BlockingObserver>>::Leaky tls_blocking_observer = LAZY_INSTANCE_INITIALIZER; // Last ScopedBlockingCall instantiated on this thread. LazyInstance<ThreadLocalPointer<ScopedBlockingCall>>::Leaky tls_last_scoped_blocking_call = LAZY_INSTANCE_INITIALIZER; } // namespace ScopedBlockingCall::ScopedBlockingCall(BlockingType blocking_type) : blocking_observer_(tls_blocking_observer.Get().Get()), previous_scoped_blocking_call_(tls_last_scoped_blocking_call.Get().Get()), is_will_block_(blocking_type == BlockingType::WILL_BLOCK || (previous_scoped_blocking_call_ && previous_scoped_blocking_call_->is_will_block_)) { tls_last_scoped_blocking_call.Get().Set(this); if (blocking_observer_) { if (!previous_scoped_blocking_call_) { blocking_observer_->BlockingStarted(blocking_type); } else if (blocking_type == BlockingType::WILL_BLOCK && !previous_scoped_blocking_call_->is_will_block_) { blocking_observer_->BlockingTypeUpgraded(); } } } ScopedBlockingCall::~ScopedBlockingCall() { DCHECK_EQ(this, tls_last_scoped_blocking_call.Get().Get()); tls_last_scoped_blocking_call.Get().Set(previous_scoped_blocking_call_); if (blocking_observer_ && !previous_scoped_blocking_call_) blocking_observer_->BlockingEnded(); } namespace internal { void SetBlockingObserverForCurrentThread(BlockingObserver* blocking_observer) { DCHECK(!tls_blocking_observer.Get().Get()); tls_blocking_observer.Get().Set(blocking_observer); } void ClearBlockingObserverForTesting() { tls_blocking_observer.Get().Set(nullptr); } ScopedClearBlockingObserverForTesting::ScopedClearBlockingObserverForTesting() : blocking_observer_(tls_blocking_observer.Get().Get()) { tls_blocking_observer.Get().Set(nullptr); } ScopedClearBlockingObserverForTesting:: ~ScopedClearBlockingObserverForTesting() { DCHECK(!tls_blocking_observer.Get().Get()); tls_blocking_observer.Get().Set(blocking_observer_); } } // namespace internal } // namespace base