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 #include <dlfcn.h> | 7 #include <dlfcn.h> |
8 #import <Foundation/Foundation.h> | 8 #import <Foundation/Foundation.h> |
9 | 9 |
10 #include <limits> | 10 #include <limits> |
(...skipping 535 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
546 if (instrumentation_) | 546 if (instrumentation_) |
547 instrumentation_->WorkSourceEntered(delegate_); | 547 instrumentation_->WorkSourceEntered(delegate_); |
548 | 548 |
549 // The NSApplication-based run loop only drains the autorelease pool at each | 549 // The NSApplication-based run loop only drains the autorelease pool at each |
550 // UI event (NSEvent). The autorelease pool is not drained for each | 550 // UI event (NSEvent). The autorelease pool is not drained for each |
551 // CFRunLoopSource target that's run. Use a local pool for any autoreleased | 551 // CFRunLoopSource target that's run. Use a local pool for any autoreleased |
552 // objects if the app is not currently handling a UI event to ensure they're | 552 // objects if the app is not currently handling a UI event to ensure they're |
553 // released promptly even in the absence of UI events. | 553 // released promptly even in the absence of UI events. |
554 MessagePumpScopedAutoreleasePool autorelease_pool(this); | 554 MessagePumpScopedAutoreleasePool autorelease_pool(this); |
555 | 555 |
556 // Call DoWork and DoDelayedWork once, and if something was done, arrange to | 556 // Allocate a time slice in which as many tasks as possible will be run. |
557 // come back here again as long as the loop is still running. | 557 // Performing only one task per run loop tick is potentially inefficient in |
558 bool did_work = delegate_->DoWork(); | 558 // the face of a large backlog of pending tasks. https://crbug.com/264886 |
559 bool resignal_work_source = did_work; | 559 base::TimeTicks now = base::TimeTicks::Now(); |
| 560 base::TimeTicks time_slice_end = now + base::TimeDelta::FromMilliseconds(50); |
| 561 int ran_task_count = 0; |
| 562 bool did_work = false, did_work_last_slice = true; |
| 563 for ( ; |
| 564 now < time_slice_end && did_work_last_slice; |
| 565 now = base::TimeTicks::Now()) { |
| 566 quit_was_called_ = false; |
| 567 did_work_last_slice = delegate_->DoWork(); |
| 568 did_work |= did_work_last_slice; |
| 569 if (quit_was_called_) |
| 570 break; |
| 571 if (did_work_last_slice) |
| 572 ++ran_task_count; |
| 573 } |
| 574 |
| 575 // Record how many tasks were accomplished in the time slice, and by how |
| 576 // much the work overran the time slice deadline. |
| 577 UMA_HISTOGRAM_CUSTOM_TIMES("MessagePumpMac.TimeSliceOverRun", |
| 578 time_slice_end - base::TimeTicks::Now(), |
| 579 base::TimeDelta::FromMilliseconds(1), |
| 580 base::TimeDelta::FromSeconds(5), |
| 581 100); |
| 582 UMA_HISTOGRAM_COUNTS("MessagePumpMac.TimeSliceTaskCount", ran_task_count); |
| 583 |
| 584 if (quit_was_called_) |
| 585 return false; |
| 586 |
| 587 // If the time slice expired and work was done in the last fraction of the |
| 588 // time slice, arrange to come back here to execute more tasks. |
| 589 bool resignal_work_source = did_work_last_slice; |
560 | 590 |
561 TimeTicks next_time; | 591 TimeTicks next_time; |
562 delegate_->DoDelayedWork(&next_time); | 592 delegate_->DoDelayedWork(&next_time); |
563 if (!did_work) { | 593 if (!did_work) { |
564 // Determine whether there's more delayed work, and if so, if it needs to | 594 // Determine whether there's more delayed work, and if so, if it needs to |
565 // be done at some point in the future or if it's already time to do it. | 595 // be done at some point in the future or if it's already time to do it. |
566 // Only do these checks if did_work is false. If did_work is true, this | 596 // Only do these checks if did_work is false. If did_work is true, this |
567 // function, and therefore any additional delayed work, will get another | 597 // function, and therefore any additional delayed work, will get another |
568 // chance to run before the loop goes to sleep. | 598 // chance to run before the loop goes to sleep. |
569 bool more_delayed_work = !next_time.is_null(); | 599 bool more_delayed_work = !next_time.is_null(); |
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
788 do { | 818 do { |
789 MessagePumpScopedAutoreleasePool autorelease_pool(this); | 819 MessagePumpScopedAutoreleasePool autorelease_pool(this); |
790 result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, | 820 result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, |
791 kCFTimeIntervalMax, | 821 kCFTimeIntervalMax, |
792 false); | 822 false); |
793 } while (result != kCFRunLoopRunStopped && result != kCFRunLoopRunFinished); | 823 } while (result != kCFRunLoopRunStopped && result != kCFRunLoopRunFinished); |
794 } | 824 } |
795 | 825 |
796 // Must be called on the run loop thread. | 826 // Must be called on the run loop thread. |
797 void MessagePumpCFRunLoop::Quit() { | 827 void MessagePumpCFRunLoop::Quit() { |
| 828 quit_was_called_ = true; |
798 // Stop the innermost run loop managed by this MessagePumpCFRunLoop object. | 829 // Stop the innermost run loop managed by this MessagePumpCFRunLoop object. |
799 if (nesting_level() == run_nesting_level()) { | 830 if (nesting_level() == run_nesting_level()) { |
800 // This object is running the innermost loop, just stop it. | 831 // This object is running the innermost loop, just stop it. |
801 CFRunLoopStop(run_loop()); | 832 CFRunLoopStop(run_loop()); |
802 } else { | 833 } else { |
803 // There's another loop running inside the loop managed by this object. | 834 // There's another loop running inside the loop managed by this object. |
804 // In other words, someone else called CFRunLoopRunInMode on the same | 835 // In other words, someone else called CFRunLoopRunInMode on the same |
805 // thread, deeper on the stack than the deepest Run call. Don't preempt | 836 // thread, deeper on the stack than the deepest Run call. Don't preempt |
806 // other run loops, just mark this object to quit the innermost Run as | 837 // other run loops, just mark this object to quit the innermost Run as |
807 // soon as the other inner loops not managed by Run are done. | 838 // soon as the other inner loops not managed by Run are done. |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
842 while (keep_running_) { | 873 while (keep_running_) { |
843 // NSRunLoop manages autorelease pools itself. | 874 // NSRunLoop manages autorelease pools itself. |
844 [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode | 875 [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode |
845 beforeDate:[NSDate distantFuture]]; | 876 beforeDate:[NSDate distantFuture]]; |
846 } | 877 } |
847 | 878 |
848 keep_running_ = true; | 879 keep_running_ = true; |
849 } | 880 } |
850 | 881 |
851 void MessagePumpNSRunLoop::Quit() { | 882 void MessagePumpNSRunLoop::Quit() { |
| 883 quit_was_called_ = true; |
852 keep_running_ = false; | 884 keep_running_ = false; |
853 CFRunLoopSourceSignal(quit_source_); | 885 CFRunLoopSourceSignal(quit_source_); |
854 CFRunLoopWakeUp(run_loop()); | 886 CFRunLoopWakeUp(run_loop()); |
855 } | 887 } |
856 | 888 |
857 #if defined(OS_IOS) | 889 #if defined(OS_IOS) |
858 MessagePumpUIApplication::MessagePumpUIApplication() | 890 MessagePumpUIApplication::MessagePumpUIApplication() |
859 : run_loop_(NULL) { | 891 : run_loop_(NULL) { |
860 } | 892 } |
861 | 893 |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
916 [NSApp sendEvent:event]; | 948 [NSApp sendEvent:event]; |
917 } | 949 } |
918 } | 950 } |
919 keep_running_ = true; | 951 keep_running_ = true; |
920 } | 952 } |
921 | 953 |
922 running_own_loop_ = last_running_own_loop_; | 954 running_own_loop_ = last_running_own_loop_; |
923 } | 955 } |
924 | 956 |
925 void MessagePumpNSApplication::Quit() { | 957 void MessagePumpNSApplication::Quit() { |
| 958 quit_was_called_ = true; |
926 if (!running_own_loop_) { | 959 if (!running_own_loop_) { |
927 [[NSApplication sharedApplication] stop:nil]; | 960 [[NSApplication sharedApplication] stop:nil]; |
928 } else { | 961 } else { |
929 keep_running_ = false; | 962 keep_running_ = false; |
930 } | 963 } |
931 | 964 |
932 // Send a fake event to wake the loop up. | 965 // Send a fake event to wake the loop up. |
933 [NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined | 966 [NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined |
934 location:NSZeroPoint | 967 location:NSZeroPoint |
935 modifierFlags:0 | 968 modifierFlags:0 |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1024 [NSApplication sharedApplication]; | 1057 [NSApplication sharedApplication]; |
1025 g_not_using_cr_app = true; | 1058 g_not_using_cr_app = true; |
1026 return new MessagePumpNSApplication; | 1059 return new MessagePumpNSApplication; |
1027 #endif | 1060 #endif |
1028 } | 1061 } |
1029 | 1062 |
1030 return new MessagePumpNSRunLoop; | 1063 return new MessagePumpNSRunLoop; |
1031 } | 1064 } |
1032 | 1065 |
1033 } // namespace base | 1066 } // namespace base |
OLD | NEW |