michael@0: // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. michael@0: // Use of this source code is governed by a BSD-style license that can be michael@0: // found in the LICENSE file. michael@0: michael@0: #include "base/message_pump_default.h" michael@0: michael@0: #include "base/logging.h" michael@0: #include "base/message_loop.h" michael@0: #include "base/scoped_nsautorelease_pool.h" michael@0: #include "GeckoProfiler.h" michael@0: michael@0: #include "mozilla/BackgroundHangMonitor.h" michael@0: michael@0: namespace base { michael@0: michael@0: MessagePumpDefault::MessagePumpDefault() michael@0: : keep_running_(true), michael@0: event_(false, false) { michael@0: } michael@0: michael@0: void MessagePumpDefault::Run(Delegate* delegate) { michael@0: DCHECK(keep_running_) << "Quit must have been called outside of Run!"; michael@0: michael@0: const MessageLoop* const loop = MessageLoop::current(); michael@0: mozilla::BackgroundHangMonitor hangMonitor( michael@0: loop->thread_name().c_str(), michael@0: loop->transient_hang_timeout(), michael@0: loop->permanent_hang_timeout()); michael@0: michael@0: for (;;) { michael@0: ScopedNSAutoreleasePool autorelease_pool; michael@0: michael@0: hangMonitor.NotifyActivity(); michael@0: bool did_work = delegate->DoWork(); michael@0: if (!keep_running_) michael@0: break; michael@0: michael@0: hangMonitor.NotifyActivity(); michael@0: did_work |= delegate->DoDelayedWork(&delayed_work_time_); michael@0: if (!keep_running_) michael@0: break; michael@0: michael@0: if (did_work) michael@0: continue; michael@0: michael@0: hangMonitor.NotifyActivity(); michael@0: did_work = delegate->DoIdleWork(); michael@0: if (!keep_running_) michael@0: break; michael@0: michael@0: if (did_work) michael@0: continue; michael@0: michael@0: if (delayed_work_time_.is_null()) { michael@0: hangMonitor.NotifyWait(); michael@0: PROFILER_LABEL("MessagePump", "Wait"); michael@0: { michael@0: GeckoProfilerSleepRAII profiler_sleep; michael@0: event_.Wait(); michael@0: } michael@0: } else { michael@0: TimeDelta delay = delayed_work_time_ - TimeTicks::Now(); michael@0: if (delay > TimeDelta()) { michael@0: hangMonitor.NotifyWait(); michael@0: PROFILER_LABEL("MessagePump", "Wait"); michael@0: { michael@0: GeckoProfilerSleepRAII profiler_sleep; michael@0: event_.TimedWait(delay); michael@0: } michael@0: } else { michael@0: // It looks like delayed_work_time_ indicates a time in the past, so we michael@0: // need to call DoDelayedWork now. michael@0: delayed_work_time_ = TimeTicks(); michael@0: } michael@0: } michael@0: // Since event_ is auto-reset, we don't need to do anything special here michael@0: // other than service each delegate method. michael@0: } michael@0: michael@0: keep_running_ = true; michael@0: } michael@0: michael@0: void MessagePumpDefault::Quit() { michael@0: keep_running_ = false; michael@0: } michael@0: michael@0: void MessagePumpDefault::ScheduleWork() { michael@0: // Since this can be called on any thread, we need to ensure that our Run michael@0: // loop wakes up. michael@0: event_.Signal(); michael@0: } michael@0: michael@0: void MessagePumpDefault::ScheduleDelayedWork( michael@0: const TimeTicks& delayed_work_time) { michael@0: // We know that we can't be blocked on Wait right now since this method can michael@0: // only be called on the same thread as Run, so we only need to update our michael@0: // record of how long to sleep when we do sleep. michael@0: delayed_work_time_ = delayed_work_time; michael@0: } michael@0: michael@0: } // namespace base