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

Side by Side Diff: base/message_loop/message_pump_mac.mm

Issue 22911026: Add instrumentation to the MessagePumpMac family of classes. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address comments Created 7 years, 4 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
OLDNEW
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 #include <stack>
10 11
11 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/mac/scoped_cftyperef.h"
14 #include "base/metrics/histogram.h"
12 #include "base/run_loop.h" 15 #include "base/run_loop.h"
16 #include "base/strings/stringprintf.h"
13 #include "base/time/time.h" 17 #include "base/time/time.h"
14 18
15 #if !defined(OS_IOS) 19 #if !defined(OS_IOS)
16 #import <AppKit/AppKit.h> 20 #import <AppKit/AppKit.h>
17 #endif // !defined(OS_IOS) 21 #endif // !defined(OS_IOS)
18 22
19 namespace { 23 namespace {
20 24
21 void NoOp(void* info) { 25 void NoOp(void* info) {
22 } 26 }
(...skipping 21 matching lines...) Expand all
44 } 48 }
45 ~MessagePumpScopedAutoreleasePool() { 49 ~MessagePumpScopedAutoreleasePool() {
46 [pool_ drain]; 50 [pool_ drain];
47 } 51 }
48 52
49 private: 53 private:
50 NSAutoreleasePool* pool_; 54 NSAutoreleasePool* pool_;
51 DISALLOW_COPY_AND_ASSIGN(MessagePumpScopedAutoreleasePool); 55 DISALLOW_COPY_AND_ASSIGN(MessagePumpScopedAutoreleasePool);
52 }; 56 };
53 57
58 // This class is used to instrument the MessagePump to gather various timing
59 // data about when the underlying run loop is entered, when it is waiting, and
60 // when it is servicing its delegate.
61 //
62 // The metrics are gathered as UMA-tracked histograms. To gather the data over
63 // time, sampling is used, such that a new histogram is created for each metric
64 // every |sampling_interval| for |sampling_duration|. After sampling is
65 // complete, this class deletes itself.
66 class MessagePumpInstrumentation {
67 public:
68 // Creates an instrument for the MessagePump on the current thread. Every
69 // |sampling_interval|, a new histogram will be created to track the metrics
70 // over time. After |sampling_duration|, this will delete itself, causing the
71 // WeakPtr to go NULL.
72 static WeakPtr<MessagePumpInstrumentation> Create(
73 const TimeDelta& sampling_interval,
74 const TimeDelta& sampling_duration) {
75 MessagePumpInstrumentation* instrument =
76 new MessagePumpInstrumentation(sampling_interval, sampling_duration);
77 return instrument->weak_ptr_factory_.GetWeakPtr();
78 }
79
80 // Starts the timer that runs the sampling instrumentation. Can be called
81 // multiple times as a noop.
82 void StartIfNeeded() {
83 if (timer_)
84 return;
85
86 sampling_start_time_ = generation_start_time_ = TimeTicks::Now();
87
88 CFRunLoopTimerContext timer_context = { .info = this };
89 timer_.reset(CFRunLoopTimerCreate(
90 NULL, // allocator
91 (Time::Now() + sampling_interval_).ToCFAbsoluteTime(),
92 sampling_interval_.InSecondsF(),
93 0, // flags
94 0, // order
95 &MessagePumpInstrumentation::TimerFired,
96 &timer_context));
97 CFRunLoopAddTimer(CFRunLoopGetCurrent(),
98 timer_,
99 kCFRunLoopCommonModes);
100 }
101
102 // Used to track kCFRunLoopEntry.
103 void LoopEntered() {
104 loop_run_times_.push(TimeTicks::Now());
105 }
106
107 // Used to track kCFRunLoopExit.
108 void LoopExited() {
109 TimeDelta duration = TimeTicks::Now() - loop_run_times_.top();
110 loop_run_times_.pop();
111 GetHistogram(LOOP_CYCLE)->AddTime(duration);
112 }
113
114 // Used to track kCFRunLoopBeforeWaiting.
115 void WaitingStarted() {
116 loop_wait_times_.push(TimeTicks::Now());
117 }
118
119 // Used to track kCFRunLoopAfterWaiting.
120 void WaitingFinished() {
121 TimeDelta duration = TimeTicks::Now() - loop_wait_times_.top();
122 loop_wait_times_.pop();
123 GetHistogram(LOOP_WAIT)->AddTime(duration);
124 }
125
126 // Used to track when the MessagePump will invoke its |delegate|.
127 void WorkSourceEntered(MessagePump::Delegate* delegate) {
128 work_source_times_.push(TimeTicks::Now());
129 if (delegate) {
130 size_t queue_size;
131 TimeDelta queuing_delay;
132 delegate->GetQueueingInformation(&queue_size, &queuing_delay);
133 GetHistogram(QUEUE_SIZE)->Add(queue_size);
134 GetHistogram(QUEUE_DELAY)->AddTime(queuing_delay);
135 }
136 }
137
138 // Used to track the completion of servicing the MessagePump::Delegate.
139 void WorkSourceExited() {
140 TimeDelta duration = TimeTicks::Now() - work_source_times_.top();
141 work_source_times_.pop();
142 GetHistogram(WORK_SOURCE)->AddTime(duration);
143 }
144
145 private:
146 enum HistogramEvent {
147 // Time-based histograms:
148 LOOP_CYCLE, // LoopEntered/LoopExited
149 LOOP_WAIT, // WaitingStarted/WaitingEnded
150 WORK_SOURCE, // WorkSourceExited
151 QUEUE_DELAY, // WorkSourceEntered
152
153 // Value-based histograms:
154 // NOTE: Do not add value-based histograms before this event, only after.
155 QUEUE_SIZE, // WorkSourceEntered
156
157 HISTOGRAM_EVENT_MAX,
158 };
159
160 MessagePumpInstrumentation(const TimeDelta& sampling_interval,
161 const TimeDelta& sampling_duration)
162 : weak_ptr_factory_(this),
163 sampling_interval_(sampling_interval),
164 sampling_duration_(sampling_duration),
165 sample_generation_(0) {
166 // Create all the histogram objects that will be used for sampling.
167 const char kHistogramName[] = "MessagePumpMac.%s.SampleMs.%lld";
Mark Mentovai 2013/08/22 18:00:12 Can you use PRId64 here?
Robert Sesek 2013/08/22 19:12:21 Done.
168 for (TimeDelta i; i < sampling_duration_; i += sampling_interval_) {
169 int64 sample = i.InMilliseconds();
170
171 // Generate the time-based histograms.
172 for (HistogramEvent j = LOOP_CYCLE; j < QUEUE_SIZE; ++j) {
173 std::string name = StringPrintf(kHistogramName, NameForEnum(j), sample);
174 histograms_[j].push_back(
175 Histogram::FactoryTimeGet(name, TimeDelta::FromMilliseconds(1),
176 sampling_interval_, 50,
177 HistogramBase::kUmaTargetedHistogramFlag));
178 }
179
180 // Generate the value-based histograms.
181 for (HistogramEvent j = QUEUE_SIZE; j < HISTOGRAM_EVENT_MAX; ++j) {
182 std::string name = StringPrintf(kHistogramName, NameForEnum(j), sample);
183 histograms_[j].push_back(
184 Histogram::FactoryGet(name, 1, 10000, 50,
185 HistogramBase::kUmaTargetedHistogramFlag));
186 }
187 }
188 }
189
190 ~MessagePumpInstrumentation() {
191 if (timer_)
192 CFRunLoopTimerInvalidate(timer_);
193 }
194
195 const char* NameForEnum(HistogramEvent event) {
196 switch (event) {
197 case LOOP_CYCLE: return "LoopCycle";
198 case LOOP_WAIT: return "Waiting";
199 case WORK_SOURCE: return "WorkSource";
200 case QUEUE_DELAY: return "QueueingDelay";
201 case QUEUE_SIZE: return "QueueSize";
202 default:
203 NOTREACHED();
204 return NULL;
205 }
206 }
207
208 static void TimerFired(CFRunLoopTimerRef timer, void* context) {
209 static_cast<MessagePumpInstrumentation*>(context)->TimerFired();
210 }
211
212 // Called by the run loop when the sampling_interval_ has elapsed. Advances
213 // the sample_generation_, which controls into which histogram data is
214 // recorded, while recording and accounting for timer skew. Will delete this
215 // object after |sampling_duration_| has elapsed.
216 void TimerFired() {
217 TimeTicks now = TimeTicks::Now();
218 TimeDelta delta = now - generation_start_time_;
219
220 UMA_HISTOGRAM_TIMES("MessagePumpMac.TimerSkew", sampling_interval_ - delta);
221
222 // The timer fired, so advance the generation by at least one.
223 ++sample_generation_;
224
225 // To account for large timer skew/drift, advance the generation by any
226 // more completed intervals.
227 for (TimeDelta skew_advance = delta - sampling_interval_;
228 skew_advance >= sampling_interval_;
229 skew_advance -= sampling_interval_) {
230 ++sample_generation_;
231 }
232
233 generation_start_time_ = now;
234 if (now >= sampling_start_time_ + sampling_duration_)
235 delete this;
236 }
237
238 HistogramBase* GetHistogram(HistogramEvent event) {
239 DCHECK_LT(sample_generation_, histograms_[event].size());
240 return histograms_[event][sample_generation_];
241 }
242
243 // Vends the pointer to the Create()or.
244 WeakPtrFactory<MessagePumpInstrumentation> weak_ptr_factory_;
245
246 // The interval and duration of the sampling, as well as the number of
247 // times the timer has fired.
248 TimeDelta sampling_interval_;
249 TimeDelta sampling_duration_;
250
251 // The time at which sampling started.
252 TimeTicks sampling_start_time_;
253
254 base::ScopedCFTypeRef<CFRunLoopTimerRef> timer_;
255
256 // The time at which MaybeAdvanceGeneration() was last called. If this plus
257 // the sample_interval_ is greater than the current time, the
258 // sample_generation_ is advanced to select the proper histogram bucket.
259 TimeTicks generation_start_time_;
260 size_t sample_generation_;
261
262 // The two-dimensional array of histograms. The first dimension is the
263 // HistogramEvent type. The second is for the sampling intervals.
264 std::vector<HistogramBase*> histograms_[HISTOGRAM_EVENT_MAX];
265
266 // MessagePump activations can be nested. Use a stack for each of the
267 // possibly reentrant HistogramEvent types to properly balance and calculate
268 // the timing information.
269 std::stack<TimeTicks> loop_run_times_;
270 std::stack<TimeTicks> loop_wait_times_;
271 std::stack<TimeTicks> work_source_times_;
272
273 DISALLOW_COPY_AND_ASSIGN(MessagePumpInstrumentation);
274 };
275
54 // Must be called on the run loop thread. 276 // Must be called on the run loop thread.
55 MessagePumpCFRunLoopBase::MessagePumpCFRunLoopBase() 277 MessagePumpCFRunLoopBase::MessagePumpCFRunLoopBase()
56 : delegate_(NULL), 278 : delegate_(NULL),
57 delayed_work_fire_time_(kCFTimeIntervalMax), 279 delayed_work_fire_time_(kCFTimeIntervalMax),
58 nesting_level_(0), 280 nesting_level_(0),
59 run_nesting_level_(0), 281 run_nesting_level_(0),
60 deepest_nesting_level_(0), 282 deepest_nesting_level_(0),
61 delegateless_work_(false), 283 delegateless_work_(false),
62 delegateless_idle_work_(false) { 284 delegateless_idle_work_(false) {
63 run_loop_ = CFRunLoopGetCurrent(); 285 run_loop_ = CFRunLoopGetCurrent();
(...skipping 30 matching lines...) Expand all
94 source_context.perform = RunNestingDeferredWorkSource; 316 source_context.perform = RunNestingDeferredWorkSource;
95 nesting_deferred_work_source_ = CFRunLoopSourceCreate(NULL, // allocator 317 nesting_deferred_work_source_ = CFRunLoopSourceCreate(NULL, // allocator
96 0, // priority 318 0, // priority
97 &source_context); 319 &source_context);
98 CFRunLoopAddSource(run_loop_, nesting_deferred_work_source_, 320 CFRunLoopAddSource(run_loop_, nesting_deferred_work_source_,
99 kCFRunLoopCommonModes); 321 kCFRunLoopCommonModes);
100 322
101 CFRunLoopObserverContext observer_context = CFRunLoopObserverContext(); 323 CFRunLoopObserverContext observer_context = CFRunLoopObserverContext();
102 observer_context.info = this; 324 observer_context.info = this;
103 pre_wait_observer_ = CFRunLoopObserverCreate(NULL, // allocator 325 pre_wait_observer_ = CFRunLoopObserverCreate(NULL, // allocator
104 kCFRunLoopBeforeWaiting, 326 kCFRunLoopBeforeWaiting |
327 kCFRunLoopAfterWaiting,
105 true, // repeat 328 true, // repeat
106 0, // priority 329 0, // priority
107 PreWaitObserver, 330 PrePostWaitObserver,
108 &observer_context); 331 &observer_context);
109 CFRunLoopAddObserver(run_loop_, pre_wait_observer_, kCFRunLoopCommonModes); 332 CFRunLoopAddObserver(run_loop_, pre_wait_observer_, kCFRunLoopCommonModes);
110 333
111 pre_source_observer_ = CFRunLoopObserverCreate(NULL, // allocator 334 pre_source_observer_ = CFRunLoopObserverCreate(NULL, // allocator
112 kCFRunLoopBeforeSources, 335 kCFRunLoopBeforeSources,
113 true, // repeat 336 true, // repeat
114 0, // priority 337 0, // priority
115 PreSourceObserver, 338 PreSourceObserver,
116 &observer_context); 339 &observer_context);
117 CFRunLoopAddObserver(run_loop_, pre_source_observer_, kCFRunLoopCommonModes); 340 CFRunLoopAddObserver(run_loop_, pre_source_observer_, kCFRunLoopCommonModes);
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
186 CFRunLoopSourceSignal(work_source_); 409 CFRunLoopSourceSignal(work_source_);
187 delegateless_work_ = false; 410 delegateless_work_ = false;
188 } 411 }
189 if (delegateless_idle_work_) { 412 if (delegateless_idle_work_) {
190 CFRunLoopSourceSignal(idle_work_source_); 413 CFRunLoopSourceSignal(idle_work_source_);
191 delegateless_idle_work_ = false; 414 delegateless_idle_work_ = false;
192 } 415 }
193 } 416 }
194 } 417 }
195 418
419 void MessagePumpCFRunLoopBase::EnableInstrumentation() {
420 instrumentation_ = MessagePumpInstrumentation::Create(
421 TimeDelta::FromSeconds(1), TimeDelta::FromSeconds(15));
422 }
423
196 // May be called on any thread. 424 // May be called on any thread.
197 void MessagePumpCFRunLoopBase::ScheduleWork() { 425 void MessagePumpCFRunLoopBase::ScheduleWork() {
198 CFRunLoopSourceSignal(work_source_); 426 CFRunLoopSourceSignal(work_source_);
199 CFRunLoopWakeUp(run_loop_); 427 CFRunLoopWakeUp(run_loop_);
200 } 428 }
201 429
202 // Must be called on the run loop thread. 430 // Must be called on the run loop thread.
203 void MessagePumpCFRunLoopBase::ScheduleDelayedWork( 431 void MessagePumpCFRunLoopBase::ScheduleDelayedWork(
204 const TimeTicks& delayed_work_time) { 432 const TimeTicks& delayed_work_time) {
205 TimeDelta delta = delayed_work_time - TimeTicks::Now(); 433 TimeDelta delta = delayed_work_time - TimeTicks::Now();
(...skipping 27 matching lines...) Expand all
233 // Called by MessagePumpCFRunLoopBase::RunWorkSource. 461 // Called by MessagePumpCFRunLoopBase::RunWorkSource.
234 bool MessagePumpCFRunLoopBase::RunWork() { 462 bool MessagePumpCFRunLoopBase::RunWork() {
235 if (!delegate_) { 463 if (!delegate_) {
236 // This point can be reached with a NULL delegate_ if Run is not on the 464 // 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 465 // stack but foreign code is spinning the CFRunLoop. Arrange to come back
238 // here when a delegate is available. 466 // here when a delegate is available.
239 delegateless_work_ = true; 467 delegateless_work_ = true;
240 return false; 468 return false;
241 } 469 }
242 470
471 if (instrumentation_)
472 instrumentation_->WorkSourceEntered(delegate_);
473
243 // The NSApplication-based run loop only drains the autorelease pool at each 474 // The NSApplication-based run loop only drains the autorelease pool at each
244 // UI event (NSEvent). The autorelease pool is not drained for each 475 // UI event (NSEvent). The autorelease pool is not drained for each
245 // CFRunLoopSource target that's run. Use a local pool for any autoreleased 476 // CFRunLoopSource target that's run. Use a local pool for any autoreleased
246 // objects if the app is not currently handling a UI event to ensure they're 477 // objects if the app is not currently handling a UI event to ensure they're
247 // released promptly even in the absence of UI events. 478 // released promptly even in the absence of UI events.
248 MessagePumpScopedAutoreleasePool autorelease_pool(this); 479 MessagePumpScopedAutoreleasePool autorelease_pool(this);
249 480
250 // Call DoWork and DoDelayedWork once, and if something was done, arrange to 481 // Call DoWork and DoDelayedWork once, and if something was done, arrange to
251 // come back here again as long as the loop is still running. 482 // come back here again as long as the loop is still running.
252 bool did_work = delegate_->DoWork(); 483 bool did_work = delegate_->DoWork();
(...skipping 19 matching lines...) Expand all
272 // running. 503 // running.
273 resignal_work_source = true; 504 resignal_work_source = true;
274 } 505 }
275 } 506 }
276 } 507 }
277 508
278 if (resignal_work_source) { 509 if (resignal_work_source) {
279 CFRunLoopSourceSignal(work_source_); 510 CFRunLoopSourceSignal(work_source_);
280 } 511 }
281 512
513 if (instrumentation_)
514 instrumentation_->WorkSourceExited();
515
282 return resignal_work_source; 516 return resignal_work_source;
283 } 517 }
284 518
285 // Called from the run loop. 519 // Called from the run loop.
286 // static 520 // static
287 void MessagePumpCFRunLoopBase::RunIdleWorkSource(void* info) { 521 void MessagePumpCFRunLoopBase::RunIdleWorkSource(void* info) {
288 MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info); 522 MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
289 self->RunIdleWork(); 523 self->RunIdleWork();
290 } 524 }
291 525
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
356 // nesting-deferred work in case any work was deferred because nested work 590 // nesting-deferred work in case any work was deferred because nested work
357 // was disallowed. 591 // was disallowed.
358 if (deepest_nesting_level_ > nesting_level_) { 592 if (deepest_nesting_level_ > nesting_level_) {
359 deepest_nesting_level_ = nesting_level_; 593 deepest_nesting_level_ = nesting_level_;
360 CFRunLoopSourceSignal(nesting_deferred_work_source_); 594 CFRunLoopSourceSignal(nesting_deferred_work_source_);
361 } 595 }
362 } 596 }
363 597
364 // Called from the run loop. 598 // Called from the run loop.
365 // static 599 // static
366 void MessagePumpCFRunLoopBase::PreWaitObserver(CFRunLoopObserverRef observer, 600 void MessagePumpCFRunLoopBase::PrePostWaitObserver(
367 CFRunLoopActivity activity, 601 CFRunLoopObserverRef observer,
368 void* info) { 602 CFRunLoopActivity activity,
603 void* info) {
369 MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info); 604 MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
370 605
606 if (activity == kCFRunLoopAfterWaiting) {
607 if (self->instrumentation_)
608 self->instrumentation_->WaitingFinished();
609 return;
610 }
611
371 // Attempt to do some idle work before going to sleep. 612 // Attempt to do some idle work before going to sleep.
372 self->RunIdleWork(); 613 self->RunIdleWork();
373 614
374 // The run loop is about to go to sleep. If any of the work done since it 615 // 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, 616 // started or woke up resulted in a nested run loop running,
376 // nesting-deferred work may have accumulated. Schedule it for processing 617 // nesting-deferred work may have accumulated. Schedule it for processing
377 // if appropriate. 618 // if appropriate.
378 self->MaybeScheduleNestingDeferredWork(); 619 self->MaybeScheduleNestingDeferredWork();
620
621 if (self->instrumentation_)
622 self->instrumentation_->WaitingStarted();
379 } 623 }
380 624
381 // Called from the run loop. 625 // Called from the run loop.
382 // static 626 // static
383 void MessagePumpCFRunLoopBase::PreSourceObserver(CFRunLoopObserverRef observer, 627 void MessagePumpCFRunLoopBase::PreSourceObserver(CFRunLoopObserverRef observer,
384 CFRunLoopActivity activity, 628 CFRunLoopActivity activity,
385 void* info) { 629 void* info) {
386 MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info); 630 MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
387 631
388 // The run loop has reached the top of the loop and is about to begin 632 // The run loop has reached the top of the loop and is about to begin
389 // processing sources. If the last iteration of the loop at this nesting 633 // processing sources. If the last iteration of the loop at this nesting
390 // level did not sleep or exit, nesting-deferred work may have accumulated 634 // level did not sleep or exit, nesting-deferred work may have accumulated
391 // if a nested loop ran. Schedule nesting-deferred work for processing if 635 // if a nested loop ran. Schedule nesting-deferred work for processing if
392 // appropriate. 636 // appropriate.
393 self->MaybeScheduleNestingDeferredWork(); 637 self->MaybeScheduleNestingDeferredWork();
394 } 638 }
395 639
396 // Called from the run loop. 640 // Called from the run loop.
397 // static 641 // static
398 void MessagePumpCFRunLoopBase::EnterExitObserver(CFRunLoopObserverRef observer, 642 void MessagePumpCFRunLoopBase::EnterExitObserver(CFRunLoopObserverRef observer,
399 CFRunLoopActivity activity, 643 CFRunLoopActivity activity,
400 void* info) { 644 void* info) {
401 MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info); 645 MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
402 646
403 switch (activity) { 647 switch (activity) {
404 case kCFRunLoopEntry: 648 case kCFRunLoopEntry:
649 if (self->instrumentation_)
650 self->instrumentation_->LoopEntered();
651
405 ++self->nesting_level_; 652 ++self->nesting_level_;
406 if (self->nesting_level_ > self->deepest_nesting_level_) { 653 if (self->nesting_level_ > self->deepest_nesting_level_) {
407 self->deepest_nesting_level_ = self->nesting_level_; 654 self->deepest_nesting_level_ = self->nesting_level_;
408 } 655 }
409 break; 656 break;
410 657
411 case kCFRunLoopExit: 658 case kCFRunLoopExit:
412 // Not all run loops go to sleep. If a run loop is stopped before it 659 // 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 660 // goes to sleep due to a CFRunLoopStop call, or if the timeout passed
414 // to CFRunLoopRunInMode expires, the run loop may proceed directly from 661 // to CFRunLoopRunInMode expires, the run loop may proceed directly from
415 // handling sources to exiting without any sleep. This most commonly 662 // handling sources to exiting without any sleep. This most commonly
416 // occurs when CFRunLoopRunInMode is passed a timeout of 0, causing it 663 // 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 664 // to make a single pass through the loop and exit without sleep. Some
418 // native loops use CFRunLoop in this way. Because PreWaitObserver will 665 // native loops use CFRunLoop in this way. Because PrePostWaitObserver
419 // not be called in these case, MaybeScheduleNestingDeferredWork needs 666 // will not be called in these case, MaybeScheduleNestingDeferredWork
420 // to be called here, as the run loop exits. 667 // needs to be called here, as the run loop exits.
421 // 668 //
422 // MaybeScheduleNestingDeferredWork consults self->nesting_level_ 669 // MaybeScheduleNestingDeferredWork consults self->nesting_level_
423 // to determine whether to schedule nesting-deferred work. It expects 670 // 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 671 // 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 672 // 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 673 // value so that the value still corresponds to the level of the exiting
427 // loop. 674 // loop.
428 self->MaybeScheduleNestingDeferredWork(); 675 self->MaybeScheduleNestingDeferredWork();
429 --self->nesting_level_; 676 --self->nesting_level_;
677
678 if (self->instrumentation_)
679 self->instrumentation_->LoopExited();
430 break; 680 break;
431 681
432 default: 682 default:
433 break; 683 break;
434 } 684 }
435 685
436 self->EnterExitRunLoop(activity); 686 self->EnterExitRunLoop(activity);
437 } 687 }
438 688
439 // Called by MessagePumpCFRunLoopBase::EnterExitRunLoop. The default 689 // Called by MessagePumpCFRunLoopBase::EnterExitRunLoop. The default
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
549 run_loop_ = new RunLoop(); 799 run_loop_ = new RunLoop();
550 CHECK(run_loop_->BeforeRun()); 800 CHECK(run_loop_->BeforeRun());
551 SetDelegate(delegate); 801 SetDelegate(delegate);
552 } 802 }
553 803
554 #else 804 #else
555 805
556 MessagePumpNSApplication::MessagePumpNSApplication() 806 MessagePumpNSApplication::MessagePumpNSApplication()
557 : keep_running_(true), 807 : keep_running_(true),
558 running_own_loop_(false) { 808 running_own_loop_(false) {
809 EnableInstrumentation();
559 } 810 }
560 811
561 MessagePumpNSApplication::~MessagePumpNSApplication() {} 812 MessagePumpNSApplication::~MessagePumpNSApplication() {}
562 813
563 void MessagePumpNSApplication::DoRun(Delegate* delegate) { 814 void MessagePumpNSApplication::DoRun(Delegate* delegate) {
815 if (instrumentation_)
816 instrumentation_->StartIfNeeded();
817
564 bool last_running_own_loop_ = running_own_loop_; 818 bool last_running_own_loop_ = running_own_loop_;
565 819
566 // NSApp must be initialized by calling: 820 // NSApp must be initialized by calling:
567 // [{some class which implements CrAppProtocol} sharedApplication] 821 // [{some class which implements CrAppProtocol} sharedApplication]
568 // Most likely candidates are CrApplication or BrowserCrApplication. 822 // Most likely candidates are CrApplication or BrowserCrApplication.
569 // These can be initialized from C++ code by calling 823 // These can be initialized from C++ code by calling
570 // RegisterCrApp() or RegisterBrowserCrApp(). 824 // RegisterCrApp() or RegisterBrowserCrApp().
571 CHECK(NSApp); 825 CHECK(NSApp);
572 826
573 if (![NSApp isRunning]) { 827 if (![NSApp isRunning]) {
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
695 [NSApplication sharedApplication]; 949 [NSApplication sharedApplication];
696 g_not_using_cr_app = true; 950 g_not_using_cr_app = true;
697 return new MessagePumpNSApplication; 951 return new MessagePumpNSApplication;
698 #endif 952 #endif
699 } 953 }
700 954
701 return new MessagePumpNSRunLoop; 955 return new MessagePumpNSRunLoop;
702 } 956 }
703 957
704 } // namespace base 958 } // namespace base
OLDNEW
« base/message_loop/message_loop.cc ('K') | « base/message_loop/message_pump_mac.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698