Commit 4b9d9276 authored by Gabriel Charette's avatar Gabriel Charette Committed by Commit Bot

[base] Move internal:: portions of scoped_blocking_call.h API to its _internal.h counterpart

This is a prequisite for more additions to ScopedBlockingCall's
internal namespace for the IO jank metric. It was getting too big and
polluting the header. Extracting an _internal.h header is the common
paradigm to work around this.

R=fdoray@chromium.org, olivierli@google.com

Bug: 1064645
Change-Id: I0b3c49222026d2d98db77eb6075efcf17d9f33e2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2102588
Commit-Queue: Kentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarFrançois Doray <fdoray@chromium.org>
Auto-Submit: Gabriel Charette <gab@chromium.org>
Cr-Commit-Position: refs/heads/master@{#753456}
parent 8fa89b04
......@@ -725,6 +725,8 @@ jumbo_component("base") {
"threading/post_task_and_reply_impl.h",
"threading/scoped_blocking_call.cc",
"threading/scoped_blocking_call.h",
"threading/scoped_blocking_call_internal.cc",
"threading/scoped_blocking_call_internal.h",
"threading/scoped_thread_priority.cc",
"threading/scoped_thread_priority.h",
"threading/sequence_bound.h",
......
......@@ -11,7 +11,7 @@
#include "base/task/thread_pool/pooled_parallel_task_runner.h"
#include "base/task/thread_pool/pooled_sequenced_task_runner.h"
#include "base/test/bind_test_util.h"
#include "base/threading/scoped_blocking_call.h"
#include "base/threading/scoped_blocking_call_internal.h"
#include "base/threading/thread_restrictions.h"
#include "testing/gtest/include/gtest/gtest.h"
......
......@@ -30,6 +30,7 @@
#include "base/task/thread_pool/task_tracker.h"
#include "base/threading/platform_thread.h"
#include "base/threading/scoped_blocking_call.h"
#include "base/threading/scoped_blocking_call_internal.h"
#include "base/threading/thread_checker.h"
#include "base/threading/thread_restrictions.h"
#include "base/time/time_override.h"
......
......@@ -6,7 +6,7 @@
#include "base/optional.h"
#include "base/task/thread_pool/task_tracker.h"
#include "base/threading/scoped_blocking_call.h"
#include "base/threading/scoped_blocking_call_internal.h"
#include "base/win/scoped_com_initializer.h"
namespace base {
......
......@@ -24,6 +24,7 @@
#include "base/test/test_timeouts.h"
#include "base/threading/platform_thread.h"
#include "base/threading/scoped_blocking_call.h"
#include "base/threading/scoped_blocking_call_internal.h"
#include "base/threading/simple_thread.h"
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
......
......@@ -5,7 +5,6 @@
#include "base/threading/scoped_blocking_call.h"
#include "base/lazy_instance.h"
#include "base/scoped_clear_last_error.h"
#include "base/threading/thread_local.h"
#include "base/threading/thread_restrictions.h"
#include "base/time/time.h"
......@@ -16,17 +15,6 @@ namespace base {
namespace {
// The first 8 characters of sha1 of "ScopedBlockingCall".
// echo -n "ScopedBlockingCall" | sha1sum
constexpr uint32_t kActivityTrackerId = 0x11be9915;
LazyInstance<ThreadLocalPointer<internal::BlockingObserver>>::Leaky
tls_blocking_observer = LAZY_INSTANCE_INITIALIZER;
// Last ScopedBlockingCall instantiated on this thread.
LazyInstance<ThreadLocalPointer<internal::UncheckedScopedBlockingCall>>::Leaky
tls_last_scoped_blocking_call = LAZY_INSTANCE_INITIALIZER;
#if DCHECK_IS_ON()
// Used to verify that the trace events used in the constructor do not result in
// instantiating a ScopedBlockingCall themselves (which would cause an infinite
......@@ -37,49 +25,6 @@ LazyInstance<ThreadLocalBoolean>::Leaky tls_construction_in_progress =
} // namespace
namespace internal {
UncheckedScopedBlockingCall::UncheckedScopedBlockingCall(
const Location& from_here,
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_)),
scoped_activity_(from_here, 0, kActivityTrackerId, 0) {
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();
}
}
if (scoped_activity_.IsRecorded()) {
// Also record the data for extended crash reporting.
const base::TimeTicks now = base::TimeTicks::Now();
auto& user_data = scoped_activity_.user_data();
user_data.SetUint("timestamp_us", now.since_origin().InMicroseconds());
user_data.SetUint("blocking_type", static_cast<uint64_t>(blocking_type));
}
}
UncheckedScopedBlockingCall::~UncheckedScopedBlockingCall() {
// TLS affects result of GetLastError() on Windows. ScopedClearLastError
// prevents side effect.
base::internal::ScopedClearLastError save_last_error;
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
ScopedBlockingCall::ScopedBlockingCall(const Location& from_here,
BlockingType blocking_type)
: UncheckedScopedBlockingCall(from_here, blocking_type) {
......@@ -127,26 +72,6 @@ ScopedBlockingCallWithBaseSyncPrimitives::
TRACE_EVENT_END0("base", "ScopedBlockingCallWithBaseSyncPrimitives");
}
void SetBlockingObserverForCurrentThread(BlockingObserver* blocking_observer) {
DCHECK(!tls_blocking_observer.Get().Get());
tls_blocking_observer.Get().Set(blocking_observer);
}
void ClearBlockingObserverForCurrentThread() {
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
......@@ -6,9 +6,8 @@
#define BASE_THREADING_SCOPED_BLOCKING_CALL_H
#include "base/base_export.h"
#include "base/debug/activity_tracker.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/threading/scoped_blocking_call_internal.h"
namespace base {
......@@ -28,35 +27,6 @@ enum class BlockingType {
WILL_BLOCK
};
namespace internal {
class BlockingObserver;
// Common implementation class for both ScopedBlockingCall and
// ScopedBlockingCallWithBaseSyncPrimitives without assertions.
class BASE_EXPORT UncheckedScopedBlockingCall {
public:
explicit UncheckedScopedBlockingCall(const Location& from_here,
BlockingType blocking_type);
~UncheckedScopedBlockingCall();
private:
internal::BlockingObserver* const blocking_observer_;
// Previous ScopedBlockingCall instantiated on this thread.
UncheckedScopedBlockingCall* const previous_scoped_blocking_call_;
// Whether the BlockingType of the current thread was WILL_BLOCK after this
// ScopedBlockingCall was instantiated.
const bool is_will_block_;
base::debug::ScopedActivity scoped_activity_;
DISALLOW_COPY_AND_ASSIGN(UncheckedScopedBlockingCall);
};
} // namespace internal
// This class must be instantiated in every scope where a blocking call is made
// and serves as a precise annotation of the scope that may/will block for the
// scheduler. When a ScopedBlockingCall is instantiated, it asserts that
......@@ -123,6 +93,7 @@ class BASE_EXPORT ScopedBlockingCall
~ScopedBlockingCall();
};
// Usage reserved for //base callers.
namespace internal {
// This class must be instantiated in every scope where a sync primitive is
......@@ -138,47 +109,6 @@ class BASE_EXPORT ScopedBlockingCallWithBaseSyncPrimitives
~ScopedBlockingCallWithBaseSyncPrimitives();
};
// Interface for an observer to be informed when a thread enters or exits
// the scope of ScopedBlockingCall objects.
class BASE_EXPORT BlockingObserver {
public:
virtual ~BlockingObserver() = default;
// Invoked when a ScopedBlockingCall is instantiated on the observed thread
// where there wasn't an existing ScopedBlockingCall.
virtual void BlockingStarted(BlockingType blocking_type) = 0;
// Invoked when a WILL_BLOCK ScopedBlockingCall is instantiated on the
// observed thread where there was a MAY_BLOCK ScopedBlockingCall but not a
// WILL_BLOCK ScopedBlockingCall.
virtual void BlockingTypeUpgraded() = 0;
// Invoked when the last ScopedBlockingCall on the observed thread is
// destroyed.
virtual void BlockingEnded() = 0;
};
// Registers |blocking_observer| on the current thread. It is invalid to call
// this on a thread where there is an active ScopedBlockingCall.
BASE_EXPORT void SetBlockingObserverForCurrentThread(
BlockingObserver* blocking_observer);
BASE_EXPORT void ClearBlockingObserverForCurrentThread();
// Unregisters the |blocking_observer| on the current thread within its scope.
// Used in ThreadPool tests to prevent calls to //base sync primitives from
// affecting the thread pool capacity.
class BASE_EXPORT ScopedClearBlockingObserverForTesting {
public:
ScopedClearBlockingObserverForTesting();
~ScopedClearBlockingObserverForTesting();
private:
BlockingObserver* const blocking_observer_;
DISALLOW_COPY_AND_ASSIGN(ScopedClearBlockingObserverForTesting);
};
} // namespace internal
} // namespace base
......
// Copyright 2020 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_internal.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/scoped_clear_last_error.h"
#include "base/threading/scoped_blocking_call.h"
#include "base/threading/thread_local.h"
#include "build/build_config.h"
namespace base {
namespace internal {
namespace {
// The first 8 characters of sha1 of "ScopedBlockingCall".
// echo -n "ScopedBlockingCall" | sha1sum
constexpr uint32_t kActivityTrackerId = 0x11be9915;
LazyInstance<ThreadLocalPointer<internal::BlockingObserver>>::Leaky
tls_blocking_observer = LAZY_INSTANCE_INITIALIZER;
// Last ScopedBlockingCall instantiated on this thread.
LazyInstance<ThreadLocalPointer<internal::UncheckedScopedBlockingCall>>::Leaky
tls_last_scoped_blocking_call = LAZY_INSTANCE_INITIALIZER;
} // namespace
void SetBlockingObserverForCurrentThread(BlockingObserver* blocking_observer) {
DCHECK(!tls_blocking_observer.Get().Get());
tls_blocking_observer.Get().Set(blocking_observer);
}
void ClearBlockingObserverForCurrentThread() {
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_);
}
UncheckedScopedBlockingCall::UncheckedScopedBlockingCall(
const Location& from_here,
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_)),
scoped_activity_(from_here, 0, kActivityTrackerId, 0) {
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();
}
}
if (scoped_activity_.IsRecorded()) {
// Also record the data for extended crash reporting.
const base::TimeTicks now = base::TimeTicks::Now();
auto& user_data = scoped_activity_.user_data();
user_data.SetUint("timestamp_us", now.since_origin().InMicroseconds());
user_data.SetUint("blocking_type", static_cast<uint64_t>(blocking_type));
}
}
UncheckedScopedBlockingCall::~UncheckedScopedBlockingCall() {
// TLS affects result of GetLastError() on Windows. ScopedClearLastError
// prevents side effect.
base::internal::ScopedClearLastError save_last_error;
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
} // namespace base
// Copyright 2020 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.
#ifndef BASE_THREADING_SCOPED_BLOCKING_CALL_INTERNAL_H_
#define BASE_THREADING_SCOPED_BLOCKING_CALL_INTERNAL_H_
#include "base/base_export.h"
#include "base/debug/activity_tracker.h"
#include "base/macros.h"
namespace base {
enum class BlockingType;
// Implementation details of types in scoped_blocking_call.h and classes for a
// few key //base types to observe and react to blocking calls.
namespace internal {
// Interface for an observer to be informed when a thread enters or exits
// the scope of ScopedBlockingCall objects.
class BASE_EXPORT BlockingObserver {
public:
virtual ~BlockingObserver() = default;
// Invoked when a ScopedBlockingCall is instantiated on the observed thread
// where there wasn't an existing ScopedBlockingCall.
virtual void BlockingStarted(BlockingType blocking_type) = 0;
// Invoked when a WILL_BLOCK ScopedBlockingCall is instantiated on the
// observed thread where there was a MAY_BLOCK ScopedBlockingCall but not a
// WILL_BLOCK ScopedBlockingCall.
virtual void BlockingTypeUpgraded() = 0;
// Invoked when the last ScopedBlockingCall on the observed thread is
// destroyed.
virtual void BlockingEnded() = 0;
};
// Registers |blocking_observer| on the current thread. It is invalid to call
// this on a thread where there is an active ScopedBlockingCall.
BASE_EXPORT void SetBlockingObserverForCurrentThread(
BlockingObserver* blocking_observer);
BASE_EXPORT void ClearBlockingObserverForCurrentThread();
// Unregisters the |blocking_observer| on the current thread within its scope.
// Used in ThreadPool tests to prevent calls to //base sync primitives from
// affecting the thread pool capacity.
class BASE_EXPORT ScopedClearBlockingObserverForTesting {
public:
ScopedClearBlockingObserverForTesting();
~ScopedClearBlockingObserverForTesting();
private:
BlockingObserver* const blocking_observer_;
DISALLOW_COPY_AND_ASSIGN(ScopedClearBlockingObserverForTesting);
};
// Common implementation class for both ScopedBlockingCall and
// ScopedBlockingCallWithBaseSyncPrimitives without assertions.
class BASE_EXPORT UncheckedScopedBlockingCall {
public:
explicit UncheckedScopedBlockingCall(const Location& from_here,
BlockingType blocking_type);
~UncheckedScopedBlockingCall();
private:
internal::BlockingObserver* const blocking_observer_;
// Previous ScopedBlockingCall instantiated on this thread.
UncheckedScopedBlockingCall* const previous_scoped_blocking_call_;
// Whether the BlockingType of the current thread was WILL_BLOCK after this
// ScopedBlockingCall was instantiated.
const bool is_will_block_;
base::debug::ScopedActivity scoped_activity_;
DISALLOW_COPY_AND_ASSIGN(UncheckedScopedBlockingCall);
};
} // namespace internal
} // namespace base
#endif // BASE_THREADING_SCOPED_BLOCKING_CALL_INTERNAL_H_
......@@ -8,6 +8,7 @@
#include "base/macros.h"
#include "base/test/gtest_util.h"
#include "base/threading/scoped_blocking_call_internal.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
......
......@@ -7,6 +7,7 @@
#include "base/bind.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/scoped_blocking_call.h"
#include "base/threading/scoped_blocking_call_internal.h"
#include "base/threading/thread.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment