Index: components/scheduler/promises/promise.cc |
diff --git a/components/scheduler/promises/promise.cc b/components/scheduler/promises/promise.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..7cd4508d2a4c263870a24709bf791dad83e11a20 |
--- /dev/null |
+++ b/components/scheduler/promises/promise.cc |
@@ -0,0 +1,202 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "components/scheduler/promises/promise.h" |
+#include "components/scheduler/promises/promise_executor.h" |
+ |
+namespace promise { |
+namespace internal { |
+ |
+PromiseBase::PromiseBase(PrerequisitePolicy prerequisite_policy) |
+ : executor_(nullptr), |
+ state_(State::NEW), |
+ prerequisite_policy_(prerequisite_policy), |
+ can_run_now_(false), |
+ should_run_refcount_(0), |
+ eager_refcount_(0) {} |
+ |
+PromiseBase::PromiseBase(std::vector<scoped_refptr<PromiseBase>> prerequisites, |
+ PrerequisitePolicy prerequisite_policy) |
+ : prerequisites_(std::move(prerequisites)), |
+ executor_(nullptr), |
+ state_(State::NEW), |
+ prerequisite_policy_(prerequisite_policy), |
+ can_run_now_(false), |
+ should_run_refcount_(0), |
+ eager_refcount_(0) { |
+ for (scoped_refptr<PromiseBase>& prerequisite : prerequisites_) { |
+ if (prerequisite->state_ != State::NEW) |
+ continue; |
+ |
+ prerequisite->dependants_.insert(this); |
+ } |
+} |
+ |
+PromiseBase::~PromiseBase() {} |
+ |
+void PromiseBase::RegisterDynamicDependancy( |
+ scoped_refptr<PromiseBase> dependency) { |
+ PromiseBase* dependency_ptr = dependency.get(); |
+ dependency_ptr->dependants_.insert(this); |
+ prerequisites_.push_back(std::move(dependency)); |
+ |
+ if (dependency_ptr->state() == PromiseBase::State::RESOLVED) { |
+ MarkAsResolved(); |
+ return; |
+ } else if (dependency_ptr->state() == PromiseBase::State::REJECTED) { |
+ MarkAsRejected(); |
+ return; |
+ } |
+ |
+ // We need to execute later when dependency has been resolved. |
+ can_run_now_ = false; |
+ |
+ if (!executor_) |
+ return; |
+ |
+ if (eager_refcount_ > 0) { |
+ executor_->eager_ready_set_.erase(this); |
+ } else { |
+ executor_->lazy_ready_set_.erase(this); |
+ } |
+ |
+ executor_->StartResolveInternal(dependency_ptr); |
+} |
+ |
+void PromiseBase::SetThisAndPrerequisitesAsEager(bool eager) { |
+ if (state_ == PromiseBase::State::RESOLVED) |
+ return; |
+ |
+ DCHECK(state_ != PromiseBase::State::CANCELLED); |
+ if (eager) { |
+ eager_refcount_++; |
+ if (executor_ && eager_refcount_ == 1 && can_run_now_) { |
+ executor_->lazy_ready_set_.erase(this); |
+ executor_->eager_ready_set_.insert(this); |
+ } |
+ } else { |
+ eager_refcount_--; |
+ DCHECK_GE(eager_refcount_, 0); |
+ if (executor_ && eager_refcount_ == 0 && can_run_now_) { |
+ executor_->eager_ready_set_.erase(this); |
+ executor_->lazy_ready_set_.insert(this); |
+ } |
+ } |
+ |
+ for (scoped_refptr<PromiseBase>& prerequisite : prerequisites_) { |
+ prerequisite->SetThisAndPrerequisitesAsEager(eager); |
+ } |
+} |
+ |
+void PromiseBase::SetThisAndPrerequisitesAsShouldRun(PromiseExecutor* executor, |
+ bool should_run) { |
+ if (state_ == State::RESOLVED) |
+ return; |
+ |
+ executor_ = executor; |
+ if (should_run) { |
+ should_run_refcount_++; |
+ DCHECK_GT(should_run_refcount_, 0); |
+ if (!can_run_now_ && AllPrerequisitesSatisfied()) |
+ SchedulePromiseForResolve(); |
+ } else { |
+ should_run_refcount_--; |
+ DCHECK_GE(should_run_refcount_, 0); |
+ if (should_run_refcount_ == 0) { |
+ can_run_now_ = false; |
+ if (executor_) { |
+ if (eager_refcount_ > 0) { |
+ executor_->eager_ready_set_.erase(this); |
+ } else { |
+ executor_->lazy_ready_set_.erase(this); |
+ } |
+ } |
+ } |
+ } |
+ |
+ for (scoped_refptr<PromiseBase>& prerequisite : prerequisites_) { |
+ prerequisite->SetThisAndPrerequisitesAsShouldRun(executor_, should_run); |
+ } |
+} |
+ |
+void PromiseBase::SchedulePromiseForResolve() { |
+ DCHECK(AllPrerequisitesSatisfied()); |
+ |
+ can_run_now_ = true; |
+ |
+ if (!executor_) |
+ return; |
+ |
+ if (eager_refcount_ > 0) { |
+ executor_->eager_ready_set_.insert(this); |
+ } else { |
+ executor_->lazy_ready_set_.insert(this); |
+ } |
+} |
+ |
+bool PromiseBase::AllPrerequisitesSatisfied() const { |
+ if (state_ == State::CANCELLED || should_run_refcount_ == 0) |
+ return false; |
+ |
+ DCHECK(state_ != State::RESOLVED); |
+ DCHECK(state_ != State::REJECTED); |
+ |
+ // No need to wait if any dependency has been rejected. |
+ if (state_ == State::DEPENDENCY_REJECTED) |
+ return true; |
+ |
+ switch (prerequisite_policy_) { |
+ case PrerequisitePolicy::ALL: |
+ for (const scoped_refptr<PromiseBase>& prerequisite : prerequisites_) { |
+ if (prerequisite->state() != PromiseBase::State::RESOLVED) { |
+ return false; |
+ } |
+ } |
+ return true; |
+ |
+ case PrerequisitePolicy::ANY: |
+ DCHECK(!prerequisites_.empty()); |
+ for (const scoped_refptr<PromiseBase>& prerequisite : prerequisites_) { |
+ if (prerequisite->state() == PromiseBase::State::RESOLVED) { |
+ return true; |
+ } |
+ } |
+ return false; |
+ |
+ case PrerequisitePolicy::ALWAYS: |
+ return true; |
+ |
+ case PrerequisitePolicy::NEVER: |
+ return false; |
+ } |
+ |
+ return false; |
+} |
+ |
+void PromiseBase::Cancel() { |
+ DCHECK(dependants_.empty()) << "Canceling a task that others are waiting for " |
+ "is unsupported and will leak memory."; |
+ |
+ if (state_ == State::PENDING || state_ == State::PARTIALLY_RESOLVED) |
+ SetThisAndPrerequisitesAsShouldRun(executor_, false); |
+ |
+ state_ = State::CANCELLED; |
+} |
+ |
+void PromiseBase::MarkAsResolved() { |
+ state_ = State::RESOLVED; |
+ |
+ if (executor_) |
+ executor_->OnPromiseResolved(this); |
+} |
+ |
+void PromiseBase::MarkAsRejected() { |
+ state_ = State::REJECTED; |
+ |
+ if (executor_) |
+ executor_->OnPromiseRejected(this); |
+} |
+ |
+} // namespace internal |
+} // namespace promise |