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