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

Side by Side Diff: base/message_pump_mac.mm

Issue 264042: Less busywork for nested Mac run loops (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 11 years, 2 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 <float.h> 9 #include <float.h>
10 10
11 #include "base/scoped_nsautorelease_pool.h" 11 #include "base/scoped_nsautorelease_pool.h"
12 #include "base/time.h" 12 #include "base/time.h"
13 13
14 namespace { 14 namespace {
15 15
16 void NoOp(void* info) { 16 void NoOp(void* info) {
17 } 17 }
18 18
19 } // namespace 19 } // namespace
20 20
21 namespace base { 21 namespace base {
22 22
23 // Must be called on the run loop thread. 23 // Must be called on the run loop thread.
24 MessagePumpCFRunLoopBase::MessagePumpCFRunLoopBase() 24 MessagePumpCFRunLoopBase::MessagePumpCFRunLoopBase()
25 : nesting_level_(0), 25 : nesting_level_(0),
26 run_nesting_level_(0),
26 delegate_(NULL), 27 delegate_(NULL),
27 delegateless_work_(false), 28 delegateless_work_(false),
28 delegateless_delayed_work_(false), 29 delegateless_delayed_work_(false),
29 delegateless_idle_work_(false) 30 delegateless_idle_work_(false)
30 { 31 {
31 run_loop_ = CFRunLoopGetCurrent(); 32 run_loop_ = CFRunLoopGetCurrent();
32 CFRetain(run_loop_); 33 CFRetain(run_loop_);
33 34
34 // Set a repeating timer with a preposterous firing time and interval. The 35 // Set a repeating timer with a preposterous firing time and interval. The
35 // timer will effectively never fire as-is. The firing time will be adjusted 36 // timer will effectively never fire as-is. The firing time will be adjusted
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
118 CFRelease(work_source_); 119 CFRelease(work_source_);
119 120
120 CFRunLoopRemoveTimer(run_loop_, delayed_work_timer_, kCFRunLoopCommonModes); 121 CFRunLoopRemoveTimer(run_loop_, delayed_work_timer_, kCFRunLoopCommonModes);
121 CFRelease(delayed_work_timer_); 122 CFRelease(delayed_work_timer_);
122 123
123 CFRelease(run_loop_); 124 CFRelease(run_loop_);
124 } 125 }
125 126
126 // Must be called on the run loop thread. 127 // Must be called on the run loop thread.
127 void MessagePumpCFRunLoopBase::Run(Delegate* delegate) { 128 void MessagePumpCFRunLoopBase::Run(Delegate* delegate) {
129 // nesting_level_ will be incremented in EnterExitRunLoop, so set
130 // run_nesting_level_ accordingly.
131 int last_run_nesting_level = run_nesting_level_;
132 run_nesting_level_ = nesting_level_ + 1;
133
128 Delegate* last_delegate = delegate_; 134 Delegate* last_delegate = delegate_;
129 delegate_ = delegate; 135 delegate_ = delegate;
130 136
131 // If any work showed up but could not be dispatched for want of a delegate, 137 // If any work showed up but could not be dispatched for want of a delegate,
132 // set it up for dispatch again now that a delegate is available. 138 // set it up for dispatch again now that a delegate is available.
133 if (delegateless_work_) { 139 if (delegateless_work_) {
134 CFRunLoopSourceSignal(work_source_); 140 CFRunLoopSourceSignal(work_source_);
135 delegateless_work_ = false; 141 delegateless_work_ = false;
136 } 142 }
137 if (delegateless_delayed_work_) { 143 if (delegateless_delayed_work_) {
138 CFRunLoopSourceSignal(delayed_work_source_); 144 CFRunLoopSourceSignal(delayed_work_source_);
139 delegateless_delayed_work_ = false; 145 delegateless_delayed_work_ = false;
140 } 146 }
141 if (delegateless_idle_work_) { 147 if (delegateless_idle_work_) {
142 CFRunLoopSourceSignal(idle_work_source_); 148 CFRunLoopSourceSignal(idle_work_source_);
143 delegateless_idle_work_ = false; 149 delegateless_idle_work_ = false;
144 } 150 }
145 151
146 DoRun(delegate); 152 DoRun(delegate);
147 153
154 // If this was an inner Run invocation, arrange to run nesting-deferred work
155 // when the stack has unwound to an outer invocation.
156 if (nesting_level_)
157 CFRunLoopSourceSignal(nesting_deferred_work_source_);
158
159 // Restore the previous state of the object.
148 delegate_ = last_delegate; 160 delegate_ = last_delegate;
161 run_nesting_level_ = last_run_nesting_level;
149 } 162 }
150 163
151 // May be called on any thread. 164 // May be called on any thread.
152 void MessagePumpCFRunLoopBase::ScheduleWork() { 165 void MessagePumpCFRunLoopBase::ScheduleWork() {
153 CFRunLoopSourceSignal(work_source_); 166 CFRunLoopSourceSignal(work_source_);
154 CFRunLoopWakeUp(run_loop_); 167 CFRunLoopWakeUp(run_loop_);
155 } 168 }
156 169
157 // Must be called on the run loop thread. 170 // Must be called on the run loop thread.
158 void MessagePumpCFRunLoopBase::ScheduleDelayedWork( 171 void MessagePumpCFRunLoopBase::ScheduleDelayedWork(
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after
350 void MessagePumpCFRunLoopBase::EnterExitObserver(CFRunLoopObserverRef observer, 363 void MessagePumpCFRunLoopBase::EnterExitObserver(CFRunLoopObserverRef observer,
351 CFRunLoopActivity activity, 364 CFRunLoopActivity activity,
352 void* info) { 365 void* info) {
353 MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info); 366 MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
354 367
355 switch (activity) { 368 switch (activity) {
356 case kCFRunLoopEntry: 369 case kCFRunLoopEntry:
357 ++self->nesting_level_; 370 ++self->nesting_level_;
358 break; 371 break;
359 case kCFRunLoopExit: 372 case kCFRunLoopExit:
373 // After decrementing self->nesting_level_, it will be one less than
374 // self->run_nesting_level_ if the loop that is now exiting was directly
375 // started by a DoRun call.
360 --self->nesting_level_; 376 --self->nesting_level_;
361 if (self->nesting_level_) { 377
378 if (self->nesting_level_ >= self->run_nesting_level_ &&
379 self->nesting_level_) {
362 // It's possible that some work was not performed because it was 380 // It's possible that some work was not performed because it was
363 // inappropriate to do within a nested loop. When leaving any inner 381 // inappropriate to do within a nested loop. When leaving any inner
364 // loop, signal the nesting-deferred work source to ensure that such 382 // loop not directly supervised by a DoRun call, such as nested native
383 // loops, signal the nesting-deferred work source to ensure that such
365 // work be afforded an opportunity to be processed if appropriate. 384 // work be afforded an opportunity to be processed if appropriate.
385 // This is not done for loops being run directly by Run/DoRun because
386 // it can be done directly as Run exits.
366 CFRunLoopSourceSignal(self->nesting_deferred_work_source_); 387 CFRunLoopSourceSignal(self->nesting_deferred_work_source_);
367 } 388 }
368 break; 389 break;
369 default: 390 default:
370 break; 391 break;
371 } 392 }
372 393
373 self->EnterExitRunLoop(activity); 394 self->EnterExitRunLoop(activity);
374 } 395 }
375 396
376 // Called by MessagePumpCFRunLoopBase::EnterExitRunLoop. The default 397 // Called by MessagePumpCFRunLoopBase::EnterExitRunLoop. The default
377 // implementation is a no-op. 398 // implementation is a no-op.
378 void MessagePumpCFRunLoopBase::EnterExitRunLoop(CFRunLoopActivity activity) { 399 void MessagePumpCFRunLoopBase::EnterExitRunLoop(CFRunLoopActivity activity) {
379 } 400 }
380 401
381 MessagePumpCFRunLoop::MessagePumpCFRunLoop() 402 MessagePumpCFRunLoop::MessagePumpCFRunLoop()
382 : innermost_quittable_(0), 403 : quit_pending_(false) {
383 quit_pending_(false) {
384 } 404 }
385 405
386 // Called by MessagePumpCFRunLoopBase::DoRun. If other CFRunLoopRun loops were 406 // Called by MessagePumpCFRunLoopBase::DoRun. If other CFRunLoopRun loops were
387 // running lower on the run loop thread's stack when this object was created, 407 // running lower on the run loop thread's stack when this object was created,
388 // the same number of CFRunLoopRun loops must be running for the outermost call 408 // the same number of CFRunLoopRun loops must be running for the outermost call
389 // to Run. Run/DoRun are reentrant after that point. 409 // to Run. Run/DoRun are reentrant after that point.
390 void MessagePumpCFRunLoop::DoRun(Delegate* delegate) { 410 void MessagePumpCFRunLoop::DoRun(Delegate* delegate) {
391 // nesting_level_ will be incremented in EnterExitRunLoop, so set
392 // innermost_quittable_ accordingly.
393 int last_innermost_quittable = innermost_quittable_;
394 innermost_quittable_ = nesting_level_ + 1;
395
396 // This is completely identical to calling CFRunLoopRun(), except autorelease 411 // This is completely identical to calling CFRunLoopRun(), except autorelease
397 // pool management is introduced. 412 // pool management is introduced.
398 int result; 413 int result;
399 do { 414 do {
400 ScopedNSAutoreleasePool autorelease_pool; 415 ScopedNSAutoreleasePool autorelease_pool;
401 result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, DBL_MAX, false); 416 result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, DBL_MAX, false);
402 } while (result != kCFRunLoopRunStopped && result != kCFRunLoopRunFinished); 417 } while (result != kCFRunLoopRunStopped && result != kCFRunLoopRunFinished);
403
404 // Restore the previous state of the object.
405 innermost_quittable_ = last_innermost_quittable;
406 } 418 }
407 419
408 // Must be called on the run loop thread. 420 // Must be called on the run loop thread.
409 void MessagePumpCFRunLoop::Quit() { 421 void MessagePumpCFRunLoop::Quit() {
410 // Stop the innermost run loop managed by this MessagePumpCFRunLoop object. 422 // Stop the innermost run loop managed by this MessagePumpCFRunLoop object.
411 if (nesting_level_ == innermost_quittable_) { 423 if (nesting_level_ == run_nesting_level_) {
412 // This object is running the innermost loop, just stop it. 424 // This object is running the innermost loop, just stop it.
413 CFRunLoopStop(run_loop_); 425 CFRunLoopStop(run_loop_);
414 } else { 426 } else {
415 // There's another loop running inside the loop managed by this object. 427 // There's another loop running inside the loop managed by this object.
416 // In other words, someone else called CFRunLoopRun on the same thread, 428 // In other words, someone else called CFRunLoopRun on the same thread,
417 // higher on the stack than our highest Run call. Don't preempt other 429 // higher on the stack than our highest Run call. Don't preempt other
418 // run loops, just mark the object to quit our innermost run loop as soon 430 // run loops, just mark the object to quit our innermost run loop as soon
419 // as the other inner loops we don't manage are done. 431 // as the other inner loops we don't manage are done.
420 quit_pending_ = true; 432 quit_pending_ = true;
421 } 433 }
422 } 434 }
423 435
424 // Called by MessagePumpCFRunLoopBase::EnterExitObserver. 436 // Called by MessagePumpCFRunLoopBase::EnterExitObserver.
425 void MessagePumpCFRunLoop::EnterExitRunLoop(CFRunLoopActivity activity) { 437 void MessagePumpCFRunLoop::EnterExitRunLoop(CFRunLoopActivity activity) {
426 if (activity == kCFRunLoopExit && 438 if (activity == kCFRunLoopExit &&
427 nesting_level_ == innermost_quittable_ && 439 nesting_level_ == run_nesting_level_ &&
428 quit_pending_) { 440 quit_pending_) {
429 // Quit was called while loops other than those managed by this object 441 // Quit was called while loops other than those managed by this object
430 // were running further inside a run loop managed by this object. Now 442 // were running further inside a run loop managed by this object. Now
431 // that all unmanaged inner run loops are gone, stop the loop running 443 // that all unmanaged inner run loops are gone, stop the loop running
432 // just inside Run. 444 // just inside Run.
433 CFRunLoopStop(run_loop_); 445 CFRunLoopStop(run_loop_);
434 quit_pending_ = false; 446 quit_pending_ = false;
435 } 447 }
436 } 448 }
437 449
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
521 // static 533 // static
522 MessagePump* MessagePumpMac::Create() { 534 MessagePump* MessagePumpMac::Create() {
523 if ([NSThread isMainThread]) { 535 if ([NSThread isMainThread]) {
524 return new MessagePumpNSApplication; 536 return new MessagePumpNSApplication;
525 } 537 }
526 538
527 return new MessagePumpNSRunLoop; 539 return new MessagePumpNSRunLoop;
528 } 540 }
529 541
530 } // namespace base 542 } // 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