summaryrefslogtreecommitdiff
path: root/chromium/chrome/renderer/chromeos_delayed_callback_group.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/chrome/renderer/chromeos_delayed_callback_group.cc')
-rw-r--r--chromium/chrome/renderer/chromeos_delayed_callback_group.cc115
1 files changed, 115 insertions, 0 deletions
diff --git a/chromium/chrome/renderer/chromeos_delayed_callback_group.cc b/chromium/chrome/renderer/chromeos_delayed_callback_group.cc
new file mode 100644
index 00000000000..8ce4700e5c0
--- /dev/null
+++ b/chromium/chrome/renderer/chromeos_delayed_callback_group.cc
@@ -0,0 +1,115 @@
+// Copyright 2019 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 "chrome/renderer/chromeos_delayed_callback_group.h"
+
+#include <utility>
+
+#include "base/task/post_task.h"
+#include "base/bind.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/threading/thread_task_runner_handle.h"
+
+DelayedCallbackGroup::CallbackEntry::CallbackEntry(
+ Callback callback,
+ const scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
+ base::TimeTicks expiration_time)
+ : callback_(std::move(callback)),
+ callback_task_runner_(std::move(callback_task_runner)),
+ expiration_time_(expiration_time) {}
+
+DelayedCallbackGroup::CallbackEntry::~CallbackEntry() {}
+
+DelayedCallbackGroup::DelayedCallbackGroup(
+ base::TimeDelta expiration_delay,
+ scoped_refptr<base::SequencedTaskRunner> expiration_task_runner)
+ : expiration_delay_(expiration_delay),
+ expiration_task_runner_(expiration_task_runner) {
+ DETACH_FROM_SEQUENCE(sequence_checker_);
+}
+
+DelayedCallbackGroup::~DelayedCallbackGroup() {
+ base::AutoLock lock(callbacks_lock_);
+ CancelExpirationTimer();
+ ExpireAllCallbacks();
+}
+
+void DelayedCallbackGroup::Add(Callback callback) {
+ DCHECK(base::SequencedTaskRunnerHandle::IsSet());
+ {
+ base::AutoLock lock(callbacks_lock_);
+ base::TimeTicks expiration_time =
+ base::TimeTicks::Now() + expiration_delay_;
+ callbacks_.emplace(std::move(callback),
+ base::SequencedTaskRunnerHandle::Get(), expiration_time);
+ }
+ expiration_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&DelayedCallbackGroup::StartExpirationTimer, this));
+}
+
+void DelayedCallbackGroup::CancelExpirationTimer() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ expiration_timeout_.Cancel();
+}
+
+void DelayedCallbackGroup::StartExpirationTimer() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ base::AutoLock lock(callbacks_lock_);
+ if (callbacks_.empty() || !expiration_timeout_.IsCancelled())
+ return;
+
+ base::TimeDelta delay_until_next_expiration =
+ callbacks_.front().expiration_time_ - base::TimeTicks::Now();
+ expiration_timeout_.Reset(
+ base::BindOnce(&DelayedCallbackGroup::OnExpirationTimer, this));
+ expiration_task_runner_->PostDelayedTask(
+ FROM_HERE, expiration_timeout_.callback(), delay_until_next_expiration);
+}
+
+void DelayedCallbackGroup::OnExpirationTimer() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ ProcessExpiredCallbacks(base::TimeTicks::Now());
+ StartExpirationTimer();
+}
+
+void DelayedCallbackGroup::RunAll() {
+ base::AutoLock lock(callbacks_lock_);
+ while (!callbacks_.empty()) {
+ CallbackEntry& entry = callbacks_.front();
+ entry.callback_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(std::move(entry.callback_), RunReason::NORMAL));
+ callbacks_.pop();
+ }
+}
+
+void DelayedCallbackGroup::ProcessExpiredCallbacks(
+ base::TimeTicks expiration_time) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ base::AutoLock lock(callbacks_lock_);
+ CancelExpirationTimer();
+ while (!callbacks_.empty()) {
+ CallbackEntry& entry = callbacks_.front();
+ if (entry.expiration_time_ <= expiration_time) {
+ entry.callback_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(std::move(entry.callback_), RunReason::TIMEOUT));
+ callbacks_.pop();
+ } else {
+ // All others in this queue expire after |expiration_time|.
+ return;
+ }
+ }
+}
+
+void DelayedCallbackGroup::ExpireAllCallbacks() {
+ while (!callbacks_.empty()) {
+ CallbackEntry& entry = callbacks_.front();
+ entry.callback_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(std::move(entry.callback_), RunReason::TIMEOUT));
+ callbacks_.pop();
+ }
+}