| OLD | NEW |
| 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 #import "base/message_loop/message_pump_mac.h" | 5 #import "base/message_loop/message_pump_mac.h" |
| 6 | 6 |
| 7 #import <Foundation/Foundation.h> | 7 #import <Foundation/Foundation.h> |
| 8 | 8 |
| 9 #include <limits> | 9 #include <limits> |
| 10 | 10 |
| 11 #include "base/debug/trace_event.h" |
| 11 #include "base/logging.h" | 12 #include "base/logging.h" |
| 12 #include "base/run_loop.h" | 13 #include "base/run_loop.h" |
| 13 #include "base/time/time.h" | 14 #include "base/time/time.h" |
| 14 | 15 |
| 15 #if !defined(OS_IOS) | 16 #if !defined(OS_IOS) |
| 16 #import <AppKit/AppKit.h> | 17 #import <AppKit/AppKit.h> |
| 17 #endif // !defined(OS_IOS) | 18 #endif // !defined(OS_IOS) |
| 18 | 19 |
| 19 namespace { | 20 namespace { |
| 20 | 21 |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 94 source_context.perform = RunNestingDeferredWorkSource; | 95 source_context.perform = RunNestingDeferredWorkSource; |
| 95 nesting_deferred_work_source_ = CFRunLoopSourceCreate(NULL, // allocator | 96 nesting_deferred_work_source_ = CFRunLoopSourceCreate(NULL, // allocator |
| 96 0, // priority | 97 0, // priority |
| 97 &source_context); | 98 &source_context); |
| 98 CFRunLoopAddSource(run_loop_, nesting_deferred_work_source_, | 99 CFRunLoopAddSource(run_loop_, nesting_deferred_work_source_, |
| 99 kCFRunLoopCommonModes); | 100 kCFRunLoopCommonModes); |
| 100 | 101 |
| 101 CFRunLoopObserverContext observer_context = CFRunLoopObserverContext(); | 102 CFRunLoopObserverContext observer_context = CFRunLoopObserverContext(); |
| 102 observer_context.info = this; | 103 observer_context.info = this; |
| 103 pre_wait_observer_ = CFRunLoopObserverCreate(NULL, // allocator | 104 pre_wait_observer_ = CFRunLoopObserverCreate(NULL, // allocator |
| 104 kCFRunLoopBeforeWaiting, | 105 kCFRunLoopBeforeWaiting | |
| 106 kCFRunLoopAfterWaiting, |
| 105 true, // repeat | 107 true, // repeat |
| 106 0, // priority | 108 0, // priority |
| 107 PreWaitObserver, | 109 PreWaitObserver, |
| 108 &observer_context); | 110 &observer_context); |
| 109 CFRunLoopAddObserver(run_loop_, pre_wait_observer_, kCFRunLoopCommonModes); | 111 CFRunLoopAddObserver(run_loop_, pre_wait_observer_, kCFRunLoopCommonModes); |
| 110 | 112 |
| 111 pre_source_observer_ = CFRunLoopObserverCreate(NULL, // allocator | 113 pre_source_observer_ = CFRunLoopObserverCreate(NULL, // allocator |
| 112 kCFRunLoopBeforeSources, | 114 kCFRunLoopBeforeSources, |
| 113 true, // repeat | 115 true, // repeat |
| 114 0, // priority | 116 0, // priority |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 219 // CFRunLoopTimers fire outside of the priority scheme for CFRunLoopSources. | 221 // CFRunLoopTimers fire outside of the priority scheme for CFRunLoopSources. |
| 220 // In order to establish the proper priority in which work and delayed work | 222 // In order to establish the proper priority in which work and delayed work |
| 221 // are processed one for one, the timer used to schedule delayed work must | 223 // are processed one for one, the timer used to schedule delayed work must |
| 222 // signal a CFRunLoopSource used to dispatch both work and delayed work. | 224 // signal a CFRunLoopSource used to dispatch both work and delayed work. |
| 223 CFRunLoopSourceSignal(self->work_source_); | 225 CFRunLoopSourceSignal(self->work_source_); |
| 224 } | 226 } |
| 225 | 227 |
| 226 // Called from the run loop. | 228 // Called from the run loop. |
| 227 // static | 229 // static |
| 228 void MessagePumpCFRunLoopBase::RunWorkSource(void* info) { | 230 void MessagePumpCFRunLoopBase::RunWorkSource(void* info) { |
| 231 TRACE_EVENT0("CFRunLoop", "RunWorkSource"); |
| 229 MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info); | 232 MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info); |
| 230 self->RunWork(); | 233 self->RunWork(); |
| 231 } | 234 } |
| 232 | 235 |
| 233 // Called by MessagePumpCFRunLoopBase::RunWorkSource. | 236 // Called by MessagePumpCFRunLoopBase::RunWorkSource. |
| 234 bool MessagePumpCFRunLoopBase::RunWork() { | 237 bool MessagePumpCFRunLoopBase::RunWork() { |
| 235 if (!delegate_) { | 238 if (!delegate_) { |
| 236 // This point can be reached with a NULL delegate_ if Run is not on the | 239 // This point can be reached with a NULL delegate_ if Run is not on the |
| 237 // stack but foreign code is spinning the CFRunLoop. Arrange to come back | 240 // stack but foreign code is spinning the CFRunLoop. Arrange to come back |
| 238 // here when a delegate is available. | 241 // here when a delegate is available. |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 278 if (resignal_work_source) { | 281 if (resignal_work_source) { |
| 279 CFRunLoopSourceSignal(work_source_); | 282 CFRunLoopSourceSignal(work_source_); |
| 280 } | 283 } |
| 281 | 284 |
| 282 return resignal_work_source; | 285 return resignal_work_source; |
| 283 } | 286 } |
| 284 | 287 |
| 285 // Called from the run loop. | 288 // Called from the run loop. |
| 286 // static | 289 // static |
| 287 void MessagePumpCFRunLoopBase::RunIdleWorkSource(void* info) { | 290 void MessagePumpCFRunLoopBase::RunIdleWorkSource(void* info) { |
| 291 TRACE_EVENT0("CFRunLoop", "RunWorkIdleSource"); |
| 288 MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info); | 292 MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info); |
| 289 self->RunIdleWork(); | 293 self->RunIdleWork(); |
| 290 } | 294 } |
| 291 | 295 |
| 292 // Called by MessagePumpCFRunLoopBase::RunIdleWorkSource. | 296 // Called by MessagePumpCFRunLoopBase::RunIdleWorkSource. |
| 293 bool MessagePumpCFRunLoopBase::RunIdleWork() { | 297 bool MessagePumpCFRunLoopBase::RunIdleWork() { |
| 294 if (!delegate_) { | 298 if (!delegate_) { |
| 295 // This point can be reached with a NULL delegate_ if Run is not on the | 299 // This point can be reached with a NULL delegate_ if Run is not on the |
| 296 // stack but foreign code is spinning the CFRunLoop. Arrange to come back | 300 // stack but foreign code is spinning the CFRunLoop. Arrange to come back |
| 297 // here when a delegate is available. | 301 // here when a delegate is available. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 312 if (did_work) { | 316 if (did_work) { |
| 313 CFRunLoopSourceSignal(idle_work_source_); | 317 CFRunLoopSourceSignal(idle_work_source_); |
| 314 } | 318 } |
| 315 | 319 |
| 316 return did_work; | 320 return did_work; |
| 317 } | 321 } |
| 318 | 322 |
| 319 // Called from the run loop. | 323 // Called from the run loop. |
| 320 // static | 324 // static |
| 321 void MessagePumpCFRunLoopBase::RunNestingDeferredWorkSource(void* info) { | 325 void MessagePumpCFRunLoopBase::RunNestingDeferredWorkSource(void* info) { |
| 326 TRACE_EVENT0("CFRunLoop", "RunNestingDeferredWorkSource"); |
| 322 MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info); | 327 MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info); |
| 323 self->RunNestingDeferredWork(); | 328 self->RunNestingDeferredWork(); |
| 324 } | 329 } |
| 325 | 330 |
| 326 // Called by MessagePumpCFRunLoopBase::RunNestingDeferredWorkSource. | 331 // Called by MessagePumpCFRunLoopBase::RunNestingDeferredWorkSource. |
| 327 bool MessagePumpCFRunLoopBase::RunNestingDeferredWork() { | 332 bool MessagePumpCFRunLoopBase::RunNestingDeferredWork() { |
| 328 if (!delegate_) { | 333 if (!delegate_) { |
| 329 // This point can be reached with a NULL delegate_ if Run is not on the | 334 // This point can be reached with a NULL delegate_ if Run is not on the |
| 330 // stack but foreign code is spinning the CFRunLoop. There's no sense in | 335 // stack but foreign code is spinning the CFRunLoop. There's no sense in |
| 331 // attempting to do any work or signalling the work sources because | 336 // attempting to do any work or signalling the work sources because |
| (...skipping 29 matching lines...) Expand all Loading... |
| 361 } | 366 } |
| 362 } | 367 } |
| 363 | 368 |
| 364 // Called from the run loop. | 369 // Called from the run loop. |
| 365 // static | 370 // static |
| 366 void MessagePumpCFRunLoopBase::PreWaitObserver(CFRunLoopObserverRef observer, | 371 void MessagePumpCFRunLoopBase::PreWaitObserver(CFRunLoopObserverRef observer, |
| 367 CFRunLoopActivity activity, | 372 CFRunLoopActivity activity, |
| 368 void* info) { | 373 void* info) { |
| 369 MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info); | 374 MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info); |
| 370 | 375 |
| 376 static uint32 last_id = 0; |
| 377 if (activity == kCFRunLoopBeforeWaiting) |
| 378 self->nesting_stack_.push(++last_id); |
| 379 uint64_t trace_id = ((uintptr_t)observer << sizeof(uint32)) | self->nesting_st
ack_.top(); |
| 380 if (activity == kCFRunLoopAfterWaiting) { |
| 381 TRACE_EVENT_ASYNC_END0("CFRunLoop", "Waiting", trace_id); |
| 382 self->nesting_stack_.pop(); |
| 383 return; |
| 384 } else { |
| 385 TRACE_EVENT_ASYNC_BEGIN0("CFRunLoop", "Waiting", trace_id); |
| 386 } |
| 387 |
| 371 // Attempt to do some idle work before going to sleep. | 388 // Attempt to do some idle work before going to sleep. |
| 372 self->RunIdleWork(); | 389 self->RunIdleWork(); |
| 373 | 390 |
| 374 // The run loop is about to go to sleep. If any of the work done since it | 391 // The run loop is about to go to sleep. If any of the work done since it |
| 375 // started or woke up resulted in a nested run loop running, | 392 // started or woke up resulted in a nested run loop running, |
| 376 // nesting-deferred work may have accumulated. Schedule it for processing | 393 // nesting-deferred work may have accumulated. Schedule it for processing |
| 377 // if appropriate. | 394 // if appropriate. |
| 378 self->MaybeScheduleNestingDeferredWork(); | 395 self->MaybeScheduleNestingDeferredWork(); |
| 379 } | 396 } |
| 380 | 397 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 392 // appropriate. | 409 // appropriate. |
| 393 self->MaybeScheduleNestingDeferredWork(); | 410 self->MaybeScheduleNestingDeferredWork(); |
| 394 } | 411 } |
| 395 | 412 |
| 396 // Called from the run loop. | 413 // Called from the run loop. |
| 397 // static | 414 // static |
| 398 void MessagePumpCFRunLoopBase::EnterExitObserver(CFRunLoopObserverRef observer, | 415 void MessagePumpCFRunLoopBase::EnterExitObserver(CFRunLoopObserverRef observer, |
| 399 CFRunLoopActivity activity, | 416 CFRunLoopActivity activity, |
| 400 void* info) { | 417 void* info) { |
| 401 MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info); | 418 MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info); |
| 419 static uint32 last_id = 0; |
| 420 |
| 421 if (activity == kCFRunLoopEntry) |
| 422 self->nesting_stack_.push(++last_id); |
| 423 |
| 424 uint64_t trace_id = ((uintptr_t)observer << sizeof(uint32)) | self->nesting_st
ack_.top(); |
| 402 | 425 |
| 403 switch (activity) { | 426 switch (activity) { |
| 404 case kCFRunLoopEntry: | 427 case kCFRunLoopEntry: |
| 428 TRACE_EVENT_ASYNC_BEGIN0("CFRunLoop", "LoopCycle", trace_id); |
| 405 ++self->nesting_level_; | 429 ++self->nesting_level_; |
| 406 if (self->nesting_level_ > self->deepest_nesting_level_) { | 430 if (self->nesting_level_ > self->deepest_nesting_level_) { |
| 407 self->deepest_nesting_level_ = self->nesting_level_; | 431 self->deepest_nesting_level_ = self->nesting_level_; |
| 408 } | 432 } |
| 409 break; | 433 break; |
| 410 | 434 |
| 411 case kCFRunLoopExit: | 435 case kCFRunLoopExit: |
| 412 // Not all run loops go to sleep. If a run loop is stopped before it | 436 // Not all run loops go to sleep. If a run loop is stopped before it |
| 413 // goes to sleep due to a CFRunLoopStop call, or if the timeout passed | 437 // goes to sleep due to a CFRunLoopStop call, or if the timeout passed |
| 414 // to CFRunLoopRunInMode expires, the run loop may proceed directly from | 438 // to CFRunLoopRunInMode expires, the run loop may proceed directly from |
| 415 // handling sources to exiting without any sleep. This most commonly | 439 // handling sources to exiting without any sleep. This most commonly |
| 416 // occurs when CFRunLoopRunInMode is passed a timeout of 0, causing it | 440 // occurs when CFRunLoopRunInMode is passed a timeout of 0, causing it |
| 417 // to make a single pass through the loop and exit without sleep. Some | 441 // to make a single pass through the loop and exit without sleep. Some |
| 418 // native loops use CFRunLoop in this way. Because PreWaitObserver will | 442 // native loops use CFRunLoop in this way. Because PreWaitObserver will |
| 419 // not be called in these case, MaybeScheduleNestingDeferredWork needs | 443 // not be called in these case, MaybeScheduleNestingDeferredWork needs |
| 420 // to be called here, as the run loop exits. | 444 // to be called here, as the run loop exits. |
| 421 // | 445 // |
| 422 // MaybeScheduleNestingDeferredWork consults self->nesting_level_ | 446 // MaybeScheduleNestingDeferredWork consults self->nesting_level_ |
| 423 // to determine whether to schedule nesting-deferred work. It expects | 447 // to determine whether to schedule nesting-deferred work. It expects |
| 424 // the nesting level to be set to the depth of the loop that is going | 448 // the nesting level to be set to the depth of the loop that is going |
| 425 // to sleep or exiting. It must be called before decrementing the | 449 // to sleep or exiting. It must be called before decrementing the |
| 426 // value so that the value still corresponds to the level of the exiting | 450 // value so that the value still corresponds to the level of the exiting |
| 427 // loop. | 451 // loop. |
| 428 self->MaybeScheduleNestingDeferredWork(); | 452 self->MaybeScheduleNestingDeferredWork(); |
| 429 --self->nesting_level_; | 453 --self->nesting_level_; |
| 454 TRACE_EVENT_ASYNC_END0("CFRunLoop", "LoopCycle", trace_id); |
| 455 self->nesting_stack_.pop(); |
| 430 break; | 456 break; |
| 431 | 457 |
| 432 default: | 458 default: |
| 433 break; | 459 break; |
| 434 } | 460 } |
| 435 | 461 |
| 436 self->EnterExitRunLoop(activity); | 462 self->EnterExitRunLoop(activity); |
| 437 } | 463 } |
| 438 | 464 |
| 439 // Called by MessagePumpCFRunLoopBase::EnterExitRunLoop. The default | 465 // Called by MessagePumpCFRunLoopBase::EnterExitRunLoop. The default |
| (...skipping 14 matching lines...) Expand all Loading... |
| 454 | 480 |
| 455 // Called by MessagePumpCFRunLoopBase::DoRun. If other CFRunLoopRun loops were | 481 // Called by MessagePumpCFRunLoopBase::DoRun. If other CFRunLoopRun loops were |
| 456 // running lower on the run loop thread's stack when this object was created, | 482 // running lower on the run loop thread's stack when this object was created, |
| 457 // the same number of CFRunLoopRun loops must be running for the outermost call | 483 // the same number of CFRunLoopRun loops must be running for the outermost call |
| 458 // to Run. Run/DoRun are reentrant after that point. | 484 // to Run. Run/DoRun are reentrant after that point. |
| 459 void MessagePumpCFRunLoop::DoRun(Delegate* delegate) { | 485 void MessagePumpCFRunLoop::DoRun(Delegate* delegate) { |
| 460 // This is completely identical to calling CFRunLoopRun(), except autorelease | 486 // This is completely identical to calling CFRunLoopRun(), except autorelease |
| 461 // pool management is introduced. | 487 // pool management is introduced. |
| 462 int result; | 488 int result; |
| 463 do { | 489 do { |
| 490 TRACE_EVENT0("CFRunLoop", "DoRun"); |
| 464 MessagePumpScopedAutoreleasePool autorelease_pool(this); | 491 MessagePumpScopedAutoreleasePool autorelease_pool(this); |
| 465 result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, | 492 result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, |
| 466 kCFTimeIntervalMax, | 493 kCFTimeIntervalMax, |
| 467 false); | 494 false); |
| 468 } while (result != kCFRunLoopRunStopped && result != kCFRunLoopRunFinished); | 495 } while (result != kCFRunLoopRunStopped && result != kCFRunLoopRunFinished); |
| 469 } | 496 } |
| 470 | 497 |
| 471 // Must be called on the run loop thread. | 498 // Must be called on the run loop thread. |
| 472 void MessagePumpCFRunLoop::Quit() { | 499 void MessagePumpCFRunLoop::Quit() { |
| 473 // Stop the innermost run loop managed by this MessagePumpCFRunLoop object. | 500 // Stop the innermost run loop managed by this MessagePumpCFRunLoop object. |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 508 CFRunLoopAddSource(run_loop(), quit_source_, kCFRunLoopCommonModes); | 535 CFRunLoopAddSource(run_loop(), quit_source_, kCFRunLoopCommonModes); |
| 509 } | 536 } |
| 510 | 537 |
| 511 MessagePumpNSRunLoop::~MessagePumpNSRunLoop() { | 538 MessagePumpNSRunLoop::~MessagePumpNSRunLoop() { |
| 512 CFRunLoopRemoveSource(run_loop(), quit_source_, kCFRunLoopCommonModes); | 539 CFRunLoopRemoveSource(run_loop(), quit_source_, kCFRunLoopCommonModes); |
| 513 CFRelease(quit_source_); | 540 CFRelease(quit_source_); |
| 514 } | 541 } |
| 515 | 542 |
| 516 void MessagePumpNSRunLoop::DoRun(Delegate* delegate) { | 543 void MessagePumpNSRunLoop::DoRun(Delegate* delegate) { |
| 517 while (keep_running_) { | 544 while (keep_running_) { |
| 545 TRACE_EVENT0("NSRunLoop", "DoRun"); |
| 518 // NSRunLoop manages autorelease pools itself. | 546 // NSRunLoop manages autorelease pools itself. |
| 519 [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode | 547 [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode |
| 520 beforeDate:[NSDate distantFuture]]; | 548 beforeDate:[NSDate distantFuture]]; |
| 521 } | 549 } |
| 522 | 550 |
| 523 keep_running_ = true; | 551 keep_running_ = true; |
| 524 } | 552 } |
| 525 | 553 |
| 526 void MessagePumpNSRunLoop::Quit() { | 554 void MessagePumpNSRunLoop::Quit() { |
| 527 keep_running_ = false; | 555 keep_running_ = false; |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 571 CHECK(NSApp); | 599 CHECK(NSApp); |
| 572 | 600 |
| 573 if (![NSApp isRunning]) { | 601 if (![NSApp isRunning]) { |
| 574 running_own_loop_ = false; | 602 running_own_loop_ = false; |
| 575 // NSApplication manages autorelease pools itself when run this way. | 603 // NSApplication manages autorelease pools itself when run this way. |
| 576 [NSApp run]; | 604 [NSApp run]; |
| 577 } else { | 605 } else { |
| 578 running_own_loop_ = true; | 606 running_own_loop_ = true; |
| 579 NSDate* distant_future = [NSDate distantFuture]; | 607 NSDate* distant_future = [NSDate distantFuture]; |
| 580 while (keep_running_) { | 608 while (keep_running_) { |
| 609 TRACE_EVENT0("NSApplication", "DoRun"); |
| 581 MessagePumpScopedAutoreleasePool autorelease_pool(this); | 610 MessagePumpScopedAutoreleasePool autorelease_pool(this); |
| 582 NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask | 611 NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask |
| 583 untilDate:distant_future | 612 untilDate:distant_future |
| 584 inMode:NSDefaultRunLoopMode | 613 inMode:NSDefaultRunLoopMode |
| 585 dequeue:YES]; | 614 dequeue:YES]; |
| 586 if (event) { | 615 if (event) { |
| 587 [NSApp sendEvent:event]; | 616 [NSApp sendEvent:event]; |
| 588 } | 617 } |
| 589 } | 618 } |
| 590 keep_running_ = true; | 619 keep_running_ = true; |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 695 [NSApplication sharedApplication]; | 724 [NSApplication sharedApplication]; |
| 696 g_not_using_cr_app = true; | 725 g_not_using_cr_app = true; |
| 697 return new MessagePumpNSApplication; | 726 return new MessagePumpNSApplication; |
| 698 #endif | 727 #endif |
| 699 } | 728 } |
| 700 | 729 |
| 701 return new MessagePumpNSRunLoop; | 730 return new MessagePumpNSRunLoop; |
| 702 } | 731 } |
| 703 | 732 |
| 704 } // namespace base | 733 } // namespace base |
| OLD | NEW |