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