1 // Copyright 2020 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/task/thread_pool.h"
6
7 #include "base/functional/bind.h"
8 #include "base/location.h"
9 #include "base/run_loop.h"
10 #include "base/task/bind_post_task.h"
11 #include "base/task/single_thread_task_executor.h"
12 #include "base/task/thread_pool/thread_pool_instance.h"
13 #include "base/test/bind.h"
14 #include "base/test/task_environment.h"
15 #include "base/test/test_waitable_event.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 namespace base {
19
TEST(ThreadPool,PostTaskAndReplyWithResultThreeArgs)20 TEST(ThreadPool, PostTaskAndReplyWithResultThreeArgs) {
21 base::test::TaskEnvironment env;
22
23 base::RunLoop run_loop;
24 base::ThreadPool::PostTaskAndReplyWithResult(
25 FROM_HERE, base::BindOnce([]() { return 3; }),
26 base::OnceCallback<void(int)>(
27 base::BindLambdaForTesting([&run_loop](int x) {
28 EXPECT_EQ(x, 3);
29 run_loop.Quit();
30 })));
31 run_loop.Run();
32 }
33
TEST(ThreadPool,PostTaskAndReplyWithResultFourArgs)34 TEST(ThreadPool, PostTaskAndReplyWithResultFourArgs) {
35 base::test::TaskEnvironment env;
36
37 base::RunLoop run_loop;
38 base::ThreadPool::PostTaskAndReplyWithResult(
39 FROM_HERE, /*traits=*/{}, base::BindOnce([]() { return 3; }),
40 base::OnceCallback<void(int)>(
41 base::BindLambdaForTesting([&run_loop](int x) {
42 EXPECT_EQ(x, 3);
43 run_loop.Quit();
44 })));
45 run_loop.Run();
46 }
47
TEST(ThreadPool,BindPostTaskFizzlesOnShutdown)48 TEST(ThreadPool, BindPostTaskFizzlesOnShutdown) {
49 // Tests that a callback bound to a BLOCK_SHUTDOWN sequence doesn't trigger a
50 // DCHECK when it's deleted without running.
51 base::ThreadPoolInstance::CreateAndStartWithDefaultParams(
52 "BindPostTaskFizzlesOnShutdownTest");
53
54 {
55 // Creating this callback and deleting it after the thread pool is shutdown
56 // used to trigger a DCHECK in task_tracker because the
57 // BindPostTaskTrampoline destructor has to delete its state on the sequence
58 // it's bound to. There is a DCHECK that ensures BLOCK_SHUTDOWN tasks aren't
59 // posted after shutdown, but BindPostTaskTrampoline uses
60 // base::ThreadPoolInstance::ScopedFizzleBlockShutdownTasks to avoid
61 // triggering it.
62 auto bound_callback =
63 base::BindPostTask(base::ThreadPool::CreateSequencedTaskRunner(
64 {TaskShutdownBehavior::BLOCK_SHUTDOWN}),
65 base::BindOnce([]() { ADD_FAILURE(); }));
66 base::ThreadPoolInstance::Get()->Shutdown();
67 }
68
69 ThreadPoolInstance::Get()->JoinForTesting();
70 ThreadPoolInstance::Set(nullptr);
71 }
72
TEST(ThreadPool,PostTaskAndReplyFizzlesOnShutdown)73 TEST(ThreadPool, PostTaskAndReplyFizzlesOnShutdown) {
74 // Tests that a PostTaskAndReply from a BLOCK_SHUTDOWN sequence doesn't
75 // trigger a DCHECK when it's not run at shutdown.
76 base::ThreadPoolInstance::CreateAndStartWithDefaultParams(
77 "PostTaskAndReplyFizzlesOnShutdown");
78
79 {
80 base::SingleThreadTaskExecutor executor;
81 auto blocking_task_runner = base::ThreadPool::CreateSequencedTaskRunner(
82 {TaskShutdownBehavior::BLOCK_SHUTDOWN});
83
84 base::RunLoop run_loop;
85
86 // The setup that this test is exercising is as follows:
87 // - A task is posted using PostTaskAndReply from a BLOCK_SHUTDOWN sequence
88 // to the main thread
89 // - The task is not run on the main thread
90 // - Shutdown happens, the ThreadPool is shutdown
91 // - The main thread destroys its un-run tasks
92 // - ~PostTaskAndReplyRelay calls `DeleteSoon` to delete its reply's state
93 // on the sequence it's bound to
94 // - TaskTracker ensures that no BLOCK_SHUTDOWN tasks can be posted after
95 // shutdown. ~PostTaskAndReplyRelay avoids triggering this DCHECK by using a
96 // base::ThreadPoolInstance::ScopedFizzleBlockShutdownTasks
97
98 // Post a task to the BLOCK_SHUTDOWN thread pool sequence to setup the test.
99 base::TestWaitableEvent event;
100 blocking_task_runner->PostTask(
101 FROM_HERE, base::BindLambdaForTesting([&]() {
102 // Enqueue a task whose only purpose is to exit the run loop, ensuring
103 // the following task is never run.
104 executor.task_runner()->PostTask(FROM_HERE,
105 base::BindLambdaForTesting([&]() {
106 event.Wait();
107 run_loop.Quit();
108 }));
109
110 // Post the task for which the reply will trigger the `DeleteSoon`
111 // from `~PostTaskAndReplyRelay`.
112 executor.task_runner()->PostTaskAndReply(
113 FROM_HERE, base::BindOnce([]() { ADD_FAILURE(); }),
114 base::BindOnce([]() { ADD_FAILURE(); }));
115
116 event.Signal();
117 }));
118
119 // Run until the first task posted to the SingleThreadTaskExecutor quits the
120 // run loop, resulting in the `PostTaskAndReply` being queued but not run.
121 run_loop.Run();
122
123 base::ThreadPoolInstance::Get()->Shutdown();
124 }
125
126 ThreadPoolInstance::Get()->JoinForTesting();
127 ThreadPoolInstance::Set(nullptr);
128 }
129
130 } // namespace base
131