diff options
author | deanm@chromium.org <deanm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-11-13 00:25:51 +0000 |
---|---|---|
committer | deanm@chromium.org <deanm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-11-13 00:25:51 +0000 |
commit | 95fac4236a1bee1de60d59c0691b0b49eb05e6ad (patch) | |
tree | a91ca0abb087be94bf7030195529813fea7df1f9 /base/message_pump_glib.cc | |
parent | 007f8e7a1b28d7a90ffac9fa31005dc9a464647c (diff) | |
download | chromium_src-95fac4236a1bee1de60d59c0691b0b49eb05e6ad.zip chromium_src-95fac4236a1bee1de60d59c0691b0b49eb05e6ad.tar.gz chromium_src-95fac4236a1bee1de60d59c0691b0b49eb05e6ad.tar.bz2 |
Restructure the the pump for nested loops.
Change our work dispatching to be based around an event source. This will allow us to still participate when a message loop is pumped by outside code (nested message loops).
Review URL: http://codereview.chromium.org/10854
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@5331 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/message_pump_glib.cc')
-rw-r--r-- | base/message_pump_glib.cc | 113 |
1 files changed, 71 insertions, 42 deletions
diff --git a/base/message_pump_glib.cc b/base/message_pump_glib.cc index ae6d88e..3201f29 100644 --- a/base/message_pump_glib.cc +++ b/base/message_pump_glib.cc @@ -51,23 +51,29 @@ int GetTimeIntervalMilliseconds(base::Time from) { // Finalize is called when the source is destroyed. struct WorkSource : public GSource { - int timeout_ms; + base::MessagePumpForUI* pump; }; gboolean WorkSourcePrepare(GSource* source, gint* timeout_ms) { - *timeout_ms = static_cast<WorkSource*>(source)->timeout_ms; + *timeout_ms = static_cast<WorkSource*>(source)->pump->HandlePrepare(); + // We always return FALSE, so that our timeout is honored. If we were + // to return TRUE, the timeout would be considered to be 0 and the poll + // would never block. Once the poll is finished, Check will be called. return FALSE; } gboolean WorkSourceCheck(GSource* source) { - return FALSE; + // Always return TRUE, and Dispatch will be called. + return TRUE; } gboolean WorkSourceDispatch(GSource* source, GSourceFunc unused_func, gpointer unused_data) { - NOTREACHED(); + + static_cast<WorkSource*>(source)->pump->HandleDispatch(); + // Always return TRUE so our source stays registered. return TRUE; } @@ -88,6 +94,9 @@ MessagePumpForUI::MessagePumpForUI() : state_(NULL), context_(g_main_context_default()) { work_source_ = g_source_new(&WorkSourceFuncs, sizeof(WorkSource)); + static_cast<WorkSource*>(work_source_)->pump = this; + // Use a low priority so that we let other events in the queue go first. + g_source_set_priority(work_source_, G_PRIORITY_DEFAULT_IDLE); // This is needed to allow Run calls inside Dispatch. g_source_set_can_recurse(work_source_, TRUE); g_source_attach(work_source_, context_); @@ -112,53 +121,73 @@ void MessagePumpForUI::Run(Delegate* delegate) { state.delegate = delegate; state.should_quit = false; state.run_depth = state_ ? state_->run_depth + 1 : 1; - - RunState* previous_state = state_; - state_ = &state; - // We really only do a single task for each iteration of the loop. If we // have done something, assume there is likely something more to do. This // will mean that we don't block on the message pump until there was nothing // more to do. We also set this to true to make sure not to block on the // first iteration of the loop, so RunAllPending() works correctly. - bool more_work_is_plausible = true; - for (;;) { - // Set up our timeout for any delayed work. - static_cast<WorkSource*>(work_source_)->timeout_ms = - GetTimeIntervalMilliseconds(delayed_work_time_); - - // Process a single iteration of the event loop. - g_main_context_iteration(context_, !more_work_is_plausible); - if (state_->should_quit) - break; - - more_work_is_plausible = false; - - if (state_->delegate->DoWork()) - more_work_is_plausible = true; - - if (state_->should_quit) - break; - - if (state_->delegate->DoDelayedWork(&delayed_work_time_)) - more_work_is_plausible = true; - if (state_->should_quit) - break; - - // Don't do idle work if we think there are more important things - // that we could be doing. - if (more_work_is_plausible) - continue; - - if (state_->delegate->DoIdleWork()) - more_work_is_plausible = true; - if (state_->should_quit) - break; - } + state.more_work_is_plausible = true; + + RunState* previous_state = state_; + state_ = &state; + + // We run our own loop instead of using g_main_loop_quit in one of the + // callbacks. This is so we only quit our own loops, and we don't quit + // nested loops run by others. TODO(deanm): Is this what we want? + while (!state_->should_quit) + g_main_context_iteration(context_, true); state_ = previous_state; } +// Return the timeout we want passed to poll. +int MessagePumpForUI::HandlePrepare() { + // If it's likely that we have more work, don't let the pump + // block so that we can do some processing. + if (state_->more_work_is_plausible) + return 0; + + // Work wasn't plausible, so we'll block. In the case where glib fires + // our Dispatch(), |more_work_is_plausible| will be reset to whatever it + // should be. However, so we don't get starved by more important work, + // we set |more_work_is_plausible| to true. This means if we come back + // here without having been through Dispatch(), we will get a chance to be + // fired and properly do our work in Dispatch(). + state_->more_work_is_plausible = true; + + // We don't think we have work to do, but make sure not to block + // longer than the next time we need to run delayed work. + return GetTimeIntervalMilliseconds(delayed_work_time_); +} + +void MessagePumpForUI::HandleDispatch() { + if (state_->should_quit) + return; + + state_->more_work_is_plausible = false; + + if (state_->delegate->DoWork()) + state_->more_work_is_plausible = true; + + if (state_->should_quit) + return; + + if (state_->delegate->DoDelayedWork(&delayed_work_time_)) + state_->more_work_is_plausible = true; + if (state_->should_quit) + return; + + // Don't do idle work if we think there are more important things + // that we could be doing. + if (state_->more_work_is_plausible) + return; + + if (state_->delegate->DoIdleWork()) + state_->more_work_is_plausible = true; + if (state_->should_quit) + return; +} + void MessagePumpForUI::Quit() { if (state_) { state_->should_quit = true; |