- add sources.
[platform/framework/web/crosswalk.git] / src / chrome_frame / task_marshaller.cc
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
3 // found in the LICENSE file.
4
5 #include "chrome_frame/task_marshaller.h"
6
7 #include "base/callback.h"
8 #include "base/logging.h"
9
10 TaskMarshallerThroughMessageQueue::TaskMarshallerThroughMessageQueue()
11     : wnd_(NULL),
12       msg_(0xFFFF) {
13 }
14
15 TaskMarshallerThroughMessageQueue::~TaskMarshallerThroughMessageQueue() {
16   ClearTasks();
17 }
18
19 void TaskMarshallerThroughMessageQueue::PostTask(
20     const tracked_objects::Location& from_here, const base::Closure& task) {
21   DCHECK(wnd_ != NULL);
22
23   lock_.Acquire();
24   bool has_work = !pending_tasks_.empty();
25   pending_tasks_.push(task);
26   lock_.Release();
27
28   // Don't post message if there is already one.
29   if (has_work)
30     return;
31
32   if (!::PostMessage(wnd_, msg_, 0, 0)) {
33     DVLOG(1) << "Dropping MSG_EXECUTE_TASK message for destroyed window.";
34     ClearTasks();
35   }
36 }
37
38 void TaskMarshallerThroughMessageQueue::PostDelayedTask(
39     const tracked_objects::Location& source,
40     const base::Closure& task,
41     base::TimeDelta& delay) {
42   DCHECK(wnd_);
43
44   base::AutoLock lock(lock_);
45   base::PendingTask delayed_task(source, task, base::TimeTicks::Now() + delay,
46                                  true);
47   base::TimeTicks top_run_time = delayed_tasks_.top().delayed_run_time;
48   delayed_tasks_.push(delayed_task);
49
50   // Reschedule the timer if |delayed_task| will be the next delayed task to
51   // run.
52   if (delayed_task.delayed_run_time < top_run_time) {
53     ::SetTimer(wnd_, reinterpret_cast<UINT_PTR>(this),
54                static_cast<DWORD>(delay.InMilliseconds()), NULL);
55   }
56 }
57
58 BOOL TaskMarshallerThroughMessageQueue::ProcessWindowMessage(HWND hWnd,
59                                                              UINT uMsg,
60                                                              WPARAM wParam,
61                                                              LPARAM lParam,
62                                                              LRESULT& lResult,
63                                                              DWORD dwMsgMapID) {
64   if (hWnd == wnd_ && uMsg == msg_) {
65     ExecuteQueuedTasks();
66     lResult = 0;
67     return TRUE;
68   }
69
70   if (hWnd == wnd_ && uMsg == WM_TIMER) {
71     ExecuteDelayedTasks();
72     lResult = 0;
73     return TRUE;
74   }
75
76   return FALSE;
77 }
78
79 base::Closure TaskMarshallerThroughMessageQueue::PopTask() {
80   base::AutoLock lock(lock_);
81   if (pending_tasks_.empty())
82     return base::Closure();
83
84   base::Closure task = pending_tasks_.front();
85   pending_tasks_.pop();
86   return task;
87 }
88
89 void TaskMarshallerThroughMessageQueue::ExecuteQueuedTasks() {
90   DCHECK(CalledOnValidThread());
91   base::Closure task;
92   while (!(task = PopTask()).is_null())
93     task.Run();
94 }
95
96 void TaskMarshallerThroughMessageQueue::ExecuteDelayedTasks() {
97   DCHECK(CalledOnValidThread());
98   ::KillTimer(wnd_, reinterpret_cast<UINT_PTR>(this));
99   while (true) {
100     lock_.Acquire();
101
102     if (delayed_tasks_.empty()) {
103       lock_.Release();
104       return;
105     }
106
107     base::PendingTask next_task = delayed_tasks_.top();
108     base::TimeTicks now = base::TimeTicks::Now();
109     base::TimeTicks next_run = next_task.delayed_run_time;
110     if (next_run > now) {
111       int64 delay = (next_run - now).InMillisecondsRoundedUp();
112       ::SetTimer(wnd_, reinterpret_cast<UINT_PTR>(this),
113                  static_cast<DWORD>(delay), NULL);
114       lock_.Release();
115       return;
116     }
117
118     delayed_tasks_.pop();
119     lock_.Release();
120
121     // Run the task outside the lock.
122     next_task.task.Run();
123   }
124 }
125
126 void TaskMarshallerThroughMessageQueue::ClearTasks() {
127   base::AutoLock lock(lock_);
128   DVLOG_IF(1, !pending_tasks_.empty()) << "Destroying "
129                                        << pending_tasks_.size()
130                                        << " pending tasks.";
131   while (!pending_tasks_.empty())
132     pending_tasks_.pop();
133
134   while (!delayed_tasks_.empty())
135     delayed_tasks_.pop();
136 }