[email protected] | 8c3881ab | 2012-01-04 19:02:38 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
[email protected] | d9ddc96 | 2010-08-24 04:29:56 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
gab | d52c912a | 2017-05-11 04:15:59 | [diff] [blame] | 5 | #include "base/threading/thread_checker.h" |
| 6 | |
dcheng | 093de9b | 2016-04-04 21:25:51 | [diff] [blame] | 7 | #include <memory> |
| 8 | |
fdoray | 59fbfc4 | 2016-08-03 01:53:06 | [diff] [blame] | 9 | #include "base/bind.h" |
| 10 | #include "base/bind_helpers.h" |
avi | 9ceb8b8 | 2015-12-24 21:53:59 | [diff] [blame] | 11 | #include "base/macros.h" |
fdoray | 59fbfc4 | 2016-08-03 01:53:06 | [diff] [blame] | 12 | #include "base/memory/ref_counted.h" |
| 13 | #include "base/sequence_token.h" |
gab | d52c912a | 2017-05-11 04:15:59 | [diff] [blame] | 14 | #include "base/test/gtest_util.h" |
fdoray | 59fbfc4 | 2016-08-03 01:53:06 | [diff] [blame] | 15 | #include "base/test/test_simple_task_runner.h" |
[email protected] | ac9ba8fe | 2010-12-30 18:08:36 | [diff] [blame] | 16 | #include "base/threading/simple_thread.h" |
fdoray | 59fbfc4 | 2016-08-03 01:53:06 | [diff] [blame] | 17 | #include "base/threading/thread_task_runner_handle.h" |
[email protected] | d9ddc96 | 2010-08-24 04:29:56 | [diff] [blame] | 18 | #include "testing/gtest/include/gtest/gtest.h" |
| 19 | |
[email protected] | ce072a7 | 2010-12-31 20:02:16 | [diff] [blame] | 20 | namespace base { |
[email protected] | 8558841 | 2012-06-27 01:39:52 | [diff] [blame] | 21 | namespace { |
| 22 | |
fdoray | 59fbfc4 | 2016-08-03 01:53:06 | [diff] [blame] | 23 | // A thread that runs a callback. |
| 24 | class RunCallbackThread : public SimpleThread { |
[email protected] | d9ddc96 | 2010-08-24 04:29:56 | [diff] [blame] | 25 | public: |
fdoray | 59fbfc4 | 2016-08-03 01:53:06 | [diff] [blame] | 26 | explicit RunCallbackThread(const Closure& callback) |
| 27 | : SimpleThread("RunCallbackThread"), callback_(callback) {} |
[email protected] | 4006448 | 2011-03-03 23:38:51 | [diff] [blame] | 28 | |
[email protected] | d9ddc96 | 2010-08-24 04:29:56 | [diff] [blame] | 29 | private: |
fdoray | 59fbfc4 | 2016-08-03 01:53:06 | [diff] [blame] | 30 | // SimpleThread: |
| 31 | void Run() override { callback_.Run(); } |
| 32 | |
| 33 | const Closure callback_; |
| 34 | |
| 35 | DISALLOW_COPY_AND_ASSIGN(RunCallbackThread); |
[email protected] | d9ddc96 | 2010-08-24 04:29:56 | [diff] [blame] | 36 | }; |
| 37 | |
fdoray | 59fbfc4 | 2016-08-03 01:53:06 | [diff] [blame] | 38 | // Runs a callback on a new thread synchronously. |
| 39 | void RunCallbackOnNewThreadSynchronously(const Closure& callback) { |
| 40 | RunCallbackThread run_callback_thread(callback); |
| 41 | run_callback_thread.Start(); |
| 42 | run_callback_thread.Join(); |
| 43 | } |
[email protected] | d9ddc96 | 2010-08-24 04:29:56 | [diff] [blame] | 44 | |
fdoray | 59fbfc4 | 2016-08-03 01:53:06 | [diff] [blame] | 45 | void ExpectCalledOnValidThread(ThreadCheckerImpl* thread_checker) { |
| 46 | ASSERT_TRUE(thread_checker); |
[email protected] | d9ddc96 | 2010-08-24 04:29:56 | [diff] [blame] | 47 | |
fdoray | 59fbfc4 | 2016-08-03 01:53:06 | [diff] [blame] | 48 | // This should bind |thread_checker| to the current thread if it wasn't |
| 49 | // already bound to a thread. |
| 50 | EXPECT_TRUE(thread_checker->CalledOnValidThread()); |
[email protected] | d9ddc96 | 2010-08-24 04:29:56 | [diff] [blame] | 51 | |
fdoray | 59fbfc4 | 2016-08-03 01:53:06 | [diff] [blame] | 52 | // Since |thread_checker| is now bound to the current thread, another call to |
| 53 | // CalledOnValidThread() should return true. |
| 54 | EXPECT_TRUE(thread_checker->CalledOnValidThread()); |
| 55 | } |
[email protected] | d9ddc96 | 2010-08-24 04:29:56 | [diff] [blame] | 56 | |
fdoray | 59fbfc4 | 2016-08-03 01:53:06 | [diff] [blame] | 57 | void ExpectNotCalledOnValidThread(ThreadCheckerImpl* thread_checker) { |
| 58 | ASSERT_TRUE(thread_checker); |
| 59 | EXPECT_FALSE(thread_checker->CalledOnValidThread()); |
| 60 | } |
[email protected] | d9ddc96 | 2010-08-24 04:29:56 | [diff] [blame] | 61 | |
fdoray | 59fbfc4 | 2016-08-03 01:53:06 | [diff] [blame] | 62 | void ExpectNotCalledOnValidThreadWithSequenceTokenAndThreadTaskRunnerHandle( |
| 63 | ThreadCheckerImpl* thread_checker, |
| 64 | SequenceToken sequence_token) { |
| 65 | ThreadTaskRunnerHandle thread_task_runner_handle( |
kylechar | 96f3eba | 2017-09-25 20:23:56 | [diff] [blame] | 66 | MakeRefCounted<TestSimpleTaskRunner>()); |
fdoray | 59fbfc4 | 2016-08-03 01:53:06 | [diff] [blame] | 67 | ScopedSetSequenceTokenForCurrentThread |
| 68 | scoped_set_sequence_token_for_current_thread(sequence_token); |
| 69 | ExpectNotCalledOnValidThread(thread_checker); |
| 70 | } |
[email protected] | d9ddc96 | 2010-08-24 04:29:56 | [diff] [blame] | 71 | |
[email protected] | 8558841 | 2012-06-27 01:39:52 | [diff] [blame] | 72 | } // namespace |
| 73 | |
fdoray | b339954b | 2016-08-09 21:49:26 | [diff] [blame] | 74 | TEST(ThreadCheckerTest, AllowedSameThreadNoSequenceToken) { |
fdoray | 59fbfc4 | 2016-08-03 01:53:06 | [diff] [blame] | 75 | ThreadCheckerImpl thread_checker; |
| 76 | EXPECT_TRUE(thread_checker.CalledOnValidThread()); |
[email protected] | d9ddc96 | 2010-08-24 04:29:56 | [diff] [blame] | 77 | } |
| 78 | |
fdoray | 59fbfc4 | 2016-08-03 01:53:06 | [diff] [blame] | 79 | TEST(ThreadCheckerTest, |
fdoray | b339954b | 2016-08-09 21:49:26 | [diff] [blame] | 80 | AllowedSameThreadAndSequenceDifferentTasksWithThreadTaskRunnerHandle) { |
fdoray | 59fbfc4 | 2016-08-03 01:53:06 | [diff] [blame] | 81 | ThreadTaskRunnerHandle thread_task_runner_handle( |
kylechar | 96f3eba | 2017-09-25 20:23:56 | [diff] [blame] | 82 | MakeRefCounted<TestSimpleTaskRunner>()); |
fdoray | b339954b | 2016-08-09 21:49:26 | [diff] [blame] | 83 | |
| 84 | std::unique_ptr<ThreadCheckerImpl> thread_checker; |
| 85 | const SequenceToken sequence_token = SequenceToken::Create(); |
| 86 | |
| 87 | { |
| 88 | ScopedSetSequenceTokenForCurrentThread |
| 89 | scoped_set_sequence_token_for_current_thread(sequence_token); |
| 90 | thread_checker.reset(new ThreadCheckerImpl); |
| 91 | } |
| 92 | |
| 93 | { |
| 94 | ScopedSetSequenceTokenForCurrentThread |
| 95 | scoped_set_sequence_token_for_current_thread(sequence_token); |
| 96 | EXPECT_TRUE(thread_checker->CalledOnValidThread()); |
| 97 | } |
| 98 | } |
| 99 | |
| 100 | TEST(ThreadCheckerTest, |
| 101 | AllowedSameThreadSequenceAndTaskNoThreadTaskRunnerHandle) { |
fdoray | 59fbfc4 | 2016-08-03 01:53:06 | [diff] [blame] | 102 | ScopedSetSequenceTokenForCurrentThread |
| 103 | scoped_set_sequence_token_for_current_thread(SequenceToken::Create()); |
| 104 | ThreadCheckerImpl thread_checker; |
| 105 | EXPECT_TRUE(thread_checker.CalledOnValidThread()); |
| 106 | } |
[email protected] | d9ddc96 | 2010-08-24 04:29:56 | [diff] [blame] | 107 | |
fdoray | 59fbfc4 | 2016-08-03 01:53:06 | [diff] [blame] | 108 | TEST(ThreadCheckerTest, |
fdoray | b339954b | 2016-08-09 21:49:26 | [diff] [blame] | 109 | DisallowedSameThreadAndSequenceDifferentTasksNoThreadTaskRunnerHandle) { |
| 110 | std::unique_ptr<ThreadCheckerImpl> thread_checker; |
| 111 | |
| 112 | { |
| 113 | ScopedSetSequenceTokenForCurrentThread |
| 114 | scoped_set_sequence_token_for_current_thread(SequenceToken::Create()); |
| 115 | thread_checker.reset(new ThreadCheckerImpl); |
| 116 | } |
| 117 | |
| 118 | { |
| 119 | ScopedSetSequenceTokenForCurrentThread |
| 120 | scoped_set_sequence_token_for_current_thread(SequenceToken::Create()); |
| 121 | EXPECT_FALSE(thread_checker->CalledOnValidThread()); |
| 122 | } |
fdoray | 59fbfc4 | 2016-08-03 01:53:06 | [diff] [blame] | 123 | } |
[email protected] | d9ddc96 | 2010-08-24 04:29:56 | [diff] [blame] | 124 | |
fdoray | b339954b | 2016-08-09 21:49:26 | [diff] [blame] | 125 | TEST(ThreadCheckerTest, DisallowedDifferentThreadsNoSequenceToken) { |
fdoray | 59fbfc4 | 2016-08-03 01:53:06 | [diff] [blame] | 126 | ThreadCheckerImpl thread_checker; |
| 127 | RunCallbackOnNewThreadSynchronously( |
| 128 | Bind(&ExpectNotCalledOnValidThread, Unretained(&thread_checker))); |
| 129 | } |
| 130 | |
fdoray | b339954b | 2016-08-09 21:49:26 | [diff] [blame] | 131 | TEST(ThreadCheckerTest, DisallowedDifferentThreadsSameSequence) { |
fdoray | 59fbfc4 | 2016-08-03 01:53:06 | [diff] [blame] | 132 | ThreadTaskRunnerHandle thread_task_runner_handle( |
kylechar | 96f3eba | 2017-09-25 20:23:56 | [diff] [blame] | 133 | MakeRefCounted<TestSimpleTaskRunner>()); |
fdoray | 59fbfc4 | 2016-08-03 01:53:06 | [diff] [blame] | 134 | const SequenceToken sequence_token(SequenceToken::Create()); |
| 135 | |
| 136 | ScopedSetSequenceTokenForCurrentThread |
| 137 | scoped_set_sequence_token_for_current_thread(sequence_token); |
| 138 | ThreadCheckerImpl thread_checker; |
| 139 | EXPECT_TRUE(thread_checker.CalledOnValidThread()); |
| 140 | |
| 141 | RunCallbackOnNewThreadSynchronously(Bind( |
| 142 | &ExpectNotCalledOnValidThreadWithSequenceTokenAndThreadTaskRunnerHandle, |
| 143 | Unretained(&thread_checker), sequence_token)); |
| 144 | } |
| 145 | |
fdoray | b339954b | 2016-08-09 21:49:26 | [diff] [blame] | 146 | TEST(ThreadCheckerTest, DisallowedSameThreadDifferentSequence) { |
fdoray | 59fbfc4 | 2016-08-03 01:53:06 | [diff] [blame] | 147 | std::unique_ptr<ThreadCheckerImpl> thread_checker; |
| 148 | |
| 149 | ThreadTaskRunnerHandle thread_task_runner_handle( |
kylechar | 96f3eba | 2017-09-25 20:23:56 | [diff] [blame] | 150 | MakeRefCounted<TestSimpleTaskRunner>()); |
fdoray | 59fbfc4 | 2016-08-03 01:53:06 | [diff] [blame] | 151 | |
| 152 | { |
| 153 | ScopedSetSequenceTokenForCurrentThread |
| 154 | scoped_set_sequence_token_for_current_thread(SequenceToken::Create()); |
| 155 | thread_checker.reset(new ThreadCheckerImpl); |
| 156 | } |
| 157 | |
| 158 | { |
| 159 | // Different SequenceToken. |
| 160 | ScopedSetSequenceTokenForCurrentThread |
| 161 | scoped_set_sequence_token_for_current_thread(SequenceToken::Create()); |
| 162 | EXPECT_FALSE(thread_checker->CalledOnValidThread()); |
| 163 | } |
| 164 | |
| 165 | // No SequenceToken. |
| 166 | EXPECT_FALSE(thread_checker->CalledOnValidThread()); |
[email protected] | d9ddc96 | 2010-08-24 04:29:56 | [diff] [blame] | 167 | } |
| 168 | |
[email protected] | 8ff67251 | 2010-10-07 20:17:33 | [diff] [blame] | 169 | TEST(ThreadCheckerTest, DetachFromThread) { |
fdoray | 59fbfc4 | 2016-08-03 01:53:06 | [diff] [blame] | 170 | ThreadCheckerImpl thread_checker; |
| 171 | thread_checker.DetachFromThread(); |
[email protected] | 8ff67251 | 2010-10-07 20:17:33 | [diff] [blame] | 172 | |
fdoray | 59fbfc4 | 2016-08-03 01:53:06 | [diff] [blame] | 173 | // Verify that CalledOnValidThread() returns true when called on a different |
| 174 | // thread after a call to DetachFromThread(). |
| 175 | RunCallbackOnNewThreadSynchronously( |
| 176 | Bind(&ExpectCalledOnValidThread, Unretained(&thread_checker))); |
[email protected] | 8ff67251 | 2010-10-07 20:17:33 | [diff] [blame] | 177 | |
fdoray | 59fbfc4 | 2016-08-03 01:53:06 | [diff] [blame] | 178 | EXPECT_FALSE(thread_checker.CalledOnValidThread()); |
[email protected] | 8ff67251 | 2010-10-07 20:17:33 | [diff] [blame] | 179 | } |
| 180 | |
fdoray | 59fbfc4 | 2016-08-03 01:53:06 | [diff] [blame] | 181 | TEST(ThreadCheckerTest, DetachFromThreadWithSequenceToken) { |
| 182 | ThreadTaskRunnerHandle thread_task_runner_handle( |
kylechar | 96f3eba | 2017-09-25 20:23:56 | [diff] [blame] | 183 | MakeRefCounted<TestSimpleTaskRunner>()); |
fdoray | 59fbfc4 | 2016-08-03 01:53:06 | [diff] [blame] | 184 | ScopedSetSequenceTokenForCurrentThread |
| 185 | scoped_set_sequence_token_for_current_thread(SequenceToken::Create()); |
| 186 | ThreadCheckerImpl thread_checker; |
| 187 | thread_checker.DetachFromThread(); |
[email protected] | d9ddc96 | 2010-08-24 04:29:56 | [diff] [blame] | 188 | |
fdoray | 59fbfc4 | 2016-08-03 01:53:06 | [diff] [blame] | 189 | // Verify that CalledOnValidThread() returns true when called on a different |
| 190 | // thread after a call to DetachFromThread(). |
| 191 | RunCallbackOnNewThreadSynchronously( |
| 192 | Bind(&ExpectCalledOnValidThread, Unretained(&thread_checker))); |
[email protected] | d9ddc96 | 2010-08-24 04:29:56 | [diff] [blame] | 193 | |
fdoray | 59fbfc4 | 2016-08-03 01:53:06 | [diff] [blame] | 194 | EXPECT_FALSE(thread_checker.CalledOnValidThread()); |
[email protected] | d9ddc96 | 2010-08-24 04:29:56 | [diff] [blame] | 195 | } |
| 196 | |
gab | d52c912a | 2017-05-11 04:15:59 | [diff] [blame] | 197 | namespace { |
| 198 | |
| 199 | // This fixture is a helper for unit testing the thread checker macros as it is |
| 200 | // not possible to inline ExpectDeathOnOtherThread() and |
| 201 | // ExpectNoDeathOnOtherThreadAfterDetach() as lambdas since binding |
| 202 | // |Unretained(&my_sequence_checker)| wouldn't compile on non-dcheck builds |
| 203 | // where it won't be defined. |
| 204 | class ThreadCheckerMacroTest : public testing::Test { |
| 205 | public: |
| 206 | ThreadCheckerMacroTest() = default; |
| 207 | |
| 208 | void ExpectDeathOnOtherThread() { |
| 209 | #if DCHECK_IS_ON() |
| 210 | EXPECT_DCHECK_DEATH({ DCHECK_CALLED_ON_VALID_THREAD(my_thread_checker_); }); |
| 211 | #else |
| 212 | // Happily no-ops on non-dcheck builds. |
| 213 | DCHECK_CALLED_ON_VALID_THREAD(my_thread_checker_); |
| 214 | #endif |
| 215 | } |
| 216 | |
| 217 | void ExpectNoDeathOnOtherThreadAfterDetach() { |
| 218 | DCHECK_CALLED_ON_VALID_THREAD(my_thread_checker_); |
Olga Sharonova | b2c3af62 | 2017-11-17 20:48:31 | [diff] [blame] | 219 | DCHECK_CALLED_ON_VALID_THREAD(my_thread_checker_) |
| 220 | << "Make sure it compiles when DCHECK is off"; |
gab | d52c912a | 2017-05-11 04:15:59 | [diff] [blame] | 221 | } |
| 222 | |
| 223 | protected: |
| 224 | THREAD_CHECKER(my_thread_checker_); |
| 225 | |
| 226 | private: |
| 227 | DISALLOW_COPY_AND_ASSIGN(ThreadCheckerMacroTest); |
| 228 | }; |
| 229 | |
| 230 | } // namespace |
| 231 | |
| 232 | TEST_F(ThreadCheckerMacroTest, Macros) { |
| 233 | THREAD_CHECKER(my_thread_checker); |
| 234 | |
| 235 | RunCallbackOnNewThreadSynchronously(Bind( |
| 236 | &ThreadCheckerMacroTest::ExpectDeathOnOtherThread, Unretained(this))); |
| 237 | |
| 238 | DETACH_FROM_THREAD(my_thread_checker_); |
| 239 | |
| 240 | RunCallbackOnNewThreadSynchronously( |
| 241 | Bind(&ThreadCheckerMacroTest::ExpectNoDeathOnOtherThreadAfterDetach, |
| 242 | Unretained(this))); |
| 243 | } |
| 244 | |
[email protected] | ce072a7 | 2010-12-31 20:02:16 | [diff] [blame] | 245 | } // namespace base |