summaryrefslogtreecommitdiffstats
path: root/base/message_pump_glib.cc
diff options
context:
space:
mode:
authordeanm@chromium.org <deanm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2008-11-13 00:25:51 +0000
committerdeanm@chromium.org <deanm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2008-11-13 00:25:51 +0000
commit95fac4236a1bee1de60d59c0691b0b49eb05e6ad (patch)
treea91ca0abb087be94bf7030195529813fea7df1f9 /base/message_pump_glib.cc
parent007f8e7a1b28d7a90ffac9fa31005dc9a464647c (diff)
downloadchromium_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.cc113
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;