| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 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/win/wait_chain.h" |
| 6 |
| 7 #include <memory> |
| 8 #include <string> |
| 9 |
| 10 #include "base/bind.h" |
| 11 #include "base/command_line.h" |
| 12 #include "base/strings/string_number_conversions.h" |
| 13 #include "base/strings/string_piece.h" |
| 14 #include "base/test/multiprocess_test.h" |
| 15 #include "base/threading/simple_thread.h" |
| 16 #include "base/win/win_util.h" |
| 17 #include "testing/gtest/include/gtest/gtest.h" |
| 18 #include "testing/multiprocess_func_list.h" |
| 19 |
| 20 namespace base { |
| 21 namespace win { |
| 22 |
| 23 namespace { |
| 24 |
| 25 // Appends |handle| as a command line switch. |
| 26 void AppendSwitchHandle(CommandLine* command_line, |
| 27 StringPiece switch_name, |
| 28 HANDLE handle) { |
| 29 command_line->AppendSwitchASCII(switch_name.as_string(), |
| 30 UintToString(HandleToUint32(handle))); |
| 31 } |
| 32 |
| 33 // Retrieves the |handle| associated to |switch_name| from the command line. |
| 34 ScopedHandle GetSwitchValueHandle(CommandLine* command_line, |
| 35 StringPiece switch_name) { |
| 36 std::string switch_string = |
| 37 command_line->GetSwitchValueASCII(switch_name.as_string()); |
| 38 unsigned int switch_uint = 0; |
| 39 if (switch_string.empty() || !StringToUint(switch_string, &switch_uint)) { |
| 40 DLOG(ERROR) << "Missing or invalid " << switch_name << " argument."; |
| 41 return ScopedHandle(); |
| 42 } |
| 43 return ScopedHandle(reinterpret_cast<HANDLE>(switch_uint)); |
| 44 } |
| 45 |
| 46 // Helper function to create a mutex. |
| 47 ScopedHandle CreateMutex(bool inheritable) { |
| 48 SECURITY_ATTRIBUTES security_attributes = {sizeof(SECURITY_ATTRIBUTES), |
| 49 nullptr, inheritable}; |
| 50 return ScopedHandle(::CreateMutex(&security_attributes, FALSE, NULL)); |
| 51 } |
| 52 |
| 53 // Helper function to create an event. |
| 54 ScopedHandle CreateEvent(bool inheritable) { |
| 55 SECURITY_ATTRIBUTES security_attributes = {sizeof(SECURITY_ATTRIBUTES), |
| 56 nullptr, inheritable}; |
| 57 return ScopedHandle( |
| 58 ::CreateEvent(&security_attributes, FALSE, FALSE, nullptr)); |
| 59 } |
| 60 |
| 61 // Helper thread class that runs the callback then stops. |
| 62 class SingleTaskThread : public SimpleThread { |
| 63 public: |
| 64 explicit SingleTaskThread(const Closure& task) |
| 65 : SimpleThread("WaitChainTest SingleTaskThread"), task_(task) {} |
| 66 |
| 67 void Run() override { task_.Run(); } |
| 68 |
| 69 private: |
| 70 Closure task_; |
| 71 |
| 72 DISALLOW_COPY_AND_ASSIGN(SingleTaskThread); |
| 73 }; |
| 74 |
| 75 // Helper thread to cause a deadlock by acquiring 2 mutexes in a given order. |
| 76 class DeadlockThread : public SimpleThread { |
| 77 public: |
| 78 DeadlockThread(HANDLE mutex_1, HANDLE mutex_2) |
| 79 : SimpleThread("WaitChainTest DeadlockThread"), |
| 80 wait_event_(CreateEvent(false)), |
| 81 mutex_acquired_event_(CreateEvent(false)), |
| 82 mutex_1_(mutex_1), |
| 83 mutex_2_(mutex_2) {} |
| 84 |
| 85 void Run() override { |
| 86 // Acquire the mutex then signal the main thread. |
| 87 EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(mutex_1_, INFINITE)); |
| 88 EXPECT_TRUE(::SetEvent(mutex_acquired_event_.Get())); |
| 89 |
| 90 // Wait until both threads are holding their mutex before trying to acquire |
| 91 // the other one. |
| 92 EXPECT_EQ(WAIT_OBJECT_0, |
| 93 ::WaitForSingleObject(wait_event_.Get(), INFINITE)); |
| 94 |
| 95 // To unblock the deadlock, one of the threads will get terminated (via |
| 96 // TerminateThread()) without releasing the mutex. This causes the other |
| 97 // thread to wake up with WAIT_ABANDONED. |
| 98 EXPECT_EQ(WAIT_ABANDONED, ::WaitForSingleObject(mutex_2_, INFINITE)); |
| 99 } |
| 100 |
| 101 // Blocks until a mutex is acquired. |
| 102 void WaitForMutexAcquired() { |
| 103 EXPECT_EQ(WAIT_OBJECT_0, |
| 104 ::WaitForSingleObject(mutex_acquired_event_.Get(), INFINITE)); |
| 105 } |
| 106 |
| 107 // Signal the thread to acquire the second mutex. |
| 108 void SignalToAcquireMutex() { EXPECT_TRUE(::SetEvent(wait_event_.Get())); } |
| 109 |
| 110 // Terminates the thread. |
| 111 bool Terminate() { |
| 112 ScopedHandle thread_handle(::OpenThread(THREAD_TERMINATE, FALSE, tid())); |
| 113 return ::TerminateThread(thread_handle.Get(), 0); |
| 114 } |
| 115 |
| 116 private: |
| 117 ScopedHandle wait_event_; |
| 118 ScopedHandle mutex_acquired_event_; |
| 119 |
| 120 // The 2 mutex to acquire. |
| 121 HANDLE mutex_1_; |
| 122 HANDLE mutex_2_; |
| 123 |
| 124 DISALLOW_COPY_AND_ASSIGN(DeadlockThread); |
| 125 }; |
| 126 |
| 127 // Creates a thread that joins |thread_to_join| and then terminates when it |
| 128 // finishes execution. |
| 129 std::unique_ptr<SingleTaskThread> CreateJoiningThread( |
| 130 SimpleThread* thread_to_join) { |
| 131 std::unique_ptr<SingleTaskThread> thread(new SingleTaskThread( |
| 132 Bind(&SimpleThread::Join, Unretained(thread_to_join)))); |
| 133 thread->Start(); |
| 134 |
| 135 return thread; |
| 136 } |
| 137 |
| 138 // Creates a thread that calls WaitForSingleObject() on the handle and then |
| 139 // terminates when it unblocks. |
| 140 std::unique_ptr<SingleTaskThread> CreateWaitingThread(HANDLE handle) { |
| 141 std::unique_ptr<SingleTaskThread> thread(new SingleTaskThread( |
| 142 Bind(IgnoreResult(&::WaitForSingleObject), handle, INFINITE))); |
| 143 thread->Start(); |
| 144 |
| 145 return thread; |
| 146 } |
| 147 |
| 148 // Creates a thread that blocks on |mutex_2| after acquiring |mutex_1|. |
| 149 std::unique_ptr<DeadlockThread> CreateDeadlockThread(HANDLE mutex_1, |
| 150 HANDLE mutex_2) { |
| 151 std::unique_ptr<DeadlockThread> thread(new DeadlockThread(mutex_1, mutex_2)); |
| 152 thread->Start(); |
| 153 |
| 154 // Wait until the first mutex is acquired before returning. |
| 155 thread->WaitForMutexAcquired(); |
| 156 |
| 157 return thread; |
| 158 } |
| 159 |
| 160 // Child process to test the cross-process capability of the WCT api. |
| 161 // This process will simulate a hang while holding a mutex that the parent |
| 162 // process is waiting on. |
| 163 MULTIPROCESS_TEST_MAIN(WaitChainTestProc) { |
| 164 CommandLine* command_line = CommandLine::ForCurrentProcess(); |
| 165 |
| 166 ScopedHandle mutex = GetSwitchValueHandle(command_line, "mutex"); |
| 167 CHECK(mutex.IsValid()); |
| 168 |
| 169 ScopedHandle sync_event(GetSwitchValueHandle(command_line, "sync_event")); |
| 170 CHECK(sync_event.IsValid()); |
| 171 |
| 172 // Acquire mutex. |
| 173 CHECK(::WaitForSingleObject(mutex.Get(), INFINITE) == WAIT_OBJECT_0); |
| 174 |
| 175 // Signal back to the parent process that the mutex is hold. |
| 176 CHECK(::SetEvent(sync_event.Get())); |
| 177 |
| 178 // Wait on a signal from the parent process before terminating. |
| 179 CHECK(::WaitForSingleObject(sync_event.Get(), INFINITE) == WAIT_OBJECT_0); |
| 180 |
| 181 return 0; |
| 182 } |
| 183 |
| 184 // Start a child process and passes the |mutex| and the |sync_event| to the |
| 185 // command line. |
| 186 Process StartChildProcess(HANDLE mutex, HANDLE sync_event) { |
| 187 CommandLine command_line = GetMultiProcessTestChildBaseCommandLine(); |
| 188 |
| 189 AppendSwitchHandle(&command_line, "mutex", mutex); |
| 190 AppendSwitchHandle(&command_line, "sync_event", sync_event); |
| 191 |
| 192 LaunchOptions options; |
| 193 HandlesToInheritVector handle_vector; |
| 194 handle_vector.push_back(mutex); |
| 195 handle_vector.push_back(sync_event); |
| 196 options.handles_to_inherit = &handle_vector; |
| 197 return SpawnMultiProcessTestChild("WaitChainTestProc", command_line, options); |
| 198 } |
| 199 |
| 200 // Returns true if the |wait_chain| is an alternating sequence of thread objects |
| 201 // and synchronization objects. |
| 202 bool WaitChainStructureIsCorrect(const WaitChainNodeVector& wait_chain) { |
| 203 // Checks thread objects. |
| 204 for (size_t i = 0; i < wait_chain.size(); i += 2) { |
| 205 if (wait_chain[i].ObjectType != WctThreadType) |
| 206 return false; |
| 207 } |
| 208 |
| 209 // Check synchronization objects. |
| 210 for (size_t i = 1; i < wait_chain.size(); i += 2) { |
| 211 if (wait_chain[i].ObjectType == WctThreadType) |
| 212 return false; |
| 213 } |
| 214 return true; |
| 215 } |
| 216 |
| 217 // Returns true if the |wait_chain| goes through more than 1 process. |
| 218 bool WaitChainIsCrossProcess(const WaitChainNodeVector& wait_chain) { |
| 219 if (wait_chain.size() == 0) |
| 220 return false; |
| 221 |
| 222 // Just check that the process id changes somewhere in the chain. |
| 223 // Note: ThreadObjects are every 2 nodes. |
| 224 DWORD first_process = wait_chain[0].ThreadObject.ProcessId; |
| 225 for (size_t i = 2; i < wait_chain.size(); i += 2) { |
| 226 if (first_process != wait_chain[i].ThreadObject.ProcessId) |
| 227 return true; |
| 228 } |
| 229 return false; |
| 230 } |
| 231 |
| 232 } // namespace |
| 233 |
| 234 // Creates 2 threads that acquire their designated mutex and then try to |
| 235 // acquire each others' mutex to cause a deadlock. |
| 236 TEST(WaitChainTest, Deadlock) { |
| 237 // 2 mutexes are needed to get a deadlock. |
| 238 ScopedHandle mutex_1 = CreateMutex(false); |
| 239 ASSERT_TRUE(mutex_1.IsValid()); |
| 240 ScopedHandle mutex_2 = CreateMutex(false); |
| 241 ASSERT_TRUE(mutex_2.IsValid()); |
| 242 |
| 243 std::unique_ptr<DeadlockThread> deadlock_thread_1 = |
| 244 CreateDeadlockThread(mutex_1.Get(), mutex_2.Get()); |
| 245 std::unique_ptr<DeadlockThread> deadlock_thread_2 = |
| 246 CreateDeadlockThread(mutex_2.Get(), mutex_1.Get()); |
| 247 |
| 248 // Signal the threads to try to acquire the other mutex. |
| 249 deadlock_thread_1->SignalToAcquireMutex(); |
| 250 deadlock_thread_2->SignalToAcquireMutex(); |
| 251 // Sleep to make sure the 2 threads got a chance to execute. |
| 252 Sleep(10); |
| 253 |
| 254 // Create a few waiting threads to get a longer wait chain. |
| 255 std::unique_ptr<SingleTaskThread> waiting_thread_1 = |
| 256 CreateJoiningThread(deadlock_thread_1.get()); |
| 257 std::unique_ptr<SingleTaskThread> waiting_thread_2 = |
| 258 CreateJoiningThread(waiting_thread_1.get()); |
| 259 |
| 260 WaitChainNodeVector wait_chain; |
| 261 bool is_deadlock; |
| 262 ASSERT_TRUE( |
| 263 GetThreadWaitChain(waiting_thread_2->tid(), &wait_chain, &is_deadlock)); |
| 264 |
| 265 EXPECT_EQ(9U, wait_chain.size()); |
| 266 EXPECT_TRUE(is_deadlock); |
| 267 EXPECT_TRUE(WaitChainStructureIsCorrect(wait_chain)); |
| 268 EXPECT_FALSE(WaitChainIsCrossProcess(wait_chain)); |
| 269 |
| 270 ASSERT_TRUE(deadlock_thread_1->Terminate()); |
| 271 |
| 272 // The SimpleThread API expect Join() to be called before destruction. |
| 273 deadlock_thread_2->Join(); |
| 274 waiting_thread_2->Join(); |
| 275 } |
| 276 |
| 277 // Creates a child process that acquires a mutex and then blocks. A chain of |
| 278 // threads then blocks on that mutex. |
| 279 TEST(WaitChainTest, CrossProcess) { |
| 280 ScopedHandle mutex = CreateMutex(true); |
| 281 ASSERT_TRUE(mutex.IsValid()); |
| 282 ScopedHandle sync_event = CreateEvent(true); |
| 283 ASSERT_TRUE(sync_event.IsValid()); |
| 284 |
| 285 Process child_process = StartChildProcess(mutex.Get(), sync_event.Get()); |
| 286 ASSERT_TRUE(child_process.IsValid()); |
| 287 |
| 288 // Wait for the child process to signal when it's holding the mutex. |
| 289 EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(sync_event.Get(), INFINITE)); |
| 290 |
| 291 // Create a few waiting threads to get a longer wait chain. |
| 292 std::unique_ptr<SingleTaskThread> waiting_thread_1 = |
| 293 CreateWaitingThread(mutex.Get()); |
| 294 std::unique_ptr<SingleTaskThread> waiting_thread_2 = |
| 295 CreateJoiningThread(waiting_thread_1.get()); |
| 296 std::unique_ptr<SingleTaskThread> waiting_thread_3 = |
| 297 CreateJoiningThread(waiting_thread_2.get()); |
| 298 |
| 299 WaitChainNodeVector wait_chain; |
| 300 bool is_deadlock; |
| 301 ASSERT_TRUE( |
| 302 GetThreadWaitChain(waiting_thread_3->tid(), &wait_chain, &is_deadlock)); |
| 303 |
| 304 EXPECT_EQ(7U, wait_chain.size()); |
| 305 EXPECT_FALSE(is_deadlock); |
| 306 EXPECT_TRUE(WaitChainStructureIsCorrect(wait_chain)); |
| 307 EXPECT_TRUE(WaitChainIsCrossProcess(wait_chain)); |
| 308 |
| 309 // Unblock child process and wait for it to terminate. |
| 310 ASSERT_TRUE(::SetEvent(sync_event.Get())); |
| 311 ASSERT_TRUE(child_process.WaitForExit(nullptr)); |
| 312 |
| 313 // The SimpleThread API expect Join() to be called before destruction. |
| 314 waiting_thread_3->Join(); |
| 315 } |
| 316 |
| 317 } // namespace win |
| 318 } // namespace base |
| OLD | NEW |