1 // Copyright 2013 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/single_thread_task_executor.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9
10 #include <optional>
11 #include <string>
12 #include <vector>
13
14 #include "base/compiler_specific.h"
15 #include "base/functional/bind.h"
16 #include "base/functional/callback_helpers.h"
17 #include "base/logging.h"
18 #include "base/memory/ptr_util.h"
19 #include "base/memory/raw_ptr.h"
20 #include "base/memory/ref_counted.h"
21 #include "base/message_loop/message_pump_for_io.h"
22 #include "base/message_loop/message_pump_type.h"
23 #include "base/pending_task.h"
24 #include "base/posix/eintr_wrapper.h"
25 #include "base/run_loop.h"
26 #include "base/synchronization/waitable_event.h"
27 #include "base/task/current_thread.h"
28 #include "base/task/single_thread_task_runner.h"
29 #include "base/task/task_observer.h"
30 #include "base/task/thread_pool/thread_pool_instance.h"
31 #include "base/test/bind.h"
32 #include "base/test/gtest_util.h"
33 #include "base/test/metrics/histogram_tester.h"
34 #include "base/test/test_simple_task_runner.h"
35 #include "base/test/test_timeouts.h"
36 #include "base/threading/platform_thread.h"
37 #include "base/threading/sequence_local_storage_slot.h"
38 #include "base/threading/thread.h"
39 #include "base/time/time.h"
40 #include "build/build_config.h"
41 #include "testing/gmock/include/gmock/gmock.h"
42 #include "testing/gtest/include/gtest/gtest.h"
43
44 #if BUILDFLAG(IS_ANDROID)
45 #include "base/android/java_handler_thread.h"
46 #include "base/android/jni_android.h"
47 #include "base/test/android/java_handler_thread_helpers.h"
48 #endif
49
50 #if BUILDFLAG(IS_WIN)
51 #include <windows.h>
52
53 #include "base/message_loop/message_pump_win.h"
54 #include "base/process/memory.h"
55 #include "base/win/current_module.h"
56 #include "base/win/message_window.h"
57 #include "base/win/scoped_handle.h"
58 #endif
59
60 using ::testing::IsNull;
61 using ::testing::NotNull;
62
63 namespace base {
64
65 // TODO(darin): Platform-specific MessageLoop tests should be grouped together
66 // to avoid chopping this file up with so many #ifdefs.
67
68 namespace {
69
70 class Foo : public RefCounted<Foo> {
71 public:
Foo()72 Foo() : test_count_(0) {}
73
74 Foo(const Foo&) = delete;
75 Foo& operator=(const Foo&) = delete;
76
Test0()77 void Test0() { ++test_count_; }
78
Test1ConstRef(const std::string & a)79 void Test1ConstRef(const std::string& a) {
80 ++test_count_;
81 result_.append(a);
82 }
83
Test1Ptr(std::string * a)84 void Test1Ptr(std::string* a) {
85 ++test_count_;
86 result_.append(*a);
87 }
88
Test1Int(int a)89 void Test1Int(int a) { test_count_ += a; }
90
Test2Ptr(std::string * a,std::string * b)91 void Test2Ptr(std::string* a, std::string* b) {
92 ++test_count_;
93 result_.append(*a);
94 result_.append(*b);
95 }
96
Test2Mixed(const std::string & a,std::string * b)97 void Test2Mixed(const std::string& a, std::string* b) {
98 ++test_count_;
99 result_.append(a);
100 result_.append(*b);
101 }
102
test_count() const103 int test_count() const { return test_count_; }
result() const104 const std::string& result() const { return result_; }
105
106 private:
107 friend class RefCounted<Foo>;
108
109 ~Foo() = default;
110
111 int test_count_;
112 std::string result_;
113 };
114
115 // This function runs slowly to simulate a large amount of work being done.
SlowFunc(TimeDelta pause,int * quit_counter,base::OnceClosure quit_closure)116 static void SlowFunc(TimeDelta pause,
117 int* quit_counter,
118 base::OnceClosure quit_closure) {
119 PlatformThread::Sleep(pause);
120 if (--(*quit_counter) == 0)
121 std::move(quit_closure).Run();
122 }
123
124 // This function records the time when Run was called in a Time object, which is
125 // useful for building a variety of SingleThreadTaskExecutor tests.
RecordRunTimeFunc(TimeTicks * run_time,int * quit_counter,base::OnceClosure quit_closure)126 static void RecordRunTimeFunc(TimeTicks* run_time,
127 int* quit_counter,
128 base::OnceClosure quit_closure) {
129 *run_time = TimeTicks::Now();
130
131 // Cause our Run function to take some time to execute. As a result we can
132 // count on subsequent RecordRunTimeFunc()s running at a future time,
133 // without worry about the resolution of our system clock being an issue.
134 SlowFunc(Milliseconds(10), quit_counter, std::move(quit_closure));
135 }
136
137 enum TaskType {
138 MESSAGEBOX,
139 ENDDIALOG,
140 RECURSIVE,
141 TIMEDMESSAGELOOP,
142 QUITMESSAGELOOP,
143 ORDERED,
144 PUMPS,
145 SLEEP,
146 RUNS,
147 };
148
149 // Saves the order in which the tasks executed.
150 struct TaskItem {
TaskItembase::__anonadaa09f90111::TaskItem151 TaskItem(TaskType t, int c, bool s) : type(t), cookie(c), start(s) {}
152
153 TaskType type;
154 int cookie;
155 bool start;
156
operator ==base::__anonadaa09f90111::TaskItem157 bool operator==(const TaskItem& other) const {
158 return type == other.type && cookie == other.cookie && start == other.start;
159 }
160 };
161
operator <<(std::ostream & os,TaskType type)162 std::ostream& operator<<(std::ostream& os, TaskType type) {
163 switch (type) {
164 case MESSAGEBOX:
165 os << "MESSAGEBOX";
166 break;
167 case ENDDIALOG:
168 os << "ENDDIALOG";
169 break;
170 case RECURSIVE:
171 os << "RECURSIVE";
172 break;
173 case TIMEDMESSAGELOOP:
174 os << "TIMEDMESSAGELOOP";
175 break;
176 case QUITMESSAGELOOP:
177 os << "QUITMESSAGELOOP";
178 break;
179 case ORDERED:
180 os << "ORDERED";
181 break;
182 case PUMPS:
183 os << "PUMPS";
184 break;
185 case SLEEP:
186 os << "SLEEP";
187 break;
188 default:
189 NOTREACHED();
190 os << "Unknown TaskType";
191 break;
192 }
193 return os;
194 }
195
operator <<(std::ostream & os,const TaskItem & item)196 std::ostream& operator<<(std::ostream& os, const TaskItem& item) {
197 if (item.start)
198 return os << item.type << " " << item.cookie << " starts";
199 return os << item.type << " " << item.cookie << " ends";
200 }
201
202 class TaskList {
203 public:
RecordStart(TaskType type,int cookie)204 void RecordStart(TaskType type, int cookie) {
205 TaskItem item(type, cookie, true);
206 DVLOG(1) << item;
207 task_list_.push_back(item);
208 }
209
RecordEnd(TaskType type,int cookie)210 void RecordEnd(TaskType type, int cookie) {
211 TaskItem item(type, cookie, false);
212 DVLOG(1) << item;
213 task_list_.push_back(item);
214 }
215
Size()216 size_t Size() { return task_list_.size(); }
217
Get(int n)218 TaskItem Get(int n) { return task_list_[n]; }
219
220 private:
221 std::vector<TaskItem> task_list_;
222 };
223
224 class DummyTaskObserver : public TaskObserver {
225 public:
DummyTaskObserver(int num_tasks)226 explicit DummyTaskObserver(int num_tasks)
227 : num_tasks_started_(0), num_tasks_processed_(0), num_tasks_(num_tasks) {}
228
DummyTaskObserver(int num_tasks,int num_tasks_started)229 DummyTaskObserver(int num_tasks, int num_tasks_started)
230 : num_tasks_started_(num_tasks_started),
231 num_tasks_processed_(0),
232 num_tasks_(num_tasks) {}
233
234 DummyTaskObserver(const DummyTaskObserver&) = delete;
235 DummyTaskObserver& operator=(const DummyTaskObserver&) = delete;
236
237 ~DummyTaskObserver() override = default;
238
WillProcessTask(const PendingTask & pending_task,bool)239 void WillProcessTask(const PendingTask& pending_task,
240 bool /* was_blocked_or_low_priority */) override {
241 num_tasks_started_++;
242 EXPECT_LE(num_tasks_started_, num_tasks_);
243 EXPECT_EQ(num_tasks_started_, num_tasks_processed_ + 1);
244 }
245
DidProcessTask(const PendingTask & pending_task)246 void DidProcessTask(const PendingTask& pending_task) override {
247 num_tasks_processed_++;
248 EXPECT_LE(num_tasks_started_, num_tasks_);
249 EXPECT_EQ(num_tasks_started_, num_tasks_processed_);
250 }
251
num_tasks_started() const252 int num_tasks_started() const { return num_tasks_started_; }
num_tasks_processed() const253 int num_tasks_processed() const { return num_tasks_processed_; }
254
255 private:
256 int num_tasks_started_;
257 int num_tasks_processed_;
258 const int num_tasks_;
259 };
260
261 // A method which reposts itself |depth| times.
RecursiveFunc(TaskList * order,int cookie,int depth)262 void RecursiveFunc(TaskList* order, int cookie, int depth) {
263 order->RecordStart(RECURSIVE, cookie);
264 if (depth > 0) {
265 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
266 FROM_HERE, BindOnce(&RecursiveFunc, order, cookie, depth - 1));
267 }
268 order->RecordEnd(RECURSIVE, cookie);
269 }
270
QuitFunc(TaskList * order,int cookie,base::OnceClosure quit_closure)271 void QuitFunc(TaskList* order, int cookie, base::OnceClosure quit_closure) {
272 order->RecordStart(QUITMESSAGELOOP, cookie);
273 std::move(quit_closure).Run();
274 order->RecordEnd(QUITMESSAGELOOP, cookie);
275 }
276
277 #if BUILDFLAG(IS_WIN)
278
SubPumpFunc(OnceClosure on_done)279 void SubPumpFunc(OnceClosure on_done) {
280 CurrentThread::ScopedAllowApplicationTasksInNativeNestedLoop
281 allow_nestable_tasks;
282 MSG msg;
283 while (::GetMessage(&msg, NULL, 0, 0)) {
284 ::TranslateMessage(&msg);
285 ::DispatchMessage(&msg);
286 }
287 std::move(on_done).Run();
288 }
289
290 const wchar_t kMessageBoxTitle[] = L"SingleThreadTaskExecutor Unit Test";
291
292 // SingleThreadTaskExecutor implicitly start a "modal message loop". Modal
293 // dialog boxes, common controls (like OpenFile) and StartDoc printing function
294 // can cause implicit message loops.
MessageBoxFunc(TaskList * order,int cookie,bool is_reentrant)295 void MessageBoxFunc(TaskList* order, int cookie, bool is_reentrant) {
296 order->RecordStart(MESSAGEBOX, cookie);
297 std::optional<CurrentThread::ScopedAllowApplicationTasksInNativeNestedLoop>
298 maybe_allow_nesting;
299 if (is_reentrant)
300 maybe_allow_nesting.emplace();
301 ::MessageBox(NULL, L"Please wait...", kMessageBoxTitle, MB_OK);
302 order->RecordEnd(MESSAGEBOX, cookie);
303 }
304
305 // Will end the MessageBox.
EndDialogFunc(TaskList * order,int cookie)306 void EndDialogFunc(TaskList* order, int cookie) {
307 order->RecordStart(ENDDIALOG, cookie);
308 HWND window = GetActiveWindow();
309 if (window != NULL) {
310 EXPECT_NE(::EndDialog(window, IDCONTINUE), 0);
311 // Cheap way to signal that the window wasn't found if RunEnd() isn't
312 // called.
313 order->RecordEnd(ENDDIALOG, cookie);
314 }
315 }
316
317 // A method which posts a RecursiveFunc that will want to run while
318 // ::MessageBox() is active.
RecursiveFuncWin(scoped_refptr<SingleThreadTaskRunner> task_runner,HANDLE event,bool expect_window,TaskList * order,bool message_box_is_reentrant,base::OnceClosure quit_closure)319 void RecursiveFuncWin(scoped_refptr<SingleThreadTaskRunner> task_runner,
320 HANDLE event,
321 bool expect_window,
322 TaskList* order,
323 bool message_box_is_reentrant,
324 base::OnceClosure quit_closure) {
325 task_runner->PostTask(FROM_HERE, BindOnce(&RecursiveFunc, order, 1, 2));
326 task_runner->PostTask(
327 FROM_HERE, BindOnce(&MessageBoxFunc, order, 2, message_box_is_reentrant));
328 task_runner->PostTask(FROM_HERE, BindOnce(&RecursiveFunc, order, 3, 2));
329 // The trick here is that for nested task processing, this task will be
330 // ran _inside_ the MessageBox message loop, dismissing the MessageBox
331 // without a chance.
332 // For non-nested task processing, this will be executed _after_ the
333 // MessageBox will have been dismissed by the code below, where
334 // expect_window_ is true.
335 task_runner->PostTask(FROM_HERE, BindOnce(&EndDialogFunc, order, 4));
336 task_runner->PostTask(FROM_HERE,
337 BindOnce(&QuitFunc, order, 5, std::move(quit_closure)));
338
339 // Enforce that every tasks are sent before starting to run the main thread
340 // message loop.
341 ASSERT_TRUE(SetEvent(event));
342
343 // Poll for the MessageBox. Don't do this at home! At the speed we do it,
344 // you will never realize one MessageBox was shown.
345 for (; expect_window;) {
346 HWND window = ::FindWindowW(L"#32770", kMessageBoxTitle);
347 if (window) {
348 // Dismiss it.
349 for (;;) {
350 HWND button = ::FindWindowExW(window, NULL, L"Button", NULL);
351 if (button != NULL) {
352 EXPECT_EQ(0, ::SendMessage(button, WM_LBUTTONDOWN, 0, 0));
353 EXPECT_EQ(0, ::SendMessage(button, WM_LBUTTONUP, 0, 0));
354 break;
355 }
356 }
357 break;
358 }
359 }
360 }
361
362 #endif // BUILDFLAG(IS_WIN)
363
Post128KTasksThenQuit(SingleThreadTaskRunner * executor_task_runner,TimeTicks begin_ticks,TimeTicks last_post_ticks,TimeDelta slowest_delay,OnceClosure on_done,int num_posts_done=0)364 void Post128KTasksThenQuit(SingleThreadTaskRunner* executor_task_runner,
365 TimeTicks begin_ticks,
366 TimeTicks last_post_ticks,
367 TimeDelta slowest_delay,
368 OnceClosure on_done,
369 int num_posts_done = 0) {
370 const int kNumTimes = 128000;
371
372 // Tasks should be running on a decent heart beat. Some platforms/bots however
373 // have a hard time posting+running *all* tasks before test timeout, add
374 // detailed logging for diagnosis where this flakes.
375 const auto now = TimeTicks::Now();
376 const auto scheduling_delay = now - last_post_ticks;
377 if (scheduling_delay > slowest_delay)
378 slowest_delay = scheduling_delay;
379
380 if (num_posts_done == kNumTimes) {
381 std::move(on_done).Run();
382 return;
383 } else if (now - begin_ticks >= TestTimeouts::action_max_timeout()) {
384 ADD_FAILURE() << "Couldn't run all tasks."
385 << "\nNumber of tasks remaining: "
386 << kNumTimes - num_posts_done
387 << "\nSlowest scheduling delay: " << slowest_delay
388 << "\nAverage per task: "
389 << (now - begin_ticks) / num_posts_done;
390 std::move(on_done).Run();
391 return;
392 }
393
394 executor_task_runner->PostTask(
395 FROM_HERE,
396 BindOnce(&Post128KTasksThenQuit, Unretained(executor_task_runner),
397 begin_ticks, now, slowest_delay, std::move(on_done),
398 num_posts_done + 1));
399 }
400
401 #if BUILDFLAG(IS_WIN)
402
403 class TestIOHandler : public MessagePumpForIO::IOHandler {
404 public:
405 TestIOHandler(const wchar_t* name, HANDLE signal);
406
407 void OnIOCompleted(MessagePumpForIO::IOContext* context,
408 DWORD bytes_transfered,
409 DWORD error) override;
410
411 void Init();
context()412 OVERLAPPED* context() { return &context_.overlapped; }
size()413 DWORD size() { return sizeof(buffer_); }
414
415 private:
416 char buffer_[48];
417 MessagePumpForIO::IOContext context_;
418 HANDLE signal_;
419 win::ScopedHandle file_;
420 };
421
TestIOHandler(const wchar_t * name,HANDLE signal)422 TestIOHandler::TestIOHandler(const wchar_t* name, HANDLE signal)
423 : MessagePumpForIO::IOHandler(FROM_HERE), signal_(signal) {
424 memset(buffer_, 0, sizeof(buffer_));
425
426 file_.Set(CreateFile(name, GENERIC_READ, 0, NULL, OPEN_EXISTING,
427 FILE_FLAG_OVERLAPPED, NULL));
428 EXPECT_TRUE(file_.is_valid());
429 }
430
Init()431 void TestIOHandler::Init() {
432 CurrentIOThread::Get()->RegisterIOHandler(file_.get(), this);
433
434 DWORD read;
435 EXPECT_FALSE(ReadFile(file_.get(), buffer_, size(), &read, context()));
436 EXPECT_EQ(static_cast<DWORD>(ERROR_IO_PENDING), GetLastError());
437 }
438
OnIOCompleted(MessagePumpForIO::IOContext * context,DWORD bytes_transfered,DWORD error)439 void TestIOHandler::OnIOCompleted(MessagePumpForIO::IOContext* context,
440 DWORD bytes_transfered,
441 DWORD error) {
442 ASSERT_TRUE(context == &context_);
443 ASSERT_TRUE(SetEvent(signal_));
444 }
445
RunTest_IOHandler()446 void RunTest_IOHandler() {
447 win::ScopedHandle callback_called(CreateEvent(NULL, TRUE, FALSE, NULL));
448 ASSERT_TRUE(callback_called.is_valid());
449
450 const wchar_t* kPipeName = L"\\\\.\\pipe\\iohandler_pipe";
451 win::ScopedHandle server(
452 CreateNamedPipe(kPipeName, PIPE_ACCESS_OUTBOUND, 0, 1, 0, 0, 0, NULL));
453 ASSERT_TRUE(server.is_valid());
454
455 Thread thread("IOHandler test");
456 Thread::Options options;
457 options.message_pump_type = MessagePumpType::IO;
458 ASSERT_TRUE(thread.StartWithOptions(std::move(options)));
459
460 TestIOHandler handler(kPipeName, callback_called.get());
461 thread.task_runner()->PostTask(
462 FROM_HERE, BindOnce(&TestIOHandler::Init, Unretained(&handler)));
463 // Make sure the thread runs and sleeps for lack of work.
464 PlatformThread::Sleep(Milliseconds(100));
465
466 const char buffer[] = "Hello there!";
467 DWORD written;
468 EXPECT_TRUE(WriteFile(server.get(), buffer, sizeof(buffer), &written, NULL));
469
470 DWORD result = WaitForSingleObject(callback_called.get(), 1000);
471 EXPECT_EQ(WAIT_OBJECT_0, result);
472
473 thread.Stop();
474 }
475
476 #endif // BUILDFLAG(IS_WIN)
477
478 } // namespace
479
480 //-----------------------------------------------------------------------------
481 // Each test is run against each type of SingleThreadTaskExecutor. That way we
482 // are sure that SingleThreadTaskExecutor works properly in all configurations.
483 // Of course, in some cases, a unit test may only be for a particular type of
484 // loop.
485
486 class SingleThreadTaskExecutorTypedTest
487 : public ::testing::TestWithParam<MessagePumpType> {
488 public:
489 SingleThreadTaskExecutorTypedTest() = default;
490
491 SingleThreadTaskExecutorTypedTest(const SingleThreadTaskExecutorTypedTest&) =
492 delete;
493 SingleThreadTaskExecutorTypedTest& operator=(
494 const SingleThreadTaskExecutorTypedTest&) = delete;
495
496 ~SingleThreadTaskExecutorTypedTest() = default;
497
ParamInfoToString(::testing::TestParamInfo<MessagePumpType> param_info)498 static std::string ParamInfoToString(
499 ::testing::TestParamInfo<MessagePumpType> param_info) {
500 switch (param_info.param) {
501 case MessagePumpType::DEFAULT:
502 return "default_pump";
503 case MessagePumpType::IO:
504 return "IO_pump";
505 case MessagePumpType::UI:
506 return "UI_pump";
507 case MessagePumpType::CUSTOM:
508 break;
509 #if BUILDFLAG(IS_ANDROID)
510 case MessagePumpType::JAVA:
511 break;
512 #endif // BUILDFLAG(IS_ANDROID)
513 #if BUILDFLAG(IS_APPLE)
514 case MessagePumpType::NS_RUNLOOP:
515 break;
516 #endif // BUILDFLAG(IS_APPLE)
517 }
518 NOTREACHED();
519 return "";
520 }
521 };
522
TEST_P(SingleThreadTaskExecutorTypedTest,PostTask)523 TEST_P(SingleThreadTaskExecutorTypedTest, PostTask) {
524 SingleThreadTaskExecutor executor(GetParam());
525 base::RunLoop loop;
526 // Add tests to message loop
527 scoped_refptr<Foo> foo(new Foo());
528 std::string a("a"), b("b"), c("c"), d("d");
529 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
530 FROM_HERE, BindOnce(&Foo::Test0, foo));
531 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
532 FROM_HERE, BindOnce(&Foo::Test1ConstRef, foo, a));
533 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
534 FROM_HERE, BindOnce(&Foo::Test1Ptr, foo, &b));
535 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
536 FROM_HERE, BindOnce(&Foo::Test1Int, foo, 100));
537 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
538 FROM_HERE, BindOnce(&Foo::Test2Ptr, foo, &a, &c));
539 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
540 FROM_HERE, BindOnce(&Foo::Test2Mixed, foo, a, &d));
541 // After all tests, post a message that will shut down the message loop
542 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
543 FROM_HERE, BindOnce(loop.QuitWhenIdleClosure()));
544
545 // Now kick things off
546 loop.Run();
547
548 EXPECT_EQ(foo->test_count(), 105);
549 EXPECT_EQ(foo->result(), "abacad");
550 }
551
TEST_P(SingleThreadTaskExecutorTypedTest,PostDelayedTask_Basic)552 TEST_P(SingleThreadTaskExecutorTypedTest, PostDelayedTask_Basic) {
553 SingleThreadTaskExecutor executor(GetParam());
554
555 // Test that PostDelayedTask results in a delayed task.
556
557 const TimeDelta kDelay = Milliseconds(100);
558
559 int num_tasks = 1;
560 TimeTicks run_time;
561 base::RunLoop loop;
562 TimeTicks time_before_run = TimeTicks::Now();
563 executor.task_runner()->PostDelayedTask(
564 FROM_HERE,
565 BindOnce(&RecordRunTimeFunc, &run_time, &num_tasks,
566 loop.QuitWhenIdleClosure()),
567 kDelay);
568 loop.Run();
569 TimeTicks time_after_run = TimeTicks::Now();
570
571 EXPECT_EQ(0, num_tasks);
572 EXPECT_LT(kDelay, time_after_run - time_before_run);
573 }
574
TEST_P(SingleThreadTaskExecutorTypedTest,PostDelayedTask_InDelayOrder)575 TEST_P(SingleThreadTaskExecutorTypedTest, PostDelayedTask_InDelayOrder) {
576 SingleThreadTaskExecutor executor(GetParam());
577
578 // Test that two tasks with different delays run in the right order.
579 int num_tasks = 2;
580 TimeTicks run_time1, run_time2;
581 base::RunLoop loop;
582 executor.task_runner()->PostDelayedTask(
583 FROM_HERE,
584 BindOnce(&RecordRunTimeFunc, &run_time1, &num_tasks,
585 loop.QuitWhenIdleClosure()),
586 Milliseconds(200));
587 // If we get a large pause in execution (due to a context switch) here, this
588 // test could fail.
589 executor.task_runner()->PostDelayedTask(
590 FROM_HERE,
591 BindOnce(&RecordRunTimeFunc, &run_time2, &num_tasks,
592 loop.QuitWhenIdleClosure()),
593 Milliseconds(10));
594
595 loop.Run();
596 EXPECT_EQ(0, num_tasks);
597
598 EXPECT_TRUE(run_time2 < run_time1);
599 }
600
TEST_P(SingleThreadTaskExecutorTypedTest,PostDelayedTask_InPostOrder)601 TEST_P(SingleThreadTaskExecutorTypedTest, PostDelayedTask_InPostOrder) {
602 SingleThreadTaskExecutor executor(GetParam());
603
604 // Test that two tasks with the same delay run in the order in which they
605 // were posted.
606 //
607 // NOTE: This is actually an approximate test since the API only takes a
608 // "delay" parameter, so we are not exactly simulating two tasks that get
609 // posted at the exact same time. It would be nice if the API allowed us to
610 // specify the desired run time.
611
612 const TimeDelta kDelay = Milliseconds(100);
613
614 int num_tasks = 2;
615 TimeTicks run_time1, run_time2;
616 base::RunLoop loop;
617 executor.task_runner()->PostDelayedTask(
618 FROM_HERE,
619 BindOnce(&RecordRunTimeFunc, &run_time1, &num_tasks,
620 loop.QuitWhenIdleClosure()),
621 kDelay);
622 executor.task_runner()->PostDelayedTask(
623 FROM_HERE,
624 BindOnce(&RecordRunTimeFunc, &run_time2, &num_tasks,
625 loop.QuitWhenIdleClosure()),
626 kDelay);
627
628 loop.Run();
629 EXPECT_EQ(0, num_tasks);
630
631 EXPECT_TRUE(run_time1 < run_time2);
632 }
633
TEST_P(SingleThreadTaskExecutorTypedTest,PostDelayedTask_InPostOrder_2)634 TEST_P(SingleThreadTaskExecutorTypedTest, PostDelayedTask_InPostOrder_2) {
635 SingleThreadTaskExecutor executor(GetParam());
636
637 // Test that a delayed task still runs after a normal tasks even if the
638 // normal tasks take a long time to run.
639
640 const TimeDelta kPause = Milliseconds(50);
641
642 int num_tasks = 2;
643 TimeTicks run_time;
644 base::RunLoop loop;
645 executor.task_runner()->PostTask(
646 FROM_HERE,
647 BindOnce(&SlowFunc, kPause, &num_tasks, loop.QuitWhenIdleClosure()));
648 executor.task_runner()->PostDelayedTask(
649 FROM_HERE,
650 BindOnce(&RecordRunTimeFunc, &run_time, &num_tasks,
651 loop.QuitWhenIdleClosure()),
652 Milliseconds(10));
653
654 TimeTicks time_before_run = TimeTicks::Now();
655 loop.Run();
656 TimeTicks time_after_run = TimeTicks::Now();
657
658 EXPECT_EQ(0, num_tasks);
659
660 EXPECT_LT(kPause, time_after_run - time_before_run);
661 }
662
TEST_P(SingleThreadTaskExecutorTypedTest,PostDelayedTask_InPostOrder_3)663 TEST_P(SingleThreadTaskExecutorTypedTest, PostDelayedTask_InPostOrder_3) {
664 SingleThreadTaskExecutor executor(GetParam());
665
666 // Test that a delayed task still runs after a pile of normal tasks. The key
667 // difference between this test and the previous one is that here we return
668 // the SingleThreadTaskExecutor a lot so we give the SingleThreadTaskExecutor
669 // plenty of opportunities to maybe run the delayed task. It should know not
670 // to do so until the delayed task's delay has passed.
671
672 int num_tasks = 11;
673 TimeTicks run_time1, run_time2;
674 base::RunLoop loop;
675 // Clutter the ML with tasks.
676 for (int i = 1; i < num_tasks; ++i)
677 executor.task_runner()->PostTask(
678 FROM_HERE, BindOnce(&RecordRunTimeFunc, &run_time1, &num_tasks,
679 loop.QuitWhenIdleClosure()));
680
681 executor.task_runner()->PostDelayedTask(
682 FROM_HERE,
683 BindOnce(&RecordRunTimeFunc, &run_time2, &num_tasks,
684 loop.QuitWhenIdleClosure()),
685 Milliseconds(1));
686
687 loop.Run();
688 EXPECT_EQ(0, num_tasks);
689
690 EXPECT_TRUE(run_time2 > run_time1);
691 }
692
TEST_P(SingleThreadTaskExecutorTypedTest,PostDelayedTask_SharedTimer)693 TEST_P(SingleThreadTaskExecutorTypedTest, PostDelayedTask_SharedTimer) {
694 SingleThreadTaskExecutor executor(GetParam());
695
696 // Test that the interval of the timer, used to run the next delayed task, is
697 // set to a value corresponding to when the next delayed task should run.
698
699 // By setting num_tasks to 1, we ensure that the first task to run causes the
700 // run loop to exit.
701 int num_tasks = 1;
702 TimeTicks run_time1, run_time2;
703 base::RunLoop loop;
704 executor.task_runner()->PostDelayedTask(
705 FROM_HERE,
706 BindOnce(&RecordRunTimeFunc, &run_time1, &num_tasks,
707 loop.QuitWhenIdleClosure()),
708 Seconds(1000));
709 executor.task_runner()->PostDelayedTask(
710 FROM_HERE,
711 BindOnce(&RecordRunTimeFunc, &run_time2, &num_tasks,
712 loop.QuitWhenIdleClosure()),
713 Milliseconds(10));
714
715 TimeTicks start_time = TimeTicks::Now();
716
717 loop.Run();
718 EXPECT_EQ(0, num_tasks);
719
720 // Ensure that we ran in far less time than the slower timer.
721 TimeDelta total_time = TimeTicks::Now() - start_time;
722 EXPECT_GT(5000, total_time.InMilliseconds());
723
724 // In case both timers somehow run at nearly the same time, sleep a little
725 // and then run all pending to force them both to have run. This is just
726 // encouraging flakiness if there is any.
727 PlatformThread::Sleep(Milliseconds(100));
728 RunLoop().RunUntilIdle();
729
730 EXPECT_TRUE(run_time1.is_null());
731 EXPECT_FALSE(run_time2.is_null());
732 }
733
734 namespace {
735
736 // This is used to inject a test point for recording the destructor calls for
737 // Closure objects send to MessageLoop::PostTask(). It is awkward usage since we
738 // are trying to hook the actual destruction, which is not a common operation.
739 class RecordDeletionProbe : public RefCounted<RecordDeletionProbe> {
740 public:
RecordDeletionProbe(RecordDeletionProbe * post_on_delete,bool * was_deleted)741 RecordDeletionProbe(RecordDeletionProbe* post_on_delete, bool* was_deleted)
742 : post_on_delete_(post_on_delete), was_deleted_(was_deleted) {}
Run()743 void Run() {}
744
745 private:
746 friend class RefCounted<RecordDeletionProbe>;
747
~RecordDeletionProbe()748 ~RecordDeletionProbe() {
749 *was_deleted_ = true;
750 if (post_on_delete_.get())
751 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
752 FROM_HERE, BindOnce(&RecordDeletionProbe::Run, post_on_delete_));
753 }
754
755 scoped_refptr<RecordDeletionProbe> post_on_delete_;
756 raw_ptr<bool> was_deleted_;
757 };
758
759 } // namespace
760
761 /* TODO(darin): SingleThreadTaskExecutor does not support deleting all tasks in
762 */
763 /* the destructor. */
764 /* Fails, http://crbug.com/50272. */
TEST_P(SingleThreadTaskExecutorTypedTest,DISABLED_EnsureDeletion)765 TEST_P(SingleThreadTaskExecutorTypedTest, DISABLED_EnsureDeletion) {
766 bool a_was_deleted = false;
767 bool b_was_deleted = false;
768 {
769 SingleThreadTaskExecutor executor(GetParam());
770 executor.task_runner()->PostTask(
771 FROM_HERE, BindOnce(&RecordDeletionProbe::Run,
772 new RecordDeletionProbe(nullptr, &a_was_deleted)));
773 // TODO(ajwong): Do we really need 1000ms here?
774 executor.task_runner()->PostDelayedTask(
775 FROM_HERE,
776 BindOnce(&RecordDeletionProbe::Run,
777 new RecordDeletionProbe(nullptr, &b_was_deleted)),
778 Milliseconds(1000));
779 }
780 EXPECT_TRUE(a_was_deleted);
781 EXPECT_TRUE(b_was_deleted);
782 }
783
784 /* TODO(darin): SingleThreadTaskExecutor does not support deleting all tasks in
785 */
786 /* the destructor. */
787 /* Fails, http://crbug.com/50272. */
TEST_P(SingleThreadTaskExecutorTypedTest,DISABLED_EnsureDeletion_Chain)788 TEST_P(SingleThreadTaskExecutorTypedTest, DISABLED_EnsureDeletion_Chain) {
789 bool a_was_deleted = false;
790 bool b_was_deleted = false;
791 bool c_was_deleted = false;
792 {
793 SingleThreadTaskExecutor executor(GetParam());
794 // The scoped_refptr for each of the below is held either by the chained
795 // RecordDeletionProbe, or the bound RecordDeletionProbe::Run() callback.
796 RecordDeletionProbe* a = new RecordDeletionProbe(nullptr, &a_was_deleted);
797 RecordDeletionProbe* b = new RecordDeletionProbe(a, &b_was_deleted);
798 RecordDeletionProbe* c = new RecordDeletionProbe(b, &c_was_deleted);
799 executor.task_runner()->PostTask(FROM_HERE,
800 BindOnce(&RecordDeletionProbe::Run, c));
801 }
802 EXPECT_TRUE(a_was_deleted);
803 EXPECT_TRUE(b_was_deleted);
804 EXPECT_TRUE(c_was_deleted);
805 }
806
807 namespace {
808
NestingFunc(int * depth,base::OnceClosure quit_closure)809 void NestingFunc(int* depth, base::OnceClosure quit_closure) {
810 if (*depth > 0) {
811 *depth -= 1;
812 base::RunLoop loop1{base::RunLoop::Type::kNestableTasksAllowed};
813 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
814 FROM_HERE, BindOnce(&NestingFunc, depth, loop1.QuitWhenIdleClosure()));
815
816 loop1.Run();
817 }
818 std::move(quit_closure).Run();
819 }
820
821 } // namespace
822
TEST_P(SingleThreadTaskExecutorTypedTest,Nesting)823 TEST_P(SingleThreadTaskExecutorTypedTest, Nesting) {
824 SingleThreadTaskExecutor executor(GetParam());
825 base::RunLoop loop;
826 int depth = 50;
827 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
828 FROM_HERE, BindOnce(&NestingFunc, &depth, loop.QuitWhenIdleClosure()));
829 loop.Run();
830 EXPECT_EQ(depth, 0);
831 }
832
TEST_P(SingleThreadTaskExecutorTypedTest,Recursive)833 TEST_P(SingleThreadTaskExecutorTypedTest, Recursive) {
834 SingleThreadTaskExecutor executor(GetParam());
835
836 TaskList order;
837 base::RunLoop loop;
838 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
839 FROM_HERE, BindOnce(&RecursiveFunc, &order, 1, 2));
840 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
841 FROM_HERE, BindOnce(&RecursiveFunc, &order, 2, 2));
842 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
843 FROM_HERE, BindOnce(&QuitFunc, &order, 3, loop.QuitWhenIdleClosure()));
844
845 loop.Run();
846
847 // FIFO order.
848 ASSERT_EQ(14U, order.Size());
849 EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
850 EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
851 EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true));
852 EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false));
853 EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true));
854 EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false));
855 EXPECT_EQ(order.Get(6), TaskItem(RECURSIVE, 1, true));
856 EXPECT_EQ(order.Get(7), TaskItem(RECURSIVE, 1, false));
857 EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true));
858 EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false));
859 EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true));
860 EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false));
861 EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 2, true));
862 EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 2, false));
863 }
864
865 namespace {
866
OrderedFunc(TaskList * order,int cookie)867 void OrderedFunc(TaskList* order, int cookie) {
868 order->RecordStart(ORDERED, cookie);
869 order->RecordEnd(ORDERED, cookie);
870 }
871
872 } // namespace
873
874 // Tests that non nestable tasks run in FIFO if there are no nested loops.
TEST_P(SingleThreadTaskExecutorTypedTest,NonNestableWithNoNesting)875 TEST_P(SingleThreadTaskExecutorTypedTest, NonNestableWithNoNesting) {
876 SingleThreadTaskExecutor executor(GetParam());
877
878 TaskList order;
879 base::RunLoop loop;
880 SingleThreadTaskRunner::GetCurrentDefault()->PostNonNestableTask(
881 FROM_HERE, BindOnce(&OrderedFunc, &order, 1));
882 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
883 FROM_HERE, BindOnce(&OrderedFunc, &order, 2));
884 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
885 FROM_HERE, BindOnce(&QuitFunc, &order, 3, loop.QuitWhenIdleClosure()));
886 loop.Run();
887
888 // FIFO order.
889 ASSERT_EQ(6U, order.Size());
890 EXPECT_EQ(order.Get(0), TaskItem(ORDERED, 1, true));
891 EXPECT_EQ(order.Get(1), TaskItem(ORDERED, 1, false));
892 EXPECT_EQ(order.Get(2), TaskItem(ORDERED, 2, true));
893 EXPECT_EQ(order.Get(3), TaskItem(ORDERED, 2, false));
894 EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true));
895 EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false));
896 }
897
898 namespace {
899
FuncThatPumps(TaskList * order,int cookie)900 void FuncThatPumps(TaskList* order, int cookie) {
901 order->RecordStart(PUMPS, cookie);
902 RunLoop(RunLoop::Type::kNestableTasksAllowed).RunUntilIdle();
903 order->RecordEnd(PUMPS, cookie);
904 }
905
SleepFunc(TaskList * order,int cookie,TimeDelta delay)906 void SleepFunc(TaskList* order, int cookie, TimeDelta delay) {
907 order->RecordStart(SLEEP, cookie);
908 PlatformThread::Sleep(delay);
909 order->RecordEnd(SLEEP, cookie);
910 }
911
912 } // namespace
913
914 // Tests that non nestable tasks don't run when there's code in the call stack.
TEST_P(SingleThreadTaskExecutorTypedTest,NonNestableDelayedInNestedLoop)915 TEST_P(SingleThreadTaskExecutorTypedTest, NonNestableDelayedInNestedLoop) {
916 SingleThreadTaskExecutor executor(GetParam());
917
918 TaskList order;
919 base::RunLoop loop;
920 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
921 FROM_HERE, BindOnce(&FuncThatPumps, &order, 1));
922 SingleThreadTaskRunner::GetCurrentDefault()->PostNonNestableTask(
923 FROM_HERE, BindOnce(&OrderedFunc, &order, 2));
924 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
925 FROM_HERE, BindOnce(&OrderedFunc, &order, 3));
926 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
927 FROM_HERE, BindOnce(&SleepFunc, &order, 4, Milliseconds(50)));
928 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
929 FROM_HERE, BindOnce(&OrderedFunc, &order, 5));
930 SingleThreadTaskRunner::GetCurrentDefault()->PostNonNestableTask(
931 FROM_HERE, BindOnce(&QuitFunc, &order, 6, loop.QuitWhenIdleClosure()));
932
933 loop.Run();
934
935 // FIFO order.
936 ASSERT_EQ(12U, order.Size());
937 EXPECT_EQ(order.Get(0), TaskItem(PUMPS, 1, true));
938 EXPECT_EQ(order.Get(1), TaskItem(ORDERED, 3, true));
939 EXPECT_EQ(order.Get(2), TaskItem(ORDERED, 3, false));
940 EXPECT_EQ(order.Get(3), TaskItem(SLEEP, 4, true));
941 EXPECT_EQ(order.Get(4), TaskItem(SLEEP, 4, false));
942 EXPECT_EQ(order.Get(5), TaskItem(ORDERED, 5, true));
943 EXPECT_EQ(order.Get(6), TaskItem(ORDERED, 5, false));
944 EXPECT_EQ(order.Get(7), TaskItem(PUMPS, 1, false));
945 EXPECT_EQ(order.Get(8), TaskItem(ORDERED, 2, true));
946 EXPECT_EQ(order.Get(9), TaskItem(ORDERED, 2, false));
947 EXPECT_EQ(order.Get(10), TaskItem(QUITMESSAGELOOP, 6, true));
948 EXPECT_EQ(order.Get(11), TaskItem(QUITMESSAGELOOP, 6, false));
949 }
950
951 namespace {
952
FuncThatRuns(TaskList * order,int cookie,RunLoop * run_loop)953 void FuncThatRuns(TaskList* order, int cookie, RunLoop* run_loop) {
954 order->RecordStart(RUNS, cookie);
955 run_loop->Run();
956 order->RecordEnd(RUNS, cookie);
957 }
958
FuncThatQuitsNow(base::OnceClosure quit_closure)959 void FuncThatQuitsNow(base::OnceClosure quit_closure) {
960 std::move(quit_closure).Run();
961 }
962
963 } // namespace
964
965 // Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
TEST_P(SingleThreadTaskExecutorTypedTest,QuitNow)966 TEST_P(SingleThreadTaskExecutorTypedTest, QuitNow) {
967 SingleThreadTaskExecutor executor(GetParam());
968
969 TaskList order;
970
971 RunLoop nested_run_loop(RunLoop::Type::kNestableTasksAllowed);
972 RunLoop outer_run_loop;
973 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
974 FROM_HERE,
975 BindOnce(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop)));
976 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
977 FROM_HERE, BindOnce(&OrderedFunc, &order, 2));
978 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
979 FROM_HERE, BindOnce(&FuncThatQuitsNow, nested_run_loop.QuitClosure()));
980 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
981 FROM_HERE, BindOnce(&OrderedFunc, &order, 3));
982 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
983 FROM_HERE, BindOnce(&FuncThatQuitsNow, outer_run_loop.QuitClosure()));
984 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
985 FROM_HERE, BindOnce(&OrderedFunc, &order, 4)); // never runs
986
987 outer_run_loop.Run();
988
989 ASSERT_EQ(6U, order.Size());
990 int task_index = 0;
991 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true));
992 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true));
993 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false));
994 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false));
995 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, true));
996 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, false));
997 EXPECT_EQ(static_cast<size_t>(task_index), order.Size());
998 }
999
1000 // Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
TEST_P(SingleThreadTaskExecutorTypedTest,RunLoopQuitTop)1001 TEST_P(SingleThreadTaskExecutorTypedTest, RunLoopQuitTop) {
1002 SingleThreadTaskExecutor executor(GetParam());
1003
1004 TaskList order;
1005
1006 RunLoop outer_run_loop;
1007 RunLoop nested_run_loop(RunLoop::Type::kNestableTasksAllowed);
1008
1009 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1010 FROM_HERE,
1011 BindOnce(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop)));
1012 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1013 FROM_HERE, outer_run_loop.QuitClosure());
1014 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1015 FROM_HERE, BindOnce(&OrderedFunc, &order, 2));
1016 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1017 FROM_HERE, nested_run_loop.QuitClosure());
1018
1019 outer_run_loop.Run();
1020
1021 ASSERT_EQ(4U, order.Size());
1022 int task_index = 0;
1023 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true));
1024 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true));
1025 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false));
1026 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false));
1027 EXPECT_EQ(static_cast<size_t>(task_index), order.Size());
1028 }
1029
1030 // Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
TEST_P(SingleThreadTaskExecutorTypedTest,RunLoopQuitNested)1031 TEST_P(SingleThreadTaskExecutorTypedTest, RunLoopQuitNested) {
1032 SingleThreadTaskExecutor executor(GetParam());
1033
1034 TaskList order;
1035
1036 RunLoop outer_run_loop;
1037 RunLoop nested_run_loop(RunLoop::Type::kNestableTasksAllowed);
1038
1039 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1040 FROM_HERE,
1041 BindOnce(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop)));
1042 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1043 FROM_HERE, nested_run_loop.QuitClosure());
1044 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1045 FROM_HERE, BindOnce(&OrderedFunc, &order, 2));
1046 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1047 FROM_HERE, outer_run_loop.QuitClosure());
1048
1049 outer_run_loop.Run();
1050
1051 ASSERT_EQ(4U, order.Size());
1052 int task_index = 0;
1053 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true));
1054 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false));
1055 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true));
1056 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false));
1057 EXPECT_EQ(static_cast<size_t>(task_index), order.Size());
1058 }
1059
1060 // Quits current loop and immediately runs a nested loop.
QuitAndRunNestedLoop(TaskList * order,int cookie,RunLoop * outer_run_loop,RunLoop * nested_run_loop)1061 void QuitAndRunNestedLoop(TaskList* order,
1062 int cookie,
1063 RunLoop* outer_run_loop,
1064 RunLoop* nested_run_loop) {
1065 order->RecordStart(RUNS, cookie);
1066 outer_run_loop->Quit();
1067 nested_run_loop->Run();
1068 order->RecordEnd(RUNS, cookie);
1069 }
1070
1071 // Test that we can run nested loop after quitting the current one.
TEST_P(SingleThreadTaskExecutorTypedTest,RunLoopNestedAfterQuit)1072 TEST_P(SingleThreadTaskExecutorTypedTest, RunLoopNestedAfterQuit) {
1073 SingleThreadTaskExecutor executor(GetParam());
1074
1075 TaskList order;
1076
1077 RunLoop outer_run_loop;
1078 RunLoop nested_run_loop;
1079
1080 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1081 FROM_HERE, nested_run_loop.QuitClosure());
1082 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1083 FROM_HERE, BindOnce(&QuitAndRunNestedLoop, &order, 1, &outer_run_loop,
1084 &nested_run_loop));
1085
1086 outer_run_loop.Run();
1087
1088 ASSERT_EQ(2U, order.Size());
1089 int task_index = 0;
1090 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true));
1091 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false));
1092 EXPECT_EQ(static_cast<size_t>(task_index), order.Size());
1093 }
1094
1095 // Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
TEST_P(SingleThreadTaskExecutorTypedTest,RunLoopQuitBogus)1096 TEST_P(SingleThreadTaskExecutorTypedTest, RunLoopQuitBogus) {
1097 SingleThreadTaskExecutor executor(GetParam());
1098
1099 TaskList order;
1100
1101 RunLoop outer_run_loop;
1102 RunLoop nested_run_loop(RunLoop::Type::kNestableTasksAllowed);
1103 RunLoop bogus_run_loop;
1104
1105 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1106 FROM_HERE,
1107 BindOnce(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop)));
1108 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1109 FROM_HERE, bogus_run_loop.QuitClosure());
1110 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1111 FROM_HERE, BindOnce(&OrderedFunc, &order, 2));
1112 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1113 FROM_HERE, outer_run_loop.QuitClosure());
1114 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1115 FROM_HERE, nested_run_loop.QuitClosure());
1116
1117 outer_run_loop.Run();
1118
1119 ASSERT_EQ(4U, order.Size());
1120 int task_index = 0;
1121 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true));
1122 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true));
1123 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false));
1124 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false));
1125 EXPECT_EQ(static_cast<size_t>(task_index), order.Size());
1126 }
1127
1128 // Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
TEST_P(SingleThreadTaskExecutorTypedTest,RunLoopQuitDeep)1129 TEST_P(SingleThreadTaskExecutorTypedTest, RunLoopQuitDeep) {
1130 SingleThreadTaskExecutor executor(GetParam());
1131
1132 TaskList order;
1133
1134 RunLoop outer_run_loop;
1135 RunLoop nested_loop1(RunLoop::Type::kNestableTasksAllowed);
1136 RunLoop nested_loop2(RunLoop::Type::kNestableTasksAllowed);
1137 RunLoop nested_loop3(RunLoop::Type::kNestableTasksAllowed);
1138 RunLoop nested_loop4(RunLoop::Type::kNestableTasksAllowed);
1139
1140 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1141 FROM_HERE, BindOnce(&FuncThatRuns, &order, 1, Unretained(&nested_loop1)));
1142 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1143 FROM_HERE, BindOnce(&FuncThatRuns, &order, 2, Unretained(&nested_loop2)));
1144 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1145 FROM_HERE, BindOnce(&FuncThatRuns, &order, 3, Unretained(&nested_loop3)));
1146 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1147 FROM_HERE, BindOnce(&FuncThatRuns, &order, 4, Unretained(&nested_loop4)));
1148 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1149 FROM_HERE, BindOnce(&OrderedFunc, &order, 5));
1150 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1151 FROM_HERE, outer_run_loop.QuitClosure());
1152 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1153 FROM_HERE, BindOnce(&OrderedFunc, &order, 6));
1154 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1155 FROM_HERE, nested_loop1.QuitClosure());
1156 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1157 FROM_HERE, BindOnce(&OrderedFunc, &order, 7));
1158 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1159 FROM_HERE, nested_loop2.QuitClosure());
1160 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1161 FROM_HERE, BindOnce(&OrderedFunc, &order, 8));
1162 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1163 FROM_HERE, nested_loop3.QuitClosure());
1164 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1165 FROM_HERE, BindOnce(&OrderedFunc, &order, 9));
1166 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1167 FROM_HERE, nested_loop4.QuitClosure());
1168 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1169 FROM_HERE, BindOnce(&OrderedFunc, &order, 10));
1170
1171 outer_run_loop.Run();
1172
1173 ASSERT_EQ(18U, order.Size());
1174 int task_index = 0;
1175 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true));
1176 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 2, true));
1177 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 3, true));
1178 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 4, true));
1179 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 5, true));
1180 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 5, false));
1181 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 6, true));
1182 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 6, false));
1183 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 7, true));
1184 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 7, false));
1185 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 8, true));
1186 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 8, false));
1187 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 9, true));
1188 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 9, false));
1189 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 4, false));
1190 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 3, false));
1191 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 2, false));
1192 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false));
1193 EXPECT_EQ(static_cast<size_t>(task_index), order.Size());
1194 }
1195
1196 // Tests RunLoopQuit works before RunWithID.
TEST_P(SingleThreadTaskExecutorTypedTest,RunLoopQuitOrderBefore)1197 TEST_P(SingleThreadTaskExecutorTypedTest, RunLoopQuitOrderBefore) {
1198 SingleThreadTaskExecutor executor(GetParam());
1199
1200 TaskList order;
1201
1202 RunLoop run_loop;
1203
1204 run_loop.Quit();
1205
1206 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1207 FROM_HERE, BindOnce(&OrderedFunc, &order, 1)); // never runs
1208 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1209 FROM_HERE, BindOnce(&FuncThatQuitsNow,
1210 run_loop.QuitClosure())); // never runs
1211
1212 run_loop.Run();
1213
1214 ASSERT_EQ(0U, order.Size());
1215 }
1216
1217 // Tests RunLoopQuit works during RunWithID.
TEST_P(SingleThreadTaskExecutorTypedTest,RunLoopQuitOrderDuring)1218 TEST_P(SingleThreadTaskExecutorTypedTest, RunLoopQuitOrderDuring) {
1219 SingleThreadTaskExecutor executor(GetParam());
1220
1221 TaskList order;
1222
1223 RunLoop run_loop;
1224
1225 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1226 FROM_HERE, BindOnce(&OrderedFunc, &order, 1));
1227 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(FROM_HERE,
1228 run_loop.QuitClosure());
1229 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1230 FROM_HERE, BindOnce(&OrderedFunc, &order, 2)); // never runs
1231 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1232 FROM_HERE, BindOnce(&FuncThatQuitsNow,
1233 run_loop.QuitClosure())); // never runs
1234
1235 run_loop.Run();
1236
1237 ASSERT_EQ(2U, order.Size());
1238 int task_index = 0;
1239 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 1, true));
1240 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 1, false));
1241 EXPECT_EQ(static_cast<size_t>(task_index), order.Size());
1242 }
1243
1244 // Tests RunLoopQuit works after RunWithID.
TEST_P(SingleThreadTaskExecutorTypedTest,RunLoopQuitOrderAfter)1245 TEST_P(SingleThreadTaskExecutorTypedTest, RunLoopQuitOrderAfter) {
1246 SingleThreadTaskExecutor executor(GetParam());
1247
1248 TaskList order;
1249
1250 RunLoop nested_run_loop(RunLoop::Type::kNestableTasksAllowed);
1251 RunLoop outer_run_loop;
1252 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1253 FROM_HERE,
1254 BindOnce(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop)));
1255 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1256 FROM_HERE, BindOnce(&OrderedFunc, &order, 2));
1257 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1258 FROM_HERE, BindOnce(&FuncThatQuitsNow, nested_run_loop.QuitClosure()));
1259 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1260 FROM_HERE, BindOnce(&OrderedFunc, &order, 3));
1261 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1262 FROM_HERE, nested_run_loop.QuitClosure()); // has no affect
1263 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1264 FROM_HERE, BindOnce(&OrderedFunc, &order, 4));
1265 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1266 FROM_HERE, BindOnce(&FuncThatQuitsNow, outer_run_loop.QuitClosure()));
1267
1268 outer_run_loop.Run();
1269
1270 ASSERT_EQ(8U, order.Size());
1271 int task_index = 0;
1272 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true));
1273 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true));
1274 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false));
1275 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false));
1276 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, true));
1277 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, false));
1278 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 4, true));
1279 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 4, false));
1280 EXPECT_EQ(static_cast<size_t>(task_index), order.Size());
1281 }
1282
1283 // Regression test for crbug.com/170904 where posting tasks recursively caused
1284 // the message loop to hang in MessagePumpGLib, due to the buffer of the
1285 // internal pipe becoming full. Test all SingleThreadTaskExecutor types to
1286 // ensure this issue does not exist in other MessagePumps.
1287 //
1288 // On Linux, the pipe buffer size is 64KiB by default. The bug caused one byte
1289 // accumulated in the pipe per two posts, so we should repeat 128K times to
1290 // reproduce the bug.
1291 #if BUILDFLAG(IS_CHROMEOS)
1292 // TODO(crbug.com/1188497): This test is unreasonably slow on CrOS and flakily
1293 // times out (100x slower than other platforms which take < 1s to complete
1294 // it).
1295 #define MAYBE_RecursivePostsDoNotFloodPipe DISABLED_RecursivePostsDoNotFloodPipe
1296 #else
1297 #define MAYBE_RecursivePostsDoNotFloodPipe RecursivePostsDoNotFloodPipe
1298 #endif
TEST_P(SingleThreadTaskExecutorTypedTest,MAYBE_RecursivePostsDoNotFloodPipe)1299 TEST_P(SingleThreadTaskExecutorTypedTest, MAYBE_RecursivePostsDoNotFloodPipe) {
1300 SingleThreadTaskExecutor executor(GetParam());
1301 const auto begin_ticks = TimeTicks::Now();
1302 RunLoop run_loop;
1303 Post128KTasksThenQuit(executor.task_runner().get(), begin_ticks, begin_ticks,
1304 TimeDelta(), run_loop.QuitClosure());
1305 run_loop.Run();
1306 }
1307
TEST_P(SingleThreadTaskExecutorTypedTest,ApplicationTasksAllowedInNativeNestedLoopAtTopLevel)1308 TEST_P(SingleThreadTaskExecutorTypedTest,
1309 ApplicationTasksAllowedInNativeNestedLoopAtTopLevel) {
1310 SingleThreadTaskExecutor executor(GetParam());
1311 EXPECT_TRUE(
1312 CurrentThread::Get()->ApplicationTasksAllowedInNativeNestedLoop());
1313 }
1314
1315 // Nestable tasks shouldn't be allowed to run reentrantly by default (regression
1316 // test for https://crbug.com/754112).
TEST_P(SingleThreadTaskExecutorTypedTest,NestableTasksDisallowedByDefault)1317 TEST_P(SingleThreadTaskExecutorTypedTest, NestableTasksDisallowedByDefault) {
1318 SingleThreadTaskExecutor executor(GetParam());
1319 RunLoop run_loop;
1320 executor.task_runner()->PostTask(
1321 FROM_HERE,
1322 BindOnce(
1323 [](RunLoop* run_loop) {
1324 EXPECT_FALSE(CurrentThread::Get()
1325 ->ApplicationTasksAllowedInNativeNestedLoop());
1326 run_loop->Quit();
1327 },
1328 Unretained(&run_loop)));
1329 run_loop.Run();
1330 }
1331
TEST_P(SingleThreadTaskExecutorTypedTest,NestableTasksProcessedWhenRunLoopAllows)1332 TEST_P(SingleThreadTaskExecutorTypedTest,
1333 NestableTasksProcessedWhenRunLoopAllows) {
1334 SingleThreadTaskExecutor executor(GetParam());
1335 RunLoop run_loop;
1336 executor.task_runner()->PostTask(
1337 FROM_HERE,
1338 BindOnce(
1339 [](RunLoop* run_loop) {
1340 // This test would hang if this RunLoop wasn't of type
1341 // kNestableTasksAllowed (i.e. this is testing that this is
1342 // processed and doesn't hang).
1343 RunLoop nested_run_loop(RunLoop::Type::kNestableTasksAllowed);
1344 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1345 FROM_HERE,
1346 BindOnce(
1347 [](RunLoop* nested_run_loop) {
1348 // Each additional layer of application task nesting
1349 // requires its own allowance. The kNestableTasksAllowed
1350 // RunLoop allowed this task to be processed but further
1351 // nestable tasks are by default disallowed from this
1352 // layer.
1353 EXPECT_FALSE(
1354 CurrentThread::Get()
1355 ->ApplicationTasksAllowedInNativeNestedLoop());
1356 nested_run_loop->Quit();
1357 },
1358 Unretained(&nested_run_loop)));
1359 nested_run_loop.Run();
1360
1361 run_loop->Quit();
1362 },
1363 Unretained(&run_loop)));
1364 run_loop.Run();
1365 }
1366
TEST_P(SingleThreadTaskExecutorTypedTest,IsIdleForTesting)1367 TEST_P(SingleThreadTaskExecutorTypedTest, IsIdleForTesting) {
1368 SingleThreadTaskExecutor executor(GetParam());
1369 EXPECT_TRUE(CurrentThread::Get()->IsIdleForTesting());
1370 executor.task_runner()->PostTask(FROM_HERE, BindOnce([]() {}));
1371 executor.task_runner()->PostDelayedTask(FROM_HERE, BindOnce([]() {}),
1372 Milliseconds(10));
1373 EXPECT_FALSE(CurrentThread::Get()->IsIdleForTesting());
1374 RunLoop().RunUntilIdle();
1375 EXPECT_TRUE(CurrentThread::Get()->IsIdleForTesting());
1376
1377 PlatformThread::Sleep(Milliseconds(20));
1378 EXPECT_TRUE(CurrentThread::Get()->IsIdleForTesting());
1379 }
1380
TEST_P(SingleThreadTaskExecutorTypedTest,IsIdleForTestingNonNestableTask)1381 TEST_P(SingleThreadTaskExecutorTypedTest, IsIdleForTestingNonNestableTask) {
1382 SingleThreadTaskExecutor executor(GetParam());
1383 RunLoop run_loop;
1384 EXPECT_TRUE(CurrentThread::Get()->IsIdleForTesting());
1385 bool nested_task_run = false;
1386 executor.task_runner()->PostTask(
1387 FROM_HERE, BindLambdaForTesting([&]() {
1388 RunLoop nested_run_loop(RunLoop::Type::kNestableTasksAllowed);
1389
1390 executor.task_runner()->PostNonNestableTask(
1391 FROM_HERE, BindLambdaForTesting([&]() { nested_task_run = true; }));
1392
1393 executor.task_runner()->PostTask(
1394 FROM_HERE, BindLambdaForTesting([&]() {
1395 EXPECT_FALSE(nested_task_run);
1396 EXPECT_TRUE(CurrentThread::Get()->IsIdleForTesting());
1397 }));
1398
1399 nested_run_loop.RunUntilIdle();
1400 EXPECT_FALSE(nested_task_run);
1401 EXPECT_FALSE(CurrentThread::Get()->IsIdleForTesting());
1402 }));
1403
1404 run_loop.RunUntilIdle();
1405
1406 EXPECT_TRUE(nested_task_run);
1407 EXPECT_TRUE(CurrentThread::Get()->IsIdleForTesting());
1408 }
1409
1410 INSTANTIATE_TEST_SUITE_P(All,
1411 SingleThreadTaskExecutorTypedTest,
1412 ::testing::Values(MessagePumpType::DEFAULT,
1413 MessagePumpType::UI,
1414 MessagePumpType::IO),
1415 SingleThreadTaskExecutorTypedTest::ParamInfoToString);
1416
1417 #if BUILDFLAG(IS_WIN)
1418
1419 // Verifies that the SingleThreadTaskExecutor ignores WM_QUIT, rather than
1420 // quitting. Users of SingleThreadTaskExecutor typically expect to control when
1421 // their RunLoops stop Run()ning explicitly, via QuitClosure() etc (see
1422 // https://crbug.com/720078).
TEST(SingleThreadTaskExecutorTest,WmQuitIsIgnored)1423 TEST(SingleThreadTaskExecutorTest, WmQuitIsIgnored) {
1424 SingleThreadTaskExecutor executor(MessagePumpType::UI);
1425
1426 // Post a WM_QUIT message to the current thread.
1427 ::PostQuitMessage(0);
1428
1429 // Post a task to the current thread, with a small delay to make it less
1430 // likely that we process the posted task before looking for WM_* messages.
1431 bool task_was_run = false;
1432 RunLoop run_loop;
1433 executor.task_runner()->PostDelayedTask(
1434 FROM_HERE,
1435 BindOnce(
1436 [](bool* flag, OnceClosure closure) {
1437 *flag = true;
1438 std::move(closure).Run();
1439 },
1440 &task_was_run, run_loop.QuitClosure()),
1441 TestTimeouts::tiny_timeout());
1442
1443 // Run the loop, and ensure that the posted task is processed before we quit.
1444 run_loop.Run();
1445 EXPECT_TRUE(task_was_run);
1446 }
1447
TEST(SingleThreadTaskExecutorTest,PostDelayedTask_SharedTimer_SubPump)1448 TEST(SingleThreadTaskExecutorTest, PostDelayedTask_SharedTimer_SubPump) {
1449 SingleThreadTaskExecutor executor(MessagePumpType::UI);
1450
1451 // Test that the interval of the timer, used to run the next delayed task, is
1452 // set to a value corresponding to when the next delayed task should run.
1453
1454 // By setting num_tasks to 1, we ensure that the first task to run causes the
1455 // run loop to exit.
1456 int num_tasks = 1;
1457 TimeTicks run_time;
1458
1459 RunLoop run_loop;
1460
1461 executor.task_runner()->PostTask(
1462 FROM_HERE, BindOnce(&SubPumpFunc, run_loop.QuitClosure()));
1463
1464 // This very delayed task should never run.
1465 executor.task_runner()->PostDelayedTask(
1466 FROM_HERE,
1467 BindOnce(&RecordRunTimeFunc, &run_time, &num_tasks,
1468 run_loop.QuitWhenIdleClosure()),
1469 Seconds(1000));
1470
1471 // This slightly delayed task should run from within SubPumpFunc.
1472 executor.task_runner()->PostDelayedTask(
1473 FROM_HERE, BindOnce(&::PostQuitMessage, 0), Milliseconds(10));
1474
1475 Time start_time = Time::Now();
1476
1477 run_loop.Run();
1478 EXPECT_EQ(1, num_tasks);
1479
1480 // Ensure that we ran in far less time than the slower timer.
1481 TimeDelta total_time = Time::Now() - start_time;
1482 EXPECT_GT(5000, total_time.InMilliseconds());
1483
1484 // In case both timers somehow run at nearly the same time, sleep a little
1485 // and then run all pending to force them both to have run. This is just
1486 // encouraging flakiness if there is any.
1487 PlatformThread::Sleep(Milliseconds(100));
1488 RunLoop().RunUntilIdle();
1489
1490 EXPECT_TRUE(run_time.is_null());
1491 }
1492
1493 namespace {
1494
1495 // When this fires (per the associated WM_TIMER firing), it posts an
1496 // application task to quit the native loop.
QuitOnSystemTimer(UINT message,WPARAM wparam,LPARAM lparam,LRESULT * result)1497 bool QuitOnSystemTimer(UINT message,
1498 WPARAM wparam,
1499 LPARAM lparam,
1500 LRESULT* result) {
1501 if (message == static_cast<UINT>(WM_TIMER)) {
1502 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1503 FROM_HERE, BindOnce(&::PostQuitMessage, 0));
1504 }
1505 *result = 0;
1506 return true;
1507 }
1508
1509 // When this fires (per the associated WM_TIMER firing), it posts a delayed
1510 // application task to quit the native loop.
DelayedQuitOnSystemTimer(UINT message,WPARAM wparam,LPARAM lparam,LRESULT * result)1511 bool DelayedQuitOnSystemTimer(UINT message,
1512 WPARAM wparam,
1513 LPARAM lparam,
1514 LRESULT* result) {
1515 if (message == static_cast<UINT>(WM_TIMER)) {
1516 SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
1517 FROM_HERE, BindOnce(&::PostQuitMessage, 0), Milliseconds(10));
1518 }
1519 *result = 0;
1520 return true;
1521 }
1522
1523 } // namespace
1524
1525 // This is a regression test for
1526 // https://crrev.com/c/1455266/9/base/message_loop/message_pump_win.cc#125
1527 // See below for the delayed task version.
TEST(SingleThreadTaskExecutorTest,PostImmediateTaskFromSystemPump)1528 TEST(SingleThreadTaskExecutorTest, PostImmediateTaskFromSystemPump) {
1529 SingleThreadTaskExecutor executor(MessagePumpType::UI);
1530
1531 RunLoop run_loop;
1532
1533 // A native message window to generate a system message which invokes
1534 // QuitOnSystemTimer() when the native timer fires.
1535 win::MessageWindow local_message_window;
1536 local_message_window.Create(BindRepeating(&QuitOnSystemTimer));
1537 ASSERT_TRUE(::SetTimer(local_message_window.hwnd(), 0, 20, nullptr));
1538
1539 // The first task will enter a native message loop. This test then verifies
1540 // that the pump is able to run an immediate application task after the native
1541 // pump went idle.
1542 executor.task_runner()->PostTask(
1543 FROM_HERE, BindOnce(&SubPumpFunc, run_loop.QuitClosure()));
1544
1545 // Test success is determined by not hanging in this Run() call.
1546 run_loop.Run();
1547 }
1548
1549 // This is a regression test for
1550 // https://crrev.com/c/1455266/9/base/message_loop/message_pump_win.cc#125 This
1551 // is the delayed task equivalent of the above PostImmediateTaskFromSystemPump
1552 // test.
1553 //
1554 // As a reminder of how this works, here's the sequence of events in this test:
1555 // 1) Test start:
1556 // work_deduplicator.cc(24): BindToCurrentThread
1557 // work_deduplicator.cc(34): OnWorkRequested
1558 // thread_controller_with_message_pump_impl.cc(237) : DoWork
1559 // work_deduplicator.cc(50): OnWorkStarted
1560 // 2) SubPumpFunc entered:
1561 // message_loop_unittest.cc(278): SubPumpFunc
1562 // 3) ScopedAllowApplicationTasksInNativeNestedLoop triggers nested
1563 // ScheduleWork: work_deduplicator.cc(34): OnWorkRequested
1564 // 4) Nested system loop starts and pumps internal kMsgHaveWork:
1565 // message_loop_unittest.cc(282): SubPumpFunc : Got Message
1566 // message_pump_win.cc(302): HandleWorkMessage
1567 // thread_controller_with_message_pump_impl.cc(237) : DoWork
1568 // 5) Attempt to DoWork(), there's nothing to do, NextWorkInfo indicates delay.
1569 // work_deduplicator.cc(50): OnWorkStarted
1570 // work_deduplicator.cc(58): WillCheckForMoreWork
1571 // work_deduplicator.cc(67): DidCheckForMoreWork
1572 // 6) Return control to HandleWorkMessage() which schedules native timer
1573 // and goes to sleep (no kMsgHaveWork in native queue).
1574 // message_pump_win.cc(328): HandleWorkMessage ScheduleNativeTimer
1575 // 7) Native timer fires and posts the delayed application task:
1576 // message_loop_unittest.cc(282): SubPumpFunc : Got Message
1577 // message_loop_unittest.cc(1581): DelayedQuitOnSystemTimer
1578 // !! This is the critical step verified by this test. Since the
1579 // ThreadController is idle after (6), it won't be invoked again and thus
1580 // won't get a chance to return a NextWorkInfo that indicates the next
1581 // delay. A native timer is thus required to have SubPumpFunc handle it.
1582 // work_deduplicator.cc(42): OnDelayedWorkRequested
1583 // message_pump_win.cc(129): ScheduleDelayedWork
1584 // 9) The scheduled native timer fires and runs application task binding
1585 // ::PostQuitMessage :
1586 // message_loop_unittest.cc(282) SubPumpFunc : Got Message
1587 // work_deduplicator.cc(50): OnWorkStarted
1588 // thread_controller_with_message_pump_impl.cc(237) : DoWork
1589 // 10) SequenceManager updates delay to none and notifies
1590 // (TODO(scheduler-dev): Could remove this step but WorkDeduplicator knows
1591 // to ignore at least):
1592 // work_deduplicator.cc(42): OnDelayedWorkRequested
1593 // 11) Nested application task completes and SubPumpFunc unwinds:
1594 // work_deduplicator.cc(58): WillCheckForMoreWork
1595 // work_deduplicator.cc(67): DidCheckForMoreWork
1596 // 12) ~ScopedAllowApplicationTasksInNativeNestedLoop() makes sure
1597 // WorkDeduplicator knows we're back in DoWork() (not relevant in this test
1598 // but important overall). work_deduplicator.cc(50): OnWorkStarted
1599 // 13) Application task which ran SubPumpFunc completes and test finishes.
1600 // work_deduplicator.cc(67): DidCheckForMoreWork
TEST(SingleThreadTaskExecutorTest,PostDelayedTaskFromSystemPump)1601 TEST(SingleThreadTaskExecutorTest, PostDelayedTaskFromSystemPump) {
1602 SingleThreadTaskExecutor executor(MessagePumpType::UI);
1603
1604 RunLoop run_loop;
1605
1606 // A native message window to generate a system message which invokes
1607 // DelayedQuitOnSystemTimer() when the native timer fires.
1608 win::MessageWindow local_message_window;
1609 local_message_window.Create(BindRepeating(&DelayedQuitOnSystemTimer));
1610 ASSERT_TRUE(::SetTimer(local_message_window.hwnd(), 0, 20, nullptr));
1611
1612 // The first task will enter a native message loop. This test then verifies
1613 // that the pump is able to run a delayed application task after the native
1614 // pump went idle.
1615 executor.task_runner()->PostTask(
1616 FROM_HERE, BindOnce(&SubPumpFunc, run_loop.QuitClosure()));
1617
1618 // Test success is determined by not hanging in this Run() call.
1619 run_loop.Run();
1620 }
1621
TEST(SingleThreadTaskExecutorTest,WmQuitIsVisibleToSubPump)1622 TEST(SingleThreadTaskExecutorTest, WmQuitIsVisibleToSubPump) {
1623 SingleThreadTaskExecutor executor(MessagePumpType::UI);
1624
1625 // Regression test for https://crbug.com/888559. When processing a
1626 // kMsgHaveWork we peek and remove the next message and dispatch that ourself,
1627 // to minimize impact of these messages on message-queue processing. If we
1628 // received kMsgHaveWork dispatched by a nested pump (e.g. ::GetMessage()
1629 // loop) then there is a risk that the next message is that loop's WM_QUIT
1630 // message, which must be processed directly by ::GetMessage() for the loop to
1631 // actually quit. This test verifies that WM_QUIT exits works as expected even
1632 // if it happens to immediately follow a kMsgHaveWork in the queue.
1633
1634 RunLoop run_loop;
1635
1636 // This application task will enter the subpump.
1637 executor.task_runner()->PostTask(
1638 FROM_HERE, BindOnce(&SubPumpFunc, run_loop.QuitClosure()));
1639
1640 // This application task will post a native WM_QUIT.
1641 executor.task_runner()->PostTask(FROM_HERE, BindOnce(&::PostQuitMessage, 0));
1642
1643 // The presence of this application task means that the pump will see a
1644 // non-empty queue after processing the previous application task (which
1645 // posted the WM_QUIT) and hence will repost a kMsgHaveWork message in the
1646 // native event queue. Without the fix to https://crbug.com/888559, this would
1647 // previously result in the subpump processing kMsgHaveWork and it stealing
1648 // the WM_QUIT message, leaving the test hung in the subpump.
1649 executor.task_runner()->PostTask(FROM_HERE, DoNothing());
1650
1651 // Test success is determined by not hanging in this Run() call.
1652 run_loop.Run();
1653 }
1654
TEST(SingleThreadTaskExecutorTest,RepostingWmQuitDoesntStarveUpcomingNativeLoop)1655 TEST(SingleThreadTaskExecutorTest,
1656 RepostingWmQuitDoesntStarveUpcomingNativeLoop) {
1657 SingleThreadTaskExecutor executor(MessagePumpType::UI);
1658
1659 // This test ensures that application tasks are being processed by the native
1660 // subpump despite the kMsgHaveWork event having already been consumed by the
1661 // time the subpump is entered. This is subtly enforced by
1662 // CurrentThread::ScopedAllowApplicationTasksInNativeNestedLoop which
1663 // will ScheduleWork() upon construction (and if it's absent, the
1664 // SingleThreadTaskExecutor shouldn't process application tasks so
1665 // kMsgHaveWork is irrelevant). Note: This test also fails prior to the fix
1666 // for https://crbug.com/888559 (in fact, the last two tasks are sufficient as
1667 // a regression test), probably because of a dangling kMsgHaveWork recreating
1668 // the effect from
1669 // SingleThreadTaskExecutorTest.NativeMsgProcessingDoesntStealWmQuit.
1670
1671 RunLoop run_loop;
1672
1673 // This application task will post a native WM_QUIT which will be ignored
1674 // by the main message pump.
1675 executor.task_runner()->PostTask(FROM_HERE, BindOnce(&::PostQuitMessage, 0));
1676
1677 // Make sure the pump does a few extra cycles and processes (ignores) the
1678 // WM_QUIT.
1679 executor.task_runner()->PostTask(FROM_HERE, DoNothing());
1680 executor.task_runner()->PostTask(FROM_HERE, DoNothing());
1681
1682 // This application task will enter the subpump.
1683 executor.task_runner()->PostTask(
1684 FROM_HERE, BindOnce(&SubPumpFunc, run_loop.QuitClosure()));
1685
1686 // Post an application task that will post WM_QUIT to the nested loop. The
1687 // test will hang if the subpump doesn't process application tasks as it
1688 // should.
1689 executor.task_runner()->PostTask(FROM_HERE, BindOnce(&::PostQuitMessage, 0));
1690
1691 // Test success is determined by not hanging in this Run() call.
1692 run_loop.Run();
1693 }
1694
1695 // TODO(https://crbug.com/890016): Enable once multiple layers of nested loops
1696 // works.
TEST(SingleThreadTaskExecutorTest,DISABLED_UnwindingMultipleSubPumpsDoesntStarveApplicationTasks)1697 TEST(SingleThreadTaskExecutorTest,
1698 DISABLED_UnwindingMultipleSubPumpsDoesntStarveApplicationTasks) {
1699 SingleThreadTaskExecutor executor(MessagePumpType::UI);
1700
1701 // Regression test for https://crbug.com/890016.
1702 // Tests that the subpump is still processing application tasks after
1703 // unwinding from nested subpumps (i.e. that they didn't consume the last
1704 // kMsgHaveWork).
1705
1706 RunLoop run_loop;
1707
1708 // Enter multiple levels of nested subpumps.
1709 executor.task_runner()->PostTask(
1710 FROM_HERE, BindOnce(&SubPumpFunc, run_loop.QuitClosure()));
1711 executor.task_runner()->PostTask(FROM_HERE,
1712 BindOnce(&SubPumpFunc, DoNothing()));
1713 executor.task_runner()->PostTask(FROM_HERE,
1714 BindOnce(&SubPumpFunc, DoNothing()));
1715
1716 // Quit two layers (with tasks in between to allow each quit to be handled
1717 // before continuing -- ::PostQuitMessage() sets a bit, it's not a real queued
1718 // message :
1719 // https://blogs.msdn.microsoft.com/oldnewthing/20051104-33/?p=33453).
1720 executor.task_runner()->PostTask(FROM_HERE, BindOnce(&::PostQuitMessage, 0));
1721 executor.task_runner()->PostTask(FROM_HERE, DoNothing());
1722 executor.task_runner()->PostTask(FROM_HERE, DoNothing());
1723 executor.task_runner()->PostTask(FROM_HERE, BindOnce(&::PostQuitMessage, 0));
1724 executor.task_runner()->PostTask(FROM_HERE, DoNothing());
1725 executor.task_runner()->PostTask(FROM_HERE, DoNothing());
1726
1727 bool last_task_ran = false;
1728 executor.task_runner()->PostTask(
1729 FROM_HERE, BindOnce([](bool* to_set) { *to_set = true; },
1730 Unretained(&last_task_ran)));
1731
1732 executor.task_runner()->PostTask(FROM_HERE, BindOnce(&::PostQuitMessage, 0));
1733
1734 run_loop.Run();
1735
1736 EXPECT_TRUE(last_task_ran);
1737 }
1738
1739 namespace {
1740
1741 // A side effect of this test is the generation a beep. Sorry.
RunTest_NestingDenial2(MessagePumpType message_pump_type)1742 void RunTest_NestingDenial2(MessagePumpType message_pump_type) {
1743 SingleThreadTaskExecutor executor(message_pump_type);
1744 base::RunLoop loop;
1745 Thread worker("NestingDenial2_worker");
1746 Thread::Options options;
1747 options.message_pump_type = message_pump_type;
1748 ASSERT_EQ(true, worker.StartWithOptions(std::move(options)));
1749 TaskList order;
1750 win::ScopedHandle event(CreateEvent(NULL, FALSE, FALSE, NULL));
1751 worker.task_runner()->PostTask(
1752 FROM_HERE,
1753 BindOnce(&RecursiveFuncWin, SingleThreadTaskRunner::GetCurrentDefault(),
1754 event.get(), true, &order, false, loop.QuitWhenIdleClosure()));
1755 // Let the other thread execute.
1756 WaitForSingleObject(event.get(), INFINITE);
1757 loop.Run();
1758
1759 ASSERT_EQ(17u, order.Size());
1760 EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
1761 EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
1762 EXPECT_EQ(order.Get(2), TaskItem(MESSAGEBOX, 2, true));
1763 EXPECT_EQ(order.Get(3), TaskItem(MESSAGEBOX, 2, false));
1764 EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 3, true));
1765 EXPECT_EQ(order.Get(5), TaskItem(RECURSIVE, 3, false));
1766 // When EndDialogFunc is processed, the window is already dismissed, hence no
1767 // "end" entry.
1768 EXPECT_EQ(order.Get(6), TaskItem(ENDDIALOG, 4, true));
1769 EXPECT_EQ(order.Get(7), TaskItem(QUITMESSAGELOOP, 5, true));
1770 EXPECT_EQ(order.Get(8), TaskItem(QUITMESSAGELOOP, 5, false));
1771 EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 1, true));
1772 EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, false));
1773 EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 3, true));
1774 EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 3, false));
1775 EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 1, true));
1776 EXPECT_EQ(order.Get(14), TaskItem(RECURSIVE, 1, false));
1777 EXPECT_EQ(order.Get(15), TaskItem(RECURSIVE, 3, true));
1778 EXPECT_EQ(order.Get(16), TaskItem(RECURSIVE, 3, false));
1779 }
1780
1781 } // namespace
1782
1783 // This test occasionally hangs, would need to be turned into an
1784 // interactive_ui_test, see http://crbug.com/44567.
TEST(SingleThreadTaskExecutorTest,DISABLED_NestingDenial2)1785 TEST(SingleThreadTaskExecutorTest, DISABLED_NestingDenial2) {
1786 RunTest_NestingDenial2(MessagePumpType::DEFAULT);
1787 RunTest_NestingDenial2(MessagePumpType::UI);
1788 RunTest_NestingDenial2(MessagePumpType::IO);
1789 }
1790
1791 // A side effect of this test is the generation a beep. Sorry. This test also
1792 // needs to process windows messages on the current thread.
TEST(SingleThreadTaskExecutorTest,NestingSupport2)1793 TEST(SingleThreadTaskExecutorTest, NestingSupport2) {
1794 SingleThreadTaskExecutor executor(MessagePumpType::UI);
1795 base::RunLoop loop;
1796 Thread worker("NestingSupport2_worker");
1797 Thread::Options options;
1798 options.message_pump_type = MessagePumpType::UI;
1799 ASSERT_EQ(true, worker.StartWithOptions(std::move(options)));
1800 TaskList order;
1801 win::ScopedHandle event(CreateEvent(NULL, FALSE, FALSE, NULL));
1802 worker.task_runner()->PostTask(
1803 FROM_HERE,
1804 BindOnce(&RecursiveFuncWin, SingleThreadTaskRunner::GetCurrentDefault(),
1805 event.get(), false, &order, true, loop.QuitWhenIdleClosure()));
1806 // Let the other thread execute.
1807 WaitForSingleObject(event.get(), INFINITE);
1808 loop.Run();
1809
1810 ASSERT_EQ(18u, order.Size());
1811 EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
1812 EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
1813 EXPECT_EQ(order.Get(2), TaskItem(MESSAGEBOX, 2, true));
1814 // Note that this executes in the MessageBox modal loop.
1815 EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 3, true));
1816 EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 3, false));
1817 EXPECT_EQ(order.Get(5), TaskItem(ENDDIALOG, 4, true));
1818 EXPECT_EQ(order.Get(6), TaskItem(ENDDIALOG, 4, false));
1819 EXPECT_EQ(order.Get(7), TaskItem(MESSAGEBOX, 2, false));
1820 /* The order can subtly change here. The reason is that when RecursiveFunc(1)
1821 is called in the main thread, if it is faster than getting to the
1822 PostTask(FROM_HERE, BindOnce(&QuitFunc) execution, the order of task
1823 execution can change. We don't care anyway that the order isn't correct.
1824 EXPECT_EQ(order.Get(8), TaskItem(QUITMESSAGELOOP, 5, true));
1825 EXPECT_EQ(order.Get(9), TaskItem(QUITMESSAGELOOP, 5, false));
1826 EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true));
1827 EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false));
1828 */
1829 EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 3, true));
1830 EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 3, false));
1831 EXPECT_EQ(order.Get(14), TaskItem(RECURSIVE, 1, true));
1832 EXPECT_EQ(order.Get(15), TaskItem(RECURSIVE, 1, false));
1833 EXPECT_EQ(order.Get(16), TaskItem(RECURSIVE, 3, true));
1834 EXPECT_EQ(order.Get(17), TaskItem(RECURSIVE, 3, false));
1835 }
1836
1837 #endif // BUILDFLAG(IS_WIN)
1838
1839 #if BUILDFLAG(IS_WIN)
TEST(SingleThreadTaskExecutorTest,IOHandler)1840 TEST(SingleThreadTaskExecutorTest, IOHandler) {
1841 RunTest_IOHandler();
1842 }
1843 #endif // BUILDFLAG(IS_WIN)
1844
1845 namespace {
1846 // Inject a test point for recording the destructor calls for Closure objects
1847 // send to MessageLoop::PostTask(). It is awkward usage since we are trying to
1848 // hook the actual destruction, which is not a common operation.
1849 class DestructionObserverProbe : public RefCounted<DestructionObserverProbe> {
1850 public:
DestructionObserverProbe(bool * task_destroyed,bool * destruction_observer_called)1851 DestructionObserverProbe(bool* task_destroyed,
1852 bool* destruction_observer_called)
1853 : task_destroyed_(task_destroyed),
1854 destruction_observer_called_(destruction_observer_called) {}
Run()1855 virtual void Run() {
1856 // This task should never run.
1857 ADD_FAILURE();
1858 }
1859
1860 private:
1861 friend class RefCounted<DestructionObserverProbe>;
1862
~DestructionObserverProbe()1863 virtual ~DestructionObserverProbe() {
1864 EXPECT_FALSE(*destruction_observer_called_);
1865 *task_destroyed_ = true;
1866 }
1867
1868 raw_ptr<bool> task_destroyed_;
1869 raw_ptr<bool> destruction_observer_called_;
1870 };
1871
1872 class MLDestructionObserver : public CurrentThread::DestructionObserver {
1873 public:
MLDestructionObserver(bool * task_destroyed,bool * destruction_observer_called)1874 MLDestructionObserver(bool* task_destroyed, bool* destruction_observer_called)
1875 : task_destroyed_(task_destroyed),
1876 destruction_observer_called_(destruction_observer_called),
1877 task_destroyed_before_message_loop_(false) {}
WillDestroyCurrentMessageLoop()1878 void WillDestroyCurrentMessageLoop() override {
1879 task_destroyed_before_message_loop_ = *task_destroyed_;
1880 *destruction_observer_called_ = true;
1881 }
task_destroyed_before_message_loop() const1882 bool task_destroyed_before_message_loop() const {
1883 return task_destroyed_before_message_loop_;
1884 }
1885
1886 private:
1887 raw_ptr<bool> task_destroyed_;
1888 raw_ptr<bool> destruction_observer_called_;
1889 bool task_destroyed_before_message_loop_;
1890 };
1891
1892 } // namespace
1893
TEST(SingleThreadTaskExecutorTest,DestructionObserverTest)1894 TEST(SingleThreadTaskExecutorTest, DestructionObserverTest) {
1895 // Verify that the destruction observer gets called at the very end (after
1896 // all the pending tasks have been destroyed).
1897 auto executor = std::make_unique<SingleThreadTaskExecutor>();
1898 const TimeDelta kDelay = Milliseconds(100);
1899
1900 bool task_destroyed = false;
1901 bool destruction_observer_called = false;
1902
1903 MLDestructionObserver observer(&task_destroyed, &destruction_observer_called);
1904 CurrentThread::Get()->AddDestructionObserver(&observer);
1905 executor->task_runner()->PostDelayedTask(
1906 FROM_HERE,
1907 BindOnce(&DestructionObserverProbe::Run,
1908 base::MakeRefCounted<DestructionObserverProbe>(
1909 &task_destroyed, &destruction_observer_called)),
1910 kDelay);
1911 executor.reset();
1912 EXPECT_TRUE(observer.task_destroyed_before_message_loop());
1913 // The task should have been destroyed when we deleted the loop.
1914 EXPECT_TRUE(task_destroyed);
1915 EXPECT_TRUE(destruction_observer_called);
1916 }
1917
1918 // Verify that SingleThreadTaskExecutor sets ThreadMainTaskRunner::current() and
1919 // it posts tasks on that message loop.
TEST(SingleThreadTaskExecutorTest,ThreadMainTaskRunner)1920 TEST(SingleThreadTaskExecutorTest, ThreadMainTaskRunner) {
1921 SingleThreadTaskExecutor executor;
1922 base::RunLoop loop;
1923 scoped_refptr<Foo> foo(new Foo());
1924 std::string a("a");
1925 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1926 FROM_HERE, BindOnce(&Foo::Test1ConstRef, foo, a));
1927
1928 // Post quit task;
1929 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1930 FROM_HERE, BindOnce(loop.QuitWhenIdleClosure()));
1931
1932 // Now kick things off
1933 loop.Run();
1934
1935 EXPECT_EQ(foo->test_count(), 1);
1936 EXPECT_EQ(foo->result(), "a");
1937 }
1938
TEST(SingleThreadTaskExecutorTest,type)1939 TEST(SingleThreadTaskExecutorTest, type) {
1940 SingleThreadTaskExecutor executor(MessagePumpType::UI);
1941 EXPECT_EQ(executor.type(), MessagePumpType::UI);
1942 }
1943
1944 #if BUILDFLAG(IS_WIN)
EmptyFunction()1945 void EmptyFunction() {}
1946
PostMultipleTasks()1947 void PostMultipleTasks() {
1948 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1949 FROM_HERE, base::BindOnce(&EmptyFunction));
1950 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1951 FROM_HERE, base::BindOnce(&EmptyFunction));
1952 }
1953
1954 static const int kSignalMsg = WM_USER + 2;
1955 // this feels wrong
1956 static base::RunLoop* g_loop_to_quit_from_message_handler = nullptr;
PostWindowsMessage(HWND message_hwnd)1957 void PostWindowsMessage(HWND message_hwnd) {
1958 PostMessage(message_hwnd, kSignalMsg, 0, 2);
1959 }
1960
EndTest(bool * did_run,HWND hwnd)1961 void EndTest(bool* did_run, HWND hwnd) {
1962 *did_run = true;
1963 PostMessage(hwnd, WM_CLOSE, 0, 0);
1964 }
1965
1966 int kMyMessageFilterCode = 0x5002;
1967
TestWndProcThunk(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam)1968 LRESULT CALLBACK TestWndProcThunk(HWND hwnd,
1969 UINT message,
1970 WPARAM wparam,
1971 LPARAM lparam) {
1972 if (message == WM_CLOSE)
1973 EXPECT_TRUE(DestroyWindow(hwnd));
1974 if (message != kSignalMsg)
1975 return DefWindowProc(hwnd, message, wparam, lparam);
1976
1977 switch (lparam) {
1978 case 1:
1979 // First, we post a task that will post multiple no-op tasks to make sure
1980 // that the pump's incoming task queue does not become empty during the
1981 // test.
1982 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1983 FROM_HERE, base::BindOnce(&PostMultipleTasks));
1984 // Next, we post a task that posts a windows message to trigger the second
1985 // stage of the test.
1986 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1987 FROM_HERE, base::BindOnce(&PostWindowsMessage, hwnd));
1988 break;
1989 case 2:
1990 // Since we're about to enter a modal loop, tell the message loop that we
1991 // intend to nest tasks.
1992 CurrentThread::ScopedAllowApplicationTasksInNativeNestedLoop
1993 allow_nestable_tasks;
1994 bool did_run = false;
1995 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1996 FROM_HERE, base::BindOnce(&EndTest, &did_run, hwnd));
1997 // Run a nested windows-style message loop and verify that our task runs.
1998 // If it doesn't, then we'll loop here until the test times out.
1999 MSG msg;
2000 while (GetMessage(&msg, 0, 0, 0)) {
2001 if (!CallMsgFilter(&msg, kMyMessageFilterCode))
2002 DispatchMessage(&msg);
2003 // If this message is a WM_CLOSE, explicitly exit the modal loop.
2004 // Posting a WM_QUIT should handle this, but unfortunately
2005 // MessagePumpWin eats WM_QUIT messages even when running inside a modal
2006 // loop.
2007 if (msg.message == WM_CLOSE)
2008 break;
2009 }
2010 EXPECT_TRUE(did_run);
2011
2012 g_loop_to_quit_from_message_handler->QuitWhenIdle();
2013
2014 break;
2015 }
2016 return 0;
2017 }
2018
TEST(SingleThreadTaskExecutorTest,AlwaysHaveUserMessageWhenNesting)2019 TEST(SingleThreadTaskExecutorTest, AlwaysHaveUserMessageWhenNesting) {
2020 SingleThreadTaskExecutor executor(MessagePumpType::UI);
2021 RunLoop loop;
2022
2023 HINSTANCE instance = CURRENT_MODULE();
2024 WNDCLASSEX wc = {0};
2025 wc.cbSize = sizeof(wc);
2026 wc.lpfnWndProc = TestWndProcThunk;
2027 wc.hInstance = instance;
2028 wc.lpszClassName = L"SingleThreadTaskExecutorTest_HWND";
2029 ATOM atom = RegisterClassEx(&wc);
2030 ASSERT_TRUE(atom);
2031
2032 g_loop_to_quit_from_message_handler = &loop;
2033 HWND message_hwnd = CreateWindow(MAKEINTATOM(atom), 0, 0, 0, 0, 0, 0,
2034 HWND_MESSAGE, 0, instance, 0);
2035
2036 ASSERT_TRUE(message_hwnd) << GetLastError();
2037
2038 ASSERT_TRUE(PostMessage(message_hwnd, kSignalMsg, 0, 1));
2039
2040 loop.Run();
2041
2042 ASSERT_TRUE(UnregisterClass(MAKEINTATOM(atom), instance));
2043 g_loop_to_quit_from_message_handler = nullptr;
2044 }
2045 #endif // BUILDFLAG(IS_WIN)
2046
TEST(SingleThreadTaskExecutorTest,ApplicationTasksAllowedInNativeNestedLoopExplicitlyInScope)2047 TEST(SingleThreadTaskExecutorTest,
2048 ApplicationTasksAllowedInNativeNestedLoopExplicitlyInScope) {
2049 // Only UI pumps support native loops.
2050 SingleThreadTaskExecutor executor(MessagePumpType::UI);
2051 RunLoop run_loop;
2052 executor.task_runner()->PostTask(
2053 FROM_HERE,
2054 BindOnce(
2055 [](RunLoop* run_loop) {
2056 {
2057 CurrentThread::ScopedAllowApplicationTasksInNativeNestedLoop
2058 allow_nestable_tasks;
2059 EXPECT_TRUE(CurrentThread::Get()
2060 ->ApplicationTasksAllowedInNativeNestedLoop());
2061 }
2062 EXPECT_FALSE(CurrentThread::Get()
2063 ->ApplicationTasksAllowedInNativeNestedLoop());
2064 run_loop->Quit();
2065 },
2066 Unretained(&run_loop)));
2067 run_loop.Run();
2068 }
2069
2070 // Verify that tasks posted to and code running in the scope of the same
2071 // SingleThreadTaskExecutor access the same SequenceLocalStorage values.
TEST(SingleThreadTaskExecutorTest,SequenceLocalStorageSetGet)2072 TEST(SingleThreadTaskExecutorTest, SequenceLocalStorageSetGet) {
2073 SingleThreadTaskExecutor executor;
2074
2075 SequenceLocalStorageSlot<int> slot;
2076
2077 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
2078 FROM_HERE, BindLambdaForTesting([&]() { slot.emplace(11); }));
2079
2080 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
2081 FROM_HERE, BindLambdaForTesting([&]() { EXPECT_EQ(*slot, 11); }));
2082
2083 RunLoop().RunUntilIdle();
2084 EXPECT_EQ(*slot, 11);
2085 }
2086
2087 // Verify that tasks posted to and code running in different MessageLoops access
2088 // different SequenceLocalStorage values.
TEST(SingleThreadTaskExecutorTest,SequenceLocalStorageDifferentMessageLoops)2089 TEST(SingleThreadTaskExecutorTest, SequenceLocalStorageDifferentMessageLoops) {
2090 SequenceLocalStorageSlot<int> slot;
2091
2092 {
2093 SingleThreadTaskExecutor executor;
2094 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
2095 FROM_HERE, BindLambdaForTesting([&]() { slot.emplace(11); }));
2096
2097 RunLoop().RunUntilIdle();
2098 EXPECT_EQ(*slot, 11);
2099 }
2100
2101 SingleThreadTaskExecutor executor;
2102 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
2103 FROM_HERE, BindLambdaForTesting([&]() { EXPECT_FALSE(slot); }));
2104
2105 RunLoop().RunUntilIdle();
2106 EXPECT_NE(slot.GetOrCreateValue(), 11);
2107 }
2108
2109 namespace {
2110
2111 class PostTaskOnDestroy {
2112 public:
PostTaskOnDestroy(int times)2113 PostTaskOnDestroy(int times) : times_remaining_(times) {}
2114
2115 PostTaskOnDestroy(const PostTaskOnDestroy&) = delete;
2116 PostTaskOnDestroy& operator=(const PostTaskOnDestroy&) = delete;
2117
~PostTaskOnDestroy()2118 ~PostTaskOnDestroy() { PostTaskWithPostingDestructor(times_remaining_); }
2119
2120 // Post a task that will repost itself on destruction |times| times.
PostTaskWithPostingDestructor(int times)2121 static void PostTaskWithPostingDestructor(int times) {
2122 if (times > 0) {
2123 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
2124 FROM_HERE, DoNothingWithBoundArgs(
2125 std::make_unique<PostTaskOnDestroy>(times - 1)));
2126 }
2127 }
2128
2129 private:
2130 const int times_remaining_;
2131 };
2132
2133 } // namespace
2134
2135 // Test that SingleThreadTaskExecutor destruction handles a task's destructor
2136 // posting another task.
TEST(SingleThreadTaskExecutorDestructionTest,DestroysFineWithPostTaskOnDestroy)2137 TEST(SingleThreadTaskExecutorDestructionTest,
2138 DestroysFineWithPostTaskOnDestroy) {
2139 SingleThreadTaskExecutor executor;
2140
2141 PostTaskOnDestroy::PostTaskWithPostingDestructor(10);
2142 }
2143
2144 } // namespace base
2145