OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome_frame/task_marshaller.h" | 5 #include "chrome_frame/task_marshaller.h" |
6 #include "base/task.h" | 6 #include "base/task.h" |
7 | 7 |
8 TaskMarshallerThroughMessageQueue::TaskMarshallerThroughMessageQueue() { | 8 TaskMarshallerThroughMessageQueue::TaskMarshallerThroughMessageQueue() |
9 wnd_ = NULL; | 9 : wnd_(NULL), |
10 msg_ = 0xFFFF; | 10 msg_(0xFFFF) { |
11 } | 11 } |
12 | 12 |
13 TaskMarshallerThroughMessageQueue::~TaskMarshallerThroughMessageQueue() { | 13 TaskMarshallerThroughMessageQueue::~TaskMarshallerThroughMessageQueue() { |
14 DeleteAll(); | 14 ClearTasks(); |
15 } | 15 } |
16 | 16 |
17 void TaskMarshallerThroughMessageQueue::PostTask( | 17 void TaskMarshallerThroughMessageQueue::PostTask( |
18 const tracked_objects::Location& from_here, Task* task) { | 18 const tracked_objects::Location& from_here, const base::Closure& task) { |
19 DCHECK(wnd_ != NULL); | 19 DCHECK(wnd_ != NULL); |
20 lock_.Acquire(); | 20 lock_.Acquire(); |
21 bool has_work = !pending_tasks_.empty(); | 21 bool has_work = !pending_tasks_.empty(); |
22 pending_tasks_.push(task); | 22 pending_tasks_.push(task); |
23 lock_.Release(); | 23 lock_.Release(); |
24 | 24 |
25 // Don't post message if there is already one. | 25 // Don't post message if there is already one. |
26 if (has_work) | 26 if (has_work) |
27 return; | 27 return; |
28 | 28 |
29 if (!::PostMessage(wnd_, msg_, 0, 0)) { | 29 if (!::PostMessage(wnd_, msg_, 0, 0)) { |
30 DVLOG(1) << "Dropping MSG_EXECUTE_TASK message for destroyed window."; | 30 DVLOG(1) << "Dropping MSG_EXECUTE_TASK message for destroyed window."; |
31 DeleteAll(); | 31 ClearTasks(); |
32 } | 32 } |
33 } | 33 } |
34 | 34 |
35 void TaskMarshallerThroughMessageQueue::PostDelayedTask( | 35 void TaskMarshallerThroughMessageQueue::PostDelayedTask( |
36 const tracked_objects::Location& source, | 36 const tracked_objects::Location& source, |
37 Task* task, | 37 const base::Closure& task, |
38 base::TimeDelta& delay) { | 38 base::TimeDelta& delay) { |
39 DCHECK(wnd_ != NULL); | 39 DCHECK(wnd_); |
| 40 |
40 base::AutoLock lock(lock_); | 41 base::AutoLock lock(lock_); |
41 DelayedTask delayed_task(task, base::Time::Now() + delay); | 42 base::PendingTask delayed_task(source, task, base::TimeTicks::Now() + delay, |
| 43 true); |
| 44 base::TimeTicks top_run_time = delayed_tasks_.top().delayed_run_time; |
42 delayed_tasks_.push(delayed_task); | 45 delayed_tasks_.push(delayed_task); |
43 // If we become the 'top' task - reschedule the timer. | 46 |
44 if (delayed_tasks_.top().task == task) { | 47 // Reschedule the timer if |delayed_task| will be the next delayed task to |
| 48 // run. |
| 49 if (delayed_task.delayed_run_time < top_run_time) { |
45 ::SetTimer(wnd_, reinterpret_cast<UINT_PTR>(this), | 50 ::SetTimer(wnd_, reinterpret_cast<UINT_PTR>(this), |
46 static_cast<DWORD>(delay.InMilliseconds()), NULL); | 51 static_cast<DWORD>(delay.InMilliseconds()), NULL); |
47 } | 52 } |
48 } | 53 } |
49 | 54 |
50 BOOL TaskMarshallerThroughMessageQueue::ProcessWindowMessage(HWND hWnd, | 55 BOOL TaskMarshallerThroughMessageQueue::ProcessWindowMessage(HWND hWnd, |
51 UINT uMsg, | 56 UINT uMsg, |
52 WPARAM wParam, | 57 WPARAM wParam, |
53 LPARAM lParam, | 58 LPARAM lParam, |
54 LRESULT& lResult, | 59 LRESULT& lResult, |
55 DWORD dwMsgMapID) { | 60 DWORD dwMsgMapID) { |
56 if (hWnd == wnd_ && uMsg == msg_) { | 61 if (hWnd == wnd_ && uMsg == msg_) { |
57 ExecuteQueuedTasks(); | 62 ExecuteQueuedTasks(); |
58 lResult = 0; | 63 lResult = 0; |
59 return TRUE; | 64 return TRUE; |
60 } | 65 } |
61 | 66 |
62 if (hWnd == wnd_ && uMsg == WM_TIMER) { | 67 if (hWnd == wnd_ && uMsg == WM_TIMER) { |
63 ExecuteDelayedTasks(); | 68 ExecuteDelayedTasks(); |
64 lResult = 0; | 69 lResult = 0; |
65 return TRUE; | 70 return TRUE; |
66 } | 71 } |
67 | 72 |
68 return FALSE; | 73 return FALSE; |
69 } | 74 } |
70 | 75 |
71 Task* TaskMarshallerThroughMessageQueue::PopTask() { | 76 base::Closure TaskMarshallerThroughMessageQueue::PopTask() { |
72 base::AutoLock lock(lock_); | 77 base::AutoLock lock(lock_); |
73 Task* task = NULL; | 78 if (pending_tasks_.empty()) |
74 if (!pending_tasks_.empty()) { | 79 return base::Closure(); |
75 task = pending_tasks_.front(); | 80 |
76 pending_tasks_.pop(); | 81 base::Closure task = pending_tasks_.front(); |
77 } | 82 pending_tasks_.pop(); |
78 return task; | 83 return task; |
79 } | 84 } |
80 | 85 |
81 void TaskMarshallerThroughMessageQueue::ExecuteQueuedTasks() { | 86 void TaskMarshallerThroughMessageQueue::ExecuteQueuedTasks() { |
82 DCHECK(CalledOnValidThread()); | 87 DCHECK(CalledOnValidThread()); |
83 Task* task; | 88 base::Closure task; |
84 while ((task = PopTask()) != NULL) { | 89 while (!(task = PopTask()).is_null()) |
85 RunTask(task); | 90 task.Run(); |
86 } | |
87 } | 91 } |
88 | 92 |
89 void TaskMarshallerThroughMessageQueue::ExecuteDelayedTasks() { | 93 void TaskMarshallerThroughMessageQueue::ExecuteDelayedTasks() { |
90 DCHECK(CalledOnValidThread()); | 94 DCHECK(CalledOnValidThread()); |
91 ::KillTimer(wnd_, reinterpret_cast<UINT_PTR>(this)); | 95 ::KillTimer(wnd_, reinterpret_cast<UINT_PTR>(this)); |
92 while (1) { | 96 while (true) { |
93 lock_.Acquire(); | 97 lock_.Acquire(); |
94 | 98 |
95 if (delayed_tasks_.empty()) { | 99 if (delayed_tasks_.empty()) { |
96 lock_.Release(); | 100 lock_.Release(); |
97 return; | 101 return; |
98 } | 102 } |
99 | 103 |
100 base::Time now = base::Time::Now(); | 104 base::PendingTask next_task = delayed_tasks_.top(); |
101 DelayedTask next_task = delayed_tasks_.top(); | 105 base::TimeTicks now = base::TimeTicks::Now(); |
102 base::Time next_run = next_task.run_at; | 106 base::TimeTicks next_run = next_task.delayed_run_time; |
103 if (next_run > now) { | 107 if (next_run > now) { |
104 int64 delay = (next_run - now).InMillisecondsRoundedUp(); | 108 int64 delay = (next_run - now).InMillisecondsRoundedUp(); |
105 ::SetTimer(wnd_, reinterpret_cast<UINT_PTR>(this), | 109 ::SetTimer(wnd_, reinterpret_cast<UINT_PTR>(this), |
106 static_cast<DWORD>(delay), NULL); | 110 static_cast<DWORD>(delay), NULL); |
107 lock_.Release(); | 111 lock_.Release(); |
108 return; | 112 return; |
109 } | 113 } |
110 | 114 |
111 delayed_tasks_.pop(); | 115 delayed_tasks_.pop(); |
112 lock_.Release(); | 116 lock_.Release(); |
113 | 117 |
114 // Run the task outside the lock. | 118 // Run the task outside the lock. |
115 RunTask(next_task.task); | 119 next_task.task.Run(); |
116 } | 120 } |
117 } | 121 } |
118 | 122 |
119 void TaskMarshallerThroughMessageQueue::DeleteAll() { | 123 void TaskMarshallerThroughMessageQueue::ClearTasks() { |
120 base::AutoLock lock(lock_); | 124 base::AutoLock lock(lock_); |
121 DVLOG_IF(1, !pending_tasks_.empty()) << "Destroying " | 125 DVLOG_IF(1, !pending_tasks_.empty()) << "Destroying " |
122 << pending_tasks_.size() | 126 << pending_tasks_.size() |
123 << " pending tasks."; | 127 << " pending tasks."; |
124 while (!pending_tasks_.empty()) { | 128 while (!pending_tasks_.empty()) |
125 Task* task = pending_tasks_.front(); | |
126 pending_tasks_.pop(); | 129 pending_tasks_.pop(); |
127 delete task; | |
128 } | |
129 | 130 |
130 while (!delayed_tasks_.empty()) { | 131 while (!delayed_tasks_.empty()) |
131 delete delayed_tasks_.top().task; | |
132 delayed_tasks_.pop(); | 132 delayed_tasks_.pop(); |
133 } | |
134 } | 133 } |
135 | |
136 void TaskMarshallerThroughMessageQueue::RunTask(Task* task) { | |
137 ++invoke_task_; | |
138 task->Run(); | |
139 --invoke_task_; | |
140 delete task; | |
141 } | |
142 | |
143 bool TaskMarshallerThroughMessageQueue::DelayedTask::operator<( | |
144 const DelayedTask& other) const { | |
145 // Since the top of a priority queue is defined as the "greatest" element, we | |
146 // need to invert the comparison here. We want the smaller time to be at the | |
147 // top of the heap. | |
148 if (run_at < other.run_at) | |
149 return false; | |
150 | |
151 if (run_at > other.run_at) | |
152 return true; | |
153 | |
154 // If the times happen to match, then we use the sequence number to decide. | |
155 // Compare the difference to support integer roll-over. | |
156 return (seq - other.seq) > 0; | |
157 } | |
OLD | NEW |