| 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
|
|
|