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()19MessagePumpDefault::MessagePumpDefault() 20 : keep_running_(true), 21 event_(WaitableEvent::ResetPolicy::AUTOMATIC, 22 WaitableEvent::InitialState::NOT_SIGNALED) {} 23 ~MessagePumpDefault()24MessagePumpDefault::~MessagePumpDefault() { 25 } 26 Run(Delegate * delegate)27void 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()97void MessagePumpDefault::Quit() { 98 keep_running_ = false; 99 } 100 ScheduleWork()101void 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)107void 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