michael@0: // Copyright (c) 2010 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_android.h" michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #include "base/eintr_wrapper.h" michael@0: #include "base/lazy_instance.h" michael@0: #include "base/logging.h" michael@0: #include "base/platform_thread.h" michael@0: michael@0: namespace mozilla { michael@0: bool ProcessNextEvent(); michael@0: void NotifyEvent(); michael@0: } michael@0: michael@0: namespace base { michael@0: michael@0: MessagePumpForUI::MessagePumpForUI() michael@0: : state_(NULL) michael@0: , pump(*this) michael@0: { michael@0: } michael@0: michael@0: MessagePumpForUI::~MessagePumpForUI() { michael@0: } michael@0: michael@0: MessagePumpAndroid::MessagePumpAndroid(MessagePumpForUI &aPump) michael@0: : pump(aPump) michael@0: { michael@0: } michael@0: michael@0: MessagePumpAndroid::~MessagePumpAndroid() michael@0: { michael@0: } michael@0: michael@0: void MessagePumpForUI::Run(Delegate* delegate) { michael@0: RunState state; michael@0: state.delegate = delegate; michael@0: state.should_quit = false; michael@0: state.run_depth = state_ ? state_->run_depth + 1 : 1; michael@0: // We really only do a single task for each iteration of the loop. If we michael@0: // have done something, assume there is likely something more to do. This michael@0: // will mean that we don't block on the message pump until there was nothing michael@0: // more to do. We also set this to true to make sure not to block on the michael@0: // first iteration of the loop, so RunAllPending() works correctly. michael@0: state.more_work_is_plausible = true; michael@0: michael@0: RunState* previous_state = state_; michael@0: state_ = &state; michael@0: michael@0: // We run our own loop instead of using g_main_loop_quit in one of the michael@0: // callbacks. This is so we only quit our own loops, and we don't quit michael@0: // nested loops run by others. TODO(deanm): Is this what we want? michael@0: michael@0: while (!state_->should_quit) { michael@0: mozilla::ProcessNextEvent(); michael@0: if (work_scheduled) { michael@0: work_scheduled = false; michael@0: HandleDispatch(); michael@0: } michael@0: } michael@0: michael@0: state_ = previous_state; michael@0: } michael@0: michael@0: void MessagePumpForUI::HandleDispatch() { michael@0: // We should only ever have a single message on the wakeup pipe, since we michael@0: // are only signaled when the queue went from empty to non-empty. The qApp michael@0: // poll will tell us whether there was data, so this read shouldn't block. michael@0: if (state_->should_quit) michael@0: return; michael@0: michael@0: state_->more_work_is_plausible = false; michael@0: michael@0: if (state_->delegate->DoWork()) michael@0: state_->more_work_is_plausible = true; michael@0: michael@0: if (state_->should_quit) michael@0: return; michael@0: michael@0: if (state_->delegate->DoDelayedWork(&delayed_work_time_)) michael@0: state_->more_work_is_plausible = true; michael@0: if (state_->should_quit) michael@0: return; michael@0: michael@0: // Don't do idle work if we think there are more important things michael@0: // that we could be doing. michael@0: if (state_->more_work_is_plausible) michael@0: return; michael@0: michael@0: if (state_->delegate->DoIdleWork()) michael@0: state_->more_work_is_plausible = true; michael@0: if (state_->should_quit) michael@0: return; michael@0: } michael@0: michael@0: void MessagePumpForUI::Quit() { michael@0: if (state_) { michael@0: state_->should_quit = true; michael@0: } else { michael@0: NOTREACHED() << "Quit called outside Run!"; michael@0: } michael@0: } michael@0: michael@0: void MessagePumpForUI::ScheduleWork() { michael@0: // This can be called on any thread, so we don't want to touch any state michael@0: // variables as we would then need locks all over. This ensures that if michael@0: // we are sleeping in a poll that we will wake up. michael@0: work_scheduled = true; michael@0: mozilla::NotifyEvent(); michael@0: } michael@0: michael@0: void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { michael@0: // We need to wake up the loop in case the poll timeout needs to be michael@0: // adjusted. This will cause us to try to do work, but that's ok. michael@0: delayed_work_time_ = delayed_work_time; michael@0: ScheduleWork(); michael@0: } michael@0: michael@0: } // namespace base