mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
- Add the functionality to merge and unmerge MessageLoopTaskQueues This introduces a notion of a "owning" and "subsumed" queue ids. Owning queue will take care of the tasks submitted to both that and it's subsumed queue. - The tasks submitted still maintain the queue affinity - Same for the task observers - Also adds MergedQueuesRunner which grabs both the locks owner and subsumed queues in RAII fashion. - Also use task queue id to verify if we are running in the same thread. - This is to enable merging the backed message loop task queues to enable dynamic thread merging in IOS.
139 lines
4.2 KiB
C++
139 lines
4.2 KiB
C++
// Copyright 2013 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#define FML_USED_ON_EMBEDDER
|
|
|
|
#include "flutter/fml/message_loop_task_queues.h"
|
|
#include "flutter/fml/synchronization/count_down_latch.h"
|
|
#include "flutter/fml/synchronization/waitable_event.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
class TestWakeable : public fml::Wakeable {
|
|
public:
|
|
using WakeUpCall = std::function<void(const fml::TimePoint)>;
|
|
|
|
TestWakeable(WakeUpCall call) : wake_up_call_(call) {}
|
|
|
|
void WakeUp(fml::TimePoint time_point) override { wake_up_call_(time_point); }
|
|
|
|
private:
|
|
WakeUpCall wake_up_call_;
|
|
};
|
|
|
|
TEST(MessageLoopTaskQueue, StartsWithNoPendingTasks) {
|
|
auto task_queue = fml::MessageLoopTaskQueues::GetInstance();
|
|
auto queue_id = task_queue->CreateTaskQueue();
|
|
ASSERT_FALSE(task_queue->HasPendingTasks(queue_id));
|
|
}
|
|
|
|
TEST(MessageLoopTaskQueue, RegisterOneTask) {
|
|
const auto time = fml::TimePoint::Max();
|
|
|
|
auto task_queue = fml::MessageLoopTaskQueues::GetInstance();
|
|
auto queue_id = task_queue->CreateTaskQueue();
|
|
task_queue->SetWakeable(queue_id,
|
|
new TestWakeable([&time](fml::TimePoint wake_time) {
|
|
ASSERT_TRUE(wake_time == time);
|
|
}));
|
|
|
|
task_queue->RegisterTask(
|
|
queue_id, [] {}, time);
|
|
ASSERT_TRUE(task_queue->HasPendingTasks(queue_id));
|
|
ASSERT_TRUE(task_queue->GetNumPendingTasks(queue_id) == 1);
|
|
}
|
|
|
|
TEST(MessageLoopTaskQueue, RegisterTwoTasksAndCount) {
|
|
auto task_queue = fml::MessageLoopTaskQueues::GetInstance();
|
|
auto queue_id = task_queue->CreateTaskQueue();
|
|
task_queue->RegisterTask(
|
|
queue_id, [] {}, fml::TimePoint::Now());
|
|
task_queue->RegisterTask(
|
|
queue_id, [] {}, fml::TimePoint::Max());
|
|
ASSERT_TRUE(task_queue->HasPendingTasks(queue_id));
|
|
ASSERT_TRUE(task_queue->GetNumPendingTasks(queue_id) == 2);
|
|
}
|
|
|
|
TEST(MessageLoopTaskQueue, PreserveTaskOrdering) {
|
|
auto task_queue = fml::MessageLoopTaskQueues::GetInstance();
|
|
auto queue_id = task_queue->CreateTaskQueue();
|
|
int test_val = 0;
|
|
|
|
// order: 0
|
|
task_queue->RegisterTask(
|
|
queue_id, [&test_val]() { test_val = 1; }, fml::TimePoint::Now());
|
|
|
|
// order: 1
|
|
task_queue->RegisterTask(
|
|
queue_id, [&test_val]() { test_val = 2; }, fml::TimePoint::Now());
|
|
|
|
std::vector<fml::closure> invocations;
|
|
task_queue->GetTasksToRunNow(queue_id, fml::FlushType::kAll, invocations);
|
|
|
|
int expected_value = 1;
|
|
|
|
for (auto& invocation : invocations) {
|
|
invocation();
|
|
ASSERT_TRUE(test_val == expected_value);
|
|
expected_value++;
|
|
}
|
|
}
|
|
|
|
TEST(MessageLoopTaskQueue, AddRemoveNotifyObservers) {
|
|
auto task_queue = fml::MessageLoopTaskQueues::GetInstance();
|
|
auto queue_id = task_queue->CreateTaskQueue();
|
|
|
|
int test_val = 0;
|
|
intptr_t key = 123;
|
|
|
|
task_queue->AddTaskObserver(queue_id, key, [&test_val]() { test_val = 1; });
|
|
task_queue->NotifyObservers(queue_id);
|
|
ASSERT_TRUE(test_val == 1);
|
|
|
|
test_val = 0;
|
|
task_queue->RemoveTaskObserver(queue_id, key);
|
|
task_queue->NotifyObservers(queue_id);
|
|
ASSERT_TRUE(test_val == 0);
|
|
}
|
|
|
|
TEST(MessageLoopTaskQueue, WakeUpIndependentOfTime) {
|
|
auto task_queue = fml::MessageLoopTaskQueues::GetInstance();
|
|
auto queue_id = task_queue->CreateTaskQueue();
|
|
|
|
int num_wakes = 0;
|
|
task_queue->SetWakeable(
|
|
queue_id, new TestWakeable(
|
|
[&num_wakes](fml::TimePoint wake_time) { ++num_wakes; }));
|
|
|
|
task_queue->RegisterTask(
|
|
queue_id, []() {}, fml::TimePoint::Now());
|
|
task_queue->RegisterTask(
|
|
queue_id, []() {}, fml::TimePoint::Max());
|
|
|
|
ASSERT_TRUE(num_wakes == 2);
|
|
}
|
|
|
|
TEST(MessageLoopTaskQueue, WokenUpWithNewerTime) {
|
|
auto task_queue = fml::MessageLoopTaskQueues::GetInstance();
|
|
auto queue_id = task_queue->CreateTaskQueue();
|
|
fml::CountDownLatch latch(2);
|
|
|
|
fml::TimePoint expected = fml::TimePoint::Max();
|
|
|
|
task_queue->SetWakeable(
|
|
queue_id, new TestWakeable([&latch, &expected](fml::TimePoint wake_time) {
|
|
ASSERT_TRUE(wake_time == expected);
|
|
latch.CountDown();
|
|
}));
|
|
|
|
task_queue->RegisterTask(
|
|
queue_id, []() {}, fml::TimePoint::Max());
|
|
|
|
const auto now = fml::TimePoint::Now();
|
|
expected = now;
|
|
task_queue->RegisterTask(
|
|
queue_id, []() {}, now);
|
|
|
|
latch.Wait();
|
|
}
|