1ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// Copyright 2013 The Chromium Authors. All rights reserved.
2ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// found in the LICENSE file.
4ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
5ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/message_loop/incoming_task_queue.h"
6ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
7ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/location.h"
8ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/message_loop/message_loop.h"
9ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/synchronization/waitable_event.h"
101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/time/time.h"
11ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
12ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochnamespace base {
13ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochnamespace internal {
14ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
15ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben MurdochIncomingTaskQueue::IncomingTaskQueue(MessageLoop* message_loop)
161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    : high_res_task_count_(0),
171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      message_loop_(message_loop),
18ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      next_sequence_num_(0) {
19ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
20ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
21ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochbool IncomingTaskQueue::AddToIncomingQueue(
22ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    const tracked_objects::Location& from_here,
23ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    const Closure& task,
24ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    TimeDelta delay,
25ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    bool nestable) {
26ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  AutoLock locked(incoming_queue_lock_);
27ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  PendingTask pending_task(
28ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      from_here, task, CalculateDelayedRuntime(delay), nestable);
291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#if defined(OS_WIN)
301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // We consider the task needs a high resolution timer if the delay is
311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // more than 0 and less than 32ms. This caps the relative error to
321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // less than 50% : a 33ms wait can wake at 48ms since the default
331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // resolution on Windows is between 10 and 15ms.
341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (delay > TimeDelta() &&
351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      delay.InMilliseconds() < (2 * Time::kMinLowResolutionThresholdMs)) {
361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    ++high_res_task_count_;
371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    pending_task.is_high_res = true;
381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#endif
40ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return PostPendingTask(&pending_task);
41ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
42ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool IncomingTaskQueue::HasHighResolutionTasks() {
441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  AutoLock lock(incoming_queue_lock_);
451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return high_res_task_count_ > 0;
46ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
47ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
48ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochbool IncomingTaskQueue::IsIdleForTesting() {
49ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  AutoLock lock(incoming_queue_lock_);
50ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return incoming_queue_.empty();
51ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
52ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciint IncomingTaskQueue::ReloadWorkQueue(TaskQueue* work_queue) {
54ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Make sure no tasks are lost.
55ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK(work_queue->empty());
56ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
57ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Acquire all we can from the inter-thread queue with one lock acquisition.
58ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  AutoLock lock(incoming_queue_lock_);
59ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (!incoming_queue_.empty())
601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    incoming_queue_.Swap(work_queue);
61ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Reset the count of high resolution tasks since our queue is now empty.
631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  int high_res_tasks = high_res_task_count_;
641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  high_res_task_count_ = 0;
651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return high_res_tasks;
66ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
67ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
68ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid IncomingTaskQueue::WillDestroyCurrentMessageLoop() {
69ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  AutoLock lock(incoming_queue_lock_);
70ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  message_loop_ = NULL;
71ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
72ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
73ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben MurdochIncomingTaskQueue::~IncomingTaskQueue() {
74ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Verify that WillDestroyCurrentMessageLoop() has been called.
75ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK(!message_loop_);
76ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
77ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
78ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben MurdochTimeTicks IncomingTaskQueue::CalculateDelayedRuntime(TimeDelta delay) {
79ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  TimeTicks delayed_run_time;
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (delay > TimeDelta())
81ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    delayed_run_time = TimeTicks::Now() + delay;
821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  else
83ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK_EQ(delay.InMilliseconds(), 0) << "delay should not be negative";
84ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return delayed_run_time;
85ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
86ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
87ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochbool IncomingTaskQueue::PostPendingTask(PendingTask* pending_task) {
88ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Warning: Don't try to short-circuit, and handle this thread's tasks more
89ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // directly, as it could starve handling of foreign threads.  Put every task
90ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // into this queue.
91ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
92ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // This should only be called while the lock is taken.
93ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  incoming_queue_lock_.AssertAcquired();
94ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
95ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (!message_loop_) {
96ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    pending_task->task.Reset();
97ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return false;
98ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
99ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
100ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Initialize the sequence number. The sequence number is used for delayed
101ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // tasks (to faciliate FIFO sorting when two tasks have the same
102ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // delayed_run_time value) and for identifying the task in about:tracing.
103ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  pending_task->sequence_num = next_sequence_num_++;
104ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1056e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  message_loop_->task_annotator()->DidQueueTask("MessageLoop::PostTask",
1066e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                                                *pending_task);
107ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
108ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  bool was_empty = incoming_queue_.empty();
109ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  incoming_queue_.push(*pending_task);
110ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  pending_task->task.Reset();
111ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
112ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Wake up the pump.
113ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  message_loop_->ScheduleWork(was_empty);
114ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
115ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return true;
116ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
117ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
118ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}  // namespace internal
119ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}  // namespace base
120