Commit c92dedd2 authored by Francois Doray's avatar Francois Doray Committed by Commit Bot

[threadpool] Support multiple fences active at the same time.

The goal is to support having a BEST_EFFORT execution fence prior to
main message loop start in BrowserMainLoop, and a fence when visible
tabs are loading in //chrome/browser/resource_coordinator. The lifetime
of both fences would overlap. The reason for not having a single fence
is that the first fence is controlled by //content whereas the second
fence is controlled by //chrome (precise tracking of whether a tab is
loading is a //chrome feature).

Bug: 839110, 1016825
Change-Id: Icaceee4cf9e5a1d4c52f9bb91e69e9f8125cee2c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1872807
Commit-Queue: François Doray <fdoray@chromium.org>
Reviewed-by: default avatarGabriel Charette <gab@chromium.org>
Cr-Commit-Position: refs/heads/master@{#711688}
parent 35396dc4
...@@ -350,17 +350,29 @@ void ThreadPoolImpl::JoinForTesting() { ...@@ -350,17 +350,29 @@ void ThreadPoolImpl::JoinForTesting() {
#endif #endif
} }
void ThreadPoolImpl::SetHasFence(bool has_fence) { void ThreadPoolImpl::BeginFence() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_NE(has_fence_, has_fence); ++num_fences_;
has_fence_ = has_fence;
UpdateCanRunPolicy(); UpdateCanRunPolicy();
} }
void ThreadPoolImpl::SetHasBestEffortFence(bool has_best_effort_fence) { void ThreadPoolImpl::EndFence() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_NE(has_best_effort_fence_, has_best_effort_fence); DCHECK_GT(num_fences_, 0);
has_best_effort_fence_ = has_best_effort_fence; --num_fences_;
UpdateCanRunPolicy();
}
void ThreadPoolImpl::BeginBestEffortFence() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
++num_best_effort_fences_;
UpdateCanRunPolicy();
}
void ThreadPoolImpl::EndBestEffortFence() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_GT(num_best_effort_fences_, 0);
--num_best_effort_fences_;
UpdateCanRunPolicy(); UpdateCanRunPolicy();
} }
...@@ -511,14 +523,14 @@ void ThreadPoolImpl::UpdateCanRunPolicy() { ...@@ -511,14 +523,14 @@ void ThreadPoolImpl::UpdateCanRunPolicy() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CanRunPolicy can_run_policy; CanRunPolicy can_run_policy;
if ((!has_fence_ && !has_best_effort_fence_ && if ((num_fences_ == 0 && num_best_effort_fences_ == 0 &&
!has_disable_best_effort_switch_) || !has_disable_best_effort_switch_) ||
task_tracker_->HasShutdownStarted()) { task_tracker_->HasShutdownStarted()) {
can_run_policy = CanRunPolicy::kAll; can_run_policy = CanRunPolicy::kAll;
} else if (has_fence_) { } else if (num_fences_ != 0) {
can_run_policy = CanRunPolicy::kNone; can_run_policy = CanRunPolicy::kNone;
} else { } else {
DCHECK(has_best_effort_fence_ || has_disable_best_effort_switch_); DCHECK(num_best_effort_fences_ > 0 || has_disable_best_effort_switch_);
can_run_policy = CanRunPolicy::kForegroundOnly; can_run_policy = CanRunPolicy::kForegroundOnly;
} }
......
...@@ -79,8 +79,10 @@ class BASE_EXPORT ThreadPoolImpl : public ThreadPoolInstance, ...@@ -79,8 +79,10 @@ class BASE_EXPORT ThreadPoolImpl : public ThreadPoolInstance,
void FlushForTesting() override; void FlushForTesting() override;
void FlushAsyncForTesting(OnceClosure flush_callback) override; void FlushAsyncForTesting(OnceClosure flush_callback) override;
void JoinForTesting() override; void JoinForTesting() override;
void SetHasFence(bool has_fence) override; void BeginFence() override;
void SetHasBestEffortFence(bool has_best_effort_fence) override; void EndFence() override;
void BeginBestEffortFence() override;
void EndBestEffortFence() override;
// TaskExecutor: // TaskExecutor:
bool PostDelayedTask(const Location& from_here, bool PostDelayedTask(const Location& from_here,
...@@ -120,8 +122,8 @@ class BASE_EXPORT ThreadPoolImpl : public ThreadPoolInstance, ...@@ -120,8 +122,8 @@ class BASE_EXPORT ThreadPoolImpl : public ThreadPoolInstance,
void ProcessRipeDelayedTasksForTesting(); void ProcessRipeDelayedTasksForTesting();
private: private:
// Invoked after |has_fence_| or |has_best_effort_fence_| is updated. Sets the // Invoked after |num_fences_| or |num_best_effort_fences_| is updated. Sets
// CanRunPolicy in TaskTracker and wakes up workers as appropriate. // the CanRunPolicy in TaskTracker and wakes up workers as appropriate.
void UpdateCanRunPolicy(); void UpdateCanRunPolicy();
// Returns |traits|, with priority set to TaskPriority::USER_BLOCKING if // Returns |traits|, with priority set to TaskPriority::USER_BLOCKING if
...@@ -170,10 +172,10 @@ class BASE_EXPORT ThreadPoolImpl : public ThreadPoolInstance, ...@@ -170,10 +172,10 @@ class BASE_EXPORT ThreadPoolImpl : public ThreadPoolInstance,
// BEST_EFFORT tasks until shutdown. // BEST_EFFORT tasks until shutdown.
const bool has_disable_best_effort_switch_; const bool has_disable_best_effort_switch_;
// Whether a fence is preventing execution of tasks of any/BEST_EFFORT // Number of fences preventing execution of tasks of any/BEST_EFFORT priority.
// priority. Access controlled by |sequence_checker_|. // Access controlled by |sequence_checker_|.
bool has_fence_ = false; int num_fences_ = 0;
bool has_best_effort_fence_ = false; int num_best_effort_fences_ = 0;
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
// Set once JoinForTesting() has returned. // Set once JoinForTesting() has returned.
......
...@@ -29,24 +29,24 @@ ThreadPoolInstance::InitParams::~InitParams() = default; ...@@ -29,24 +29,24 @@ ThreadPoolInstance::InitParams::~InitParams() = default;
ThreadPoolInstance::ScopedExecutionFence::ScopedExecutionFence() { ThreadPoolInstance::ScopedExecutionFence::ScopedExecutionFence() {
DCHECK(g_thread_pool); DCHECK(g_thread_pool);
g_thread_pool->SetHasFence(true); g_thread_pool->BeginFence();
} }
ThreadPoolInstance::ScopedExecutionFence::~ScopedExecutionFence() { ThreadPoolInstance::ScopedExecutionFence::~ScopedExecutionFence() {
DCHECK(g_thread_pool); DCHECK(g_thread_pool);
g_thread_pool->SetHasFence(false); g_thread_pool->EndFence();
} }
ThreadPoolInstance::ScopedBestEffortExecutionFence:: ThreadPoolInstance::ScopedBestEffortExecutionFence::
ScopedBestEffortExecutionFence() { ScopedBestEffortExecutionFence() {
DCHECK(g_thread_pool); DCHECK(g_thread_pool);
g_thread_pool->SetHasBestEffortFence(true); g_thread_pool->BeginBestEffortFence();
} }
ThreadPoolInstance::ScopedBestEffortExecutionFence:: ThreadPoolInstance::ScopedBestEffortExecutionFence::
~ScopedBestEffortExecutionFence() { ~ScopedBestEffortExecutionFence() {
DCHECK(g_thread_pool); DCHECK(g_thread_pool);
g_thread_pool->SetHasBestEffortFence(false); g_thread_pool->EndBestEffortFence();
} }
#if !defined(OS_NACL) #if !defined(OS_NACL)
......
...@@ -100,11 +100,12 @@ class BASE_EXPORT ThreadPoolInstance { ...@@ -100,11 +100,12 @@ class BASE_EXPORT ThreadPoolInstance {
}; };
// A Scoped(BestEffort)ExecutionFence prevents new tasks of any/BEST_EFFORT // A Scoped(BestEffort)ExecutionFence prevents new tasks of any/BEST_EFFORT
// priority from being scheduled in ThreadPoolInstance within its scope. Upon // priority from being scheduled in ThreadPoolInstance within its scope.
// its destruction, tasks that were preeempted are released. Note: the // Multiple fences can exist at the same time. Upon destruction of all
// constructor of Scoped(BestEffort)ExecutionFence will not wait for currently // Scoped(BestEffort)ExecutionFences, tasks that were preeempted are released.
// running tasks (as they were posted before entering this scope and do not // Note: the constructor of Scoped(BestEffort)ExecutionFence will not wait for
// violate the contract; some of them could be CONTINUE_ON_SHUTDOWN and // currently running tasks (as they were posted before entering this scope and
// do not violate the contract; some of them could be CONTINUE_ON_SHUTDOWN and
// waiting for them to complete is ill-advised). // waiting for them to complete is ill-advised).
class BASE_EXPORT ScopedExecutionFence { class BASE_EXPORT ScopedExecutionFence {
public: public:
...@@ -244,10 +245,12 @@ class BASE_EXPORT ThreadPoolInstance { ...@@ -244,10 +245,12 @@ class BASE_EXPORT ThreadPoolInstance {
virtual int GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated( virtual int GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated(
const TaskTraits& traits) const = 0; const TaskTraits& traits) const = 0;
// Sets whether a fence prevents execution of tasks of any / BEST_EFFORT // Starts/stops a fence that prevents execution of tasks of any / BEST_EFFORT
// priority. // priority.
virtual void SetHasFence(bool can_run) = 0; virtual void BeginFence() = 0;
virtual void SetHasBestEffortFence(bool can_run) = 0; virtual void EndFence() = 0;
virtual void BeginBestEffortFence() = 0;
virtual void EndBestEffortFence() = 0;
}; };
} // namespace base } // namespace base
......
...@@ -12,25 +12,28 @@ namespace base { ...@@ -12,25 +12,28 @@ namespace base {
class ThreadPoolTestHelpers { class ThreadPoolTestHelpers {
public: public:
// Enables/disables an execution fence that prevents tasks from running. // Enables/disables an execution fence that prevents tasks from running.
static void SetThreadPoolExecutionFenceEnabledForTesting(bool has_fence); static void BeginFenceForTesting();
static void EndFenceForTesting();
}; };
// static // static
void ThreadPoolTestHelpers::SetThreadPoolExecutionFenceEnabledForTesting( void ThreadPoolTestHelpers::BeginFenceForTesting() {
bool has_fence) { ThreadPoolInstance::Get()->BeginFence();
ThreadPoolInstance::Get()->SetHasFence(has_fence); }
// static
void ThreadPoolTestHelpers::EndFenceForTesting() {
ThreadPoolInstance::Get()->EndFence();
} }
} // namespace base } // namespace base
void JNI_ThreadPoolTestHelpers_EnableThreadPoolExecutionForTesting( void JNI_ThreadPoolTestHelpers_EnableThreadPoolExecutionForTesting(
JNIEnv* env) { JNIEnv* env) {
base::ThreadPoolTestHelpers:: base::ThreadPoolTestHelpers::EndFenceForTesting();
SetThreadPoolExecutionFenceEnabledForTesting(false);
} }
void JNI_ThreadPoolTestHelpers_DisableThreadPoolExecutionForTesting( void JNI_ThreadPoolTestHelpers_DisableThreadPoolExecutionForTesting(
JNIEnv* env) { JNIEnv* env) {
base::ThreadPoolTestHelpers:: base::ThreadPoolTestHelpers::BeginFenceForTesting();
SetThreadPoolExecutionFenceEnabledForTesting(true); }
} \ No newline at end of file
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