Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5393)

Unified Diff: components/scheduler/promises/promise.cc

Issue 1401553002: NOT INTENDED FOR LANDING: A promises demo (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Support for rejectatble promises! Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « components/scheduler/promises/promise.h ('k') | components/scheduler/promises/promise_executor.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
« no previous file with comments | « components/scheduler/promises/promise.h ('k') | components/scheduler/promises/promise_executor.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698