Index: base/message_pump_glib.cc |
=================================================================== |
--- base/message_pump_glib.cc (revision 14449) |
+++ base/message_pump_glib.cc (working copy) |
@@ -4,12 +4,14 @@ |
#include "base/message_pump_glib.h" |
+#include <errno.h> |
#include <fcntl.h> |
#include <math.h> |
#include "base/lazy_instance.h" |
#include "base/logging.h" |
#include "base/platform_thread.h" |
+#include "base/scoped_ptr.h" |
namespace { |
@@ -90,6 +92,9 @@ |
namespace base { |
+// static |
+Lock MessagePumpForUI::glib_main_loop_lock_; |
+ |
MessagePumpForUI::MessagePumpForUI() |
: state_(NULL), |
context_(g_main_context_default()) { |
@@ -118,6 +123,45 @@ |
close(wakeup_pipe_write_); |
} |
+// Runs a glib main loop iteration. Grabs glib_main_loop_lock_ while |
+// calling glib functions, but releases it while polling. |
+static void GMainIterate(GMainContext* context) { |
+ AutoLock locked(MessagePumpForUI::glib_main_loop_lock_); |
+ int fds_array_size = 50; |
+ scoped_array<GPollFD> fds(new GPollFD[fds_array_size]); |
+ |
+ // We use the lower-level component functions and do the poll |
+ // ourselves so that we can release glib_main_loop_lock_ while |
+ // polling, otherwise waiters might starve. |
+ |
+ // I'll assume no other thread will g_main_context_acquire the |
+ // context away from this thread. We cannot g_main_context_wait as |
+ // we can't get to the condition and mutex in the context (which is |
+ // externally opaque). |
+ |
+ gint max_priority, timeout; |
+ g_main_context_prepare(context, &max_priority); |
+ int number_of_fds = g_main_context_query(context, max_priority, &timeout, |
+ fds.get(), fds_array_size); |
+ // We could reallocate instead, then we'd want to cache the array size... |
+ CHECK(number_of_fds <= fds_array_size); |
+ GPollFunc poll_func = g_main_context_get_poll_func(context); |
+ |
+ { |
+ // Release the lock while polling |
+ AutoUnlock locked(MessagePumpForUI::glib_main_loop_lock_); |
+ |
+ if ((*poll_func) (fds.get(), number_of_fds, timeout) < 0) { |
+ if (errno != EINTR) |
+ LOG(ERROR) << "g_main_loop poll error: " << strerror(errno); |
+ // Just carry on. |
+ } |
+ } |
+ |
+ g_main_context_check(context, max_priority, fds.get(), number_of_fds); |
+ g_main_context_dispatch(context); |
+} |
+ |
void MessagePumpForUI::Run(Delegate* delegate) { |
#ifndef NDEBUG |
// Make sure we only run this on one thread. GTK only has one message pump |
@@ -146,7 +190,7 @@ |
// 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); |
+ GMainIterate(context_); |
state_ = previous_state; |
} |