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

Side by Side Diff: trunk/src/base/message_pump_win.cc

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

Powered by Google App Engine
This is Rietveld 408576698