OLD | NEW |
---|---|
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/task_scheduler/scheduler_single_thread_task_runner_manager.h" | 5 #include "base/task_scheduler/scheduler_single_thread_task_runner_manager.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/memory/ptr_util.h" | 8 #include "base/memory/ptr_util.h" |
9 #include "base/synchronization/lock.h" | 9 #include "base/synchronization/lock.h" |
10 #include "base/synchronization/waitable_event.h" | 10 #include "base/synchronization/waitable_event.h" |
11 #include "base/task_scheduler/delayed_task_manager.h" | 11 #include "base/task_scheduler/delayed_task_manager.h" |
12 #include "base/task_scheduler/post_task.h" | 12 #include "base/task_scheduler/post_task.h" |
13 #include "base/task_scheduler/scheduler_worker_pool_params.h" | 13 #include "base/task_scheduler/scheduler_worker_pool_params.h" |
14 #include "base/task_scheduler/task_tracker.h" | 14 #include "base/task_scheduler/task_tracker.h" |
15 #include "base/task_scheduler/task_traits.h" | 15 #include "base/task_scheduler/task_traits.h" |
16 #include "base/test/test_timeouts.h" | 16 #include "base/test/test_timeouts.h" |
17 #include "base/threading/platform_thread.h" | |
17 #include "base/threading/simple_thread.h" | 18 #include "base/threading/simple_thread.h" |
18 #include "base/threading/thread.h" | 19 #include "base/threading/thread.h" |
19 #include "testing/gtest/include/gtest/gtest.h" | 20 #include "testing/gtest/include/gtest/gtest.h" |
20 | 21 |
21 #if defined(OS_WIN) | 22 #if defined(OS_WIN) |
22 #include <windows.h> | 23 #include <windows.h> |
23 #include <objbase.h> | 24 #include <objbase.h> |
24 | 25 |
25 #include "base/win/current_module.h" | 26 #include "base/win/current_module.h" |
26 #endif // defined(OS_WIN) | 27 #endif // defined(OS_WIN) |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
105 *thread_priority = PlatformThread::GetCurrentThreadPriority(); | 106 *thread_priority = PlatformThread::GetCurrentThreadPriority(); |
106 } | 107 } |
107 | 108 |
108 void ShouldNotRun() { | 109 void ShouldNotRun() { |
109 ADD_FAILURE() << "Ran a task that shouldn't run."; | 110 ADD_FAILURE() << "Ran a task that shouldn't run."; |
110 } | 111 } |
111 | 112 |
112 } // namespace | 113 } // namespace |
113 | 114 |
114 TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerTest, DifferentThreadsUsed) { | 115 TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerTest, DifferentThreadsUsed) { |
116 single_thread_task_runner_manager_->Start(); | |
115 scoped_refptr<SingleThreadTaskRunner> task_runner_1 = | 117 scoped_refptr<SingleThreadTaskRunner> task_runner_1 = |
116 single_thread_task_runner_manager_ | 118 single_thread_task_runner_manager_ |
117 ->CreateSingleThreadTaskRunnerWithTraits( | 119 ->CreateSingleThreadTaskRunnerWithTraits( |
118 TaskTraits().WithShutdownBehavior( | 120 TaskTraits().WithShutdownBehavior( |
119 TaskShutdownBehavior::BLOCK_SHUTDOWN)); | 121 TaskShutdownBehavior::BLOCK_SHUTDOWN)); |
120 scoped_refptr<SingleThreadTaskRunner> task_runner_2 = | 122 scoped_refptr<SingleThreadTaskRunner> task_runner_2 = |
121 single_thread_task_runner_manager_ | 123 single_thread_task_runner_manager_ |
122 ->CreateSingleThreadTaskRunnerWithTraits( | 124 ->CreateSingleThreadTaskRunnerWithTraits( |
123 TaskTraits().WithShutdownBehavior( | 125 TaskTraits().WithShutdownBehavior( |
124 TaskShutdownBehavior::BLOCK_SHUTDOWN)); | 126 TaskShutdownBehavior::BLOCK_SHUTDOWN)); |
125 | 127 |
126 PlatformThreadRef thread_ref_1; | 128 PlatformThreadRef thread_ref_1; |
127 task_runner_1->PostTask(FROM_HERE, Bind(&CaptureThreadRef, &thread_ref_1)); | 129 task_runner_1->PostTask(FROM_HERE, Bind(&CaptureThreadRef, &thread_ref_1)); |
128 PlatformThreadRef thread_ref_2; | 130 PlatformThreadRef thread_ref_2; |
129 task_runner_2->PostTask(FROM_HERE, Bind(&CaptureThreadRef, &thread_ref_2)); | 131 task_runner_2->PostTask(FROM_HERE, Bind(&CaptureThreadRef, &thread_ref_2)); |
130 | 132 |
131 task_tracker_.Shutdown(); | 133 task_tracker_.Shutdown(); |
132 | 134 |
133 ASSERT_FALSE(thread_ref_1.is_null()); | 135 ASSERT_FALSE(thread_ref_1.is_null()); |
134 ASSERT_FALSE(thread_ref_2.is_null()); | 136 ASSERT_FALSE(thread_ref_2.is_null()); |
135 EXPECT_NE(thread_ref_1, thread_ref_2); | 137 EXPECT_NE(thread_ref_1, thread_ref_2); |
136 } | 138 } |
137 | 139 |
138 TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerTest, PrioritySetCorrectly) { | 140 TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerTest, PrioritySetCorrectly) { |
141 single_thread_task_runner_manager_->Start(); | |
139 // Why are events used here instead of the task tracker? | 142 // Why are events used here instead of the task tracker? |
140 // Shutting down can cause priorities to get raised. This means we have to use | 143 // Shutting down can cause priorities to get raised. This means we have to use |
141 // events to determine when a task is run. | 144 // events to determine when a task is run. |
142 scoped_refptr<SingleThreadTaskRunner> task_runner_background = | 145 scoped_refptr<SingleThreadTaskRunner> task_runner_background = |
143 single_thread_task_runner_manager_ | 146 single_thread_task_runner_manager_ |
144 ->CreateSingleThreadTaskRunnerWithTraits( | 147 ->CreateSingleThreadTaskRunnerWithTraits( |
145 TaskTraits().WithPriority(TaskPriority::BACKGROUND)); | 148 TaskTraits().WithPriority(TaskPriority::BACKGROUND)); |
146 scoped_refptr<SingleThreadTaskRunner> task_runner_user_visible = | 149 scoped_refptr<SingleThreadTaskRunner> task_runner_user_visible = |
147 single_thread_task_runner_manager_ | 150 single_thread_task_runner_manager_ |
148 ->CreateSingleThreadTaskRunnerWithTraits( | 151 ->CreateSingleThreadTaskRunnerWithTraits( |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
189 waitable_event_user_blocking.Wait(); | 192 waitable_event_user_blocking.Wait(); |
190 | 193 |
191 if (Lock::HandlesMultipleThreadPriorities()) | 194 if (Lock::HandlesMultipleThreadPriorities()) |
192 EXPECT_EQ(ThreadPriority::BACKGROUND, thread_priority_background); | 195 EXPECT_EQ(ThreadPriority::BACKGROUND, thread_priority_background); |
193 else | 196 else |
194 EXPECT_EQ(ThreadPriority::NORMAL, thread_priority_background); | 197 EXPECT_EQ(ThreadPriority::NORMAL, thread_priority_background); |
195 EXPECT_EQ(ThreadPriority::NORMAL, thread_priority_user_visible); | 198 EXPECT_EQ(ThreadPriority::NORMAL, thread_priority_user_visible); |
196 EXPECT_EQ(ThreadPriority::NORMAL, thread_priority_user_blocking); | 199 EXPECT_EQ(ThreadPriority::NORMAL, thread_priority_user_blocking); |
197 } | 200 } |
198 | 201 |
202 // Verify that a task posted before Start() doesn't run until Start() is called. | |
203 TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerTest, PostTaskBeforeStart) { | |
204 bool started = false; | |
205 WaitableEvent task_running(WaitableEvent::ResetPolicy::MANUAL, | |
206 WaitableEvent::InitialState::NOT_SIGNALED); | |
207 single_thread_task_runner_manager_ | |
208 ->CreateSingleThreadTaskRunnerWithTraits(TaskTraits()) | |
209 ->PostTask(FROM_HERE, | |
210 Bind( | |
211 [](WaitableEvent* task_running, bool* started) { | |
212 task_running->Signal(); | |
213 | |
214 // The task should not run before Start(). | |
215 EXPECT_TRUE(*started); | |
216 }, | |
217 Unretained(&task_running), Unretained(&started))); | |
218 | |
219 // Wait a little bit to make sure that the task isn't scheduled before start. | |
220 // Note: This test won't catch a case where the task is scheduled between | |
221 // setting |start| and calling Start(). However, we expect the test to be | |
222 // flaky if the tested code allows that to happen. | |
223 PlatformThread::Sleep(TestTimeouts::tiny_timeout()); | |
224 started = true; | |
gab
2017/04/10 18:04:56
Need to use AtomicFlag or this a data race (no suc
fdoray
2017/04/10 19:05:00
Done.
| |
225 single_thread_task_runner_manager_->Start(); | |
226 | |
227 // This should not hang if the task is scheduled after Start(). | |
228 task_running.Wait(); | |
229 } | |
230 | |
199 TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerTest, PostTaskAfterShutdown) { | 231 TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerTest, PostTaskAfterShutdown) { |
232 single_thread_task_runner_manager_->Start(); | |
200 auto task_runner = single_thread_task_runner_manager_ | 233 auto task_runner = single_thread_task_runner_manager_ |
201 ->CreateSingleThreadTaskRunnerWithTraits(TaskTraits()); | 234 ->CreateSingleThreadTaskRunnerWithTraits(TaskTraits()); |
202 task_tracker_.Shutdown(); | 235 task_tracker_.Shutdown(); |
203 EXPECT_FALSE(task_runner->PostTask(FROM_HERE, Bind(&ShouldNotRun))); | 236 EXPECT_FALSE(task_runner->PostTask(FROM_HERE, Bind(&ShouldNotRun))); |
204 } | 237 } |
205 | 238 |
206 // Verify that a Task runs shortly after its delay expires. | 239 // Verify that a Task runs shortly after its delay expires. |
207 TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerTest, PostDelayedTask) { | 240 TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerTest, PostDelayedTask) { |
241 single_thread_task_runner_manager_->Start(); | |
208 TimeTicks start_time = TimeTicks::Now(); | 242 TimeTicks start_time = TimeTicks::Now(); |
209 | 243 |
210 // Post a task with a short delay. | 244 // Post a task with a short delay. |
211 WaitableEvent task_ran(WaitableEvent::ResetPolicy::MANUAL, | 245 WaitableEvent task_ran(WaitableEvent::ResetPolicy::MANUAL, |
212 WaitableEvent::InitialState::NOT_SIGNALED); | 246 WaitableEvent::InitialState::NOT_SIGNALED); |
213 auto task_runner = single_thread_task_runner_manager_ | 247 auto task_runner = single_thread_task_runner_manager_ |
214 ->CreateSingleThreadTaskRunnerWithTraits(TaskTraits()); | 248 ->CreateSingleThreadTaskRunnerWithTraits(TaskTraits()); |
215 EXPECT_TRUE(task_runner->PostDelayedTask( | 249 EXPECT_TRUE(task_runner->PostDelayedTask( |
216 FROM_HERE, Bind(&WaitableEvent::Signal, Unretained(&task_ran)), | 250 FROM_HERE, Bind(&WaitableEvent::Signal, Unretained(&task_ran)), |
217 TestTimeouts::tiny_timeout())); | 251 TestTimeouts::tiny_timeout())); |
218 | 252 |
219 // Wait until the task runs. | 253 // Wait until the task runs. |
220 task_ran.Wait(); | 254 task_ran.Wait(); |
221 | 255 |
222 // Expect the task to run after its delay expires, but not more than 250 ms | 256 // Expect the task to run after its delay expires, but not more than 250 ms |
223 // after that. | 257 // after that. |
224 const TimeDelta actual_delay = TimeTicks::Now() - start_time; | 258 const TimeDelta actual_delay = TimeTicks::Now() - start_time; |
225 EXPECT_GE(actual_delay, TestTimeouts::tiny_timeout()); | 259 EXPECT_GE(actual_delay, TestTimeouts::tiny_timeout()); |
226 EXPECT_LT(actual_delay, | 260 EXPECT_LT(actual_delay, |
227 TimeDelta::FromMilliseconds(250) + TestTimeouts::tiny_timeout()); | 261 TimeDelta::FromMilliseconds(250) + TestTimeouts::tiny_timeout()); |
228 } | 262 } |
229 | 263 |
230 TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerTest, | 264 TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerTest, |
231 RunsTasksOnCurrentThread) { | 265 RunsTasksOnCurrentThread) { |
266 single_thread_task_runner_manager_->Start(); | |
232 scoped_refptr<SingleThreadTaskRunner> task_runner_1 = | 267 scoped_refptr<SingleThreadTaskRunner> task_runner_1 = |
233 single_thread_task_runner_manager_ | 268 single_thread_task_runner_manager_ |
234 ->CreateSingleThreadTaskRunnerWithTraits( | 269 ->CreateSingleThreadTaskRunnerWithTraits( |
235 TaskTraits().WithShutdownBehavior( | 270 TaskTraits().WithShutdownBehavior( |
236 TaskShutdownBehavior::BLOCK_SHUTDOWN)); | 271 TaskShutdownBehavior::BLOCK_SHUTDOWN)); |
237 scoped_refptr<SingleThreadTaskRunner> task_runner_2 = | 272 scoped_refptr<SingleThreadTaskRunner> task_runner_2 = |
238 single_thread_task_runner_manager_ | 273 single_thread_task_runner_manager_ |
239 ->CreateSingleThreadTaskRunnerWithTraits( | 274 ->CreateSingleThreadTaskRunnerWithTraits( |
240 TaskTraits().WithShutdownBehavior( | 275 TaskTraits().WithShutdownBehavior( |
241 TaskShutdownBehavior::BLOCK_SHUTDOWN)); | 276 TaskShutdownBehavior::BLOCK_SHUTDOWN)); |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
303 single_thread_task_runner_manager_.reset(); | 338 single_thread_task_runner_manager_.reset(); |
304 } | 339 } |
305 | 340 |
306 private: | 341 private: |
307 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerSingleThreadTaskRunnerManagerJoinTest); | 342 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerSingleThreadTaskRunnerManagerJoinTest); |
308 }; | 343 }; |
309 | 344 |
310 } // namespace | 345 } // namespace |
311 | 346 |
312 TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerJoinTest, ConcurrentJoin) { | 347 TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerJoinTest, ConcurrentJoin) { |
348 single_thread_task_runner_manager_->Start(); | |
313 // Exercises the codepath where the workers are unavailable for unregistration | 349 // Exercises the codepath where the workers are unavailable for unregistration |
314 // because of a Join call. | 350 // because of a Join call. |
315 WaitableEvent task_running(WaitableEvent::ResetPolicy::MANUAL, | 351 WaitableEvent task_running(WaitableEvent::ResetPolicy::MANUAL, |
316 WaitableEvent::InitialState::NOT_SIGNALED); | 352 WaitableEvent::InitialState::NOT_SIGNALED); |
317 WaitableEvent task_blocking(WaitableEvent::ResetPolicy::MANUAL, | 353 WaitableEvent task_blocking(WaitableEvent::ResetPolicy::MANUAL, |
318 WaitableEvent::InitialState::NOT_SIGNALED); | 354 WaitableEvent::InitialState::NOT_SIGNALED); |
319 | 355 |
320 { | 356 { |
321 auto task_runner = single_thread_task_runner_manager_ | 357 auto task_runner = single_thread_task_runner_manager_ |
322 ->CreateSingleThreadTaskRunnerWithTraits( | 358 ->CreateSingleThreadTaskRunnerWithTraits( |
323 TaskTraits().WithBaseSyncPrimitives()); | 359 TaskTraits().WithBaseSyncPrimitives()); |
324 EXPECT_TRUE(task_runner->PostTask( | 360 EXPECT_TRUE(task_runner->PostTask( |
325 FROM_HERE, Bind(&WaitableEvent::Signal, Unretained(&task_running)))); | 361 FROM_HERE, Bind(&WaitableEvent::Signal, Unretained(&task_running)))); |
326 EXPECT_TRUE(task_runner->PostTask( | 362 EXPECT_TRUE(task_runner->PostTask( |
327 FROM_HERE, Bind(&WaitableEvent::Wait, Unretained(&task_blocking)))); | 363 FROM_HERE, Bind(&WaitableEvent::Wait, Unretained(&task_blocking)))); |
328 } | 364 } |
329 | 365 |
330 task_running.Wait(); | 366 task_running.Wait(); |
331 CallJoinFromDifferentThread join_from_different_thread( | 367 CallJoinFromDifferentThread join_from_different_thread( |
332 single_thread_task_runner_manager_.get()); | 368 single_thread_task_runner_manager_.get()); |
333 join_from_different_thread.Start(); | 369 join_from_different_thread.Start(); |
334 join_from_different_thread.WaitForRunToStart(); | 370 join_from_different_thread.WaitForRunToStart(); |
335 task_blocking.Signal(); | 371 task_blocking.Signal(); |
336 join_from_different_thread.Join(); | 372 join_from_different_thread.Join(); |
337 } | 373 } |
338 | 374 |
339 TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerJoinTest, | 375 TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerJoinTest, |
340 ConcurrentJoinExtraSkippedTask) { | 376 ConcurrentJoinExtraSkippedTask) { |
377 single_thread_task_runner_manager_->Start(); | |
341 // Tests to make sure that tasks are properly cleaned up at Join, allowing | 378 // Tests to make sure that tasks are properly cleaned up at Join, allowing |
342 // SingleThreadTaskRunners to unregister themselves. | 379 // SingleThreadTaskRunners to unregister themselves. |
343 WaitableEvent task_running(WaitableEvent::ResetPolicy::MANUAL, | 380 WaitableEvent task_running(WaitableEvent::ResetPolicy::MANUAL, |
344 WaitableEvent::InitialState::NOT_SIGNALED); | 381 WaitableEvent::InitialState::NOT_SIGNALED); |
345 WaitableEvent task_blocking(WaitableEvent::ResetPolicy::MANUAL, | 382 WaitableEvent task_blocking(WaitableEvent::ResetPolicy::MANUAL, |
346 WaitableEvent::InitialState::NOT_SIGNALED); | 383 WaitableEvent::InitialState::NOT_SIGNALED); |
347 | 384 |
348 { | 385 { |
349 auto task_runner = single_thread_task_runner_manager_ | 386 auto task_runner = single_thread_task_runner_manager_ |
350 ->CreateSingleThreadTaskRunnerWithTraits( | 387 ->CreateSingleThreadTaskRunnerWithTraits( |
(...skipping 10 matching lines...) Expand all Loading... | |
361 single_thread_task_runner_manager_.get()); | 398 single_thread_task_runner_manager_.get()); |
362 join_from_different_thread.Start(); | 399 join_from_different_thread.Start(); |
363 join_from_different_thread.WaitForRunToStart(); | 400 join_from_different_thread.WaitForRunToStart(); |
364 task_blocking.Signal(); | 401 task_blocking.Signal(); |
365 join_from_different_thread.Join(); | 402 join_from_different_thread.Join(); |
366 } | 403 } |
367 | 404 |
368 #if defined(OS_WIN) | 405 #if defined(OS_WIN) |
369 | 406 |
370 TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerTest, COMSTAInitialized) { | 407 TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerTest, COMSTAInitialized) { |
408 single_thread_task_runner_manager_->Start(); | |
371 scoped_refptr<SingleThreadTaskRunner> com_task_runner = | 409 scoped_refptr<SingleThreadTaskRunner> com_task_runner = |
372 single_thread_task_runner_manager_->CreateCOMSTATaskRunnerWithTraits( | 410 single_thread_task_runner_manager_->CreateCOMSTATaskRunnerWithTraits( |
373 TaskTraits().WithShutdownBehavior( | 411 TaskTraits().WithShutdownBehavior( |
374 TaskShutdownBehavior::BLOCK_SHUTDOWN)); | 412 TaskShutdownBehavior::BLOCK_SHUTDOWN)); |
375 | 413 |
376 com_task_runner->PostTask( | 414 com_task_runner->PostTask( |
377 FROM_HERE, Bind([]() { | 415 FROM_HERE, Bind([]() { |
378 HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); | 416 HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); |
379 if (SUCCEEDED(hr)) { | 417 if (SUCCEEDED(hr)) { |
380 ADD_FAILURE() << "COM STA was not initialized on this thread"; | 418 ADD_FAILURE() << "COM STA was not initialized on this thread"; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
424 } | 462 } |
425 | 463 |
426 bool register_class_succeeded_ = false; | 464 bool register_class_succeeded_ = false; |
427 | 465 |
428 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerSingleThreadTaskRunnerManagerTestWin); | 466 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerSingleThreadTaskRunnerManagerTestWin); |
429 }; | 467 }; |
430 | 468 |
431 } // namespace | 469 } // namespace |
432 | 470 |
433 TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerTestWin, PumpsMessages) { | 471 TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerTestWin, PumpsMessages) { |
472 single_thread_task_runner_manager_->Start(); | |
434 scoped_refptr<SingleThreadTaskRunner> com_task_runner = | 473 scoped_refptr<SingleThreadTaskRunner> com_task_runner = |
435 single_thread_task_runner_manager_->CreateCOMSTATaskRunnerWithTraits( | 474 single_thread_task_runner_manager_->CreateCOMSTATaskRunnerWithTraits( |
436 TaskTraits().WithShutdownBehavior( | 475 TaskTraits().WithShutdownBehavior( |
437 TaskShutdownBehavior::BLOCK_SHUTDOWN)); | 476 TaskShutdownBehavior::BLOCK_SHUTDOWN)); |
438 HWND hwnd = nullptr; | 477 HWND hwnd = nullptr; |
439 // HWNDs process messages on the thread that created them, so we have to | 478 // HWNDs process messages on the thread that created them, so we have to |
440 // create them within the context of the task runner to properly simulate a | 479 // create them within the context of the task runner to properly simulate a |
441 // COM callback. | 480 // COM callback. |
442 com_task_runner->PostTask( | 481 com_task_runner->PostTask( |
443 FROM_HERE, | 482 FROM_HERE, |
(...skipping 11 matching lines...) Expand all Loading... | |
455 com_task_runner->PostTask( | 494 com_task_runner->PostTask( |
456 FROM_HERE, Bind([](HWND hwnd) { ::DestroyWindow(hwnd); }, hwnd)); | 495 FROM_HERE, Bind([](HWND hwnd) { ::DestroyWindow(hwnd); }, hwnd)); |
457 | 496 |
458 task_tracker_.Shutdown(); | 497 task_tracker_.Shutdown(); |
459 } | 498 } |
460 | 499 |
461 #endif // defined(OS_WIN) | 500 #endif // defined(OS_WIN) |
462 | 501 |
463 } // namespace internal | 502 } // namespace internal |
464 } // namespace base | 503 } // namespace base |
OLD | NEW |