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