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/debug/trace_event.h"
8ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/location.h"
9ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/message_loop/message_loop.h"
10ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/synchronization/waitable_event.h"
11ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
12ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochnamespace base {
13ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochnamespace internal {
14ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
15ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben MurdochIncomingTaskQueue::IncomingTaskQueue(MessageLoop* message_loop)
16ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    : message_loop_(message_loop),
17ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      next_sequence_num_(0) {
18ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
19ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
20ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochbool IncomingTaskQueue::AddToIncomingQueue(
21ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    const tracked_objects::Location& from_here,
22ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    const Closure& task,
23ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    TimeDelta delay,
24ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    bool nestable) {
25ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  AutoLock locked(incoming_queue_lock_);
26ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  PendingTask pending_task(
27ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      from_here, task, CalculateDelayedRuntime(delay), nestable);
28ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return PostPendingTask(&pending_task);
29ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
30ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
31ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochbool IncomingTaskQueue::TryAddToIncomingQueue(
32ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    const tracked_objects::Location& from_here,
33ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    const Closure& task) {
34ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (!incoming_queue_lock_.Try()) {
35ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // Reset |task|.
36ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    Closure local_task = task;
37ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return false;
38ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
39ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
40ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  AutoLock locked(incoming_queue_lock_, AutoLock::AlreadyAcquired());
41ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  PendingTask pending_task(
42ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      from_here, task, CalculateDelayedRuntime(TimeDelta()), true);
43ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return PostPendingTask(&pending_task);
44ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
45ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
46ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochbool IncomingTaskQueue::IsHighResolutionTimerEnabledForTesting() {
47ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#if defined(OS_WIN)
48ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return !high_resolution_timer_expiration_.is_null();
49ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#else
50ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return true;
51ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#endif
52ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
53ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
54ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochbool IncomingTaskQueue::IsIdleForTesting() {
55ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  AutoLock lock(incoming_queue_lock_);
56ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return incoming_queue_.empty();
57ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
58ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
59ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid IncomingTaskQueue::LockWaitUnLockForTesting(WaitableEvent* caller_wait,
60ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                                 WaitableEvent* caller_signal) {
61ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  AutoLock lock(incoming_queue_lock_);
62ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  caller_wait->Signal();
63ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  caller_signal->Wait();
64ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
65ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
66ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid IncomingTaskQueue::ReloadWorkQueue(TaskQueue* work_queue) {
67ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Make sure no tasks are lost.
68ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK(work_queue->empty());
69ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
70ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Acquire all we can from the inter-thread queue with one lock acquisition.
71ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  AutoLock lock(incoming_queue_lock_);
72ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (!incoming_queue_.empty())
73ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    incoming_queue_.Swap(work_queue);  // Constant time
74ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
75ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK(incoming_queue_.empty());
76ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
77ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
78ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid IncomingTaskQueue::WillDestroyCurrentMessageLoop() {
79ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#if defined(OS_WIN)
80ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // If we left the high-resolution timer activated, deactivate it now.
81ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Doing this is not-critical, it is mainly to make sure we track
82ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // the high resolution timer activations properly in our unit tests.
83ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (!high_resolution_timer_expiration_.is_null()) {
84ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    Time::ActivateHighResolutionTimer(false);
85ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    high_resolution_timer_expiration_ = TimeTicks();
86ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
87ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#endif
88ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
89ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  AutoLock lock(incoming_queue_lock_);
90ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  message_loop_ = NULL;
91ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
92ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
93ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben MurdochIncomingTaskQueue::~IncomingTaskQueue() {
94ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Verify that WillDestroyCurrentMessageLoop() has been called.
95ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK(!message_loop_);
96ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
97ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
98ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben MurdochTimeTicks IncomingTaskQueue::CalculateDelayedRuntime(TimeDelta delay) {
99ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  TimeTicks delayed_run_time;
100ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (delay > TimeDelta()) {
101ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    delayed_run_time = TimeTicks::Now() + delay;
102ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
103ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#if defined(OS_WIN)
104ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (high_resolution_timer_expiration_.is_null()) {
105ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      // Windows timers are granular to 15.6ms.  If we only set high-res
106ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      // timers for those under 15.6ms, then a 18ms timer ticks at ~32ms,
107ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      // which as a percentage is pretty inaccurate.  So enable high
108ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      // res timers for any timer which is within 2x of the granularity.
109ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      // This is a tradeoff between accuracy and power management.
110ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      bool needs_high_res_timers = delay.InMilliseconds() <
111ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          (2 * Time::kMinLowResolutionThresholdMs);
112ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      if (needs_high_res_timers) {
113ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        if (Time::ActivateHighResolutionTimer(true)) {
114ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          high_resolution_timer_expiration_ = TimeTicks::Now() +
115ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch              TimeDelta::FromMilliseconds(
116ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                  MessageLoop::kHighResolutionTimerModeLeaseTimeMs);
117ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        }
118ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      }
119ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
120ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#endif
121ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  } else {
122ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK_EQ(delay.InMilliseconds(), 0) << "delay should not be negative";
123ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
124ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
125ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#if defined(OS_WIN)
126ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (!high_resolution_timer_expiration_.is_null()) {
127ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (TimeTicks::Now() > high_resolution_timer_expiration_) {
128ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      Time::ActivateHighResolutionTimer(false);
129ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      high_resolution_timer_expiration_ = TimeTicks();
130ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
131ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
132ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#endif
133ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
134ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return delayed_run_time;
135ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
136ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
137ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochbool IncomingTaskQueue::PostPendingTask(PendingTask* pending_task) {
138ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Warning: Don't try to short-circuit, and handle this thread's tasks more
139ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // directly, as it could starve handling of foreign threads.  Put every task
140ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // into this queue.
141ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
142ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // This should only be called while the lock is taken.
143ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  incoming_queue_lock_.AssertAcquired();
144ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
145ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (!message_loop_) {
146ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    pending_task->task.Reset();
147ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return false;
148ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
149ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
150ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Initialize the sequence number. The sequence number is used for delayed
151ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // tasks (to faciliate FIFO sorting when two tasks have the same
152ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // delayed_run_time value) and for identifying the task in about:tracing.
153ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  pending_task->sequence_num = next_sequence_num_++;
154ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
155ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  TRACE_EVENT_FLOW_BEGIN0("task", "MessageLoop::PostTask",
156ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      TRACE_ID_MANGLE(message_loop_->GetTaskTraceID(*pending_task)));
157ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
158ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  bool was_empty = incoming_queue_.empty();
159ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  incoming_queue_.push(*pending_task);
160ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  pending_task->task.Reset();
161ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
162ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Wake up the pump.
163ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  message_loop_->ScheduleWork(was_empty);
164ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
165ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return true;
166ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
167ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
168ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}  // namespace internal
169ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}  // namespace base
170