1 // Copyright 2017 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/threading/scoped_blocking_call.h" 6 7 #include "base/lazy_instance.h" 8 #include "base/threading/thread_local.h" 9 10 namespace base { 11 12 namespace { 13 14 LazyInstance<ThreadLocalPointer<internal::BlockingObserver>>::Leaky 15 tls_blocking_observer = LAZY_INSTANCE_INITIALIZER; 16 17 // Last ScopedBlockingCall instantiated on this thread. 18 LazyInstance<ThreadLocalPointer<ScopedBlockingCall>>::Leaky 19 tls_last_scoped_blocking_call = LAZY_INSTANCE_INITIALIZER; 20 21 } // namespace 22 23 ScopedBlockingCall::ScopedBlockingCall(BlockingType blocking_type) 24 : blocking_observer_(tls_blocking_observer.Get().Get()), 25 previous_scoped_blocking_call_(tls_last_scoped_blocking_call.Get().Get()), 26 is_will_block_(blocking_type == BlockingType::WILL_BLOCK || 27 (previous_scoped_blocking_call_ && 28 previous_scoped_blocking_call_->is_will_block_)) { 29 tls_last_scoped_blocking_call.Get().Set(this); 30 31 if (blocking_observer_) { 32 if (!previous_scoped_blocking_call_) { 33 blocking_observer_->BlockingStarted(blocking_type); 34 } else if (blocking_type == BlockingType::WILL_BLOCK && 35 !previous_scoped_blocking_call_->is_will_block_) { 36 blocking_observer_->BlockingTypeUpgraded(); 37 } 38 } 39 } 40 41 ScopedBlockingCall::~ScopedBlockingCall() { 42 DCHECK_EQ(this, tls_last_scoped_blocking_call.Get().Get()); 43 tls_last_scoped_blocking_call.Get().Set(previous_scoped_blocking_call_); 44 if (blocking_observer_ && !previous_scoped_blocking_call_) 45 blocking_observer_->BlockingEnded(); 46 } 47 48 namespace internal { 49 50 void SetBlockingObserverForCurrentThread(BlockingObserver* blocking_observer) { 51 DCHECK(!tls_blocking_observer.Get().Get()); 52 tls_blocking_observer.Get().Set(blocking_observer); 53 } 54 55 void ClearBlockingObserverForTesting() { 56 tls_blocking_observer.Get().Set(nullptr); 57 } 58 59 ScopedClearBlockingObserverForTesting::ScopedClearBlockingObserverForTesting() 60 : blocking_observer_(tls_blocking_observer.Get().Get()) { 61 tls_blocking_observer.Get().Set(nullptr); 62 } 63 64 ScopedClearBlockingObserverForTesting:: 65 ~ScopedClearBlockingObserverForTesting() { 66 DCHECK(!tls_blocking_observer.Get().Get()); 67 tls_blocking_observer.Get().Set(blocking_observer_); 68 } 69 70 } // namespace internal 71 72 } // namespace base 73