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

Side by Side Diff: base/message_pump_win.cc

Issue 16020005: Fixed the racy code around the message-only window in base::MessagePumpForUI on Windows. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
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 | « 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 BOOL result = FALSE;
114 BOOL ret = PostMessage(message_hwnd_, kMsgHaveWork, 111
115 reinterpret_cast<WPARAM>(this), 0); 112 {
116 if (ret) 113 // Take the lock to make sure the window will not be destroyed until
117 return; // There was room in the Window Message queue. 114 // PostMessage() returns below.
115 AutoLock lock(window_lock_);
darin (slow to review) 2013/05/25 21:23:17 Is it perhaps worth avoiding this lock when Schedu
alexeypa (please no reviews) 2013/05/29 18:11:52 Just an FYI. I wrote a test that posts tasks to t
116 if (window_) {
117 // Make sure the MessagePump does some work for us.
118 if (PostMessage(window_->hwnd(), kMsgHaveWork, 0, 0))
darin (slow to review) 2013/05/24 21:42:58 Perhaps MessageWindow should be reference counted
alexeypa (please no reviews) 2013/05/24 22:22:48 No, the problem is that DestroyWindow() should be
119 return;
120 }
121 }
118 122
119 // We have failed to insert a have-work message, so there is a chance that we 123 // 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 124 // 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 125 // 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. :-( 126 // 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 127 // 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 128 // 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 129 // recovery. Nested loops are pretty transient (we think), so this will
126 // probably be recoverable. 130 // probably be recoverable.
127 InterlockedExchange(&have_work_, 0); // Clarify that we didn't really insert. 131 InterlockedExchange(&have_work_, 0); // Clarify that we didn't really insert.
128 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", MESSAGE_POST_ERROR, 132 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", MESSAGE_POST_ERROR,
129 MESSAGE_LOOP_PROBLEM_MAX); 133 MESSAGE_LOOP_PROBLEM_MAX);
130 } 134 }
131 135
132 void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { 136 void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
137 DCHECK(window_->CalledOnValidThread());
138
133 // 139 //
134 // We would *like* to provide high resolution timers. Windows timers using 140 // We would *like* to provide high resolution timers. Windows timers using
135 // SetTimer() have a 10ms granularity. We have to use WM_TIMER as a wakeup 141 // SetTimer() have a 10ms granularity. We have to use WM_TIMER as a wakeup
136 // mechanism because the application can enter modal windows loops where it 142 // mechanism because the application can enter modal windows loops where it
137 // is not running our MessageLoop; the only way to have our timers fire in 143 // is not running our MessageLoop; the only way to have our timers fire in
138 // these cases is to post messages there. 144 // these cases is to post messages there.
139 // 145 //
140 // To provide sub-10ms timers, we process timers directly from our run loop. 146 // To provide sub-10ms timers, we process timers directly from our run loop.
141 // For the common case, timers will be processed there as the run loop does 147 // For the common case, timers will be processed there as the run loop does
142 // its normal work. However, we *also* set the system timer so that WM_TIMER 148 // its normal work. However, we *also* set the system timer so that WM_TIMER
143 // events fire. This mops up the case of timers not being able to work in 149 // events fire. This mops up the case of timers not being able to work in
144 // modal message loops. It is possible for the SetTimer to pop and have no 150 // modal message loops. It is possible for the SetTimer to pop and have no
145 // pending timers, because they could have already been processed by the 151 // pending timers, because they could have already been processed by the
146 // run loop itself. 152 // run loop itself.
147 // 153 //
148 // We use a single SetTimer corresponding to the timer that will expire 154 // We use a single SetTimer corresponding to the timer that will expire
149 // soonest. As new timers are created and destroyed, we update SetTimer. 155 // soonest. As new timers are created and destroyed, we update SetTimer.
150 // Getting a spurrious SetTimer event firing is benign, as we'll just be 156 // Getting a spurrious SetTimer event firing is benign, as we'll just be
151 // processing an empty timer queue. 157 // processing an empty timer queue.
152 // 158 //
153 delayed_work_time_ = delayed_work_time; 159 delayed_work_time_ = delayed_work_time;
154 160
155 int delay_msec = GetCurrentDelay(); 161 int delay_msec = GetCurrentDelay();
156 DCHECK_GE(delay_msec, 0); 162 DCHECK_GE(delay_msec, 0);
157 if (delay_msec < USER_TIMER_MINIMUM) 163 if (delay_msec < USER_TIMER_MINIMUM)
158 delay_msec = USER_TIMER_MINIMUM; 164 delay_msec = USER_TIMER_MINIMUM;
159 165
160 // Create a WM_TIMER event that will wake us up to check for any pending 166 // 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). 167 // timers (in case we are running within a nested, external sub-pump).
162 BOOL ret = SetTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this), 168 BOOL ret = SetTimer(window_->hwnd(), kTimerId, delay_msec, NULL);
163 delay_msec, NULL);
164 if (ret) 169 if (ret)
165 return; 170 return;
166 // If we can't set timers, we are in big trouble... but cross our fingers for 171 // If we can't set timers, we are in big trouble... but cross our fingers for
167 // now. 172 // now.
168 // TODO(jar): If we don't see this error, use a CHECK() here instead. 173 // TODO(jar): If we don't see this error, use a CHECK() here instead.
169 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", SET_TIMER_ERROR, 174 UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", SET_TIMER_ERROR,
170 MESSAGE_LOOP_PROBLEM_MAX); 175 MESSAGE_LOOP_PROBLEM_MAX);
171 } 176 }
172 177
178 void MessagePumpForUI::WillDestroyCurrentMessageLoop() {
179 DCHECK(window_->CalledOnValidThread());
180
181 // Synchronize with MessagePumpForUI::ScheduleWork() that can access |window_|
182 // on arbitrary thread.
183 AutoLock lock(window_lock_);
184 window_.reset();
185 }
186
173 void MessagePumpForUI::PumpOutPendingPaintMessages() { 187 void MessagePumpForUI::PumpOutPendingPaintMessages() {
174 // If we are being called outside of the context of Run, then don't try to do 188 // If we are being called outside of the context of Run, then don't try to do
175 // any work. 189 // any work.
176 if (!state_) 190 if (!state_)
177 return; 191 return;
178 192
179 // Create a mini-message-pump to force immediate processing of only Windows 193 // Create a mini-message-pump to force immediate processing of only Windows
180 // WM_PAINT messages. Don't provide an infinite loop, but do enough peeking 194 // WM_PAINT messages. Don't provide an infinite loop, but do enough peeking
181 // to get the job done. Actual common max is 4 peeks, but we'll be a little 195 // to get the job done. Actual common max is 4 peeks, but we'll be a little
182 // safe here. 196 // safe here.
183 const int kMaxPeekCount = 20; 197 const int kMaxPeekCount = 20;
184 int peek_count; 198 int peek_count;
185 for (peek_count = 0; peek_count < kMaxPeekCount; ++peek_count) { 199 for (peek_count = 0; peek_count < kMaxPeekCount; ++peek_count) {
186 MSG msg; 200 MSG msg;
187 if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE | PM_QS_PAINT)) 201 if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE | PM_QS_PAINT))
188 break; 202 break;
189 ProcessMessageHelper(msg); 203 ProcessMessageHelper(msg);
190 if (state_->should_quit) // Handle WM_QUIT. 204 if (state_->should_quit) // Handle WM_QUIT.
191 break; 205 break;
192 } 206 }
193 // Histogram what was really being used, to help to adjust kMaxPeekCount. 207 // Histogram what was really being used, to help to adjust kMaxPeekCount.
194 DHISTOGRAM_COUNTS("Loop.PumpOutPendingPaintMessages Peeks", peek_count); 208 DHISTOGRAM_COUNTS("Loop.PumpOutPendingPaintMessages Peeks", peek_count);
195 } 209 }
196 210
197 //----------------------------------------------------------------------------- 211 //-----------------------------------------------------------------------------
198 // MessagePumpForUI private: 212 // MessagePumpForUI private:
199 213
200 // static 214 bool MessagePumpForUI::HandleMessage(HWND hwnd,
201 LRESULT CALLBACK MessagePumpForUI::WndProcThunk( 215 UINT message,
202 HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { 216 WPARAM wparam,
217 LPARAM lparam,
218 LRESULT* result) {
203 switch (message) { 219 switch (message) {
204 case kMsgHaveWork: 220 case kMsgHaveWork:
205 reinterpret_cast<MessagePumpForUI*>(wparam)->HandleWorkMessage(); 221 HandleWorkMessage();
206 break; 222 break;
223
207 case WM_TIMER: 224 case WM_TIMER:
208 reinterpret_cast<MessagePumpForUI*>(wparam)->HandleTimerMessage(); 225 HandleTimerMessage();
209 break; 226 break;
210 } 227 }
211 return DefWindowProc(hwnd, message, wparam, lparam); 228
229 // Do default processing for all messages.
230 return false;
212 } 231 }
213 232
214 void MessagePumpForUI::DoRunLoop() { 233 void MessagePumpForUI::DoRunLoop() {
234 DCHECK(window_->CalledOnValidThread());
235
215 // IF this was just a simple PeekMessage() loop (servicing all possible work 236 // IF this was just a simple PeekMessage() loop (servicing all possible work
216 // queues), then Windows would try to achieve the following order according 237 // queues), then Windows would try to achieve the following order according
217 // to MSDN documentation about PeekMessage with no filter): 238 // to MSDN documentation about PeekMessage with no filter):
218 // * Sent messages 239 // * Sent messages
219 // * Posted messages 240 // * Posted messages
220 // * Sent messages (again) 241 // * Sent messages (again)
221 // * WM_PAINT messages 242 // * WM_PAINT messages
222 // * WM_TIMER messages 243 // * WM_TIMER messages
223 // 244 //
224 // Summary: none of the above classes is starved, and sent messages has twice 245 // Summary: none of the above classes is starved, and sent messages has twice
(...skipping 17 matching lines...) Expand all
242 if (state_->should_quit) 263 if (state_->should_quit)
243 break; 264 break;
244 265
245 more_work_is_plausible |= 266 more_work_is_plausible |=
246 state_->delegate->DoDelayedWork(&delayed_work_time_); 267 state_->delegate->DoDelayedWork(&delayed_work_time_);
247 // If we did not process any delayed work, then we can assume that our 268 // 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 269 // 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, 270 // 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. 271 // 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()) 272 if (more_work_is_plausible && delayed_work_time_.is_null())
252 KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this)); 273 KillTimer(window_->hwnd(), kTimerId);
253 if (state_->should_quit) 274 if (state_->should_quit)
254 break; 275 break;
255 276
256 if (more_work_is_plausible) 277 if (more_work_is_plausible)
257 continue; 278 continue;
258 279
259 more_work_is_plausible = state_->delegate->DoIdleWork(); 280 more_work_is_plausible = state_->delegate->DoIdleWork();
260 if (state_->should_quit) 281 if (state_->should_quit)
261 break; 282 break;
262 283
263 if (more_work_is_plausible) 284 if (more_work_is_plausible)
264 continue; 285 continue;
265 286
266 WaitForWork(); // Wait (sleep) until we have work to do again. 287 WaitForWork(); // Wait (sleep) until we have work to do again.
267 } 288 }
268 } 289 }
269 290
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() { 291 void MessagePumpForUI::WaitForWork() {
285 // Wait until a message is available, up to the time needed by the timer 292 // Wait until a message is available, up to the time needed by the timer
286 // manager to fire the next set of timers. 293 // manager to fire the next set of timers.
287 int delay = GetCurrentDelay(); 294 int delay = GetCurrentDelay();
288 if (delay < 0) // Negative value means no timers waiting. 295 if (delay < 0) // Negative value means no timers waiting.
289 delay = INFINITE; 296 delay = INFINITE;
290 297
291 DWORD result; 298 DWORD result;
292 result = MsgWaitForMultipleObjectsEx(0, NULL, delay, QS_ALLINPUT, 299 result = MsgWaitForMultipleObjectsEx(0, NULL, delay, QS_ALLINPUT,
293 MWMO_INPUTAVAILABLE); 300 MWMO_INPUTAVAILABLE);
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
331 // messages that may be in the Windows message queue. 338 // messages that may be in the Windows message queue.
332 ProcessPumpReplacementMessage(); 339 ProcessPumpReplacementMessage();
333 340
334 // Now give the delegate a chance to do some work. He'll let us know if he 341 // Now give the delegate a chance to do some work. He'll let us know if he
335 // needs to do more work. 342 // needs to do more work.
336 if (state_->delegate->DoWork()) 343 if (state_->delegate->DoWork())
337 ScheduleWork(); 344 ScheduleWork();
338 } 345 }
339 346
340 void MessagePumpForUI::HandleTimerMessage() { 347 void MessagePumpForUI::HandleTimerMessage() {
341 KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this)); 348 KillTimer(window_->hwnd(), kTimerId);
342 349
343 // If we are being called outside of the context of Run, then don't do 350 // 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 351 // anything. This could correspond to a MessageBox call or something of
345 // that sort. 352 // that sort.
346 if (!state_) 353 if (!state_)
347 return; 354 return;
348 355
349 state_->delegate->DoDelayedWork(&delayed_work_time_); 356 state_->delegate->DoDelayedWork(&delayed_work_time_);
350 if (!delayed_work_time_.is_null()) { 357 if (!delayed_work_time_.is_null()) {
351 // A bit gratuitous to set delayed_work_time_ again, but oh well. 358 // A bit gratuitous to set delayed_work_time_ again, but oh well.
(...skipping 23 matching lines...) Expand all
375 "message", msg.message); 382 "message", msg.message);
376 if (WM_QUIT == msg.message) { 383 if (WM_QUIT == msg.message) {
377 // Repost the QUIT message so that it will be retrieved by the primary 384 // Repost the QUIT message so that it will be retrieved by the primary
378 // GetMessage() loop. 385 // GetMessage() loop.
379 state_->should_quit = true; 386 state_->should_quit = true;
380 PostQuitMessage(static_cast<int>(msg.wParam)); 387 PostQuitMessage(static_cast<int>(msg.wParam));
381 return false; 388 return false;
382 } 389 }
383 390
384 // While running our main message pump, we discard kMsgHaveWork messages. 391 // While running our main message pump, we discard kMsgHaveWork messages.
385 if (msg.message == kMsgHaveWork && msg.hwnd == message_hwnd_) 392 if (msg.message == kMsgHaveWork && msg.hwnd == window_->hwnd())
386 return ProcessPumpReplacementMessage(); 393 return ProcessPumpReplacementMessage();
387 394
388 if (CallMsgFilter(const_cast<MSG*>(&msg), kMessageFilterCode)) 395 if (CallMsgFilter(const_cast<MSG*>(&msg), kMessageFilterCode))
389 return true; 396 return true;
390 397
391 WillProcessMessage(msg); 398 WillProcessMessage(msg);
392 399
393 if (!message_filter_->ProcessMessage(msg)) { 400 if (!message_filter_->ProcessMessage(msg)) {
394 if (state_->dispatcher) { 401 if (state_->dispatcher) {
395 if (!state_->dispatcher->Dispatch(msg)) 402 if (!state_->dispatcher->Dispatch(msg))
(...skipping 26 matching lines...) Expand all
422 if (MessageLoop::current()->os_modal_loop()) { 429 if (MessageLoop::current()->os_modal_loop()) {
423 // We only peek out WM_PAINT and WM_TIMER here for reasons mentioned above. 430 // 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) || 431 have_message = PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE) ||
425 PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE); 432 PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE);
426 } else { 433 } else {
427 have_message = !!message_filter_->DoPeekMessage(&msg, NULL, 0, 0, 434 have_message = !!message_filter_->DoPeekMessage(&msg, NULL, 0, 0,
428 PM_REMOVE); 435 PM_REMOVE);
429 } 436 }
430 437
431 DCHECK(!have_message || kMsgHaveWork != msg.message || 438 DCHECK(!have_message || kMsgHaveWork != msg.message ||
432 msg.hwnd != message_hwnd_); 439 msg.hwnd != window_->hwnd());
433 440
434 // Since we discarded a kMsgHaveWork message, we must update the flag. 441 // Since we discarded a kMsgHaveWork message, we must update the flag.
435 int old_have_work = InterlockedExchange(&have_work_, 0); 442 int old_have_work = InterlockedExchange(&have_work_, 0);
436 DCHECK(old_have_work); 443 DCHECK(old_have_work);
437 444
438 // We don't need a special time slice if we didn't have_message to process. 445 // We don't need a special time slice if we didn't have_message to process.
439 if (!have_message) 446 if (!have_message)
440 return false; 447 return false;
441 448
442 // Guarantee we'll get another time slice in the case where we go into native 449 // 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 678
672 // static 679 // static
673 MessagePumpForIO::IOHandler* MessagePumpForIO::KeyToHandler( 680 MessagePumpForIO::IOHandler* MessagePumpForIO::KeyToHandler(
674 ULONG_PTR key, 681 ULONG_PTR key,
675 bool* has_valid_io_context) { 682 bool* has_valid_io_context) {
676 *has_valid_io_context = ((key & 1) == 0); 683 *has_valid_io_context = ((key & 1) == 0);
677 return reinterpret_cast<IOHandler*>(key & ~static_cast<ULONG_PTR>(1)); 684 return reinterpret_cast<IOHandler*>(key & ~static_cast<ULONG_PTR>(1));
678 } 685 }
679 686
680 } // namespace base 687 } // 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