| // 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 |