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

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: rebased 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
« no previous file with comments | « base/message_pump_win.h ('k') | base/win/message_window.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/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
30 // Used by MessagePumpUI to wake up the thread and check any pending timers.
31 static const int kTimerId = 1;
32
34 //----------------------------------------------------------------------------- 33 //-----------------------------------------------------------------------------
35 // MessagePumpWin public: 34 // MessagePumpWin public:
36 35
37 void MessagePumpWin::AddObserver(MessagePumpObserver* observer) { 36 void MessagePumpWin::AddObserver(MessagePumpObserver* observer) {
38 observers_.AddObserver(observer); 37 observers_.AddObserver(observer);
39 } 38 }
40 39
41 void MessagePumpWin::RemoveObserver(MessagePumpObserver* observer) { 40 void MessagePumpWin::RemoveObserver(MessagePumpObserver* observer) {
42 observers_.RemoveObserver(observer); 41 observers_.RemoveObserver(observer);
43 } 42 }
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
89 if (delay < 0) 88 if (delay < 0)
90 delay = 0; 89 delay = 0;
91 90
92 return delay; 91 return delay;
93 } 92 }
94 93
95 //----------------------------------------------------------------------------- 94 //-----------------------------------------------------------------------------
96 // MessagePumpForUI public: 95 // MessagePumpForUI public:
97 96
98 MessagePumpForUI::MessagePumpForUI() 97 MessagePumpForUI::MessagePumpForUI()
99 : instance_(NULL), 98 : message_filter_(new MessageFilter),
100 message_filter_(new MessageFilter) { 99 window_(new win::MessageWindow()) {
101 InitMessageWnd(); 100 CHECK(window_->Create(this));
102 } 101 }
103 102
104 MessagePumpForUI::~MessagePumpForUI() { 103 MessagePumpForUI::~MessagePumpForUI() {
105 DestroyWindow(message_hwnd_);
106 UnregisterClass(kWndClass, instance_);
107 } 104 }
108 105
109 void MessagePumpForUI::ScheduleWork() { 106 void MessagePumpForUI::ScheduleWork() {
110 if (InterlockedExchange(&have_work_, 1)) 107 if (InterlockedExchange(&have_work_, 1))
111 return; // Someone else continued the pumping. 108 return; // Someone else continued the pumping.
112 109
113 // Make sure the MessagePump does some work for us. 110 // Make sure the MessagePump does some work for us.
114 BOOL ret = PostMessage(message_hwnd_, kMsgHaveWork, 111 BOOL ret = PostMessage(window_->hwnd(), kMsgHaveWork, 0, 0);
115 reinterpret_cast<WPARAM>(this), 0);
116 if (ret) 112 if (ret)
117 return; // There was room in the Window Message queue. 113 return; // There was room in the Window Message queue.
118 114
119 // We have failed to insert a have-work message, so there is a chance that we 115 // 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 116 // 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 117 // 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. :-( 118 // 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 119 // 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 120 // 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 121 // recovery. Nested loops are pretty transient (we think), so this will
(...skipping 26 matching lines...) Expand all
152 // 148 //
153 delayed_work_time_ = delayed_work_time; 149 delayed_work_time_ = delayed_work_time;
154 150
155 int delay_msec = GetCurrentDelay(); 151 int delay_msec = GetCurrentDelay();
156 DCHECK_GE(delay_msec, 0); 152 DCHECK_GE(delay_msec, 0);
157 if (delay_msec < USER_TIMER_MINIMUM) 153 if (delay_msec < USER_TIMER_MINIMUM)
158 delay_msec = USER_TIMER_MINIMUM; 154 delay_msec = USER_TIMER_MINIMUM;
159 155
160 // Create a WM_TIMER event that will wake us up to check for any pending 156 // 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). 157 // timers (in case we are running within a nested, external sub-pump).
162 BOOL ret = SetTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this), 158 BOOL ret = SetTimer(window_->hwnd(), kTimerId, delay_msec, NULL);
163 delay_msec, NULL);
164 if (ret) 159 if (ret)
165 return; 160 return;
166 // If we can't set timers, we are in big trouble... but cross our fingers for 161 // If we can't set timers, we are in big trouble... but cross our fingers for
167 // now. 162 // now.
168 // TODO(jar): If we don't see this error, use a CHECK() here instead. 163 // TODO(jar): If we don't see this error, use a CHECK() here instead.
169 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", SET_TIMER_ERROR, 164 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", SET_TIMER_ERROR,
170 MESSAGE_LOOP_PROBLEM_MAX); 165 MESSAGE_LOOP_PROBLEM_MAX);
171 } 166 }
172 167
173 void MessagePumpForUI::PumpOutPendingPaintMessages() { 168 void MessagePumpForUI::PumpOutPendingPaintMessages() {
(...skipping 16 matching lines...) Expand all
190 if (state_->should_quit) // Handle WM_QUIT. 185 if (state_->should_quit) // Handle WM_QUIT.
191 break; 186 break;
192 } 187 }
193 // Histogram what was really being used, to help to adjust kMaxPeekCount. 188 // Histogram what was really being used, to help to adjust kMaxPeekCount.
194 DHISTOGRAM_COUNTS("Loop.PumpOutPendingPaintMessages Peeks", peek_count); 189 DHISTOGRAM_COUNTS("Loop.PumpOutPendingPaintMessages Peeks", peek_count);
195 } 190 }
196 191
197 //----------------------------------------------------------------------------- 192 //-----------------------------------------------------------------------------
198 // MessagePumpForUI private: 193 // MessagePumpForUI private:
199 194
200 // static 195 bool MessagePumpForUI::HandleMessage(HWND hwnd,
201 LRESULT CALLBACK MessagePumpForUI::WndProcThunk( 196 UINT message,
202 HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { 197 WPARAM wparam,
198 LPARAM lparam,
199 LRESULT* result) {
203 switch (message) { 200 switch (message) {
204 case kMsgHaveWork: 201 case kMsgHaveWork:
205 reinterpret_cast<MessagePumpForUI*>(wparam)->HandleWorkMessage(); 202 HandleWorkMessage();
206 break; 203 break;
204
207 case WM_TIMER: 205 case WM_TIMER:
208 reinterpret_cast<MessagePumpForUI*>(wparam)->HandleTimerMessage(); 206 HandleTimerMessage();
209 break; 207 break;
210 } 208 }
211 return DefWindowProc(hwnd, message, wparam, lparam); 209
210 // Do default processing for all messages.
211 return false;
212 } 212 }
213 213
214 void MessagePumpForUI::DoRunLoop() { 214 void MessagePumpForUI::DoRunLoop() {
215 // IF this was just a simple PeekMessage() loop (servicing all possible work 215 // IF this was just a simple PeekMessage() loop (servicing all possible work
216 // queues), then Windows would try to achieve the following order according 216 // queues), then Windows would try to achieve the following order according
217 // to MSDN documentation about PeekMessage with no filter): 217 // to MSDN documentation about PeekMessage with no filter):
218 // * Sent messages 218 // * Sent messages
219 // * Posted messages 219 // * Posted messages
220 // * Sent messages (again) 220 // * Sent messages (again)
221 // * WM_PAINT messages 221 // * WM_PAINT messages
(...skipping 20 matching lines...) Expand all
242 if (state_->should_quit) 242 if (state_->should_quit)
243 break; 243 break;
244 244
245 more_work_is_plausible |= 245 more_work_is_plausible |=
246 state_->delegate->DoDelayedWork(&delayed_work_time_); 246 state_->delegate->DoDelayedWork(&delayed_work_time_);
247 // If we did not process any delayed work, then we can assume that our 247 // 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 248 // 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, 249 // 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. 250 // 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()) 251 if (more_work_is_plausible && delayed_work_time_.is_null())
252 KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this)); 252 KillTimer(window_->hwnd(), kTimerId);
253 if (state_->should_quit) 253 if (state_->should_quit)
254 break; 254 break;
255 255
256 if (more_work_is_plausible) 256 if (more_work_is_plausible)
257 continue; 257 continue;
258 258
259 more_work_is_plausible = state_->delegate->DoIdleWork(); 259 more_work_is_plausible = state_->delegate->DoIdleWork();
260 if (state_->should_quit) 260 if (state_->should_quit)
261 break; 261 break;
262 262
263 if (more_work_is_plausible) 263 if (more_work_is_plausible)
264 continue; 264 continue;
265 265
266 WaitForWork(); // Wait (sleep) until we have work to do again. 266 WaitForWork(); // Wait (sleep) until we have work to do again.
267 } 267 }
268 } 268 }
269 269
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;
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() { 270 void MessagePumpForUI::WaitForWork() {
285 // Wait until a message is available, up to the time needed by the timer 271 // Wait until a message is available, up to the time needed by the timer
286 // manager to fire the next set of timers. 272 // manager to fire the next set of timers.
287 int delay = GetCurrentDelay(); 273 int delay = GetCurrentDelay();
288 if (delay < 0) // Negative value means no timers waiting. 274 if (delay < 0) // Negative value means no timers waiting.
289 delay = INFINITE; 275 delay = INFINITE;
290 276
291 DWORD result; 277 DWORD result;
292 result = MsgWaitForMultipleObjectsEx(0, NULL, delay, QS_ALLINPUT, 278 result = MsgWaitForMultipleObjectsEx(0, NULL, delay, QS_ALLINPUT,
293 MWMO_INPUTAVAILABLE); 279 MWMO_INPUTAVAILABLE);
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
331 // messages that may be in the Windows message queue. 317 // messages that may be in the Windows message queue.
332 ProcessPumpReplacementMessage(); 318 ProcessPumpReplacementMessage();
333 319
334 // Now give the delegate a chance to do some work. He'll let us know if he 320 // Now give the delegate a chance to do some work. He'll let us know if he
335 // needs to do more work. 321 // needs to do more work.
336 if (state_->delegate->DoWork()) 322 if (state_->delegate->DoWork())
337 ScheduleWork(); 323 ScheduleWork();
338 } 324 }
339 325
340 void MessagePumpForUI::HandleTimerMessage() { 326 void MessagePumpForUI::HandleTimerMessage() {
341 KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this)); 327 KillTimer(window_->hwnd(), kTimerId);
342 328
343 // If we are being called outside of the context of Run, then don't do 329 // 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 330 // anything. This could correspond to a MessageBox call or something of
345 // that sort. 331 // that sort.
346 if (!state_) 332 if (!state_)
347 return; 333 return;
348 334
349 state_->delegate->DoDelayedWork(&delayed_work_time_); 335 state_->delegate->DoDelayedWork(&delayed_work_time_);
350 if (!delayed_work_time_.is_null()) { 336 if (!delayed_work_time_.is_null()) {
351 // A bit gratuitous to set delayed_work_time_ again, but oh well. 337 // A bit gratuitous to set delayed_work_time_ again, but oh well.
(...skipping 23 matching lines...) Expand all
375 "message", msg.message); 361 "message", msg.message);
376 if (WM_QUIT == msg.message) { 362 if (WM_QUIT == msg.message) {
377 // Repost the QUIT message so that it will be retrieved by the primary 363 // Repost the QUIT message so that it will be retrieved by the primary
378 // GetMessage() loop. 364 // GetMessage() loop.
379 state_->should_quit = true; 365 state_->should_quit = true;
380 PostQuitMessage(static_cast<int>(msg.wParam)); 366 PostQuitMessage(static_cast<int>(msg.wParam));
381 return false; 367 return false;
382 } 368 }
383 369
384 // While running our main message pump, we discard kMsgHaveWork messages. 370 // While running our main message pump, we discard kMsgHaveWork messages.
385 if (msg.message == kMsgHaveWork && msg.hwnd == message_hwnd_) 371 if (msg.message == kMsgHaveWork && msg.hwnd == window_->hwnd())
386 return ProcessPumpReplacementMessage(); 372 return ProcessPumpReplacementMessage();
387 373
388 if (CallMsgFilter(const_cast<MSG*>(&msg), kMessageFilterCode)) 374 if (CallMsgFilter(const_cast<MSG*>(&msg), kMessageFilterCode))
389 return true; 375 return true;
390 376
391 WillProcessMessage(msg); 377 WillProcessMessage(msg);
392 378
393 if (!message_filter_->ProcessMessage(msg)) { 379 if (!message_filter_->ProcessMessage(msg)) {
394 if (state_->dispatcher) { 380 if (state_->dispatcher) {
395 if (!state_->dispatcher->Dispatch(msg)) 381 if (!state_->dispatcher->Dispatch(msg))
(...skipping 26 matching lines...) Expand all
422 if (MessageLoop::current()->os_modal_loop()) { 408 if (MessageLoop::current()->os_modal_loop()) {
423 // We only peek out WM_PAINT and WM_TIMER here for reasons mentioned above. 409 // 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) || 410 have_message = PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE) ||
425 PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE); 411 PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE);
426 } else { 412 } else {
427 have_message = !!message_filter_->DoPeekMessage(&msg, NULL, 0, 0, 413 have_message = !!message_filter_->DoPeekMessage(&msg, NULL, 0, 0,
428 PM_REMOVE); 414 PM_REMOVE);
429 } 415 }
430 416
431 DCHECK(!have_message || kMsgHaveWork != msg.message || 417 DCHECK(!have_message || kMsgHaveWork != msg.message ||
432 msg.hwnd != message_hwnd_); 418 msg.hwnd != window_->hwnd());
433 419
434 // Since we discarded a kMsgHaveWork message, we must update the flag. 420 // Since we discarded a kMsgHaveWork message, we must update the flag.
435 int old_have_work = InterlockedExchange(&have_work_, 0); 421 int old_have_work = InterlockedExchange(&have_work_, 0);
436 DCHECK(old_have_work); 422 DCHECK(old_have_work);
437 423
438 // We don't need a special time slice if we didn't have_message to process. 424 // We don't need a special time slice if we didn't have_message to process.
439 if (!have_message) 425 if (!have_message)
440 return false; 426 return false;
441 427
442 // Guarantee we'll get another time slice in the case where we go into native 428 // 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 657
672 // static 658 // static
673 MessagePumpForIO::IOHandler* MessagePumpForIO::KeyToHandler( 659 MessagePumpForIO::IOHandler* MessagePumpForIO::KeyToHandler(
674 ULONG_PTR key, 660 ULONG_PTR key,
675 bool* has_valid_io_context) { 661 bool* has_valid_io_context) {
676 *has_valid_io_context = ((key & 1) == 0); 662 *has_valid_io_context = ((key & 1) == 0);
677 return reinterpret_cast<IOHandler*>(key & ~static_cast<ULONG_PTR>(1)); 663 return reinterpret_cast<IOHandler*>(key & ~static_cast<ULONG_PTR>(1));
678 } 664 }
679 665
680 } // namespace base 666 } // namespace base
OLDNEW
« no previous file with comments | « base/message_pump_win.h ('k') | base/win/message_window.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698