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 } 137