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

Side by Side Diff: base/message_pump_mac.mm

Issue 6507017: MessagePump implementations should call DoWork and DoDelayedWork at equal priority (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 10 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_mac.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) 2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2008 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_mac.h" 5 #include "base/message_pump_mac.h"
6 6
7 #import <AppKit/AppKit.h> 7 #import <AppKit/AppKit.h>
8 #import <Foundation/Foundation.h> 8 #import <Foundation/Foundation.h>
9 #include <IOKit/IOMessage.h> 9 #include <IOKit/IOMessage.h>
10 #include <IOKit/pwr_mgt/IOPMLib.h> 10 #include <IOKit/pwr_mgt/IOPMLib.h>
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
44 }; 44 };
45 45
46 // Must be called on the run loop thread. 46 // Must be called on the run loop thread.
47 MessagePumpCFRunLoopBase::MessagePumpCFRunLoopBase() 47 MessagePumpCFRunLoopBase::MessagePumpCFRunLoopBase()
48 : delegate_(NULL), 48 : delegate_(NULL),
49 delayed_work_fire_time_(kCFTimeIntervalMax), 49 delayed_work_fire_time_(kCFTimeIntervalMax),
50 nesting_level_(0), 50 nesting_level_(0),
51 run_nesting_level_(0), 51 run_nesting_level_(0),
52 deepest_nesting_level_(0), 52 deepest_nesting_level_(0),
53 delegateless_work_(false), 53 delegateless_work_(false),
54 delegateless_delayed_work_(false),
55 delegateless_idle_work_(false) { 54 delegateless_idle_work_(false) {
56 run_loop_ = CFRunLoopGetCurrent(); 55 run_loop_ = CFRunLoopGetCurrent();
57 CFRetain(run_loop_); 56 CFRetain(run_loop_);
58 57
59 // Set a repeating timer with a preposterous firing time and interval. The 58 // Set a repeating timer with a preposterous firing time and interval. The
60 // timer will effectively never fire as-is. The firing time will be adjusted 59 // timer will effectively never fire as-is. The firing time will be adjusted
61 // as needed when ScheduleDelayedWork is called. 60 // as needed when ScheduleDelayedWork is called.
62 CFRunLoopTimerContext timer_context = CFRunLoopTimerContext(); 61 CFRunLoopTimerContext timer_context = CFRunLoopTimerContext();
63 timer_context.info = this; 62 timer_context.info = this;
64 delayed_work_timer_ = CFRunLoopTimerCreate(NULL, // allocator 63 delayed_work_timer_ = CFRunLoopTimerCreate(NULL, // allocator
65 kCFTimeIntervalMax, // fire time 64 kCFTimeIntervalMax, // fire time
66 kCFTimeIntervalMax, // interval 65 kCFTimeIntervalMax, // interval
67 0, // flags 66 0, // flags
68 0, // priority 67 0, // priority
69 RunDelayedWorkTimer, 68 RunDelayedWorkTimer,
70 &timer_context); 69 &timer_context);
71 CFRunLoopAddTimer(run_loop_, delayed_work_timer_, kCFRunLoopCommonModes); 70 CFRunLoopAddTimer(run_loop_, delayed_work_timer_, kCFRunLoopCommonModes);
72 71
73 CFRunLoopSourceContext source_context = CFRunLoopSourceContext(); 72 CFRunLoopSourceContext source_context = CFRunLoopSourceContext();
74 source_context.info = this; 73 source_context.info = this;
75 source_context.perform = RunWorkSource; 74 source_context.perform = RunWorkSource;
76 work_source_ = CFRunLoopSourceCreate(NULL, // allocator 75 work_source_ = CFRunLoopSourceCreate(NULL, // allocator
77 1, // priority 76 1, // priority
78 &source_context); 77 &source_context);
79 CFRunLoopAddSource(run_loop_, work_source_, kCFRunLoopCommonModes); 78 CFRunLoopAddSource(run_loop_, work_source_, kCFRunLoopCommonModes);
80 79
81 source_context.perform = RunDelayedWorkSource;
82 delayed_work_source_ = CFRunLoopSourceCreate(NULL, // allocator
83 2, // priority
84 &source_context);
85 CFRunLoopAddSource(run_loop_, delayed_work_source_, kCFRunLoopCommonModes);
86
87 source_context.perform = RunIdleWorkSource; 80 source_context.perform = RunIdleWorkSource;
88 idle_work_source_ = CFRunLoopSourceCreate(NULL, // allocator 81 idle_work_source_ = CFRunLoopSourceCreate(NULL, // allocator
89 3, // priority 82 2, // priority
90 &source_context); 83 &source_context);
91 CFRunLoopAddSource(run_loop_, idle_work_source_, kCFRunLoopCommonModes); 84 CFRunLoopAddSource(run_loop_, idle_work_source_, kCFRunLoopCommonModes);
92 85
93 source_context.perform = RunNestingDeferredWorkSource; 86 source_context.perform = RunNestingDeferredWorkSource;
94 nesting_deferred_work_source_ = CFRunLoopSourceCreate(NULL, // allocator 87 nesting_deferred_work_source_ = CFRunLoopSourceCreate(NULL, // allocator
95 0, // priority 88 0, // priority
96 &source_context); 89 &source_context);
97 CFRunLoopAddSource(run_loop_, nesting_deferred_work_source_, 90 CFRunLoopAddSource(run_loop_, nesting_deferred_work_source_,
98 kCFRunLoopCommonModes); 91 kCFRunLoopCommonModes);
99 92
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
162 kCFRunLoopCommonModes); 155 kCFRunLoopCommonModes);
163 CFRelease(pre_wait_observer_); 156 CFRelease(pre_wait_observer_);
164 157
165 CFRunLoopRemoveSource(run_loop_, nesting_deferred_work_source_, 158 CFRunLoopRemoveSource(run_loop_, nesting_deferred_work_source_,
166 kCFRunLoopCommonModes); 159 kCFRunLoopCommonModes);
167 CFRelease(nesting_deferred_work_source_); 160 CFRelease(nesting_deferred_work_source_);
168 161
169 CFRunLoopRemoveSource(run_loop_, idle_work_source_, kCFRunLoopCommonModes); 162 CFRunLoopRemoveSource(run_loop_, idle_work_source_, kCFRunLoopCommonModes);
170 CFRelease(idle_work_source_); 163 CFRelease(idle_work_source_);
171 164
172 CFRunLoopRemoveSource(run_loop_, delayed_work_source_, kCFRunLoopCommonModes);
173 CFRelease(delayed_work_source_);
174
175 CFRunLoopRemoveSource(run_loop_, work_source_, kCFRunLoopCommonModes); 165 CFRunLoopRemoveSource(run_loop_, work_source_, kCFRunLoopCommonModes);
176 CFRelease(work_source_); 166 CFRelease(work_source_);
177 167
178 CFRunLoopRemoveTimer(run_loop_, delayed_work_timer_, kCFRunLoopCommonModes); 168 CFRunLoopRemoveTimer(run_loop_, delayed_work_timer_, kCFRunLoopCommonModes);
179 CFRelease(delayed_work_timer_); 169 CFRelease(delayed_work_timer_);
180 170
181 CFRelease(run_loop_); 171 CFRelease(run_loop_);
182 } 172 }
183 173
184 // Must be called on the run loop thread. 174 // Must be called on the run loop thread.
185 void MessagePumpCFRunLoopBase::Run(Delegate* delegate) { 175 void MessagePumpCFRunLoopBase::Run(Delegate* delegate) {
186 // nesting_level_ will be incremented in EnterExitRunLoop, so set 176 // nesting_level_ will be incremented in EnterExitRunLoop, so set
187 // run_nesting_level_ accordingly. 177 // run_nesting_level_ accordingly.
188 int last_run_nesting_level = run_nesting_level_; 178 int last_run_nesting_level = run_nesting_level_;
189 run_nesting_level_ = nesting_level_ + 1; 179 run_nesting_level_ = nesting_level_ + 1;
190 180
191 Delegate* last_delegate = delegate_; 181 Delegate* last_delegate = delegate_;
192 delegate_ = delegate; 182 delegate_ = delegate;
193 183
194 if (delegate) { 184 if (delegate) {
195 // If any work showed up but could not be dispatched for want of a 185 // If any work showed up but could not be dispatched for want of a
196 // delegate, set it up for dispatch again now that a delegate is 186 // delegate, set it up for dispatch again now that a delegate is
197 // available. 187 // available.
198 if (delegateless_work_) { 188 if (delegateless_work_) {
199 CFRunLoopSourceSignal(work_source_); 189 CFRunLoopSourceSignal(work_source_);
200 delegateless_work_ = false; 190 delegateless_work_ = false;
201 } 191 }
202 if (delegateless_delayed_work_) {
203 CFRunLoopSourceSignal(delayed_work_source_);
204 delegateless_delayed_work_ = false;
205 }
206 if (delegateless_idle_work_) { 192 if (delegateless_idle_work_) {
207 CFRunLoopSourceSignal(idle_work_source_); 193 CFRunLoopSourceSignal(idle_work_source_);
208 delegateless_idle_work_ = false; 194 delegateless_idle_work_ = false;
209 } 195 }
210 } 196 }
211 197
212 DoRun(delegate); 198 DoRun(delegate);
213 199
214 // Restore the previous state of the object. 200 // Restore the previous state of the object.
215 delegate_ = last_delegate; 201 delegate_ = last_delegate;
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
253 // Called from the run loop. 239 // Called from the run loop.
254 // static 240 // static
255 void MessagePumpCFRunLoopBase::RunDelayedWorkTimer(CFRunLoopTimerRef timer, 241 void MessagePumpCFRunLoopBase::RunDelayedWorkTimer(CFRunLoopTimerRef timer,
256 void* info) { 242 void* info) {
257 MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info); 243 MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
258 244
259 // The timer won't fire again until it's reset. 245 // The timer won't fire again until it's reset.
260 self->delayed_work_fire_time_ = kCFTimeIntervalMax; 246 self->delayed_work_fire_time_ = kCFTimeIntervalMax;
261 247
262 // CFRunLoopTimers fire outside of the priority scheme for CFRunLoopSources. 248 // CFRunLoopTimers fire outside of the priority scheme for CFRunLoopSources.
263 // In order to establish the proper priority where delegate_->DoDelayedWork 249 // In order to establish the proper priority in which work and delayed work
264 // can only be called if delegate_->DoWork returns false, the timer used 250 // are processed one for one, the timer used to schedule delayed work must
265 // to schedule delayed work must signal a CFRunLoopSource set at a lower 251 // signal a CFRunLoopSource used to dispatch both work and delayed work.
266 // priority than the one used for delegate_->DoWork. 252 CFRunLoopSourceSignal(self->work_source_);
267 CFRunLoopSourceSignal(self->delayed_work_source_);
268 } 253 }
269 254
270 // Called from the run loop. 255 // Called from the run loop.
271 // static 256 // static
272 void MessagePumpCFRunLoopBase::RunWorkSource(void* info) { 257 void MessagePumpCFRunLoopBase::RunWorkSource(void* info) {
273 MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info); 258 MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
274 self->RunWork(); 259 self->RunWork();
275 } 260 }
276 261
277 // Called by MessagePumpCFRunLoopBase::RunWorkSource. 262 // Called by MessagePumpCFRunLoopBase::RunWorkSource.
278 bool MessagePumpCFRunLoopBase::RunWork() { 263 bool MessagePumpCFRunLoopBase::RunWork() {
279 if (!delegate_) { 264 if (!delegate_) {
280 // This point can be reached with a NULL delegate_ if Run is not on the 265 // This point can be reached with a NULL delegate_ if Run is not on the
281 // stack but foreign code is spinning the CFRunLoop. Arrange to come back 266 // stack but foreign code is spinning the CFRunLoop. Arrange to come back
282 // here when a delegate is available. 267 // here when a delegate is available.
283 delegateless_work_ = true; 268 delegateless_work_ = true;
284 return false; 269 return false;
285 } 270 }
286 271
287 // The NSApplication-based run loop only drains the autorelease pool at each 272 // The NSApplication-based run loop only drains the autorelease pool at each
288 // UI event (NSEvent). The autorelease pool is not drained for each 273 // UI event (NSEvent). The autorelease pool is not drained for each
289 // CFRunLoopSource target that's run. Use a local pool for any autoreleased 274 // CFRunLoopSource target that's run. Use a local pool for any autoreleased
290 // objects if the app is not currently handling a UI event to ensure they're 275 // objects if the app is not currently handling a UI event to ensure they're
291 // released promptly even in the absence of UI events. 276 // released promptly even in the absence of UI events.
292 MessagePumpScopedAutoreleasePool autorelease_pool(this); 277 MessagePumpScopedAutoreleasePool autorelease_pool(this);
293 278
294 // Call DoWork once, and if something was done, arrange to come back here 279 // Call DoWork and DoDelayedWork once, and if something was done, arrange to
295 // again as long as the loop is still running. 280 // come back here again as long as the loop is still running.
296 bool did_work = delegate_->DoWork(); 281 bool did_work = delegate_->DoWork();
297 if (did_work) { 282 bool resignal_work_source = did_work;
283
284 TimeTicks next_time;
285 delegate_->DoDelayedWork(&next_time);
286 if (!did_work) {
287 // Determine whether there's more delayed work, and if so, if it needs to
288 // be done at some point in the future or if it's already time to do it.
289 // Only do these checks if did_work is false. If did_work is true, this
290 // function, and therefore any additional delayed work, will get another
291 // chance to run before the loop goes to sleep.
292 bool more_delayed_work = !next_time.is_null();
293 if (more_delayed_work) {
294 TimeDelta delay = next_time - TimeTicks::Now();
295 if (delay > TimeDelta()) {
296 // There's more delayed work to be done in the future.
297 ScheduleDelayedWork(next_time);
298 } else {
299 // There's more delayed work to be done, and its time is in the past.
300 // Arrange to come back here directly as long as the loop is still
301 // running.
302 resignal_work_source = true;
303 }
304 }
305 }
306
307 if (resignal_work_source) {
298 CFRunLoopSourceSignal(work_source_); 308 CFRunLoopSourceSignal(work_source_);
299 } 309 }
300 310
301 return did_work; 311 return resignal_work_source;
302 } 312 }
303 313
304 // Called from the run loop. 314 // Called from the run loop.
305 // static
306 void MessagePumpCFRunLoopBase::RunDelayedWorkSource(void* info) {
307 MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
308 self->RunDelayedWork();
309 }
310
311 // Called by MessagePumpCFRunLoopBase::RunDelayedWorkSource.
312 bool MessagePumpCFRunLoopBase::RunDelayedWork() {
313 if (!delegate_) {
314 // This point can be reached with a NULL delegate_ if Run is not on the
315 // stack but foreign code is spinning the CFRunLoop. Arrange to come back
316 // here when a delegate is available.
317 delegateless_delayed_work_ = true;
318 return false;
319 }
320
321 // The NSApplication-based run loop only drains the autorelease pool at each
322 // UI event (NSEvent). The autorelease pool is not drained for each
323 // CFRunLoopSource target that's run. Use a local pool for any autoreleased
324 // objects if the app is not currently handling a UI event to ensure they're
325 // released promptly even in the absence of UI events.
326 MessagePumpScopedAutoreleasePool autorelease_pool(this);
327
328 TimeTicks next_time;
329 delegate_->DoDelayedWork(&next_time);
330
331 bool more_work = !next_time.is_null();
332 if (more_work) {
333 TimeDelta delay = next_time - TimeTicks::Now();
334 if (delay > TimeDelta()) {
335 // There's more delayed work to be done in the future.
336 ScheduleDelayedWork(next_time);
337 } else {
338 // There's more delayed work to be done, and its time is in the past.
339 // Arrange to come back here directly as long as the loop is still
340 // running.
341 CFRunLoopSourceSignal(delayed_work_source_);
342 }
343 }
344
345 return more_work;
346 }
347
348 // Called from the run loop.
349 // static 315 // static
350 void MessagePumpCFRunLoopBase::RunIdleWorkSource(void* info) { 316 void MessagePumpCFRunLoopBase::RunIdleWorkSource(void* info) {
351 MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info); 317 MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
352 self->RunIdleWork(); 318 self->RunIdleWork();
353 } 319 }
354 320
355 // Called by MessagePumpCFRunLoopBase::RunIdleWorkSource. 321 // Called by MessagePumpCFRunLoopBase::RunIdleWorkSource.
356 bool MessagePumpCFRunLoopBase::RunIdleWork() { 322 bool MessagePumpCFRunLoopBase::RunIdleWork() {
357 if (!delegate_) { 323 if (!delegate_) {
358 // This point can be reached with a NULL delegate_ if Run is not on the 324 // This point can be reached with a NULL delegate_ if Run is not on the
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
391 if (!delegate_) { 357 if (!delegate_) {
392 // This point can be reached with a NULL delegate_ if Run is not on the 358 // This point can be reached with a NULL delegate_ if Run is not on the
393 // stack but foreign code is spinning the CFRunLoop. There's no sense in 359 // stack but foreign code is spinning the CFRunLoop. There's no sense in
394 // attempting to do any work or signalling the work sources because 360 // attempting to do any work or signalling the work sources because
395 // without a delegate, work is not possible. 361 // without a delegate, work is not possible.
396 return false; 362 return false;
397 } 363 }
398 364
399 // Immediately try work in priority order. 365 // Immediately try work in priority order.
400 if (!RunWork()) { 366 if (!RunWork()) {
401 if (!RunDelayedWork()) { 367 if (!RunIdleWork()) {
402 if (!RunIdleWork()) { 368 return false;
403 return false;
404 }
405 } else {
406 // There was no work, and delayed work was done. Arrange for the loop
407 // to try non-nestable idle work on a subsequent pass.
408 CFRunLoopSourceSignal(idle_work_source_);
409 } 369 }
410 } else { 370 } else {
411 // Work was done. Arrange for the loop to try non-nestable delayed and 371 // Work was done. Arrange for the loop to try non-nestable idle work on
412 // idle work on a subsequent pass. 372 // a subsequent pass.
413 CFRunLoopSourceSignal(delayed_work_source_);
414 CFRunLoopSourceSignal(idle_work_source_); 373 CFRunLoopSourceSignal(idle_work_source_);
415 } 374 }
416 375
417 return true; 376 return true;
418 } 377 }
419 378
420 // Called before the run loop goes to sleep or exits, or processes sources. 379 // Called before the run loop goes to sleep or exits, or processes sources.
421 void MessagePumpCFRunLoopBase::MaybeScheduleNestingDeferredWork() { 380 void MessagePumpCFRunLoopBase::MaybeScheduleNestingDeferredWork() {
422 // deepest_nesting_level_ is set as run loops are entered. If the deepest 381 // deepest_nesting_level_ is set as run loops are entered. If the deepest
423 // level encountered is deeper than the current level, a nested loop 382 // level encountered is deeper than the current level, a nested loop
(...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after
758 // static 717 // static
759 MessagePump* MessagePumpMac::Create() { 718 MessagePump* MessagePumpMac::Create() {
760 if ([NSThread isMainThread]) { 719 if ([NSThread isMainThread]) {
761 return new MessagePumpNSApplication; 720 return new MessagePumpNSApplication;
762 } 721 }
763 722
764 return new MessagePumpNSRunLoop; 723 return new MessagePumpNSRunLoop;
765 } 724 }
766 725
767 } // namespace base 726 } // namespace base
OLDNEW
« no previous file with comments | « base/message_pump_mac.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698