Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(525)

Side by Side Diff: base/message_pump_win.cc

Issue 10134001: Make sure that base::MessagePumpForUI from different modules are isolated from each other and add p… (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: CR feedback. Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « base/message_pump_win.h ('k') | base/process_util.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "base/message_pump_win.h" 5 #include "base/message_pump_win.h"
6 6
7 #include <math.h> 7 #include <math.h>
8 8
9 #include "base/message_loop.h" 9 #include "base/message_loop.h"
10 #include "base/metrics/histogram.h" 10 #include "base/metrics/histogram.h"
11 #include "base/process_util.h"
12 #include "base/stringprintf.h"
11 #include "base/win/wrapped_window_proc.h" 13 #include "base/win/wrapped_window_proc.h"
12 14
15 namespace {
16
17 // The ID of the timer used by the UI message pump.
18 const int kMessagePumpTimerId = 0;
19
20 } // namespace
21
13 namespace base { 22 namespace base {
14 23
15 static const wchar_t kWndClass[] = L"Chrome_MessagePumpWindow"; 24 static const wchar_t kWndClassFormat[] = L"Chrome_MessagePumpWindow%p";
16 25
17 // Message sent to get an additional time slice for pumping (processing) another 26 // Message sent to get an additional time slice for pumping (processing) another
18 // task (a series of such messages creates a continuous task pump). 27 // task (a series of such messages creates a continuous task pump).
19 static const int kMsgHaveWork = WM_USER + 1; 28 static const int kMsgHaveWork = WM_USER + 1;
20 29
21 //----------------------------------------------------------------------------- 30 //-----------------------------------------------------------------------------
22 // MessagePumpWin public: 31 // MessagePumpWin public:
23 32
24 void MessagePumpWin::AddObserver(MessagePumpObserver* observer) { 33 void MessagePumpWin::AddObserver(MessagePumpObserver* observer) {
25 observers_.AddObserver(observer); 34 observers_.AddObserver(observer);
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
75 int delay = static_cast<int>(timeout); 84 int delay = static_cast<int>(timeout);
76 if (delay < 0) 85 if (delay < 0)
77 delay = 0; 86 delay = 0;
78 87
79 return delay; 88 return delay;
80 } 89 }
81 90
82 //----------------------------------------------------------------------------- 91 //-----------------------------------------------------------------------------
83 // MessagePumpForUI public: 92 // MessagePumpForUI public:
84 93
85 MessagePumpForUI::MessagePumpForUI() { 94 MessagePumpForUI::MessagePumpForUI()
95 : atom_(0),
96 instance_(NULL),
97 message_hwnd_(NULL) {
86 InitMessageWnd(); 98 InitMessageWnd();
87 } 99 }
88 100
89 MessagePumpForUI::~MessagePumpForUI() { 101 MessagePumpForUI::~MessagePumpForUI() {
90 DestroyWindow(message_hwnd_); 102 if (message_hwnd_ != NULL)
91 UnregisterClass(kWndClass, GetModuleHandle(NULL)); 103 DestroyWindow(message_hwnd_);
104
105 if (atom_ != 0)
106 UnregisterClass(reinterpret_cast<const char16*>(atom_), instance_);
92 } 107 }
93 108
94 void MessagePumpForUI::ScheduleWork() { 109 void MessagePumpForUI::ScheduleWork() {
95 if (InterlockedExchange(&have_work_, 1)) 110 if (InterlockedExchange(&have_work_, 1))
96 return; // Someone else continued the pumping. 111 return; // Someone else continued the pumping.
97 112
98 // Make sure the MessagePump does some work for us. 113 // Make sure the MessagePump does some work for us.
99 PostMessage(message_hwnd_, kMsgHaveWork, reinterpret_cast<WPARAM>(this), 0); 114 PostMessage(message_hwnd_, kMsgHaveWork, 0, 0);
100 } 115 }
101 116
102 void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { 117 void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
103 // 118 //
104 // We would *like* to provide high resolution timers. Windows timers using 119 // We would *like* to provide high resolution timers. Windows timers using
105 // SetTimer() have a 10ms granularity. We have to use WM_TIMER as a wakeup 120 // SetTimer() have a 10ms granularity. We have to use WM_TIMER as a wakeup
106 // mechanism because the application can enter modal windows loops where it 121 // mechanism because the application can enter modal windows loops where it
107 // is not running our MessageLoop; the only way to have our timers fire in 122 // is not running our MessageLoop; the only way to have our timers fire in
108 // these cases is to post messages there. 123 // these cases is to post messages there.
109 // 124 //
(...skipping 12 matching lines...) Expand all
122 // 137 //
123 delayed_work_time_ = delayed_work_time; 138 delayed_work_time_ = delayed_work_time;
124 139
125 int delay_msec = GetCurrentDelay(); 140 int delay_msec = GetCurrentDelay();
126 DCHECK_GE(delay_msec, 0); 141 DCHECK_GE(delay_msec, 0);
127 if (delay_msec < USER_TIMER_MINIMUM) 142 if (delay_msec < USER_TIMER_MINIMUM)
128 delay_msec = USER_TIMER_MINIMUM; 143 delay_msec = USER_TIMER_MINIMUM;
129 144
130 // Create a WM_TIMER event that will wake us up to check for any pending 145 // Create a WM_TIMER event that will wake us up to check for any pending
131 // timers (in case we are running within a nested, external sub-pump). 146 // timers (in case we are running within a nested, external sub-pump).
132 SetTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this), delay_msec, NULL); 147 SetTimer(message_hwnd_, kMessagePumpTimerId, delay_msec, NULL);
133 } 148 }
134 149
135 void MessagePumpForUI::PumpOutPendingPaintMessages() { 150 void MessagePumpForUI::PumpOutPendingPaintMessages() {
136 // If we are being called outside of the context of Run, then don't try to do 151 // If we are being called outside of the context of Run, then don't try to do
137 // any work. 152 // any work.
138 if (!state_) 153 if (!state_)
139 return; 154 return;
140 155
141 // Create a mini-message-pump to force immediate processing of only Windows 156 // Create a mini-message-pump to force immediate processing of only Windows
142 // WM_PAINT messages. Don't provide an infinite loop, but do enough peeking 157 // WM_PAINT messages. Don't provide an infinite loop, but do enough peeking
(...skipping 12 matching lines...) Expand all
155 // Histogram what was really being used, to help to adjust kMaxPeekCount. 170 // Histogram what was really being used, to help to adjust kMaxPeekCount.
156 DHISTOGRAM_COUNTS("Loop.PumpOutPendingPaintMessages Peeks", peek_count); 171 DHISTOGRAM_COUNTS("Loop.PumpOutPendingPaintMessages Peeks", peek_count);
157 } 172 }
158 173
159 //----------------------------------------------------------------------------- 174 //-----------------------------------------------------------------------------
160 // MessagePumpForUI private: 175 // MessagePumpForUI private:
161 176
162 // static 177 // static
163 LRESULT CALLBACK MessagePumpForUI::WndProcThunk( 178 LRESULT CALLBACK MessagePumpForUI::WndProcThunk(
164 HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { 179 HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) {
165 switch (message) { 180 // Retrieve |this| from the user data, associated with the window.
166 case kMsgHaveWork: 181 MessagePumpForUI* self = reinterpret_cast<MessagePumpForUI*>(
167 reinterpret_cast<MessagePumpForUI*>(wparam)->HandleWorkMessage(); 182 GetWindowLongPtr(hwnd, GWLP_USERDATA));
168 break; 183 if (self != NULL) {
jar (doing other things) 2012/05/15 21:39:42 Perchance we should not check the value of |self|,
alexeypa (please no reviews) 2012/05/15 22:10:27 |self| should never be NULL except for WM_CREATE m
169 case WM_TIMER: 184 switch (message) {
170 reinterpret_cast<MessagePumpForUI*>(wparam)->HandleTimerMessage(); 185 case kMsgHaveWork:
171 break; 186 self->HandleWorkMessage();
187 break;
188 case WM_TIMER:
189 DCHECK(wparam == kMessagePumpTimerId);
190 self->HandleTimerMessage();
191 break;
192 }
172 } 193 }
173 return DefWindowProc(hwnd, message, wparam, lparam); 194 return DefWindowProc(hwnd, message, wparam, lparam);
174 } 195 }
175 196
176 void MessagePumpForUI::DoRunLoop() { 197 void MessagePumpForUI::DoRunLoop() {
177 // IF this was just a simple PeekMessage() loop (servicing all possible work 198 // IF this was just a simple PeekMessage() loop (servicing all possible work
178 // queues), then Windows would try to achieve the following order according 199 // queues), then Windows would try to achieve the following order according
179 // to MSDN documentation about PeekMessage with no filter): 200 // to MSDN documentation about PeekMessage with no filter):
180 // * Sent messages 201 // * Sent messages
181 // * Posted messages 202 // * Posted messages
(...skipping 22 matching lines...) Expand all
204 if (state_->should_quit) 225 if (state_->should_quit)
205 break; 226 break;
206 227
207 more_work_is_plausible |= 228 more_work_is_plausible |=
208 state_->delegate->DoDelayedWork(&delayed_work_time_); 229 state_->delegate->DoDelayedWork(&delayed_work_time_);
209 // If we did not process any delayed work, then we can assume that our 230 // If we did not process any delayed work, then we can assume that our
210 // existing WM_TIMER if any will fire when delayed work should run. We 231 // existing WM_TIMER if any will fire when delayed work should run. We
211 // don't want to disturb that timer if it is already in flight. However, 232 // don't want to disturb that timer if it is already in flight. However,
212 // if we did do all remaining delayed work, then lets kill the WM_TIMER. 233 // if we did do all remaining delayed work, then lets kill the WM_TIMER.
213 if (more_work_is_plausible && delayed_work_time_.is_null()) 234 if (more_work_is_plausible && delayed_work_time_.is_null())
214 KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this)); 235 KillTimer(message_hwnd_, kMessagePumpTimerId);
215 if (state_->should_quit) 236 if (state_->should_quit)
216 break; 237 break;
217 238
218 if (more_work_is_plausible) 239 if (more_work_is_plausible)
219 continue; 240 continue;
220 241
221 more_work_is_plausible = state_->delegate->DoIdleWork(); 242 more_work_is_plausible = state_->delegate->DoIdleWork();
222 if (state_->should_quit) 243 if (state_->should_quit)
223 break; 244 break;
224 245
225 if (more_work_is_plausible) 246 if (more_work_is_plausible)
226 continue; 247 continue;
227 248
228 WaitForWork(); // Wait (sleep) until we have work to do again. 249 WaitForWork(); // Wait (sleep) until we have work to do again.
229 } 250 }
230 } 251 }
231 252
232 void MessagePumpForUI::InitMessageWnd() { 253 void MessagePumpForUI::InitMessageWnd() {
233 HINSTANCE hinst = GetModuleHandle(NULL); 254 // Register a unique window class for each instance of UI pump.
255 string16 class_name = base::StringPrintf(kWndClassFormat, this);
256 WNDPROC window_procedure = &base::win::WrappedWindowProc<WndProcThunk>;
234 257
235 WNDCLASSEX wc = {0}; 258 // RegisterClassEx uses a handle of the module containing the window procedure
259 // to distinguish identically named classes registered in different modules.
260 instance_ = GetModuleFromAddress(window_procedure);
261
262 WNDCLASSEXW wc = {0};
236 wc.cbSize = sizeof(wc); 263 wc.cbSize = sizeof(wc);
237 wc.lpfnWndProc = base::win::WrappedWindowProc<WndProcThunk>; 264 wc.lpfnWndProc = window_procedure;
238 wc.hInstance = hinst; 265 wc.hInstance = instance_;
239 wc.lpszClassName = kWndClass; 266 wc.lpszClassName = class_name.c_str();
240 RegisterClassEx(&wc); 267 atom_ = RegisterClassEx(&wc);
268 if (atom_ == 0) {
269 DCHECK(atom_);
alexeypa (please no reviews) 2012/05/15 22:10:27 We should also CHECK here.
270 return;
271 }
241 272
242 message_hwnd_ = 273 // Create the message-only window.
243 CreateWindow(kWndClass, 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, hinst, 0); 274 message_hwnd_ = CreateWindow(
244 DCHECK(message_hwnd_); 275 reinterpret_cast<const char16*>(atom_), 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0,
276 instance_, 0);
277 if (message_hwnd_ == NULL) {
278 DCHECK(message_hwnd_);
279 return;
jar (doing other things) 2012/05/15 21:39:42 These return on error condition appear to mask a s
alexeypa (please no reviews) 2012/05/15 22:10:27 Those DCHECKs migrated from the previous version o
280 }
281
282 // Store |this| so that the window procedure could retrieve it later.
283 SetWindowLongPtr(message_hwnd_,
alexeypa (please no reviews) 2012/05/15 22:10:27 The return value of SetWindowLongPtr should be che
284 GWLP_USERDATA,
285 reinterpret_cast<LONG_PTR>(this));
245 } 286 }
246 287
247 void MessagePumpForUI::WaitForWork() { 288 void MessagePumpForUI::WaitForWork() {
248 // Wait until a message is available, up to the time needed by the timer 289 // Wait until a message is available, up to the time needed by the timer
249 // manager to fire the next set of timers. 290 // manager to fire the next set of timers.
250 int delay = GetCurrentDelay(); 291 int delay = GetCurrentDelay();
251 if (delay < 0) // Negative value means no timers waiting. 292 if (delay < 0) // Negative value means no timers waiting.
252 delay = INFINITE; 293 delay = INFINITE;
253 294
254 DWORD result; 295 DWORD result;
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
293 // messages that may be in the Windows message queue. 334 // messages that may be in the Windows message queue.
294 ProcessPumpReplacementMessage(); 335 ProcessPumpReplacementMessage();
295 336
296 // Now give the delegate a chance to do some work. He'll let us know if he 337 // Now give the delegate a chance to do some work. He'll let us know if he
297 // needs to do more work. 338 // needs to do more work.
298 if (state_->delegate->DoWork()) 339 if (state_->delegate->DoWork())
299 ScheduleWork(); 340 ScheduleWork();
300 } 341 }
301 342
302 void MessagePumpForUI::HandleTimerMessage() { 343 void MessagePumpForUI::HandleTimerMessage() {
303 KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this)); 344 KillTimer(message_hwnd_, kMessagePumpTimerId);
304 345
305 // If we are being called outside of the context of Run, then don't do 346 // If we are being called outside of the context of Run, then don't do
306 // anything. This could correspond to a MessageBox call or something of 347 // anything. This could correspond to a MessageBox call or something of
307 // that sort. 348 // that sort.
308 if (!state_) 349 if (!state_)
309 return; 350 return;
310 351
311 state_->delegate->DoDelayedWork(&delayed_work_time_); 352 state_->delegate->DoDelayedWork(&delayed_work_time_);
312 if (!delayed_work_time_.is_null()) { 353 if (!delayed_work_time_.is_null()) {
313 // A bit gratuitous to set delayed_work_time_ again, but oh well. 354 // A bit gratuitous to set delayed_work_time_ again, but oh well.
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after
574 615
575 void MessagePumpForIO::WillProcessIOEvent() { 616 void MessagePumpForIO::WillProcessIOEvent() {
576 FOR_EACH_OBSERVER(IOObserver, io_observers_, WillProcessIOEvent()); 617 FOR_EACH_OBSERVER(IOObserver, io_observers_, WillProcessIOEvent());
577 } 618 }
578 619
579 void MessagePumpForIO::DidProcessIOEvent() { 620 void MessagePumpForIO::DidProcessIOEvent() {
580 FOR_EACH_OBSERVER(IOObserver, io_observers_, DidProcessIOEvent()); 621 FOR_EACH_OBSERVER(IOObserver, io_observers_, DidProcessIOEvent());
581 } 622 }
582 623
583 } // namespace base 624 } // namespace base
OLDNEW
« no previous file with comments | « base/message_pump_win.h ('k') | base/process_util.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698