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

Side by Side Diff: base/message_loop/message_pump_win.cc

Issue 2488843002: Switch MessagePumpWin to use base::win::MessageWindow (Closed)
Patch Set: NULL -> 0 Created 4 years, 1 month 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
« no previous file with comments | « base/message_loop/message_pump_win.h ('k') | no next file » | 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_loop/message_pump_win.h" 5 #include "base/message_loop/message_pump_win.h"
6 6
7 #include <math.h> 7 #include <math.h>
8 #include <stdint.h> 8 #include <stdint.h>
9 9
10 #include <limits> 10 #include <limits>
(...skipping 13 matching lines...) Expand all
24 enum MessageLoopProblems { 24 enum MessageLoopProblems {
25 MESSAGE_POST_ERROR, 25 MESSAGE_POST_ERROR,
26 COMPLETION_POST_ERROR, 26 COMPLETION_POST_ERROR,
27 SET_TIMER_ERROR, 27 SET_TIMER_ERROR,
28 RECEIVED_WM_QUIT_ERROR, 28 RECEIVED_WM_QUIT_ERROR,
29 MESSAGE_LOOP_PROBLEM_MAX, 29 MESSAGE_LOOP_PROBLEM_MAX,
30 }; 30 };
31 31
32 } // namespace 32 } // namespace
33 33
34 static const wchar_t kWndClassFormat[] = L"Chrome_MessagePumpWindow_%p";
35
36 // Message sent to get an additional time slice for pumping (processing) another 34 // Message sent to get an additional time slice for pumping (processing) another
37 // task (a series of such messages creates a continuous task pump). 35 // task (a series of such messages creates a continuous task pump).
38 static const int kMsgHaveWork = WM_USER + 1; 36 static const int kMsgHaveWork = WM_USER + 1;
39 37
40 // The application-defined code passed to the hook procedure. 38 // The application-defined code passed to the hook procedure.
41 static const int kMessageFilterCode = 0x5001; 39 static const int kMessageFilterCode = 0x5001;
42 40
43 //----------------------------------------------------------------------------- 41 //-----------------------------------------------------------------------------
44 // MessagePumpWin public: 42 // MessagePumpWin public:
45 43
46 MessagePumpWin::MessagePumpWin() { 44 MessagePumpWin::MessagePumpWin() = default;
47 }
48 45
49 void MessagePumpWin::Run(Delegate* delegate) { 46 void MessagePumpWin::Run(Delegate* delegate) {
50 RunState s; 47 RunState s;
51 s.delegate = delegate; 48 s.delegate = delegate;
52 s.should_quit = false; 49 s.should_quit = false;
53 s.run_depth = state_ ? state_->run_depth + 1 : 1; 50 s.run_depth = state_ ? state_->run_depth + 1 : 1;
54 51
55 // TODO(stanisc): crbug.com/596190: Remove this code once the bug is fixed. 52 // TODO(stanisc): crbug.com/596190: Remove this code once the bug is fixed.
56 s.schedule_work_error_count = 0; 53 s.schedule_work_error_count = 0;
57 s.last_schedule_work_error_time = Time(); 54 s.last_schedule_work_error_time = Time();
(...skipping 29 matching lines...) Expand all
87 // "overflowingly" large, that means a delayed task was posted with a 84 // "overflowingly" large, that means a delayed task was posted with a
88 // super-long delay. 85 // super-long delay.
89 return timeout < 0 ? 0 : 86 return timeout < 0 ? 0 :
90 (timeout > std::numeric_limits<int>::max() ? 87 (timeout > std::numeric_limits<int>::max() ?
91 std::numeric_limits<int>::max() : static_cast<int>(timeout)); 88 std::numeric_limits<int>::max() : static_cast<int>(timeout));
92 } 89 }
93 90
94 //----------------------------------------------------------------------------- 91 //-----------------------------------------------------------------------------
95 // MessagePumpForUI public: 92 // MessagePumpForUI public:
96 93
97 MessagePumpForUI::MessagePumpForUI() 94 MessagePumpForUI::MessagePumpForUI() {
98 : atom_(0) { 95 bool succeeded = message_window_.Create(
99 InitMessageWnd(); 96 Bind(&MessagePumpForUI::MessageCallback, Unretained(this)));
97 DCHECK(succeeded);
100 } 98 }
101 99
102 MessagePumpForUI::~MessagePumpForUI() { 100 MessagePumpForUI::~MessagePumpForUI() = default;
103 DestroyWindow(message_hwnd_);
104 UnregisterClass(MAKEINTATOM(atom_), CURRENT_MODULE());
105 }
106 101
107 void MessagePumpForUI::ScheduleWork() { 102 void MessagePumpForUI::ScheduleWork() {
108 if (InterlockedExchange(&work_state_, HAVE_WORK) != READY) 103 if (InterlockedExchange(&work_state_, HAVE_WORK) != READY)
109 return; // Someone else continued the pumping. 104 return; // Someone else continued the pumping.
110 105
111 // Make sure the MessagePump does some work for us. 106 // Make sure the MessagePump does some work for us.
112 BOOL ret = PostMessage(message_hwnd_, kMsgHaveWork, 107 BOOL ret = PostMessage(message_window_.hwnd(), kMsgHaveWork, 0, 0);
113 reinterpret_cast<WPARAM>(this), 0);
114 if (ret) 108 if (ret)
115 return; // There was room in the Window Message queue. 109 return; // There was room in the Window Message queue.
116 110
117 // We have failed to insert a have-work message, so there is a chance that we 111 // We have failed to insert a have-work message, so there is a chance that we
118 // will starve tasks/timers while sitting in a nested message loop. Nested 112 // will starve tasks/timers while sitting in a nested message loop. Nested
119 // loops only look at Windows Message queues, and don't look at *our* task 113 // loops only look at Windows Message queues, and don't look at *our* task
120 // queues, etc., so we might not get a time slice in such. :-( 114 // queues, etc., so we might not get a time slice in such. :-(
121 // We could abort here, but the fear is that this failure mode is plausibly 115 // We could abort here, but the fear is that this failure mode is plausibly
122 // common (queue is full, of about 2000 messages), so we'll do a near-graceful 116 // common (queue is full, of about 2000 messages), so we'll do a near-graceful
123 // recovery. Nested loops are pretty transient (we think), so this will 117 // recovery. Nested loops are pretty transient (we think), so this will
124 // probably be recoverable. 118 // probably be recoverable.
125 119
126 // Clarify that we didn't really insert. 120 // Clarify that we didn't really insert.
127 InterlockedExchange(&work_state_, READY); 121 InterlockedExchange(&work_state_, READY);
128 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", MESSAGE_POST_ERROR, 122 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", MESSAGE_POST_ERROR,
129 MESSAGE_LOOP_PROBLEM_MAX); 123 MESSAGE_LOOP_PROBLEM_MAX);
130 state_->schedule_work_error_count++; 124 state_->schedule_work_error_count++;
131 state_->last_schedule_work_error_time = Time::Now(); 125 state_->last_schedule_work_error_time = Time::Now();
132 } 126 }
133 127
134 void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { 128 void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
135 delayed_work_time_ = delayed_work_time; 129 delayed_work_time_ = delayed_work_time;
136 RescheduleTimer(); 130 RescheduleTimer();
137 } 131 }
138 132
139 //----------------------------------------------------------------------------- 133 //-----------------------------------------------------------------------------
140 // MessagePumpForUI private: 134 // MessagePumpForUI private:
141 135
142 // static 136 bool MessagePumpForUI::MessageCallback(
143 LRESULT CALLBACK MessagePumpForUI::WndProcThunk( 137 UINT message, WPARAM wparam, LPARAM lparam, LRESULT* result) {
144 HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) {
145 switch (message) { 138 switch (message) {
146 case kMsgHaveWork: 139 case kMsgHaveWork:
147 reinterpret_cast<MessagePumpForUI*>(wparam)->HandleWorkMessage(); 140 HandleWorkMessage();
148 break; 141 break;
149 case WM_TIMER: 142 case WM_TIMER:
150 reinterpret_cast<MessagePumpForUI*>(wparam)->HandleTimerMessage(); 143 HandleTimerMessage();
151 break; 144 break;
152 } 145 }
153 return DefWindowProc(hwnd, message, wparam, lparam); 146 return false;
154 } 147 }
155 148
156 void MessagePumpForUI::DoRunLoop() { 149 void MessagePumpForUI::DoRunLoop() {
157 // IF this was just a simple PeekMessage() loop (servicing all possible work 150 // IF this was just a simple PeekMessage() loop (servicing all possible work
158 // queues), then Windows would try to achieve the following order according 151 // queues), then Windows would try to achieve the following order according
159 // to MSDN documentation about PeekMessage with no filter): 152 // to MSDN documentation about PeekMessage with no filter):
160 // * Sent messages 153 // * Sent messages
161 // * Posted messages 154 // * Posted messages
162 // * Sent messages (again) 155 // * Sent messages (again)
163 // * WM_PAINT messages 156 // * WM_PAINT messages
(...skipping 20 matching lines...) Expand all
184 if (state_->should_quit) 177 if (state_->should_quit)
185 break; 178 break;
186 179
187 more_work_is_plausible |= 180 more_work_is_plausible |=
188 state_->delegate->DoDelayedWork(&delayed_work_time_); 181 state_->delegate->DoDelayedWork(&delayed_work_time_);
189 // If we did not process any delayed work, then we can assume that our 182 // If we did not process any delayed work, then we can assume that our
190 // existing WM_TIMER if any will fire when delayed work should run. We 183 // existing WM_TIMER if any will fire when delayed work should run. We
191 // don't want to disturb that timer if it is already in flight. However, 184 // don't want to disturb that timer if it is already in flight. However,
192 // if we did do all remaining delayed work, then lets kill the WM_TIMER. 185 // if we did do all remaining delayed work, then lets kill the WM_TIMER.
193 if (more_work_is_plausible && delayed_work_time_.is_null()) 186 if (more_work_is_plausible && delayed_work_time_.is_null())
194 KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this)); 187 KillTimer(message_window_.hwnd(), reinterpret_cast<UINT_PTR>(this));
195 if (state_->should_quit) 188 if (state_->should_quit)
196 break; 189 break;
197 190
198 if (more_work_is_plausible) 191 if (more_work_is_plausible)
199 continue; 192 continue;
200 193
201 more_work_is_plausible = state_->delegate->DoIdleWork(); 194 more_work_is_plausible = state_->delegate->DoIdleWork();
202 if (state_->should_quit) 195 if (state_->should_quit)
203 break; 196 break;
204 197
205 if (more_work_is_plausible) 198 if (more_work_is_plausible)
206 continue; 199 continue;
207 200
208 WaitForWork(); // Wait (sleep) until we have work to do again. 201 WaitForWork(); // Wait (sleep) until we have work to do again.
209 } 202 }
210 } 203 }
211 204
212 void MessagePumpForUI::InitMessageWnd() {
213 // Generate a unique window class name.
214 string16 class_name = StringPrintf(kWndClassFormat, this);
215
216 HINSTANCE instance = CURRENT_MODULE();
217 WNDCLASSEX wc = {0};
218 wc.cbSize = sizeof(wc);
219 wc.lpfnWndProc = base::win::WrappedWindowProc<WndProcThunk>;
220 wc.hInstance = instance;
221 wc.lpszClassName = class_name.c_str();
222 atom_ = RegisterClassEx(&wc);
223 DCHECK(atom_);
224
225 message_hwnd_ = CreateWindowEx(0, MAKEINTATOM(atom_), 0, 0, 0, 0, 0, 0,
226 HWND_MESSAGE, 0, instance, 0);
227 DCHECK(message_hwnd_);
228 }
229
230 void MessagePumpForUI::WaitForWork() { 205 void MessagePumpForUI::WaitForWork() {
231 // Wait until a message is available, up to the time needed by the timer 206 // Wait until a message is available, up to the time needed by the timer
232 // manager to fire the next set of timers. 207 // manager to fire the next set of timers.
233 int delay; 208 int delay;
234 DWORD wait_flags = MWMO_INPUTAVAILABLE; 209 DWORD wait_flags = MWMO_INPUTAVAILABLE;
235 210
236 while ((delay = GetCurrentDelay()) != 0) { 211 while ((delay = GetCurrentDelay()) != 0) {
237 if (delay < 0) // Negative value means no timers waiting. 212 if (delay < 0) // Negative value means no timers waiting.
238 delay = INFINITE; 213 delay = INFINITE;
239 214
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
289 264
290 // Now give the delegate a chance to do some work. It'll let us know if it 265 // Now give the delegate a chance to do some work. It'll let us know if it
291 // needs to do more work. 266 // needs to do more work.
292 if (state_->delegate->DoWork()) 267 if (state_->delegate->DoWork())
293 ScheduleWork(); 268 ScheduleWork();
294 state_->delegate->DoDelayedWork(&delayed_work_time_); 269 state_->delegate->DoDelayedWork(&delayed_work_time_);
295 RescheduleTimer(); 270 RescheduleTimer();
296 } 271 }
297 272
298 void MessagePumpForUI::HandleTimerMessage() { 273 void MessagePumpForUI::HandleTimerMessage() {
299 KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this)); 274 KillTimer(message_window_.hwnd(), reinterpret_cast<UINT_PTR>(this));
300 275
301 // If we are being called outside of the context of Run, then don't do 276 // If we are being called outside of the context of Run, then don't do
302 // anything. This could correspond to a MessageBox call or something of 277 // anything. This could correspond to a MessageBox call or something of
303 // that sort. 278 // that sort.
304 if (!state_) 279 if (!state_)
305 return; 280 return;
306 281
307 state_->delegate->DoDelayedWork(&delayed_work_time_); 282 state_->delegate->DoDelayedWork(&delayed_work_time_);
308 RescheduleTimer(); 283 RescheduleTimer();
309 } 284 }
(...skipping 24 matching lines...) Expand all
334 int delay_msec = GetCurrentDelay(); 309 int delay_msec = GetCurrentDelay();
335 DCHECK_GE(delay_msec, 0); 310 DCHECK_GE(delay_msec, 0);
336 if (delay_msec == 0) { 311 if (delay_msec == 0) {
337 ScheduleWork(); 312 ScheduleWork();
338 } else { 313 } else {
339 if (delay_msec < USER_TIMER_MINIMUM) 314 if (delay_msec < USER_TIMER_MINIMUM)
340 delay_msec = USER_TIMER_MINIMUM; 315 delay_msec = USER_TIMER_MINIMUM;
341 316
342 // Create a WM_TIMER event that will wake us up to check for any pending 317 // Create a WM_TIMER event that will wake us up to check for any pending
343 // timers (in case we are running within a nested, external sub-pump). 318 // timers (in case we are running within a nested, external sub-pump).
344 BOOL ret = SetTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this), 319 BOOL ret = SetTimer(message_window_.hwnd(), 0, delay_msec, nullptr);
345 delay_msec, nullptr);
346 if (ret) 320 if (ret)
347 return; 321 return;
348 // If we can't set timers, we are in big trouble... but cross our fingers 322 // If we can't set timers, we are in big trouble... but cross our fingers
349 // for now. 323 // for now.
350 // TODO(jar): If we don't see this error, use a CHECK() here instead. 324 // TODO(jar): If we don't see this error, use a CHECK() here instead.
351 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", SET_TIMER_ERROR, 325 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", SET_TIMER_ERROR,
352 MESSAGE_LOOP_PROBLEM_MAX); 326 MESSAGE_LOOP_PROBLEM_MAX);
353 } 327 }
354 } 328 }
355 329
(...skipping 22 matching lines...) Expand all
378 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", 352 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem",
379 RECEIVED_WM_QUIT_ERROR, MESSAGE_LOOP_PROBLEM_MAX); 353 RECEIVED_WM_QUIT_ERROR, MESSAGE_LOOP_PROBLEM_MAX);
380 // Repost the QUIT message so that it will be retrieved by the primary 354 // Repost the QUIT message so that it will be retrieved by the primary
381 // GetMessage() loop. 355 // GetMessage() loop.
382 state_->should_quit = true; 356 state_->should_quit = true;
383 PostQuitMessage(static_cast<int>(msg.wParam)); 357 PostQuitMessage(static_cast<int>(msg.wParam));
384 return false; 358 return false;
385 } 359 }
386 360
387 // While running our main message pump, we discard kMsgHaveWork messages. 361 // While running our main message pump, we discard kMsgHaveWork messages.
388 if (msg.message == kMsgHaveWork && msg.hwnd == message_hwnd_) 362 if (msg.message == kMsgHaveWork && msg.hwnd == message_window_.hwnd())
389 return ProcessPumpReplacementMessage(); 363 return ProcessPumpReplacementMessage();
390 364
391 if (CallMsgFilter(const_cast<MSG*>(&msg), kMessageFilterCode)) 365 if (CallMsgFilter(const_cast<MSG*>(&msg), kMessageFilterCode))
392 return true; 366 return true;
393 367
394 TranslateMessage(&msg); 368 TranslateMessage(&msg);
395 DispatchMessage(&msg); 369 DispatchMessage(&msg);
396 370
397 return true; 371 return true;
398 } 372 }
399 373
400 bool MessagePumpForUI::ProcessPumpReplacementMessage() { 374 bool MessagePumpForUI::ProcessPumpReplacementMessage() {
401 // When we encounter a kMsgHaveWork message, this method is called to peek and 375 // When we encounter a kMsgHaveWork message, this method is called to peek and
402 // process a replacement message. The goal is to make the kMsgHaveWork as non- 376 // process a replacement message. The goal is to make the kMsgHaveWork as non-
403 // intrusive as possible, even though a continuous stream of such messages are 377 // intrusive as possible, even though a continuous stream of such messages are
404 // posted. This method carefully peeks a message while there is no chance for 378 // posted. This method carefully peeks a message while there is no chance for
405 // a kMsgHaveWork to be pending, then resets the |have_work_| flag (allowing a 379 // a kMsgHaveWork to be pending, then resets the |have_work_| flag (allowing a
406 // replacement kMsgHaveWork to possibly be posted), and finally dispatches 380 // replacement kMsgHaveWork to possibly be posted), and finally dispatches
407 // that peeked replacement. Note that the re-post of kMsgHaveWork may be 381 // that peeked replacement. Note that the re-post of kMsgHaveWork may be
408 // asynchronous to this thread!! 382 // asynchronous to this thread!!
409 383
410 MSG msg; 384 MSG msg;
411 const bool have_message = 385 const bool have_message =
412 PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE) != FALSE; 386 PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE) != FALSE;
413 387
414 // Expect no message or a message different than kMsgHaveWork. 388 // Expect no message or a message different than kMsgHaveWork.
415 DCHECK(!have_message || kMsgHaveWork != msg.message || 389 DCHECK(!have_message || kMsgHaveWork != msg.message ||
416 msg.hwnd != message_hwnd_); 390 msg.hwnd != message_window_.hwnd());
417 391
418 // Since we discarded a kMsgHaveWork message, we must update the flag. 392 // Since we discarded a kMsgHaveWork message, we must update the flag.
419 int old_work_state_ = InterlockedExchange(&work_state_, READY); 393 int old_work_state_ = InterlockedExchange(&work_state_, READY);
420 DCHECK_EQ(HAVE_WORK, old_work_state_); 394 DCHECK_EQ(HAVE_WORK, old_work_state_);
421 395
422 // We don't need a special time slice if we didn't have_message to process. 396 // We don't need a special time slice if we didn't have_message to process.
423 if (!have_message) 397 if (!have_message)
424 return false; 398 return false;
425 399
426 // Guarantee we'll get another time slice in the case where we go into native 400 // Guarantee we'll get another time slice in the case where we go into native
427 // windows code. This ScheduleWork() may hurt performance a tiny bit when 401 // windows code. This ScheduleWork() may hurt performance a tiny bit when
428 // tasks appear very infrequently, but when the event queue is busy, the 402 // tasks appear very infrequently, but when the event queue is busy, the
429 // kMsgHaveWork events get (percentage wise) rarer and rarer. 403 // kMsgHaveWork events get (percentage wise) rarer and rarer.
430 ScheduleWork(); 404 ScheduleWork();
431 return ProcessMessageHelper(msg); 405 return ProcessMessageHelper(msg);
432 } 406 }
433 407
434 //----------------------------------------------------------------------------- 408 //-----------------------------------------------------------------------------
435 // MessagePumpForGpu public: 409 // MessagePumpForGpu public:
436 410
437 MessagePumpForGpu::MessagePumpForGpu() { 411 MessagePumpForGpu::MessagePumpForGpu() {
438 event_.Set(CreateEvent(nullptr, FALSE, FALSE, nullptr)); 412 event_.Set(CreateEvent(nullptr, FALSE, FALSE, nullptr));
439 } 413 }
440 414
441 MessagePumpForGpu::~MessagePumpForGpu() {} 415 MessagePumpForGpu::~MessagePumpForGpu() = default;
442 416
443 // static 417 // static
444 void MessagePumpForGpu::InitFactory() { 418 void MessagePumpForGpu::InitFactory() {
445 bool init_result = MessageLoop::InitMessagePumpForUIFactory( 419 bool init_result = MessageLoop::InitMessagePumpForUIFactory(
446 &MessagePumpForGpu::CreateMessagePumpForGpu); 420 &MessagePumpForGpu::CreateMessagePumpForGpu);
447 DCHECK(init_result); 421 DCHECK(init_result);
448 } 422 }
449 423
450 // static 424 // static
451 std::unique_ptr<MessagePump> MessagePumpForGpu::CreateMessagePumpForGpu() { 425 std::unique_ptr<MessagePump> MessagePumpForGpu::CreateMessagePumpForGpu() {
(...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after
742 if (!filter || it->handler == filter) { 716 if (!filter || it->handler == filter) {
743 *item = *it; 717 *item = *it;
744 completed_io_.erase(it); 718 completed_io_.erase(it);
745 return true; 719 return true;
746 } 720 }
747 } 721 }
748 return false; 722 return false;
749 } 723 }
750 724
751 } // namespace base 725 } // namespace base
OLDNEW
« no previous file with comments | « base/message_loop/message_pump_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698