• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/message_loop/message_pump_default.h"
6 
7 #include <algorithm>
8 
9 #include "base/logging.h"
10 #include "base/threading/thread_restrictions.h"
11 #include "build/build_config.h"
12 
13 #if defined(OS_MACOSX)
14 #include "base/mac/scoped_nsautorelease_pool.h"
15 #endif
16 
17 namespace base {
18 
MessagePumpDefault()19 MessagePumpDefault::MessagePumpDefault()
20     : keep_running_(true),
21       event_(WaitableEvent::ResetPolicy::AUTOMATIC,
22              WaitableEvent::InitialState::NOT_SIGNALED) {}
23 
~MessagePumpDefault()24 MessagePumpDefault::~MessagePumpDefault() {
25 }
26 
Run(Delegate * delegate)27 void MessagePumpDefault::Run(Delegate* delegate) {
28   DCHECK(keep_running_) << "Quit must have been called outside of Run!";
29 
30   for (;;) {
31 #if defined(OS_MACOSX)
32     mac::ScopedNSAutoreleasePool autorelease_pool;
33 #endif
34 
35     bool did_work = delegate->DoWork();
36     if (!keep_running_)
37       break;
38 
39     did_work |= delegate->DoDelayedWork(&delayed_work_time_);
40     if (!keep_running_)
41       break;
42 
43     if (did_work)
44       continue;
45 
46     did_work = delegate->DoIdleWork();
47     if (!keep_running_)
48       break;
49 
50     if (did_work)
51       continue;
52 
53     ThreadRestrictions::ScopedAllowWait allow_wait;
54     if (delayed_work_time_.is_null()) {
55       event_.Wait();
56     } else {
57       TimeDelta delay = delayed_work_time_ - TimeTicks::Now();
58       if (delay > TimeDelta()) {
59 #if defined(OS_WIN)
60         // TODO(stanisc): crbug.com/623223: Consider moving the OS_WIN specific
61         // logic into TimedWait implementation in waitable_event_win.cc.
62 
63         // crbug.com/487724: on Windows, waiting for less than 1 ms results in
64         // returning from TimedWait promptly and spinning
65         // MessagePumpDefault::Run loop for up to 1 ms - until it is time to
66         // run a delayed task. |min_delay| is the minimum possible wait to
67         // to avoid the spinning.
68         constexpr TimeDelta min_delay = TimeDelta::FromMilliseconds(1);
69         do {
70           delay = std::max(delay, min_delay);
71           if (event_.TimedWait(delay))
72             break;
73 
74           // TimedWait can time out earlier than the specified |delay| on
75           // Windows. It doesn't make sense to run the outer loop in that case
76           // because there isn't going to be any new work. It is less overhead
77           // to just go back to wait.
78           // In practice this inner wait loop might have up to 3 iterations.
79           delay = delayed_work_time_ - TimeTicks::Now();
80         } while (delay > TimeDelta());
81 #else
82         event_.TimedWait(delay);
83 #endif
84       } else {
85         // It looks like delayed_work_time_ indicates a time in the past, so we
86         // need to call DoDelayedWork now.
87         delayed_work_time_ = TimeTicks();
88       }
89     }
90     // Since event_ is auto-reset, we don't need to do anything special here
91     // other than service each delegate method.
92   }
93 
94   keep_running_ = true;
95 }
96 
Quit()97 void MessagePumpDefault::Quit() {
98   keep_running_ = false;
99 }
100 
ScheduleWork()101 void MessagePumpDefault::ScheduleWork() {
102   // Since this can be called on any thread, we need to ensure that our Run
103   // loop wakes up.
104   event_.Signal();
105 }
106 
ScheduleDelayedWork(const TimeTicks & delayed_work_time)107 void MessagePumpDefault::ScheduleDelayedWork(
108     const TimeTicks& delayed_work_time) {
109   // We know that we can't be blocked on Wait right now since this method can
110   // only be called on the same thread as Run, so we only need to update our
111   // record of how long to sleep when we do sleep.
112   delayed_work_time_ = delayed_work_time;
113 }
114 
115 }  // namespace base
116