Unmerge threads if the current merger is the only one that's merged. (flutter/engine#43652)

`UnMergeNowIfLastOne` is called during shell destruction. When there are other shells with threads unmerged and the current destroying shell with thread merged. `UnMergeNowIfLastOne` should unmerge the threads. 

This PR Make `UnMergeNowIfLastOne` not only unmerge if the current merger is the last merger, but also unmerge if the current merger is the last merger that is merged.

Fixes https://github.com/flutter/flutter/issues/127168

[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
This commit is contained in:
Chris Yang 2023-07-13 15:17:21 -07:00 committed by GitHub
parent 6fdde7e901
commit 4e696fc84d
3 changed files with 43 additions and 7 deletions

View File

@ -53,10 +53,10 @@ class RasterThreadMerger
TaskQueueId platform_id,
TaskQueueId raster_id);
// Un-merges the threads now if current caller is the last merge caller,
// and it resets the lease term to 0, otherwise it will remove the caller
// record and return. The multiple caller records were recorded after
// |MergeWithLease| or |ExtendLeaseTo| method.
// Un-merges the threads now if current caller is the last merged caller,
// and it resets the lease term to 0, otherwise it will remove
// the caller record and return. The multiple caller records were recorded
// after |MergeWithLease| or |ExtendLeaseTo| method.
//
// Must be executed on the raster task runner.
//

View File

@ -594,6 +594,42 @@ TEST(RasterThreadMerger, TheLastCallerOfMultipleMergersCanUnmergeNow) {
ASSERT_FALSE(raster_thread_merger2->IsMerged());
}
TEST(RasterThreadMerger, TheLastMergedCallerOfMultipleMergersCanUnmergeNow) {
TaskQueueWrapper queue1;
TaskQueueWrapper queue2;
fml::TaskQueueId qid1 = queue1.GetTaskQueueId();
fml::TaskQueueId qid2 = queue2.GetTaskQueueId();
// Two mergers will share one same inner merger
const auto raster_thread_merger1 =
fml::RasterThreadMerger::CreateOrShareThreadMerger(nullptr, qid1, qid2);
const size_t kNumFramesMerged = 1;
ASSERT_FALSE(raster_thread_merger1->IsMerged());
// Merge using the mergers
raster_thread_merger1->MergeWithLease(kNumFramesMerged);
ASSERT_TRUE(raster_thread_merger1->IsMerged());
for (size_t i = 0; i < kNumFramesMerged; i++) {
// Un-merge thread merger 1.
raster_thread_merger1->DecrementLease();
}
ASSERT_FALSE(raster_thread_merger1->IsMerged());
const auto raster_thread_merger2 =
fml::RasterThreadMerger::CreateOrShareThreadMerger(raster_thread_merger1,
qid1, qid2);
ASSERT_FALSE(raster_thread_merger2->IsMerged());
raster_thread_merger2->MergeWithLease(kNumFramesMerged);
ASSERT_TRUE(raster_thread_merger2->IsMerged());
// One caller state becomes no callers left.
raster_thread_merger2->UnMergeNowIfLastOne();
// Check if unmerged
ASSERT_FALSE(raster_thread_merger1->IsMerged());
ASSERT_FALSE(raster_thread_merger2->IsMerged());
}
/// This case tests multiple standalone engines using independent merger to
/// merge two different raster threads into the same platform thread.
TEST(RasterThreadMerger,

View File

@ -44,10 +44,10 @@ bool SharedThreadMerger::UnMergeNowUnSafe() {
bool SharedThreadMerger::UnMergeNowIfLastOne(RasterThreadMergerId caller) {
std::scoped_lock lock(mutex_);
lease_term_by_caller_.erase(caller);
if (!lease_term_by_caller_.empty()) {
return true;
if (lease_term_by_caller_.empty() || IsAllLeaseTermsZeroUnSafe()) {
return UnMergeNowUnSafe();
}
return UnMergeNowUnSafe();
return true;
}
bool SharedThreadMerger::DecrementLease(RasterThreadMergerId caller) {