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

Side by Side Diff: base/message_pump_win.cc

Issue 15261005: Allow multiple base::MessagePumpForUI instances to be created simultanenously on Windows. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fixed the component build. Created 7 years, 7 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
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/debug/trace_event.h" 9 #include "base/debug/trace_event.h"
10 #include "base/message_loop.h" 10 #include "base/message_loop.h"
11 #include "base/metrics/histogram.h" 11 #include "base/metrics/histogram.h"
12 #include "base/process_util.h"
13 #include "base/win/wrapped_window_proc.h"
14 12
15 namespace { 13 namespace {
16 14
17 enum MessageLoopProblems { 15 enum MessageLoopProblems {
18 MESSAGE_POST_ERROR, 16 MESSAGE_POST_ERROR,
19 COMPLETION_POST_ERROR, 17 COMPLETION_POST_ERROR,
20 SET_TIMER_ERROR, 18 SET_TIMER_ERROR,
21 MESSAGE_LOOP_PROBLEM_MAX, 19 MESSAGE_LOOP_PROBLEM_MAX,
22 }; 20 };
23 21
24 } // namespace 22 } // namespace
25 23
26 namespace base { 24 namespace base {
27 25
28 static const wchar_t kWndClass[] = L"Chrome_MessagePumpWindow";
29
30 // 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
31 // task (a series of such messages creates a continuous task pump). 27 // task (a series of such messages creates a continuous task pump).
32 static const int kMsgHaveWork = WM_USER + 1; 28 static const int kMsgHaveWork = WM_USER + 1;
33 29
34 //----------------------------------------------------------------------------- 30 //-----------------------------------------------------------------------------
35 // MessagePumpWin public: 31 // MessagePumpWin public:
36 32
37 void MessagePumpWin::AddObserver(MessagePumpObserver* observer) { 33 void MessagePumpWin::AddObserver(MessagePumpObserver* observer) {
38 observers_.AddObserver(observer); 34 observers_.AddObserver(observer);
39 } 35 }
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
89 if (delay < 0) 85 if (delay < 0)
90 delay = 0; 86 delay = 0;
91 87
92 return delay; 88 return delay;
93 } 89 }
94 90
95 //----------------------------------------------------------------------------- 91 //-----------------------------------------------------------------------------
96 // MessagePumpForUI public: 92 // MessagePumpForUI public:
97 93
98 MessagePumpForUI::MessagePumpForUI() 94 MessagePumpForUI::MessagePumpForUI()
99 : instance_(NULL), 95 : message_filter_(new MessageFilter),
100 message_filter_(new MessageFilter) { 96 window_(new win::MessageWindow()) {
101 InitMessageWnd(); 97 CHECK(window_->Create(this)) << "Couldn't create a message-only window.";
102 } 98 }
103 99
104 MessagePumpForUI::~MessagePumpForUI() { 100 MessagePumpForUI::~MessagePumpForUI() {
105 DestroyWindow(message_hwnd_);
106 UnregisterClass(kWndClass, instance_);
107 } 101 }
108 102
109 void MessagePumpForUI::ScheduleWork() { 103 void MessagePumpForUI::ScheduleWork() {
110 if (InterlockedExchange(&have_work_, 1)) 104 if (InterlockedExchange(&have_work_, 1))
111 return; // Someone else continued the pumping. 105 return; // Someone else continued the pumping.
112 106
113 // Make sure the MessagePump does some work for us. 107 // Make sure the MessagePump does some work for us.
114 BOOL ret = PostMessage(message_hwnd_, kMsgHaveWork, 108 BOOL ret = PostMessage(window_->hwnd(), kMsgHaveWork,
115 reinterpret_cast<WPARAM>(this), 0); 109 reinterpret_cast<WPARAM>(this), 0);
darin (slow to review) 2013/05/23 00:07:14 it looks like it is no longer necessary to stuff |
alexeypa (please no reviews) 2013/05/23 17:45:54 Done.
116 if (ret) 110 if (ret)
117 return; // There was room in the Window Message queue. 111 return; // There was room in the Window Message queue.
118 112
119 // We have failed to insert a have-work message, so there is a chance that we 113 // We have failed to insert a have-work message, so there is a chance that we
120 // will starve tasks/timers while sitting in a nested message loop. Nested 114 // will starve tasks/timers while sitting in a nested message loop. Nested
121 // loops only look at Windows Message queues, and don't look at *our* task 115 // loops only look at Windows Message queues, and don't look at *our* task
122 // queues, etc., so we might not get a time slice in such. :-( 116 // queues, etc., so we might not get a time slice in such. :-(
123 // We could abort here, but the fear is that this failure mode is plausibly 117 // We could abort here, but the fear is that this failure mode is plausibly
124 // common (queue is full, of about 2000 messages), so we'll do a near-graceful 118 // common (queue is full, of about 2000 messages), so we'll do a near-graceful
125 // recovery. Nested loops are pretty transient (we think), so this will 119 // recovery. Nested loops are pretty transient (we think), so this will
(...skipping 26 matching lines...) Expand all
152 // 146 //
153 delayed_work_time_ = delayed_work_time; 147 delayed_work_time_ = delayed_work_time;
154 148
155 int delay_msec = GetCurrentDelay(); 149 int delay_msec = GetCurrentDelay();
156 DCHECK_GE(delay_msec, 0); 150 DCHECK_GE(delay_msec, 0);
157 if (delay_msec < USER_TIMER_MINIMUM) 151 if (delay_msec < USER_TIMER_MINIMUM)
158 delay_msec = USER_TIMER_MINIMUM; 152 delay_msec = USER_TIMER_MINIMUM;
159 153
160 // Create a WM_TIMER event that will wake us up to check for any pending 154 // Create a WM_TIMER event that will wake us up to check for any pending
161 // timers (in case we are running within a nested, external sub-pump). 155 // timers (in case we are running within a nested, external sub-pump).
162 BOOL ret = SetTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this), 156 BOOL ret = SetTimer(window_->hwnd(), reinterpret_cast<UINT_PTR>(this),
darin (slow to review) 2013/05/23 00:07:14 ditto.
alexeypa (please no reviews) 2013/05/23 17:45:54 Done.
163 delay_msec, NULL); 157 delay_msec, NULL);
164 if (ret) 158 if (ret)
165 return; 159 return;
166 // If we can't set timers, we are in big trouble... but cross our fingers for 160 // If we can't set timers, we are in big trouble... but cross our fingers for
167 // now. 161 // now.
168 // TODO(jar): If we don't see this error, use a CHECK() here instead. 162 // TODO(jar): If we don't see this error, use a CHECK() here instead.
169 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", SET_TIMER_ERROR, 163 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", SET_TIMER_ERROR,
170 MESSAGE_LOOP_PROBLEM_MAX); 164 MESSAGE_LOOP_PROBLEM_MAX);
171 } 165 }
172 166
(...skipping 17 matching lines...) Expand all
190 if (state_->should_quit) // Handle WM_QUIT. 184 if (state_->should_quit) // Handle WM_QUIT.
191 break; 185 break;
192 } 186 }
193 // Histogram what was really being used, to help to adjust kMaxPeekCount. 187 // Histogram what was really being used, to help to adjust kMaxPeekCount.
194 DHISTOGRAM_COUNTS("Loop.PumpOutPendingPaintMessages Peeks", peek_count); 188 DHISTOGRAM_COUNTS("Loop.PumpOutPendingPaintMessages Peeks", peek_count);
195 } 189 }
196 190
197 //----------------------------------------------------------------------------- 191 //-----------------------------------------------------------------------------
198 // MessagePumpForUI private: 192 // MessagePumpForUI private:
199 193
200 // static 194 bool MessagePumpForUI::HandleMessage(HWND hwnd,
201 LRESULT CALLBACK MessagePumpForUI::WndProcThunk( 195 UINT message,
202 HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { 196 WPARAM wparam,
197 LPARAM lparam,
198 LRESULT* result) {
203 switch (message) { 199 switch (message) {
204 case kMsgHaveWork: 200 case kMsgHaveWork:
205 reinterpret_cast<MessagePumpForUI*>(wparam)->HandleWorkMessage(); 201 HandleWorkMessage();
206 break; 202 break;
203
207 case WM_TIMER: 204 case WM_TIMER:
208 reinterpret_cast<MessagePumpForUI*>(wparam)->HandleTimerMessage(); 205 HandleTimerMessage();
209 break; 206 break;
210 } 207 }
211 return DefWindowProc(hwnd, message, wparam, lparam); 208
209 // Do default processing for all messages.
210 return false;
212 } 211 }
213 212
214 void MessagePumpForUI::DoRunLoop() { 213 void MessagePumpForUI::DoRunLoop() {
215 // IF this was just a simple PeekMessage() loop (servicing all possible work 214 // IF this was just a simple PeekMessage() loop (servicing all possible work
216 // queues), then Windows would try to achieve the following order according 215 // queues), then Windows would try to achieve the following order according
217 // to MSDN documentation about PeekMessage with no filter): 216 // to MSDN documentation about PeekMessage with no filter):
218 // * Sent messages 217 // * Sent messages
219 // * Posted messages 218 // * Posted messages
220 // * Sent messages (again) 219 // * Sent messages (again)
221 // * WM_PAINT messages 220 // * WM_PAINT messages
(...skipping 20 matching lines...) Expand all
242 if (state_->should_quit) 241 if (state_->should_quit)
243 break; 242 break;
244 243
245 more_work_is_plausible |= 244 more_work_is_plausible |=
246 state_->delegate->DoDelayedWork(&delayed_work_time_); 245 state_->delegate->DoDelayedWork(&delayed_work_time_);
247 // If we did not process any delayed work, then we can assume that our 246 // If we did not process any delayed work, then we can assume that our
248 // existing WM_TIMER if any will fire when delayed work should run. We 247 // existing WM_TIMER if any will fire when delayed work should run. We
249 // don't want to disturb that timer if it is already in flight. However, 248 // don't want to disturb that timer if it is already in flight. However,
250 // if we did do all remaining delayed work, then lets kill the WM_TIMER. 249 // if we did do all remaining delayed work, then lets kill the WM_TIMER.
251 if (more_work_is_plausible && delayed_work_time_.is_null()) 250 if (more_work_is_plausible && delayed_work_time_.is_null())
252 KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this)); 251 KillTimer(window_->hwnd(), reinterpret_cast<UINT_PTR>(this));
253 if (state_->should_quit) 252 if (state_->should_quit)
254 break; 253 break;
255 254
256 if (more_work_is_plausible) 255 if (more_work_is_plausible)
257 continue; 256 continue;
258 257
259 more_work_is_plausible = state_->delegate->DoIdleWork(); 258 more_work_is_plausible = state_->delegate->DoIdleWork();
260 if (state_->should_quit) 259 if (state_->should_quit)
261 break; 260 break;
262 261
263 if (more_work_is_plausible) 262 if (more_work_is_plausible)
264 continue; 263 continue;
265 264
266 WaitForWork(); // Wait (sleep) until we have work to do again. 265 WaitForWork(); // Wait (sleep) until we have work to do again.
267 } 266 }
268 } 267 }
269 268
270 void MessagePumpForUI::InitMessageWnd() {
271 WNDCLASSEX wc = {0};
272 wc.cbSize = sizeof(wc);
273 wc.lpfnWndProc = base::win::WrappedWindowProc<WndProcThunk>;
274 wc.hInstance = base::GetModuleFromAddress(wc.lpfnWndProc);
275 wc.lpszClassName = kWndClass;
darin (slow to review) 2013/05/22 22:53:24 wouldn't it be a simpler change to just give each
alexeypa (please no reviews) 2013/05/22 23:04:48 This is pretty much what this CL does. It is just
276 instance_ = wc.hInstance;
277 RegisterClassEx(&wc);
278
279 message_hwnd_ =
280 CreateWindow(kWndClass, 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, instance_, 0);
281 DCHECK(message_hwnd_);
282 }
283
284 void MessagePumpForUI::WaitForWork() { 269 void MessagePumpForUI::WaitForWork() {
285 // Wait until a message is available, up to the time needed by the timer 270 // Wait until a message is available, up to the time needed by the timer
286 // manager to fire the next set of timers. 271 // manager to fire the next set of timers.
287 int delay = GetCurrentDelay(); 272 int delay = GetCurrentDelay();
288 if (delay < 0) // Negative value means no timers waiting. 273 if (delay < 0) // Negative value means no timers waiting.
289 delay = INFINITE; 274 delay = INFINITE;
290 275
291 DWORD result; 276 DWORD result;
292 result = MsgWaitForMultipleObjectsEx(0, NULL, delay, QS_ALLINPUT, 277 result = MsgWaitForMultipleObjectsEx(0, NULL, delay, QS_ALLINPUT,
293 MWMO_INPUTAVAILABLE); 278 MWMO_INPUTAVAILABLE);
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
331 // messages that may be in the Windows message queue. 316 // messages that may be in the Windows message queue.
332 ProcessPumpReplacementMessage(); 317 ProcessPumpReplacementMessage();
333 318
334 // Now give the delegate a chance to do some work. He'll let us know if he 319 // Now give the delegate a chance to do some work. He'll let us know if he
335 // needs to do more work. 320 // needs to do more work.
336 if (state_->delegate->DoWork()) 321 if (state_->delegate->DoWork())
337 ScheduleWork(); 322 ScheduleWork();
338 } 323 }
339 324
340 void MessagePumpForUI::HandleTimerMessage() { 325 void MessagePumpForUI::HandleTimerMessage() {
341 KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this)); 326 KillTimer(window_->hwnd(), reinterpret_cast<UINT_PTR>(this));
342 327
343 // If we are being called outside of the context of Run, then don't do 328 // If we are being called outside of the context of Run, then don't do
344 // anything. This could correspond to a MessageBox call or something of 329 // anything. This could correspond to a MessageBox call or something of
345 // that sort. 330 // that sort.
346 if (!state_) 331 if (!state_)
347 return; 332 return;
348 333
349 state_->delegate->DoDelayedWork(&delayed_work_time_); 334 state_->delegate->DoDelayedWork(&delayed_work_time_);
350 if (!delayed_work_time_.is_null()) { 335 if (!delayed_work_time_.is_null()) {
351 // A bit gratuitous to set delayed_work_time_ again, but oh well. 336 // A bit gratuitous to set delayed_work_time_ again, but oh well.
(...skipping 23 matching lines...) Expand all
375 "message", msg.message); 360 "message", msg.message);
376 if (WM_QUIT == msg.message) { 361 if (WM_QUIT == msg.message) {
377 // Repost the QUIT message so that it will be retrieved by the primary 362 // Repost the QUIT message so that it will be retrieved by the primary
378 // GetMessage() loop. 363 // GetMessage() loop.
379 state_->should_quit = true; 364 state_->should_quit = true;
380 PostQuitMessage(static_cast<int>(msg.wParam)); 365 PostQuitMessage(static_cast<int>(msg.wParam));
381 return false; 366 return false;
382 } 367 }
383 368
384 // While running our main message pump, we discard kMsgHaveWork messages. 369 // While running our main message pump, we discard kMsgHaveWork messages.
385 if (msg.message == kMsgHaveWork && msg.hwnd == message_hwnd_) 370 if (msg.message == kMsgHaveWork && msg.hwnd == window_->hwnd())
386 return ProcessPumpReplacementMessage(); 371 return ProcessPumpReplacementMessage();
387 372
388 if (CallMsgFilter(const_cast<MSG*>(&msg), kMessageFilterCode)) 373 if (CallMsgFilter(const_cast<MSG*>(&msg), kMessageFilterCode))
389 return true; 374 return true;
390 375
391 WillProcessMessage(msg); 376 WillProcessMessage(msg);
392 377
393 if (!message_filter_->ProcessMessage(msg)) { 378 if (!message_filter_->ProcessMessage(msg)) {
394 if (state_->dispatcher) { 379 if (state_->dispatcher) {
395 if (!state_->dispatcher->Dispatch(msg)) 380 if (!state_->dispatcher->Dispatch(msg))
(...skipping 26 matching lines...) Expand all
422 if (MessageLoop::current()->os_modal_loop()) { 407 if (MessageLoop::current()->os_modal_loop()) {
423 // We only peek out WM_PAINT and WM_TIMER here for reasons mentioned above. 408 // We only peek out WM_PAINT and WM_TIMER here for reasons mentioned above.
424 have_message = PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE) || 409 have_message = PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE) ||
425 PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE); 410 PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE);
426 } else { 411 } else {
427 have_message = !!message_filter_->DoPeekMessage(&msg, NULL, 0, 0, 412 have_message = !!message_filter_->DoPeekMessage(&msg, NULL, 0, 0,
428 PM_REMOVE); 413 PM_REMOVE);
429 } 414 }
430 415
431 DCHECK(!have_message || kMsgHaveWork != msg.message || 416 DCHECK(!have_message || kMsgHaveWork != msg.message ||
432 msg.hwnd != message_hwnd_); 417 msg.hwnd != window_->hwnd());
433 418
434 // Since we discarded a kMsgHaveWork message, we must update the flag. 419 // Since we discarded a kMsgHaveWork message, we must update the flag.
435 int old_have_work = InterlockedExchange(&have_work_, 0); 420 int old_have_work = InterlockedExchange(&have_work_, 0);
436 DCHECK(old_have_work); 421 DCHECK(old_have_work);
437 422
438 // We don't need a special time slice if we didn't have_message to process. 423 // We don't need a special time slice if we didn't have_message to process.
439 if (!have_message) 424 if (!have_message)
440 return false; 425 return false;
441 426
442 // Guarantee we'll get another time slice in the case where we go into native 427 // Guarantee we'll get another time slice in the case where we go into native
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after
671 656
672 // static 657 // static
673 MessagePumpForIO::IOHandler* MessagePumpForIO::KeyToHandler( 658 MessagePumpForIO::IOHandler* MessagePumpForIO::KeyToHandler(
674 ULONG_PTR key, 659 ULONG_PTR key,
675 bool* has_valid_io_context) { 660 bool* has_valid_io_context) {
676 *has_valid_io_context = ((key & 1) == 0); 661 *has_valid_io_context = ((key & 1) == 0);
677 return reinterpret_cast<IOHandler*>(key & ~static_cast<ULONG_PTR>(1)); 662 return reinterpret_cast<IOHandler*>(key & ~static_cast<ULONG_PTR>(1));
678 } 663 }
679 664
680 } // namespace base 665 } // namespace base
OLDNEW
« no previous file with comments | « base/message_pump_win.h ('k') | base/win/message_window.h » ('j') | base/win/message_window.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698