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