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

Unified Diff: base/task/task_queue_manager.cc

Issue 637303003: content: Add task queue manager (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Strip out everything else than TaskQueueManager. Added tests. Created 6 years, 2 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
Index: base/task/task_queue_manager.cc
diff --git a/base/task/task_queue_manager.cc b/base/task/task_queue_manager.cc
new file mode 100644
index 0000000000000000000000000000000000000000..b9c518e427e14dc922516e4ebc188789632bc7ce
--- /dev/null
+++ b/base/task/task_queue_manager.cc
@@ -0,0 +1,207 @@
+// Copyright 2014 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 "base/task/task_queue_manager.h"
+
+#include "base/bind.h"
+#include "base/debug/trace_event.h"
+#include "base/task/task_queue_scheduler.h"
+
+namespace base {
+
+TaskQueueManager::TaskRunner::TaskRunner(TaskQueueManager* task_queue_manager,
+ size_t queue_index)
+ : task_queue_manager_(task_queue_manager), queue_index_(queue_index) {
+}
+
+TaskQueueManager::TaskRunner::~TaskRunner() {
+}
+
+bool TaskQueueManager::TaskRunner::RunsTasksOnCurrentThread() const {
+ return task_queue_manager_->RunsTasksOnCurrentThread();
+}
+
+bool TaskQueueManager::TaskRunner::PostDelayedTask(
+ const tracked_objects::Location& from_here,
+ const Closure& task,
+ TimeDelta delay) {
+ return task_queue_manager_->PostDelayedTask(
+ queue_index_, from_here, task, delay);
+}
+
+bool TaskQueueManager::TaskRunner::PostNonNestableDelayedTask(
+ const tracked_objects::Location& from_here,
+ const Closure& task,
+ TimeDelta delay) {
+ return task_queue_manager_->PostNonNestableDelayedTask(
+ queue_index_, from_here, task, delay);
+}
+
+TaskQueueManager::InternalTaskQueue::InternalTaskQueue(size_t index)
+ : index(index), auto_pump(true) {
+}
picksi1 2014/10/15 09:07:38 Should auto_pump be called pump_when_empty?
Sami 2014/10/15 12:05:24 No, because it also involves how DoWork is schedul
+
+TaskQueueManager::InternalTaskQueue::~InternalTaskQueue() {
+}
+
+TaskQueueManager::TaskQueueManager(
+ size_t task_queue_count,
+ scoped_refptr<SingleThreadTaskRunner> main_task_runner,
+ TaskQueueScheduler* scheduler)
+ : main_task_runner_(main_task_runner),
+ scheduler_(scheduler),
+ weak_factory_(this) {
+ DCHECK(main_task_runner->RunsTasksOnCurrentThread());
+
+ for (size_t i = 0; i < task_queue_count; i++) {
+ scoped_ptr<InternalTaskQueue> queue(new InternalTaskQueue(i));
+ queue->task_runner = make_scoped_refptr(new TaskRunner(this, i));
+ queues_.push_back(queue.release());
+ }
+
+ std::vector<const TaskQueue*> work_queues;
+ for (size_t i = 0; i < queues_.size(); i++)
+ work_queues.push_back(&queues_[i]->work_queue);
+ scheduler_->RegisterWorkQueues(work_queues);
picksi1 2014/10/15 09:07:38 Are we exposing our inner workings (i.e. the work_
Sami 2014/10/15 12:05:24 I'm not sure I follow the last half of your sugges
+}
+
+TaskQueueManager::~TaskQueueManager() {
+}
+
+scoped_refptr<SingleThreadTaskRunner> TaskQueueManager::TaskRunnerForQueue(
+ size_t queue_index) {
+ DCHECK_LT(queue_index, queues_.size());
+ return queues_[queue_index]->task_runner;
+}
+
+bool TaskQueueManager::PollQueue(size_t queue_index) {
+ DCHECK_LT(queue_index, queues_.size());
+ if (!queues_[queue_index]->work_queue.empty())
+ return true;
+ InternalTaskQueue* queue = queues_[queue_index];
picksi1 2014/10/15 09:07:38 Getting a queue from an index is repeated a lot, s
Sami 2014/10/15 12:05:24 Good idea, done.
+ AutoLock lock(queue->incoming_queue_lock);
+ return !queue->incoming_queue.empty();
petrcermak 2014/10/15 10:05:40 Shouldn't this be "return queue->auto_pump && !que
alexclarke 2014/10/15 10:09:14 The TaskQueueScheduler is responsible for setting
petrcermak 2014/10/15 10:13:05 Acknowledged.
+}
+
+bool TaskQueueManager::ReloadWorkQueue(size_t queue_index) {
+ main_thread_checker_.CalledOnValidThread();
+ DCHECK_LT(queue_index, queues_.size());
+ InternalTaskQueue* queue = queues_[queue_index];
+ DCHECK(queue->work_queue.empty());
+ AutoLock lock(queue->incoming_queue_lock);
+ if (!queue->auto_pump)
+ return false;
+ queue->work_queue.Swap(&queue->incoming_queue);
+ return !queue->work_queue.empty();
+}
+
+void TaskQueueManager::EnqueueTask(size_t queue_index,
+ const PendingTask& pending_task) {
+ DCHECK_LT(queue_index, queues_.size());
+ InternalTaskQueue* queue = queues_[queue_index];
+ AutoLock lock(queue->incoming_queue_lock);
+ if (queue->auto_pump && queue->incoming_queue.empty())
+ ScheduleWork();
+ queue->incoming_queue.push(pending_task);
picksi1 2014/10/15 09:07:38 Is it possible for the incoming queue to be empty
Sami 2014/10/15 12:05:24 Yes, that's possible. This is written to be slight
+}
+
+void TaskQueueManager::SetAutoPump(size_t queue_index, bool auto_pump) {
+ DCHECK_LT(queue_index, queues_.size());
+ InternalTaskQueue* queue = queues_[queue_index];
+ {
+ AutoLock lock(queue->incoming_queue_lock);
+ queue->auto_pump = auto_pump;
+ }
+ if (auto_pump)
+ PumpQueue(queue_index);
+}
picksi1 2014/10/15 09:07:38 Would you consider having two different functions
Sami 2014/10/15 12:05:24 Hmm, having two different functions makes this a l
+
+void TaskQueueManager::PumpQueue(size_t queue_index) {
+ DCHECK_LT(queue_index, queues_.size());
+ InternalTaskQueue* queue = queues_[queue_index];
+ if (queue->work_queue.empty()) {
+ AutoLock lock(queue->incoming_queue_lock);
+ queue->work_queue.Swap(&queue->incoming_queue);
+ }
+ if (!queue->work_queue.empty())
+ ScheduleWork();
+}
+
+void TaskQueueManager::ScheduleWork() {
+ main_task_runner_->PostTask(
+ FROM_HERE, Bind(&TaskQueueManager::DoWork, weak_factory_.GetWeakPtr()));
+}
picksi1 2014/10/15 09:07:38 Is ScheduleWork the right name? Should it be more
Sami 2014/10/15 12:05:24 ScheduleWork/DoWork seems like a reasonable pairin
rmcilroy 2014/10/15 13:02:45 I somewhat agree with Simon that it's difficult to
Sami 2014/10/15 14:34:30 Ah, I was hoping it was now more clear since we ha
+
+bool TaskQueueManager::ReloadWorkQueues() {
+ bool has_work = false;
+ for (auto& queue : queues_) {
+ if (!queue->work_queue.empty())
+ has_work = true;
+ else if (ReloadWorkQueue(queue->index))
+ has_work = true;
+ }
+ return has_work;
+}
+
+void TaskQueueManager::DoWork() {
+ main_thread_checker_.CalledOnValidThread();
+ if (!ReloadWorkQueues())
+ return;
+
+ size_t queue_index;
+ if (!scheduler_->ChooseWorkQueueToService(&queue_index))
+ return;
+ ScheduleWork();
+ RunTaskFromWorkQueue(queue_index);
+}
+
+void TaskQueueManager::RunTaskFromWorkQueue(size_t queue_index) {
+ main_thread_checker_.CalledOnValidThread();
+ DCHECK_LT(queue_index, queues_.size());
+ InternalTaskQueue* queue = queues_[queue_index];
+ DCHECK(!queue->work_queue.empty());
+ PendingTask pending_task = queue->work_queue.front();
+ queue->work_queue.pop();
+ task_annotator_.RunTask(
+ "TaskQueueManager::PostTask", "TaskQueueManager::RunTask", pending_task);
+}
+
+bool TaskQueueManager::RunsTasksOnCurrentThread() const {
+ return main_task_runner_->RunsTasksOnCurrentThread();
+}
+
+bool TaskQueueManager::PostDelayedTask(
+ size_t queue_index,
+ const tracked_objects::Location& from_here,
+ const Closure& task,
+ TimeDelta delay) {
+ int sequence_num = task_sequence_num_.GetNext();
+
+ PendingTask pending_task(from_here, task);
+ pending_task.sequence_num = sequence_num;
+
+ task_annotator_.DidQueueTask("TaskQueueManager::PostTask", pending_task);
+ if (delay > TimeDelta()) {
+ return main_task_runner_->PostDelayedTask(
+ from_here,
+ Bind(&TaskQueueManager::EnqueueTask,
+ weak_factory_.GetWeakPtr(),
+ queue_index,
+ pending_task),
+ delay);
+ }
+ EnqueueTask(queue_index, pending_task);
+ return true;
+}
+
+bool TaskQueueManager::PostNonNestableDelayedTask(
+ size_t queue_index,
+ const tracked_objects::Location& from_here,
+ const Closure& task,
+ TimeDelta delay) {
+ // Defer non-nestable work to the main task runner.
+ return main_task_runner_->PostNonNestableDelayedTask(from_here, task, delay);
+}
+
+} // namespace content

Powered by Google App Engine
This is Rietveld 408576698