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 |