Flutter Engine
raster_thread_merger_unittests.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #define FML_USED_ON_EMBEDDER
6 
7 #include "flutter/fml/raster_thread_merger.h"
8 
9 #include <thread>
10 
11 #include "flutter/fml/memory/ref_ptr.h"
12 #include "flutter/fml/message_loop.h"
13 #include "flutter/fml/synchronization/count_down_latch.h"
14 #include "flutter/fml/synchronization/waitable_event.h"
15 #include "flutter/fml/task_runner.h"
16 #include "flutter/fml/thread.h"
17 #include "gtest/gtest.h"
18 
19 namespace fml {
20 namespace testing {
21 
22 /// A mock task queue NOT calling MessageLoop->Run() in thread
24  fml::MessageLoop* loop = nullptr;
25 
26  /// The waiter for message loop initialized ok
28 
29  /// The waiter for thread finished
31 
32  /// This field must below latch and term member, because
33  /// cpp standard reference:
34  /// non-static data members are initialized in the order they were declared in
35  /// the class definition
36  std::thread thread;
37 
39  : thread([this]() {
42  latch.Signal();
43  term.Wait();
44  }) {
45  latch.Wait();
46  }
47 
49  term.Signal();
50  thread.join();
51  }
52 
54  return loop->GetTaskRunner()->GetTaskQueueId();
55  }
56 };
57 
58 TEST(RasterThreadMerger, RemainMergedTillLeaseExpires) {
59  TaskQueueWrapper queue1;
60  TaskQueueWrapper queue2;
61  fml::TaskQueueId qid1 = queue1.GetTaskQueueId();
62  fml::TaskQueueId qid2 = queue2.GetTaskQueueId();
63  const auto raster_thread_merger =
64  fml::MakeRefCounted<fml::RasterThreadMerger>(qid1, qid2);
65  const size_t kNumFramesMerged = 5;
66 
67  ASSERT_FALSE(raster_thread_merger->IsMerged());
68 
69  raster_thread_merger->MergeWithLease(kNumFramesMerged);
70 
71  for (size_t i = 0; i < kNumFramesMerged; i++) {
72  ASSERT_TRUE(raster_thread_merger->IsMerged());
73  raster_thread_merger->DecrementLease();
74  }
75 
76  ASSERT_FALSE(raster_thread_merger->IsMerged());
77 }
78 
79 TEST(RasterThreadMerger, IsNotOnRasterizingThread) {
80  fml::MessageLoop* loop1 = nullptr;
82  std::thread thread1([&loop1, &latch1]() {
85  loop1->GetTaskRunner()->PostTask([&]() { latch1.Signal(); });
86  loop1->Run();
87  });
88 
89  fml::MessageLoop* loop2 = nullptr;
91  std::thread thread2([&loop2, &latch2]() {
94  loop2->GetTaskRunner()->PostTask([&]() { latch2.Signal(); });
95  loop2->Run();
96  });
97 
98  latch1.Wait();
99  latch2.Wait();
100 
101  fml::TaskQueueId qid1 = loop1->GetTaskRunner()->GetTaskQueueId();
102  fml::TaskQueueId qid2 = loop2->GetTaskRunner()->GetTaskQueueId();
103  const auto raster_thread_merger =
104  fml::MakeRefCounted<fml::RasterThreadMerger>(qid1, qid2);
105 
106  fml::CountDownLatch pre_merge(2), post_merge(2), post_unmerge(2);
107 
108  loop1->GetTaskRunner()->PostTask([&]() {
109  ASSERT_FALSE(raster_thread_merger->IsOnRasterizingThread());
110  ASSERT_TRUE(raster_thread_merger->IsOnPlatformThread());
111  ASSERT_EQ(fml::MessageLoop::GetCurrentTaskQueueId(), qid1);
112  pre_merge.CountDown();
113  });
114 
115  loop2->GetTaskRunner()->PostTask([&]() {
116  ASSERT_TRUE(raster_thread_merger->IsOnRasterizingThread());
117  ASSERT_FALSE(raster_thread_merger->IsOnPlatformThread());
118  ASSERT_EQ(fml::MessageLoop::GetCurrentTaskQueueId(), qid2);
119  pre_merge.CountDown();
120  });
121 
122  pre_merge.Wait();
123 
124  raster_thread_merger->MergeWithLease(1);
125 
126  loop1->GetTaskRunner()->PostTask([&]() {
127  ASSERT_TRUE(raster_thread_merger->IsOnRasterizingThread());
128  ASSERT_TRUE(raster_thread_merger->IsOnPlatformThread());
129  ASSERT_EQ(fml::MessageLoop::GetCurrentTaskQueueId(), qid1);
130  post_merge.CountDown();
131  });
132 
133  loop2->GetTaskRunner()->PostTask([&]() {
134  // this will be false since this is going to be run
135  // on loop1 really.
136  ASSERT_TRUE(raster_thread_merger->IsOnRasterizingThread());
137  ASSERT_TRUE(raster_thread_merger->IsOnPlatformThread());
138  ASSERT_EQ(fml::MessageLoop::GetCurrentTaskQueueId(), qid1);
139  post_merge.CountDown();
140  });
141 
142  post_merge.Wait();
143 
144  raster_thread_merger->DecrementLease();
145 
146  loop1->GetTaskRunner()->PostTask([&]() {
147  ASSERT_FALSE(raster_thread_merger->IsOnRasterizingThread());
148  ASSERT_TRUE(raster_thread_merger->IsOnPlatformThread());
149  ASSERT_EQ(fml::MessageLoop::GetCurrentTaskQueueId(), qid1);
150  post_unmerge.CountDown();
151  });
152 
153  loop2->GetTaskRunner()->PostTask([&]() {
154  ASSERT_TRUE(raster_thread_merger->IsOnRasterizingThread());
155  ASSERT_FALSE(raster_thread_merger->IsOnPlatformThread());
156  ASSERT_EQ(fml::MessageLoop::GetCurrentTaskQueueId(), qid2);
157  post_unmerge.CountDown();
158  });
159 
160  post_unmerge.Wait();
161 
162  loop1->GetTaskRunner()->PostTask([&]() { loop1->Terminate(); });
163 
164  loop2->GetTaskRunner()->PostTask([&]() { loop2->Terminate(); });
165 
166  thread1.join();
167  thread2.join();
168 }
169 
170 TEST(RasterThreadMerger, LeaseExtension) {
171  TaskQueueWrapper queue1;
172  TaskQueueWrapper queue2;
173 
174  fml::TaskQueueId qid1 = queue1.GetTaskQueueId();
175  fml::TaskQueueId qid2 = queue2.GetTaskQueueId();
176  const auto raster_thread_merger =
177  fml::MakeRefCounted<fml::RasterThreadMerger>(qid1, qid2);
178  const size_t kNumFramesMerged = 5;
179 
180  ASSERT_FALSE(raster_thread_merger->IsMerged());
181 
182  raster_thread_merger->MergeWithLease(kNumFramesMerged);
183 
184  // let there be one more turn till the leases expire.
185  for (size_t i = 0; i < kNumFramesMerged - 1; i++) {
186  ASSERT_TRUE(raster_thread_merger->IsMerged());
187  raster_thread_merger->DecrementLease();
188  }
189 
190  // extend the lease once.
191  raster_thread_merger->ExtendLeaseTo(kNumFramesMerged);
192 
193  // we will NOT last for 1 extra turn, we just set it.
194  for (size_t i = 0; i < kNumFramesMerged; i++) {
195  ASSERT_TRUE(raster_thread_merger->IsMerged());
196  raster_thread_merger->DecrementLease();
197  }
198 
199  ASSERT_FALSE(raster_thread_merger->IsMerged());
200 }
201 
202 TEST(RasterThreadMerger, WaitUntilMerged) {
203  fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger;
204 
205  fml::AutoResetWaitableEvent create_thread_merger_latch;
206  fml::MessageLoop* loop_platform = nullptr;
207  fml::AutoResetWaitableEvent latch_platform;
208  fml::AutoResetWaitableEvent term_platform;
209  fml::AutoResetWaitableEvent latch_merged;
210  std::thread thread_platform([&]() {
212  loop_platform = &fml::MessageLoop::GetCurrent();
213  latch_platform.Signal();
214  create_thread_merger_latch.Wait();
215  raster_thread_merger->WaitUntilMerged();
216  latch_merged.Signal();
217  term_platform.Wait();
218  });
219 
220  const size_t kNumFramesMerged = 5;
221  fml::MessageLoop* loop_raster = nullptr;
222  fml::AutoResetWaitableEvent term_raster;
223  std::thread thread_raster([&]() {
225  loop_raster = &fml::MessageLoop::GetCurrent();
226  latch_platform.Wait();
227  fml::TaskQueueId qid_platform =
228  loop_platform->GetTaskRunner()->GetTaskQueueId();
229  fml::TaskQueueId qid_raster =
230  loop_raster->GetTaskRunner()->GetTaskQueueId();
231  raster_thread_merger =
232  fml::MakeRefCounted<fml::RasterThreadMerger>(qid_platform, qid_raster);
233  ASSERT_FALSE(raster_thread_merger->IsMerged());
234  create_thread_merger_latch.Signal();
235  raster_thread_merger->MergeWithLease(kNumFramesMerged);
236  term_raster.Wait();
237  });
238 
239  latch_merged.Wait();
240  ASSERT_TRUE(raster_thread_merger->IsMerged());
241 
242  for (size_t i = 0; i < kNumFramesMerged; i++) {
243  ASSERT_TRUE(raster_thread_merger->IsMerged());
244  raster_thread_merger->DecrementLease();
245  }
246 
247  ASSERT_FALSE(raster_thread_merger->IsMerged());
248 
249  term_platform.Signal();
250  term_raster.Signal();
251  thread_platform.join();
252  thread_raster.join();
253 }
254 
255 TEST(RasterThreadMerger, HandleTaskQueuesAreTheSame) {
256  TaskQueueWrapper queue;
257  fml::TaskQueueId qid1 = queue.GetTaskQueueId();
258  fml::TaskQueueId qid2 = qid1;
259  const auto raster_thread_merger =
260  fml::MakeRefCounted<fml::RasterThreadMerger>(qid1, qid2);
261  // Statically merged.
262  ASSERT_TRUE(raster_thread_merger->IsMerged());
263 
264  // Test decrement lease and unmerge are both no-ops.
265  // The task queues should be always merged.
266  const size_t kNumFramesMerged = 5;
267  raster_thread_merger->MergeWithLease(kNumFramesMerged);
268 
269  for (size_t i = 0; i < kNumFramesMerged; i++) {
270  ASSERT_TRUE(raster_thread_merger->IsMerged());
271  raster_thread_merger->DecrementLease();
272  }
273 
274  ASSERT_TRUE(raster_thread_merger->IsMerged());
275 
276  // Wait until merged should also return immediately.
277  raster_thread_merger->WaitUntilMerged();
278  ASSERT_TRUE(raster_thread_merger->IsMerged());
279 }
280 
282  TaskQueueWrapper queue1;
283  TaskQueueWrapper queue2;
284  fml::TaskQueueId qid1 = queue1.GetTaskQueueId();
285  fml::TaskQueueId qid2 = queue2.GetTaskQueueId();
286  const auto raster_thread_merger =
287  fml::MakeRefCounted<fml::RasterThreadMerger>(qid1, qid2);
288 
289  raster_thread_merger->Disable();
290  raster_thread_merger->MergeWithLease(1);
291  ASSERT_FALSE(raster_thread_merger->IsMerged());
292 
293  raster_thread_merger->Enable();
294  ASSERT_FALSE(raster_thread_merger->IsMerged());
295 
296  raster_thread_merger->MergeWithLease(1);
297  ASSERT_TRUE(raster_thread_merger->IsMerged());
298 
299  raster_thread_merger->DecrementLease();
300  ASSERT_FALSE(raster_thread_merger->IsMerged());
301 }
302 
304  TaskQueueWrapper queue1;
305  TaskQueueWrapper queue2;
306  fml::TaskQueueId qid1 = queue1.GetTaskQueueId();
307  fml::TaskQueueId qid2 = queue2.GetTaskQueueId();
308  const auto raster_thread_merger =
309  fml::MakeRefCounted<fml::RasterThreadMerger>(qid1, qid2);
310 
311  raster_thread_merger->Disable();
312  ASSERT_FALSE(raster_thread_merger->IsMerged());
313 
314  raster_thread_merger->MergeWithLease(1);
315  ASSERT_FALSE(raster_thread_merger->IsMerged());
316 
317  raster_thread_merger->Enable();
318  raster_thread_merger->MergeWithLease(1);
319  ASSERT_TRUE(raster_thread_merger->IsMerged());
320 
321  raster_thread_merger->Disable();
322  raster_thread_merger->UnMergeNowIfLastOne();
323  ASSERT_TRUE(raster_thread_merger->IsMerged());
324 
325  {
326  auto decrement_result = raster_thread_merger->DecrementLease();
327  ASSERT_EQ(fml::RasterThreadStatus::kRemainsMerged, decrement_result);
328  }
329 
330  ASSERT_TRUE(raster_thread_merger->IsMerged());
331 
332  raster_thread_merger->Enable();
333  raster_thread_merger->UnMergeNowIfLastOne();
334  ASSERT_FALSE(raster_thread_merger->IsMerged());
335 
336  raster_thread_merger->MergeWithLease(1);
337 
338  ASSERT_TRUE(raster_thread_merger->IsMerged());
339 
340  {
341  auto decrement_result = raster_thread_merger->DecrementLease();
342  ASSERT_EQ(fml::RasterThreadStatus::kUnmergedNow, decrement_result);
343  }
344 
345  ASSERT_FALSE(raster_thread_merger->IsMerged());
346 }
347 
349  TaskQueueWrapper queue1;
350  TaskQueueWrapper queue2;
351  fml::TaskQueueId qid1 = queue1.GetTaskQueueId();
352  fml::TaskQueueId qid2 = queue2.GetTaskQueueId();
353  const auto raster_thread_merger =
354  fml::MakeRefCounted<fml::RasterThreadMerger>(qid1, qid2);
355  ASSERT_TRUE(raster_thread_merger->IsEnabled());
356 
357  raster_thread_merger->Disable();
358  ASSERT_FALSE(raster_thread_merger->IsEnabled());
359 
360  raster_thread_merger->Enable();
361  ASSERT_TRUE(raster_thread_merger->IsEnabled());
362 }
363 
364 TEST(RasterThreadMerger, TwoMergersWithSameThreadPairShareEnabledState) {
365  TaskQueueWrapper queue1;
366  TaskQueueWrapper queue2;
367  fml::TaskQueueId qid1 = queue1.GetTaskQueueId();
368  fml::TaskQueueId qid2 = queue2.GetTaskQueueId();
369  const auto merger1 =
371  const auto merger2 =
373  ASSERT_TRUE(merger1->IsEnabled());
374  ASSERT_TRUE(merger2->IsEnabled());
375 
376  merger1->Disable();
377  ASSERT_FALSE(merger1->IsEnabled());
378  ASSERT_FALSE(merger2->IsEnabled());
379 
380  merger2->Enable();
381  ASSERT_TRUE(merger1->IsEnabled());
382  ASSERT_TRUE(merger2->IsEnabled());
383 }
384 
385 TEST(RasterThreadMerger, RunExpiredTasksWhileFirstTaskMergesThreads) {
386  fml::MessageLoop* loop_platform = nullptr;
388  std::thread thread_platform([&loop_platform, &latch1]() {
390  loop_platform = &fml::MessageLoop::GetCurrent();
391  loop_platform->GetTaskRunner()->PostTask([&]() { latch1.Signal(); });
392  loop_platform->Run();
393  });
394 
395  fml::MessageLoop* loop_raster = nullptr;
397  std::thread thread_raster([&loop_raster, &loop_platform, &latch1, &latch2]() {
398  latch1.Wait();
399 
401  loop_raster = &fml::MessageLoop::GetCurrent();
402  fml::TaskQueueId qid_platform =
403  loop_platform->GetTaskRunner()->GetTaskQueueId();
404  fml::TaskQueueId qid_raster =
405  loop_raster->GetTaskRunner()->GetTaskQueueId();
406  fml::CountDownLatch post_merge(2);
407  const auto raster_thread_merger =
408  fml::MakeRefCounted<fml::RasterThreadMerger>(qid_platform, qid_raster);
409  loop_raster->GetTaskRunner()->PostTask([&]() {
410  ASSERT_TRUE(raster_thread_merger->IsOnRasterizingThread());
411  ASSERT_FALSE(raster_thread_merger->IsOnPlatformThread());
412  ASSERT_EQ(fml::MessageLoop::GetCurrentTaskQueueId(), qid_raster);
413  raster_thread_merger->MergeWithLease(1);
414  post_merge.CountDown();
415  });
416 
417  loop_raster->GetTaskRunner()->PostTask([&]() {
418  ASSERT_TRUE(raster_thread_merger->IsOnRasterizingThread());
419  ASSERT_TRUE(raster_thread_merger->IsOnPlatformThread());
420  ASSERT_EQ(fml::MessageLoop::GetCurrentTaskQueueId(), qid_platform);
421  raster_thread_merger->DecrementLease();
422  post_merge.CountDown();
423  });
424 
425  loop_raster->RunExpiredTasksNow();
426  post_merge.Wait();
427  latch2.Signal();
428  });
429 
430  latch2.Wait();
431  loop_platform->GetTaskRunner()->PostTask(
432  [&]() { loop_platform->Terminate(); });
433 
434  thread_platform.join();
435  thread_raster.join();
436 }
437 
438 TEST(RasterThreadMerger, RunExpiredTasksWhileFirstTaskUnMergesThreads) {
439  fml::Thread platform_thread("test_platform_thread");
440 
441  fml::AutoResetWaitableEvent raster_latch;
442  std::thread thread_raster([&]() {
445 
446  fml::TaskQueueId qid_platform =
447  platform_thread.GetTaskRunner()->GetTaskQueueId();
448  fml::TaskQueueId qid_raster =
449  loop_raster->GetTaskRunner()->GetTaskQueueId();
450 
451  fml::AutoResetWaitableEvent merge_latch;
452  const auto raster_thread_merger =
453  fml::MakeRefCounted<fml::RasterThreadMerger>(qid_platform, qid_raster);
454  loop_raster->GetTaskRunner()->PostTask([&]() {
455  raster_thread_merger->MergeWithLease(1);
456  merge_latch.Signal();
457  });
458 
459  loop_raster->RunExpiredTasksNow();
460  merge_latch.Wait();
461 
462  // threads should be merged at this point.
463  fml::AutoResetWaitableEvent unmerge_latch;
464  loop_raster->GetTaskRunner()->PostTask([&]() {
465  ASSERT_TRUE(raster_thread_merger->IsOnRasterizingThread());
466  ASSERT_TRUE(raster_thread_merger->IsOnPlatformThread());
467  ASSERT_EQ(fml::MessageLoop::GetCurrentTaskQueueId(), qid_platform);
468  raster_thread_merger->DecrementLease();
469  unmerge_latch.Signal();
470  });
471 
472  fml::AutoResetWaitableEvent post_unmerge_latch;
473  loop_raster->GetTaskRunner()->PostTask([&]() {
474  ASSERT_TRUE(raster_thread_merger->IsOnRasterizingThread());
475  ASSERT_FALSE(raster_thread_merger->IsOnPlatformThread());
476  ASSERT_EQ(fml::MessageLoop::GetCurrentTaskQueueId(), qid_raster);
477  post_unmerge_latch.Signal();
478  });
479 
480  unmerge_latch.Wait();
481  loop_raster->RunExpiredTasksNow();
482 
483  post_unmerge_latch.Wait();
484  raster_latch.Signal();
485  });
486 
487  raster_latch.Wait();
488  thread_raster.join();
489 }
490 
491 TEST(RasterThreadMerger, SetMergeUnmergeCallback) {
492  TaskQueueWrapper queue1;
493  TaskQueueWrapper queue2;
494  fml::TaskQueueId qid1 = queue1.GetTaskQueueId();
495  fml::TaskQueueId qid2 = queue2.GetTaskQueueId();
496 
497  const auto raster_thread_merger =
498  fml::MakeRefCounted<fml::RasterThreadMerger>(qid1, qid2);
499 
500  int callbacks = 0;
501  raster_thread_merger->SetMergeUnmergeCallback(
502  [&callbacks]() { callbacks++; });
503 
504  ASSERT_EQ(0, callbacks);
505 
506  raster_thread_merger->MergeWithLease(1);
507  ASSERT_EQ(1, callbacks);
508 
509  raster_thread_merger->DecrementLease();
510  ASSERT_EQ(2, callbacks);
511 }
512 
513 TEST(RasterThreadMerger, MultipleMergersCanMergeSameThreadPair) {
514  TaskQueueWrapper queue1;
515  TaskQueueWrapper queue2;
516  fml::TaskQueueId qid1 = queue1.GetTaskQueueId();
517  fml::TaskQueueId qid2 = queue2.GetTaskQueueId();
518  // Two mergers will share one same inner merger
519  const auto raster_thread_merger1 =
521  const auto raster_thread_merger2 =
523  qid1, qid2);
524  const size_t kNumFramesMerged = 5;
525  ASSERT_FALSE(raster_thread_merger1->IsMerged());
526  ASSERT_FALSE(raster_thread_merger2->IsMerged());
527 
528  // Merge using the first merger
529  raster_thread_merger1->MergeWithLease(kNumFramesMerged);
530 
531  ASSERT_TRUE(raster_thread_merger1->IsMerged());
532  ASSERT_TRUE(raster_thread_merger2->IsMerged());
533 
534  // let there be one more turn till the leases expire.
535  for (size_t i = 0; i < kNumFramesMerged - 1; i++) {
536  // Check merge state using the two merger
537  ASSERT_TRUE(raster_thread_merger1->IsMerged());
538  ASSERT_TRUE(raster_thread_merger2->IsMerged());
539  raster_thread_merger1->DecrementLease();
540  }
541 
542  ASSERT_TRUE(raster_thread_merger1->IsMerged());
543  ASSERT_TRUE(raster_thread_merger2->IsMerged());
544 
545  // extend the lease once with the first merger
546  raster_thread_merger1->ExtendLeaseTo(kNumFramesMerged);
547 
548  // we will NOT last for 1 extra turn, we just set it.
549  for (size_t i = 0; i < kNumFramesMerged; i++) {
550  // Check merge state using the two merger
551  ASSERT_TRUE(raster_thread_merger1->IsMerged());
552  ASSERT_TRUE(raster_thread_merger2->IsMerged());
553  raster_thread_merger1->DecrementLease();
554  }
555 
556  ASSERT_FALSE(raster_thread_merger1->IsMerged());
557  ASSERT_FALSE(raster_thread_merger2->IsMerged());
558 }
559 
560 TEST(RasterThreadMerger, TheLastCallerOfMultipleMergersCanUnmergeNow) {
561  TaskQueueWrapper queue1;
562  TaskQueueWrapper queue2;
563  fml::TaskQueueId qid1 = queue1.GetTaskQueueId();
564  fml::TaskQueueId qid2 = queue2.GetTaskQueueId();
565  // Two mergers will share one same inner merger
566  const auto raster_thread_merger1 =
568  const auto raster_thread_merger2 =
570  qid1, qid2);
571  const size_t kNumFramesMerged = 5;
572  ASSERT_FALSE(raster_thread_merger1->IsMerged());
573  ASSERT_FALSE(raster_thread_merger2->IsMerged());
574 
575  // Merge using the mergers
576  raster_thread_merger1->MergeWithLease(kNumFramesMerged);
577  ASSERT_TRUE(raster_thread_merger1->IsMerged());
578  ASSERT_TRUE(raster_thread_merger2->IsMerged());
579  // Extend the second merger's lease
580  raster_thread_merger2->ExtendLeaseTo(kNumFramesMerged);
581  ASSERT_TRUE(raster_thread_merger1->IsMerged());
582  ASSERT_TRUE(raster_thread_merger2->IsMerged());
583 
584  // Two callers state becomes one caller left.
585  raster_thread_merger1->UnMergeNowIfLastOne();
586  // Check if still merged
587  ASSERT_TRUE(raster_thread_merger1->IsMerged());
588  ASSERT_TRUE(raster_thread_merger2->IsMerged());
589 
590  // One caller state becomes no callers left.
591  raster_thread_merger2->UnMergeNowIfLastOne();
592  // Check if unmerged
593  ASSERT_FALSE(raster_thread_merger1->IsMerged());
594  ASSERT_FALSE(raster_thread_merger2->IsMerged());
595 }
596 
597 /// This case tests multiple standalone engines using independent merger to
598 /// merge two different raster threads into the same platform thread.
600  TwoIndependentMergersCanMergeTwoDifferentThreadsIntoSamePlatformThread) {
601  TaskQueueWrapper queue1;
602  TaskQueueWrapper queue2;
603  TaskQueueWrapper queue3;
604  fml::TaskQueueId qid1 = queue1.GetTaskQueueId();
605  fml::TaskQueueId qid2 = queue2.GetTaskQueueId();
606  fml::TaskQueueId qid3 = queue3.GetTaskQueueId();
607 
608  // Two mergers will NOT share same inner merger
609  const auto merger_from_2_to_1 =
611  const auto merger_from_3_to_1 =
613  qid1, qid3);
614  const size_t kNumFramesMerged = 5;
615  ASSERT_FALSE(merger_from_2_to_1->IsMerged());
616  ASSERT_FALSE(merger_from_3_to_1->IsMerged());
617 
618  // Merge thread2 into thread1
619  merger_from_2_to_1->MergeWithLease(kNumFramesMerged);
620  // Merge thread3 into thread1
621  merger_from_3_to_1->MergeWithLease(kNumFramesMerged);
622 
623  ASSERT_TRUE(merger_from_2_to_1->IsMerged());
624  ASSERT_TRUE(merger_from_3_to_1->IsMerged());
625 
626  for (size_t i = 0; i < kNumFramesMerged; i++) {
627  ASSERT_TRUE(merger_from_2_to_1->IsMerged());
628  merger_from_2_to_1->DecrementLease();
629  }
630 
631  ASSERT_FALSE(merger_from_2_to_1->IsMerged());
632  ASSERT_TRUE(merger_from_3_to_1->IsMerged());
633 
634  for (size_t i = 0; i < kNumFramesMerged; i++) {
635  ASSERT_TRUE(merger_from_3_to_1->IsMerged());
636  merger_from_3_to_1->DecrementLease();
637  }
638 
639  ASSERT_FALSE(merger_from_2_to_1->IsMerged());
640  ASSERT_FALSE(merger_from_3_to_1->IsMerged());
641 
642  merger_from_2_to_1->MergeWithLease(kNumFramesMerged);
643  ASSERT_TRUE(merger_from_2_to_1->IsMerged());
644  ASSERT_FALSE(merger_from_3_to_1->IsMerged());
645  merger_from_3_to_1->MergeWithLease(kNumFramesMerged);
646  ASSERT_TRUE(merger_from_2_to_1->IsMerged());
647  ASSERT_TRUE(merger_from_3_to_1->IsMerged());
648 
649  // Can unmerge independently
650  merger_from_2_to_1->UnMergeNowIfLastOne();
651  ASSERT_FALSE(merger_from_2_to_1->IsMerged());
652  ASSERT_TRUE(merger_from_3_to_1->IsMerged());
653 
654  // Can unmerge independently
655  merger_from_3_to_1->UnMergeNowIfLastOne();
656  ASSERT_FALSE(merger_from_2_to_1->IsMerged());
657  ASSERT_FALSE(merger_from_3_to_1->IsMerged());
658 }
659 
660 } // namespace testing
661 } // namespace fml
static fml::RefPtr< fml::RasterThreadMerger > CreateOrShareThreadMerger(const fml::RefPtr< fml::RasterThreadMerger > &parent_merger, TaskQueueId platform_id, TaskQueueId raster_id)
virtual TaskQueueId GetTaskQueueId()
Definition: task_runner.cc:38
fml::RefPtr< fml::TaskRunner > GetTaskRunner() const
Definition: thread.cc:45
static FML_EMBEDDER_ONLY MessageLoop & GetCurrent()
Definition: message_loop.cc:19
fml::AutoResetWaitableEvent term
The waiter for thread finished.
static void EnsureInitializedForCurrentThread()
Definition: message_loop.cc:27
Definition: ascii_trie.cc:9
void MergeWithLease(size_t lease_term)
fml::RefPtr< fml::TaskRunner > GetTaskRunner() const
Definition: message_loop.cc:56
A mock task queue NOT calling MessageLoop->Run() in thread.
static TaskQueueId GetCurrentTaskQueueId()
Definition: message_loop.cc:76
TEST(BacktraceTest, CanGatherBacktrace)
RasterThreadStatus DecrementLease()
fml::AutoResetWaitableEvent latch
The waiter for message loop initialized ok.
void RunExpiredTasksNow()
Definition: message_loop.cc:72
virtual void PostTask(const fml::closure &task) override
Definition: task_runner.cc:24