blob: 4f9d3febf00436559b9ac653442a4ebeffff173b [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/task/thread_pool.h"
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/run_loop.h"
#include "base/task/bind_post_task.h"
#include "base/task/single_thread_task_executor.h"
#include "base/task/thread_pool/thread_pool_instance.h"
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "base/test/test_waitable_event.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
TEST(ThreadPool, PostTaskAndReplyWithResultThreeArgs) {
base::test::TaskEnvironment env;
base::RunLoop run_loop;
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, base::BindOnce([]() { return 3; }),
base::OnceCallback<void(int)>(
base::BindLambdaForTesting([&run_loop](int x) {
EXPECT_EQ(x, 3);
run_loop.Quit();
})));
run_loop.Run();
}
TEST(ThreadPool, PostTaskAndReplyWithResultFourArgs) {
base::test::TaskEnvironment env;
base::RunLoop run_loop;
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, /*traits=*/{}, base::BindOnce([]() { return 3; }),
base::OnceCallback<void(int)>(
base::BindLambdaForTesting([&run_loop](int x) {
EXPECT_EQ(x, 3);
run_loop.Quit();
})));
run_loop.Run();
}
TEST(ThreadPool, BindPostTaskFizzlesOnShutdown) {
// Tests that a callback bound to a BLOCK_SHUTDOWN sequence doesn't trigger a
// DCHECK when it's deleted without running.
base::ThreadPoolInstance::CreateAndStartWithDefaultParams(
"BindPostTaskFizzlesOnShutdownTest");
{
// Creating this callback and deleting it after the thread pool is shutdown
// used to trigger a DCHECK in task_tracker because the
// BindPostTaskTrampoline destructor has to delete its state on the sequence
// it's bound to. There is a DCHECK that ensures BLOCK_SHUTDOWN tasks aren't
// posted after shutdown, but BindPostTaskTrampoline uses
// base::ThreadPoolInstance::ScopedFizzleBlockShutdownTasks to avoid
// triggering it.
auto bound_callback =
base::BindPostTask(base::ThreadPool::CreateSequencedTaskRunner(
{TaskShutdownBehavior::BLOCK_SHUTDOWN}),
base::BindOnce([]() { ADD_FAILURE(); }));
base::ThreadPoolInstance::Get()->Shutdown();
}
ThreadPoolInstance::Get()->JoinForTesting();
ThreadPoolInstance::Set(nullptr);
}
TEST(ThreadPool, PostTaskAndReplyFizzlesOnShutdown) {
// Tests that a PostTaskAndReply from a BLOCK_SHUTDOWN sequence doesn't
// trigger a DCHECK when it's not run at shutdown.
base::ThreadPoolInstance::CreateAndStartWithDefaultParams(
"PostTaskAndReplyFizzlesOnShutdown");
{
base::SingleThreadTaskExecutor executor;
auto blocking_task_runner = base::ThreadPool::CreateSequencedTaskRunner(
{TaskShutdownBehavior::BLOCK_SHUTDOWN});
base::RunLoop run_loop;
// The setup that this test is exercising is as follows:
// - A task is posted using PostTaskAndReply from a BLOCK_SHUTDOWN sequence
// to the main thread
// - The task is not run on the main thread
// - Shutdown happens, the ThreadPool is shutdown
// - The main thread destroys its un-run tasks
// - ~PostTaskAndReplyRelay calls `DeleteSoon` to delete its reply's state
// on the sequence it's bound to
// - TaskTracker ensures that no BLOCK_SHUTDOWN tasks can be posted after
// shutdown. ~PostTaskAndReplyRelay avoids triggering this DCHECK by using a
// base::ThreadPoolInstance::ScopedFizzleBlockShutdownTasks
// Post a task to the BLOCK_SHUTDOWN thread pool sequence to setup the test.
base::TestWaitableEvent event;
blocking_task_runner->PostTask(
FROM_HERE, base::BindLambdaForTesting([&]() {
// Enqueue a task whose only purpose is to exit the run loop, ensuring
// the following task is never run.
executor.task_runner()->PostTask(FROM_HERE,
base::BindLambdaForTesting([&]() {
event.Wait();
run_loop.Quit();
}));
// Post the task for which the reply will trigger the `DeleteSoon`
// from `~PostTaskAndReplyRelay`.
executor.task_runner()->PostTaskAndReply(
FROM_HERE, base::BindOnce([]() { ADD_FAILURE(); }),
base::BindOnce([]() { ADD_FAILURE(); }));
event.Signal();
}));
// Run until the first task posted to the SingleThreadTaskExecutor quits the
// run loop, resulting in the `PostTaskAndReply` being queued but not run.
run_loop.Run();
base::ThreadPoolInstance::Get()->Shutdown();
}
ThreadPoolInstance::Get()->JoinForTesting();
ThreadPoolInstance::Set(nullptr);
}
} // namespace base