| // 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/shared_thread_merger.h" | |
| #include <algorithm> | |
| #include <set> | |
| namespace fml { | |
| SharedThreadMerger::SharedThreadMerger(fml::TaskQueueId owner, | |
| fml::TaskQueueId subsumed) | |
| : owner_(owner), | |
| subsumed_(subsumed), | |
| task_queues_(fml::MessageLoopTaskQueues::GetInstance()), | |
| enabled_(true) {} | |
| bool SharedThreadMerger::MergeWithLease(RasterThreadMergerId caller, | |
| size_t lease_term) { | |
| FML_DCHECK(lease_term > 0) << "lease_term should be positive."; | |
| std::scoped_lock lock(mutex_); | |
| if (IsMergedUnSafe()) { | |
| return true; | |
| } | |
| bool success = task_queues_->Merge(owner_, subsumed_); | |
| FML_CHECK(success) << "Unable to merge the raster and platform threads."; | |
| // Save the lease term | |
| lease_term_by_caller_[caller] = lease_term; | |
| return success; | |
| } | |
| bool SharedThreadMerger::UnMergeNowUnSafe() { | |
| FML_CHECK(IsAllLeaseTermsZeroUnSafe()) | |
| << "all lease term records must be zero before calling " | |
| "UnMergeNowUnSafe()"; | |
| bool success = task_queues_->Unmerge(owner_, subsumed_); | |
| FML_CHECK(success) << "Unable to un-merge the raster and platform threads."; | |
| return success; | |
| } | |
| bool SharedThreadMerger::UnMergeNowIfLastOne(RasterThreadMergerId caller) { | |
| std::scoped_lock lock(mutex_); | |
| lease_term_by_caller_.erase(caller); | |
| if (!lease_term_by_caller_.empty()) { | |
| return true; | |
| } | |
| return UnMergeNowUnSafe(); | |
| } | |
| bool SharedThreadMerger::DecrementLease(RasterThreadMergerId caller) { | |
| std::scoped_lock lock(mutex_); | |
| auto entry = lease_term_by_caller_.find(caller); | |
| bool exist = entry != lease_term_by_caller_.end(); | |
| if (exist) { | |
| std::atomic_size_t& lease_term_ref = entry->second; | |
| FML_CHECK(lease_term_ref > 0) | |
| << "lease_term should always be positive when merged, lease_term=" | |
| << lease_term_ref; | |
| lease_term_ref--; | |
| } else { | |
| FML_LOG(WARNING) << "The caller does not exist when calling " | |
| "DecrementLease(), ignored. This may happens after " | |
| "caller is erased in UnMergeNowIfLastOne(). caller=" | |
| << caller; | |
| } | |
| if (IsAllLeaseTermsZeroUnSafe()) { | |
| // Unmerge now because lease_term_ decreased to zero. | |
| UnMergeNowUnSafe(); | |
| return true; | |
| } | |
| return false; | |
| } | |
| void SharedThreadMerger::ExtendLeaseTo(RasterThreadMergerId caller, | |
| size_t lease_term) { | |
| FML_DCHECK(lease_term > 0) << "lease_term should be positive."; | |
| std::scoped_lock lock(mutex_); | |
| FML_DCHECK(IsMergedUnSafe()) | |
| << "should be merged state when calling this method"; | |
| lease_term_by_caller_[caller] = lease_term; | |
| } | |
| bool SharedThreadMerger::IsMergedUnSafe() const { | |
| return !IsAllLeaseTermsZeroUnSafe(); | |
| } | |
| bool SharedThreadMerger::IsEnabledUnSafe() const { | |
| return enabled_; | |
| } | |
| void SharedThreadMerger::SetEnabledUnSafe(bool enabled) { | |
| enabled_ = enabled; | |
| } | |
| bool SharedThreadMerger::IsAllLeaseTermsZeroUnSafe() const { | |
| return std::all_of(lease_term_by_caller_.begin(), lease_term_by_caller_.end(), | |
| [&](const auto& item) { return item.second == 0; }); | |
| } | |
| } // namespace fml |