summaryrefslogtreecommitdiffstats
path: root/base/message_loop
diff options
context:
space:
mode:
authorbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-18 20:27:52 +0000
committerbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-18 20:27:52 +0000
commit59e69e745ba3fa290ff3c50e65c3db03ee9dde6b (patch)
tree64b82fd1e2375845b59f278f2a1e892dcf54377b /base/message_loop
parentbd41e70e44d19eb809eb8565b1d8479daef5d8f5 (diff)
downloadchromium_src-59e69e745ba3fa290ff3c50e65c3db03ee9dde6b.zip
chromium_src-59e69e745ba3fa290ff3c50e65c3db03ee9dde6b.tar.gz
chromium_src-59e69e745ba3fa290ff3c50e65c3db03ee9dde6b.tar.bz2
Move message_pump to base/message_loop.
This also fixes some namespace usage inside the message pump files and updates all users of these files to use the new location. Reland of 206507. Original review https://codereview.chromium.org/17078005/ TBR=sky Review URL: https://codereview.chromium.org/16897006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@207075 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/message_loop')
-rw-r--r--base/message_loop/message_loop.cc8
-rw-r--r--base/message_loop/message_loop.h164
-rw-r--r--base/message_loop/message_loop_unittest.cc12
-rw-r--r--base/message_loop/message_pump.cc15
-rw-r--r--base/message_loop/message_pump.h129
-rw-r--r--base/message_loop/message_pump_android.cc139
-rw-r--r--base/message_loop/message_pump_android.h45
-rw-r--r--base/message_loop/message_pump_aurax11.cc307
-rw-r--r--base/message_loop/message_pump_aurax11.h122
-rw-r--r--base/message_loop/message_pump_default.cc85
-rw-r--r--base/message_loop/message_pump_default.h42
-rw-r--r--base/message_loop/message_pump_dispatcher.h32
-rw-r--r--base/message_loop/message_pump_glib.cc334
-rw-r--r--base/message_loop/message_pump_glib.h110
-rw-r--r--base/message_loop/message_pump_glib_unittest.cc580
-rw-r--r--base/message_loop/message_pump_gtk.cc114
-rw-r--r--base/message_loop/message_pump_gtk.h76
-rw-r--r--base/message_loop/message_pump_io_ios.cc209
-rw-r--r--base/message_loop/message_pump_io_ios.h142
-rw-r--r--base/message_loop/message_pump_io_ios_unittest.cc188
-rw-r--r--base/message_loop/message_pump_libevent.cc375
-rw-r--r--base/message_loop/message_pump_libevent.h179
-rw-r--r--base/message_loop/message_pump_libevent_unittest.cc162
-rw-r--r--base/message_loop/message_pump_mac.h337
-rw-r--r--base/message_loop/message_pump_mac.mm701
-rw-r--r--base/message_loop/message_pump_observer.h47
-rw-r--r--base/message_loop/message_pump_ozone.cc61
-rw-r--r--base/message_loop/message_pump_ozone.h52
-rw-r--r--base/message_loop/message_pump_win.cc686
-rw-r--r--base/message_loop/message_pump_win.h396
30 files changed, 5755 insertions, 94 deletions
diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc
index 0364a52..4e0c5f6 100644
--- a/base/message_loop/message_loop.cc
+++ b/base/message_loop/message_loop.cc
@@ -14,7 +14,7 @@
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop_proxy_impl.h"
-#include "base/message_pump_default.h"
+#include "base/message_loop/message_pump_default.h"
#include "base/metrics/histogram.h"
#include "base/metrics/statistics_recorder.h"
#include "base/run_loop.h"
@@ -25,13 +25,13 @@
#include "base/tracked_objects.h"
#if defined(OS_MACOSX)
-#include "base/message_pump_mac.h"
+#include "base/message_loop/message_pump_mac.h"
#endif
#if defined(OS_POSIX) && !defined(OS_IOS)
-#include "base/message_pump_libevent.h"
+#include "base/message_loop/message_pump_libevent.h"
#endif
#if defined(OS_ANDROID)
-#include "base/message_pump_android.h"
+#include "base/message_loop/message_pump_android.h"
#endif
#if defined(TOOLKIT_GTK)
diff --git a/base/message_loop/message_loop.h b/base/message_loop/message_loop.h
index d26b673..e765cef 100644
--- a/base/message_loop/message_loop.h
+++ b/base/message_loop/message_loop.h
@@ -14,7 +14,7 @@
#include "base/location.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop_proxy.h"
-#include "base/message_pump.h"
+#include "base/message_loop/message_pump.h"
#include "base/observer_list.h"
#include "base/pending_task.h"
#include "base/sequenced_task_runner_helpers.h"
@@ -25,25 +25,26 @@
#if defined(OS_WIN)
// We need this to declare base::MessagePumpWin::Dispatcher, which we should
// really just eliminate.
-#include "base/message_pump_win.h"
+#include "base/message_loop/message_pump_win.h"
#elif defined(OS_IOS)
-#include "base/message_pump_io_ios.h"
+#include "base/message_loop/message_pump_io_ios.h"
#elif defined(OS_POSIX)
-#include "base/message_pump_libevent.h"
+#include "base/message_loop/message_pump_libevent.h"
#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
#if defined(USE_AURA) && defined(USE_X11) && !defined(OS_NACL)
-#include "base/message_pump_aurax11.h"
+#include "base/message_loop/message_pump_aurax11.h"
#elif defined(USE_OZONE) && !defined(OS_NACL)
-#include "base/message_pump_ozone.h"
+#include "base/message_loop/message_pump_ozone.h"
#else
-#include "base/message_pump_gtk.h"
+#include "base/message_loop/message_pump_gtk.h"
#endif
#endif
#endif
namespace base {
+
class HistogramBase;
class MessageLoopLockTest;
class RunLoop;
@@ -83,12 +84,12 @@ class MessagePumpForUI;
// Please be SURE your task is reentrant (nestable) and all global variables
// are stable and accessible before calling SetNestableTasksAllowed(true).
//
-class BASE_EXPORT MessageLoop : public base::MessagePump::Delegate {
+class BASE_EXPORT MessageLoop : public MessagePump::Delegate {
public:
#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
- typedef base::MessagePumpDispatcher Dispatcher;
- typedef base::MessagePumpObserver Observer;
+ typedef MessagePumpDispatcher Dispatcher;
+ typedef MessagePumpObserver Observer;
#endif
// A MessageLoop has a particular type, which indicates the set of
@@ -121,7 +122,7 @@ class BASE_EXPORT MessageLoop : public base::MessagePump::Delegate {
static void EnableHistogrammer(bool enable_histogrammer);
- typedef base::MessagePump* (MessagePumpFactory)();
+ typedef MessagePump* (MessagePumpFactory)();
// Uses the given base::MessagePumpForUIFactory to override the default
// MessagePump implementation for 'TYPE_UI'. Returns true if the factory
// was successfully registered.
@@ -174,27 +175,22 @@ class BASE_EXPORT MessageLoop : public base::MessagePump::Delegate {
//
// NOTE: These methods may be called on any thread. The Task will be invoked
// on the thread that executes MessageLoop::Run().
- void PostTask(
- const tracked_objects::Location& from_here,
- const base::Closure& task);
+ void PostTask(const tracked_objects::Location& from_here,
+ const Closure& task);
- bool TryPostTask(
- const tracked_objects::Location& from_here,
- const base::Closure& task);
+ bool TryPostTask(const tracked_objects::Location& from_here,
+ const Closure& task);
- void PostDelayedTask(
- const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay);
+ void PostDelayedTask(const tracked_objects::Location& from_here,
+ const Closure& task,
+ TimeDelta delay);
- void PostNonNestableTask(
- const tracked_objects::Location& from_here,
- const base::Closure& task);
+ void PostNonNestableTask(const tracked_objects::Location& from_here,
+ const Closure& task);
- void PostNonNestableDelayedTask(
- const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay);
+ void PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
+ const Closure& task,
+ TimeDelta delay);
// A variant on PostTask that deletes the given object. This is useful
// if the object needs to live until the next run of the MessageLoop (for
@@ -264,12 +260,12 @@ class BASE_EXPORT MessageLoop : public base::MessagePump::Delegate {
void QuitNow();
// TODO(jbates) remove this. crbug.com/131220. See QuitWhenIdleClosure().
- static base::Closure QuitClosure() { return QuitWhenIdleClosure(); }
+ static Closure QuitClosure() { return QuitWhenIdleClosure(); }
// Deprecated: use RunLoop instead.
// Construct a Closure that will call QuitWhenIdle(). Useful to schedule an
// arbitrary MessageLoop to QuitWhenIdle.
- static base::Closure QuitWhenIdleClosure();
+ static Closure QuitWhenIdleClosure();
// Returns true if this loop is |type|. This allows subclasses (especially
// those in tests) to specialize how they are identified.
@@ -286,7 +282,7 @@ class BASE_EXPORT MessageLoop : public base::MessagePump::Delegate {
const std::string& thread_name() const { return thread_name_; }
// Gets the message loop proxy associated with this message loop.
- scoped_refptr<base::MessageLoopProxy> message_loop_proxy() {
+ scoped_refptr<MessageLoopProxy> message_loop_proxy() {
return message_loop_proxy_.get();
}
@@ -349,10 +345,10 @@ class BASE_EXPORT MessageLoop : public base::MessagePump::Delegate {
TaskObserver();
// This method is called before processing a task.
- virtual void WillProcessTask(const base::PendingTask& pending_task) = 0;
+ virtual void WillProcessTask(const PendingTask& pending_task) = 0;
// This method is called after processing a task.
- virtual void DidProcessTask(const base::PendingTask& pending_task) = 0;
+ virtual void DidProcessTask(const PendingTask& pending_task) = 0;
protected:
virtual ~TaskObserver();
@@ -397,20 +393,20 @@ class BASE_EXPORT MessageLoop : public base::MessagePump::Delegate {
protected:
#if defined(OS_WIN)
- base::MessagePumpWin* pump_win() {
- return static_cast<base::MessagePumpWin*>(pump_.get());
+ MessagePumpWin* pump_win() {
+ return static_cast<MessagePumpWin*>(pump_.get());
}
#elif defined(OS_POSIX) && !defined(OS_IOS)
- base::MessagePumpLibevent* pump_libevent() {
- return static_cast<base::MessagePumpLibevent*>(pump_.get());
+ MessagePumpLibevent* pump_libevent() {
+ return static_cast<MessagePumpLibevent*>(pump_.get());
}
#endif
- scoped_refptr<base::MessagePump> pump_;
+ scoped_refptr<MessagePump> pump_;
private:
- friend class base::RunLoop;
- friend class base::MessageLoopLockTest;
+ friend class RunLoop;
+ friend class MessageLoopLockTest;
// A function to encapsulate all the exception handling capability in the
// stacks around the running of a main message loop. It will run the message
@@ -431,14 +427,14 @@ class BASE_EXPORT MessageLoop : public base::MessagePump::Delegate {
bool ProcessNextDelayedNonNestableTask();
// Runs the specified PendingTask.
- void RunTask(const base::PendingTask& pending_task);
+ void RunTask(const PendingTask& pending_task);
// Calls RunTask or queues the pending_task on the deferred task list if it
// cannot be run right now. Returns true if the task was run.
- bool DeferOrRunPendingTask(const base::PendingTask& pending_task);
+ bool DeferOrRunPendingTask(const PendingTask& pending_task);
// Adds the pending task to delayed_work_queue_.
- void AddToDelayedWorkQueue(const base::PendingTask& pending_task);
+ void AddToDelayedWorkQueue(const PendingTask& pending_task);
// This function attempts to add pending task to our incoming_queue_.
// The append can only possibly fail when |use_try_lock| is true.
@@ -454,7 +450,7 @@ class BASE_EXPORT MessageLoop : public base::MessagePump::Delegate {
// function will reset the value of pending_task->task. This is needed to
// ensure that the posting call stack does not retain pending_task->task
// beyond this function call.
- bool AddToIncomingQueue(base::PendingTask* pending_task, bool use_try_lock);
+ bool AddToIncomingQueue(PendingTask* pending_task, bool use_try_lock);
// Load tasks from the incoming_queue_ into work_queue_ if the latter is
// empty. The former requires a lock to access, while the latter is directly
@@ -467,7 +463,7 @@ class BASE_EXPORT MessageLoop : public base::MessagePump::Delegate {
bool DeletePendingTasks();
// Calculates the time at which a PendingTask should run.
- base::TimeTicks CalculateDelayedRuntime(base::TimeDelta delay);
+ TimeTicks CalculateDelayedRuntime(TimeDelta delay);
// Start recording histogram info about events and action IF it was enabled
// and IF the statistics recorder can accept a registration of our histogram.
@@ -478,27 +474,27 @@ class BASE_EXPORT MessageLoop : public base::MessagePump::Delegate {
// If message_histogram_ is NULL, this is a no-op.
void HistogramEvent(int event);
- // base::MessagePump::Delegate methods:
+ // MessagePump::Delegate methods:
virtual bool DoWork() OVERRIDE;
- virtual bool DoDelayedWork(base::TimeTicks* next_delayed_work_time) OVERRIDE;
+ virtual bool DoDelayedWork(TimeTicks* next_delayed_work_time) OVERRIDE;
virtual bool DoIdleWork() OVERRIDE;
Type type_;
// A list of tasks that need to be processed by this instance. Note that
// this queue is only accessed (push/pop) by our current thread.
- base::TaskQueue work_queue_;
+ TaskQueue work_queue_;
// Contains delayed tasks, sorted by their 'delayed_run_time' property.
- base::DelayedTaskQueue delayed_work_queue_;
+ DelayedTaskQueue delayed_work_queue_;
// A recent snapshot of Time::Now(), used to check delayed_work_queue_.
- base::TimeTicks recent_time_;
+ TimeTicks recent_time_;
// A queue of non-nestable tasks that we had to defer because when it came
// time to execute them we were in a nested message loop. They will execute
// once we're out of nested message loops.
- base::TaskQueue deferred_non_nestable_work_queue_;
+ TaskQueue deferred_non_nestable_work_queue_;
ObserverList<DestructionObserver> destruction_observers_;
@@ -510,19 +506,19 @@ class BASE_EXPORT MessageLoop : public base::MessagePump::Delegate {
std::string thread_name_;
// A profiling histogram showing the counts of various messages and events.
- base::HistogramBase* message_histogram_;
+ HistogramBase* message_histogram_;
// An incoming queue of tasks that are acquired under a mutex for processing
// on this instance's thread. These tasks have not yet been sorted out into
// items for our work_queue_ vs delayed_work_queue_.
- base::TaskQueue incoming_queue_;
+ TaskQueue incoming_queue_;
// Protect access to incoming_queue_.
- mutable base::Lock incoming_queue_lock_;
+ mutable Lock incoming_queue_lock_;
- base::RunLoop* run_loop_;
+ RunLoop* run_loop_;
#if defined(OS_WIN)
- base::TimeTicks high_resolution_timer_expiration_;
+ TimeTicks high_resolution_timer_expiration_;
// Should be set to true before calling Windows APIs like TrackPopupMenu, etc
// which enter a modal message loop.
bool os_modal_loop_;
@@ -535,8 +531,8 @@ class BASE_EXPORT MessageLoop : public base::MessagePump::Delegate {
ObserverList<TaskObserver> task_observers_;
// The message loop proxy associated with this message loop, if one exists.
- scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
- scoped_ptr<base::ThreadTaskRunnerHandle> thread_task_runner_handle_;
+ scoped_refptr<MessageLoopProxy> message_loop_proxy_;
+ scoped_ptr<ThreadTaskRunnerHandle> thread_task_runner_handle_;
template <class T, class R> friend class base::subtle::DeleteHelperInternal;
template <class T, class R> friend class base::subtle::ReleaseHelperInternal;
@@ -561,7 +557,7 @@ class BASE_EXPORT MessageLoop : public base::MessagePump::Delegate {
class BASE_EXPORT MessageLoopForUI : public MessageLoop {
public:
#if defined(OS_WIN)
- typedef base::MessagePumpForUI::MessageFilter MessageFilter;
+ typedef MessagePumpForUI::MessageFilter MessageFilter;
#endif
MessageLoopForUI() : MessageLoop(TYPE_UI) {
@@ -607,15 +603,15 @@ class BASE_EXPORT MessageLoopForUI : public MessageLoop {
protected:
#if defined(USE_AURA) && defined(USE_X11) && !defined(OS_NACL)
- friend class base::MessagePumpAuraX11;
+ friend class MessagePumpAuraX11;
#endif
#if defined(USE_OZONE) && !defined(OS_NACL)
- friend class base::MessagePumpOzone;
+ friend class MessagePumpOzone;
#endif
// TODO(rvargas): Make this platform independent.
- base::MessagePumpForUI* pump_ui() {
- return static_cast<base::MessagePumpForUI*>(pump_.get());
+ MessagePumpForUI* pump_ui() {
+ return static_cast<MessagePumpForUI*>(pump_.get());
}
#endif // !defined(OS_MACOSX)
};
@@ -636,30 +632,30 @@ COMPILE_ASSERT(sizeof(MessageLoop) == sizeof(MessageLoopForUI),
class BASE_EXPORT MessageLoopForIO : public MessageLoop {
public:
#if defined(OS_WIN)
- typedef base::MessagePumpForIO::IOHandler IOHandler;
- typedef base::MessagePumpForIO::IOContext IOContext;
- typedef base::MessagePumpForIO::IOObserver IOObserver;
+ typedef MessagePumpForIO::IOHandler IOHandler;
+ typedef MessagePumpForIO::IOContext IOContext;
+ typedef MessagePumpForIO::IOObserver IOObserver;
#elif defined(OS_IOS)
- typedef base::MessagePumpIOSForIO::Watcher Watcher;
- typedef base::MessagePumpIOSForIO::FileDescriptorWatcher
+ typedef MessagePumpIOSForIO::Watcher Watcher;
+ typedef MessagePumpIOSForIO::FileDescriptorWatcher
FileDescriptorWatcher;
- typedef base::MessagePumpIOSForIO::IOObserver IOObserver;
+ typedef MessagePumpIOSForIO::IOObserver IOObserver;
enum Mode {
- WATCH_READ = base::MessagePumpIOSForIO::WATCH_READ,
- WATCH_WRITE = base::MessagePumpIOSForIO::WATCH_WRITE,
- WATCH_READ_WRITE = base::MessagePumpIOSForIO::WATCH_READ_WRITE
+ WATCH_READ = MessagePumpIOSForIO::WATCH_READ,
+ WATCH_WRITE = MessagePumpIOSForIO::WATCH_WRITE,
+ WATCH_READ_WRITE = MessagePumpIOSForIO::WATCH_READ_WRITE
};
#elif defined(OS_POSIX)
- typedef base::MessagePumpLibevent::Watcher Watcher;
- typedef base::MessagePumpLibevent::FileDescriptorWatcher
+ typedef MessagePumpLibevent::Watcher Watcher;
+ typedef MessagePumpLibevent::FileDescriptorWatcher
FileDescriptorWatcher;
- typedef base::MessagePumpLibevent::IOObserver IOObserver;
+ typedef MessagePumpLibevent::IOObserver IOObserver;
enum Mode {
- WATCH_READ = base::MessagePumpLibevent::WATCH_READ,
- WATCH_WRITE = base::MessagePumpLibevent::WATCH_WRITE,
- WATCH_READ_WRITE = base::MessagePumpLibevent::WATCH_READ_WRITE
+ WATCH_READ = MessagePumpLibevent::WATCH_READ,
+ WATCH_WRITE = MessagePumpLibevent::WATCH_WRITE,
+ WATCH_READ_WRITE = MessagePumpLibevent::WATCH_READ_WRITE
};
#endif
@@ -690,8 +686,8 @@ class BASE_EXPORT MessageLoopForIO : public MessageLoop {
protected:
// TODO(rvargas): Make this platform independent.
- base::MessagePumpForIO* pump_io() {
- return static_cast<base::MessagePumpForIO*>(pump_.get());
+ MessagePumpForIO* pump_io() {
+ return static_cast<MessagePumpForIO*>(pump_.get());
}
#elif defined(OS_IOS)
@@ -703,8 +699,8 @@ class BASE_EXPORT MessageLoopForIO : public MessageLoop {
Watcher *delegate);
private:
- base::MessagePumpIOSForIO* pump_io() {
- return static_cast<base::MessagePumpIOSForIO*>(pump_.get());
+ MessagePumpIOSForIO* pump_io() {
+ return static_cast<MessagePumpIOSForIO*>(pump_.get());
}
#elif defined(OS_POSIX)
@@ -716,8 +712,8 @@ class BASE_EXPORT MessageLoopForIO : public MessageLoop {
Watcher* delegate);
private:
- base::MessagePumpLibevent* pump_io() {
- return static_cast<base::MessagePumpLibevent*>(pump_.get());
+ MessagePumpLibevent* pump_io() {
+ return static_cast<MessagePumpLibevent*>(pump_.get());
}
#endif // defined(OS_POSIX)
};
diff --git a/base/message_loop/message_loop_unittest.cc b/base/message_loop/message_loop_unittest.cc
index 0f85b14..504c8e3 100644
--- a/base/message_loop/message_loop_unittest.cc
+++ b/base/message_loop/message_loop_unittest.cc
@@ -9,7 +9,7 @@
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop.h"
+#include "base/message_loop/message_loop.h"
#include "base/pending_task.h"
#include "base/posix/eintr_wrapper.h"
#include "base/run_loop.h"
@@ -20,7 +20,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_WIN)
-#include "base/message_pump_win.h"
+#include "base/message_loop/message_pump_win.h"
#include "base/win/scoped_handle.h"
#endif
@@ -29,8 +29,8 @@ namespace base {
class MessageLoopLockTest {
public:
static void LockWaitUnLock(MessageLoop* loop,
- base::WaitableEvent* caller_wait,
- base::WaitableEvent* caller_signal) {
+ WaitableEvent* caller_wait,
+ WaitableEvent* caller_signal) {
loop->incoming_queue_lock_.Acquire();
caller_wait->Signal();
@@ -121,7 +121,7 @@ void RunTest_PostTask(MessageLoop::Type message_loop_type) {
thread.Start();
thread.message_loop()->PostTask(
FROM_HERE,
- base::Bind(&MessageLoopLockTest::LockWaitUnLock,
+ Bind(&MessageLoopLockTest::LockWaitUnLock,
MessageLoop::current(),
&wait,
&signal));
@@ -1419,7 +1419,7 @@ void RunTest_RecursivePosts(MessageLoop::Type message_loop_type,
#if defined(OS_WIN)
-class DispatcherImpl : public base::MessageLoopForUI::Dispatcher {
+class DispatcherImpl : public MessageLoopForUI::Dispatcher {
public:
DispatcherImpl() : dispatch_count_(0) {}
diff --git a/base/message_loop/message_pump.cc b/base/message_loop/message_pump.cc
new file mode 100644
index 0000000..7ffc2b1
--- /dev/null
+++ b/base/message_loop/message_pump.cc
@@ -0,0 +1,15 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_pump.h"
+
+namespace base {
+
+MessagePump::MessagePump() {
+}
+
+MessagePump::~MessagePump() {
+}
+
+} // namespace base
diff --git a/base/message_loop/message_pump.h b/base/message_loop/message_pump.h
new file mode 100644
index 0000000..5b72232
--- /dev/null
+++ b/base/message_loop/message_pump.h
@@ -0,0 +1,129 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_H_
+
+#include "base/base_export.h"
+#include "base/memory/ref_counted.h"
+
+namespace base {
+
+class TimeTicks;
+
+class BASE_EXPORT MessagePump : public RefCountedThreadSafe<MessagePump> {
+ public:
+ // Please see the comments above the Run method for an illustration of how
+ // these delegate methods are used.
+ class BASE_EXPORT Delegate {
+ public:
+ virtual ~Delegate() {}
+
+ // Called from within Run in response to ScheduleWork or when the message
+ // pump would otherwise call DoDelayedWork. Returns true to indicate that
+ // work was done. DoDelayedWork will still be called if DoWork returns
+ // true, but DoIdleWork will not.
+ virtual bool DoWork() = 0;
+
+ // Called from within Run in response to ScheduleDelayedWork or when the
+ // message pump would otherwise sleep waiting for more work. Returns true
+ // to indicate that delayed work was done. DoIdleWork will not be called
+ // if DoDelayedWork returns true. Upon return |next_delayed_work_time|
+ // indicates the time when DoDelayedWork should be called again. If
+ // |next_delayed_work_time| is null (per Time::is_null), then the queue of
+ // future delayed work (timer events) is currently empty, and no additional
+ // calls to this function need to be scheduled.
+ virtual bool DoDelayedWork(TimeTicks* next_delayed_work_time) = 0;
+
+ // Called from within Run just before the message pump goes to sleep.
+ // Returns true to indicate that idle work was done.
+ virtual bool DoIdleWork() = 0;
+ };
+
+ MessagePump();
+
+ // The Run method is called to enter the message pump's run loop.
+ //
+ // Within the method, the message pump is responsible for processing native
+ // messages as well as for giving cycles to the delegate periodically. The
+ // message pump should take care to mix delegate callbacks with native
+ // message processing so neither type of event starves the other of cycles.
+ //
+ // The anatomy of a typical run loop:
+ //
+ // for (;;) {
+ // bool did_work = DoInternalWork();
+ // if (should_quit_)
+ // break;
+ //
+ // did_work |= delegate_->DoWork();
+ // if (should_quit_)
+ // break;
+ //
+ // TimeTicks next_time;
+ // did_work |= delegate_->DoDelayedWork(&next_time);
+ // if (should_quit_)
+ // break;
+ //
+ // if (did_work)
+ // continue;
+ //
+ // did_work = delegate_->DoIdleWork();
+ // if (should_quit_)
+ // break;
+ //
+ // if (did_work)
+ // continue;
+ //
+ // WaitForWork();
+ // }
+ //
+ // Here, DoInternalWork is some private method of the message pump that is
+ // responsible for dispatching the next UI message or notifying the next IO
+ // completion (for example). WaitForWork is a private method that simply
+ // blocks until there is more work of any type to do.
+ //
+ // Notice that the run loop cycles between calling DoInternalWork, DoWork,
+ // and DoDelayedWork methods. This helps ensure that none of these work
+ // queues starve the others. This is important for message pumps that are
+ // used to drive animations, for example.
+ //
+ // Notice also that after each callout to foreign code, the run loop checks
+ // to see if it should quit. The Quit method is responsible for setting this
+ // flag. No further work is done once the quit flag is set.
+ //
+ // NOTE: Care must be taken to handle Run being called again from within any
+ // of the callouts to foreign code. Native message pumps may also need to
+ // deal with other native message pumps being run outside their control
+ // (e.g., the MessageBox API on Windows pumps UI messages!). To be specific,
+ // the callouts (DoWork and DoDelayedWork) MUST still be provided even in
+ // nested sub-loops that are "seemingly" outside the control of this message
+ // pump. DoWork in particular must never be starved for time slices unless
+ // it returns false (meaning it has run out of things to do).
+ //
+ virtual void Run(Delegate* delegate) = 0;
+
+ // Quit immediately from the most recently entered run loop. This method may
+ // only be used on the thread that called Run.
+ virtual void Quit() = 0;
+
+ // Schedule a DoWork callback to happen reasonably soon. Does nothing if a
+ // DoWork callback is already scheduled. This method may be called from any
+ // thread. Once this call is made, DoWork should not be "starved" at least
+ // until it returns a value of false.
+ virtual void ScheduleWork() = 0;
+
+ // Schedule a DoDelayedWork callback to happen at the specified time,
+ // cancelling any pending DoDelayedWork callback. This method may only be
+ // used on the thread that called Run.
+ virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) = 0;
+
+ protected:
+ virtual ~MessagePump();
+ friend class RefCountedThreadSafe<MessagePump>;
+};
+
+} // namespace base
+
+#endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_H_
diff --git a/base/message_loop/message_pump_android.cc b/base/message_loop/message_pump_android.cc
new file mode 100644
index 0000000..d7bf9a9
--- /dev/null
+++ b/base/message_loop/message_pump_android.cc
@@ -0,0 +1,139 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_pump_android.h"
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/run_loop.h"
+#include "base/time.h"
+#include "jni/SystemMessageHandler_jni.h"
+
+using base::android::ScopedJavaLocalRef;
+
+namespace {
+
+base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> >
+ g_system_message_handler_obj = LAZY_INSTANCE_INITIALIZER;
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+// Native JNI methods called by Java.
+// ----------------------------------------------------------------------------
+// This method can not move to anonymous namespace as it has been declared as
+// 'static' in system_message_handler_jni.h.
+static jboolean DoRunLoopOnce(JNIEnv* env, jobject obj, jint native_delegate) {
+ base::MessagePump::Delegate* delegate =
+ reinterpret_cast<base::MessagePump::Delegate*>(native_delegate);
+ DCHECK(delegate);
+ // This is based on MessagePumpForUI::DoRunLoop() from desktop.
+ // Note however that our system queue is handled in the java side.
+ // In desktop we inspect and process a single system message and then
+ // we call DoWork() / DoDelayedWork().
+ // On Android, the java message queue may contain messages for other handlers
+ // that will be processed before calling here again.
+ bool more_work_is_plausible = delegate->DoWork();
+
+ // This is the time when we need to do delayed work.
+ base::TimeTicks delayed_work_time;
+ more_work_is_plausible |= delegate->DoDelayedWork(&delayed_work_time);
+
+ // This is a major difference between android and other platforms: since we
+ // can't inspect it and process just one single message, instead we'll yeld
+ // the callstack, and post a message to call us back soon.
+ if (more_work_is_plausible)
+ return true;
+
+ more_work_is_plausible = delegate->DoIdleWork();
+ if (!more_work_is_plausible && !delayed_work_time.is_null()) {
+ // We only set the timer here as returning true would post a message.
+ jlong millis =
+ (delayed_work_time - base::TimeTicks::Now()).InMillisecondsRoundedUp();
+ Java_SystemMessageHandler_setDelayedTimer(env, obj, millis);
+ }
+ return more_work_is_plausible;
+}
+
+namespace base {
+
+MessagePumpForUI::MessagePumpForUI()
+ : run_loop_(NULL) {
+}
+
+MessagePumpForUI::~MessagePumpForUI() {
+}
+
+void MessagePumpForUI::Run(Delegate* delegate) {
+ NOTREACHED() << "UnitTests should rely on MessagePumpForUIStub in"
+ " test_stub_android.h";
+}
+
+void MessagePumpForUI::Start(Delegate* delegate) {
+ run_loop_ = new RunLoop();
+ // Since the RunLoop was just created above, BeforeRun should be guaranteed to
+ // return true (it only returns false if the RunLoop has been Quit already).
+ if (!run_loop_->BeforeRun())
+ NOTREACHED();
+
+ DCHECK(g_system_message_handler_obj.Get().is_null());
+
+ JNIEnv* env = base::android::AttachCurrentThread();
+ DCHECK(env);
+
+ g_system_message_handler_obj.Get().Reset(
+ Java_SystemMessageHandler_create(env, reinterpret_cast<jint>(delegate)));
+}
+
+void MessagePumpForUI::Quit() {
+ if (!g_system_message_handler_obj.Get().is_null()) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ DCHECK(env);
+
+ Java_SystemMessageHandler_removeTimer(env,
+ g_system_message_handler_obj.Get().obj());
+ g_system_message_handler_obj.Get().Reset();
+ }
+
+ if (run_loop_) {
+ run_loop_->AfterRun();
+ delete run_loop_;
+ run_loop_ = NULL;
+ }
+}
+
+void MessagePumpForUI::ScheduleWork() {
+ DCHECK(!g_system_message_handler_obj.Get().is_null());
+
+ JNIEnv* env = base::android::AttachCurrentThread();
+ DCHECK(env);
+
+ Java_SystemMessageHandler_setTimer(env,
+ g_system_message_handler_obj.Get().obj());
+}
+
+void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
+ DCHECK(!g_system_message_handler_obj.Get().is_null());
+
+ JNIEnv* env = base::android::AttachCurrentThread();
+ DCHECK(env);
+
+ jlong millis =
+ (delayed_work_time - TimeTicks::Now()).InMillisecondsRoundedUp();
+ // Note that we're truncating to milliseconds as required by the java side,
+ // even though delayed_work_time is microseconds resolution.
+ Java_SystemMessageHandler_setDelayedTimer(env,
+ g_system_message_handler_obj.Get().obj(), millis);
+}
+
+// static
+bool MessagePumpForUI::RegisterBindings(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+} // namespace base
diff --git a/base/message_loop/message_pump_android.h b/base/message_loop/message_pump_android.h
new file mode 100644
index 0000000..fd934a7
--- /dev/null
+++ b/base/message_loop/message_pump_android.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_ANDROID_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_ANDROID_H_
+
+#include <jni.h>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/message_loop/message_pump.h"
+
+namespace base {
+
+class RunLoop;
+class TimeTicks;
+
+// This class implements a MessagePump needed for TYPE_UI MessageLoops on
+// OS_ANDROID platform.
+class BASE_EXPORT MessagePumpForUI : public MessagePump {
+ public:
+ MessagePumpForUI();
+
+ virtual void Run(Delegate* delegate) OVERRIDE;
+ virtual void Quit() OVERRIDE;
+ virtual void ScheduleWork() OVERRIDE;
+ virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) OVERRIDE;
+
+ virtual void Start(Delegate* delegate);
+
+ static bool RegisterBindings(JNIEnv* env);
+
+ protected:
+ virtual ~MessagePumpForUI();
+
+ private:
+ RunLoop* run_loop_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessagePumpForUI);
+};
+
+} // namespace base
+
+#endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_ANDROID_H_
diff --git a/base/message_loop/message_pump_aurax11.cc b/base/message_loop/message_pump_aurax11.cc
new file mode 100644
index 0000000..70cae64
--- /dev/null
+++ b/base/message_loop/message_pump_aurax11.cc
@@ -0,0 +1,307 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_pump_aurax11.h"
+
+#include <glib.h>
+#include <X11/X.h>
+#include <X11/extensions/XInput2.h>
+#include <X11/XKBlib.h>
+
+#include "base/basictypes.h"
+#include "base/message_loop.h"
+
+namespace base {
+
+namespace {
+
+gboolean XSourcePrepare(GSource* source, gint* timeout_ms) {
+ if (XPending(MessagePumpAuraX11::GetDefaultXDisplay()))
+ *timeout_ms = 0;
+ else
+ *timeout_ms = -1;
+ return FALSE;
+}
+
+gboolean XSourceCheck(GSource* source) {
+ return XPending(MessagePumpAuraX11::GetDefaultXDisplay());
+}
+
+gboolean XSourceDispatch(GSource* source,
+ GSourceFunc unused_func,
+ gpointer data) {
+ MessagePumpAuraX11* pump = static_cast<MessagePumpAuraX11*>(data);
+ return pump->DispatchXEvents();
+}
+
+GSourceFuncs XSourceFuncs = {
+ XSourcePrepare,
+ XSourceCheck,
+ XSourceDispatch,
+ NULL
+};
+
+// The connection is essentially a global that's accessed through a static
+// method and destroyed whenever ~MessagePumpAuraX11() is called. We do this
+// for historical reasons so user code can call
+// MessagePumpForUI::GetDefaultXDisplay() where MessagePumpForUI is a typedef
+// to whatever type in the current build.
+//
+// TODO(erg): This can be changed to something more sane like
+// MessagePumpAuraX11::Current()->display() once MessagePumpGtk goes away.
+Display* g_xdisplay = NULL;
+int g_xinput_opcode = -1;
+
+bool InitializeXInput2Internal() {
+ Display* display = MessagePumpAuraX11::GetDefaultXDisplay();
+ if (!display)
+ return false;
+
+ int event, err;
+
+ int xiopcode;
+ if (!XQueryExtension(display, "XInputExtension", &xiopcode, &event, &err)) {
+ DVLOG(1) << "X Input extension not available.";
+ return false;
+ }
+ g_xinput_opcode = xiopcode;
+
+#if defined(USE_XI2_MT)
+ // USE_XI2_MT also defines the required XI2 minor minimum version.
+ int major = 2, minor = USE_XI2_MT;
+#else
+ int major = 2, minor = 0;
+#endif
+ if (XIQueryVersion(display, &major, &minor) == BadRequest) {
+ DVLOG(1) << "XInput2 not supported in the server.";
+ return false;
+ }
+#if defined(USE_XI2_MT)
+ if (major < 2 || (major == 2 && minor < USE_XI2_MT)) {
+ DVLOG(1) << "XI version on server is " << major << "." << minor << ". "
+ << "But 2." << USE_XI2_MT << " is required.";
+ return false;
+ }
+#endif
+
+ return true;
+}
+
+Window FindEventTarget(const NativeEvent& xev) {
+ Window target = xev->xany.window;
+ if (xev->type == GenericEvent &&
+ static_cast<XIEvent*>(xev->xcookie.data)->extension == g_xinput_opcode) {
+ target = static_cast<XIDeviceEvent*>(xev->xcookie.data)->event;
+ }
+ return target;
+}
+
+bool InitializeXInput2() {
+ static bool xinput2_supported = InitializeXInput2Internal();
+ return xinput2_supported;
+}
+
+bool InitializeXkb() {
+ Display* display = MessagePumpAuraX11::GetDefaultXDisplay();
+ if (!display)
+ return false;
+
+ int opcode, event, error;
+ int major = XkbMajorVersion;
+ int minor = XkbMinorVersion;
+ if (!XkbQueryExtension(display, &opcode, &event, &error, &major, &minor)) {
+ DVLOG(1) << "Xkb extension not available.";
+ return false;
+ }
+
+ // Ask the server not to send KeyRelease event when the user holds down a key.
+ // crbug.com/138092
+ Bool supported_return;
+ if (!XkbSetDetectableAutoRepeat(display, True, &supported_return)) {
+ DVLOG(1) << "XKB not supported in the server.";
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace
+
+MessagePumpAuraX11::MessagePumpAuraX11() : MessagePumpGlib(),
+ x_source_(NULL) {
+ InitializeXInput2();
+ InitializeXkb();
+ InitXSource();
+
+ // Can't put this in the initializer list because g_xdisplay may not exist
+ // until after InitXSource().
+ x_root_window_ = DefaultRootWindow(g_xdisplay);
+}
+
+// static
+Display* MessagePumpAuraX11::GetDefaultXDisplay() {
+ if (!g_xdisplay)
+ g_xdisplay = XOpenDisplay(NULL);
+ return g_xdisplay;
+}
+
+// static
+bool MessagePumpAuraX11::HasXInput2() {
+ return InitializeXInput2();
+}
+
+// static
+MessagePumpAuraX11* MessagePumpAuraX11::Current() {
+ MessageLoopForUI* loop = MessageLoopForUI::current();
+ return static_cast<MessagePumpAuraX11*>(loop->pump_ui());
+}
+
+void MessagePumpAuraX11::AddDispatcherForWindow(
+ MessagePumpDispatcher* dispatcher,
+ unsigned long xid) {
+ dispatchers_.insert(std::make_pair(xid, dispatcher));
+}
+
+void MessagePumpAuraX11::RemoveDispatcherForWindow(unsigned long xid) {
+ dispatchers_.erase(xid);
+}
+
+void MessagePumpAuraX11::AddDispatcherForRootWindow(
+ MessagePumpDispatcher* dispatcher) {
+ root_window_dispatchers_.AddObserver(dispatcher);
+}
+
+void MessagePumpAuraX11::RemoveDispatcherForRootWindow(
+ MessagePumpDispatcher* dispatcher) {
+ root_window_dispatchers_.RemoveObserver(dispatcher);
+}
+
+bool MessagePumpAuraX11::DispatchXEvents() {
+ Display* display = GetDefaultXDisplay();
+ DCHECK(display);
+ MessagePumpDispatcher* dispatcher =
+ GetDispatcher() ? GetDispatcher() : this;
+
+ // In the general case, we want to handle all pending events before running
+ // the tasks. This is what happens in the message_pump_glib case.
+ while (XPending(display)) {
+ XEvent xev;
+ XNextEvent(display, &xev);
+ if (dispatcher && ProcessXEvent(dispatcher, &xev))
+ return TRUE;
+ }
+ return TRUE;
+}
+
+void MessagePumpAuraX11::BlockUntilWindowMapped(unsigned long xid) {
+ XEvent event;
+
+ Display* display = GetDefaultXDisplay();
+ DCHECK(display);
+
+ MessagePumpDispatcher* dispatcher =
+ GetDispatcher() ? GetDispatcher() : this;
+
+ do {
+ // Block until there's a message of |event_mask| type on |w|. Then remove
+ // it from the queue and stuff it in |event|.
+ XWindowEvent(display, xid, StructureNotifyMask, &event);
+ ProcessXEvent(dispatcher, &event);
+ } while (event.type != MapNotify);
+}
+
+MessagePumpAuraX11::~MessagePumpAuraX11() {
+ g_source_destroy(x_source_);
+ g_source_unref(x_source_);
+ XCloseDisplay(g_xdisplay);
+ g_xdisplay = NULL;
+}
+
+void MessagePumpAuraX11::InitXSource() {
+ // CHECKs are to help track down crbug.com/113106.
+ CHECK(!x_source_);
+ Display* display = GetDefaultXDisplay();
+ CHECK(display) << "Unable to get connection to X server";
+ x_poll_.reset(new GPollFD());
+ CHECK(x_poll_.get());
+ x_poll_->fd = ConnectionNumber(display);
+ x_poll_->events = G_IO_IN;
+
+ x_source_ = g_source_new(&XSourceFuncs, sizeof(GSource));
+ g_source_add_poll(x_source_, x_poll_.get());
+ g_source_set_can_recurse(x_source_, TRUE);
+ g_source_set_callback(x_source_, NULL, this, NULL);
+ g_source_attach(x_source_, g_main_context_default());
+}
+
+bool MessagePumpAuraX11::ProcessXEvent(MessagePumpDispatcher* dispatcher,
+ XEvent* xev) {
+ bool should_quit = false;
+
+ bool have_cookie = false;
+ if (xev->type == GenericEvent &&
+ XGetEventData(xev->xgeneric.display, &xev->xcookie)) {
+ have_cookie = true;
+ }
+
+ if (!WillProcessXEvent(xev)) {
+ if (!dispatcher->Dispatch(xev)) {
+ should_quit = true;
+ Quit();
+ }
+ DidProcessXEvent(xev);
+ }
+
+ if (have_cookie) {
+ XFreeEventData(xev->xgeneric.display, &xev->xcookie);
+ }
+
+ return should_quit;
+}
+
+bool MessagePumpAuraX11::WillProcessXEvent(XEvent* xevent) {
+ if (!observers().might_have_observers())
+ return false;
+ ObserverListBase<MessagePumpObserver>::Iterator it(observers());
+ MessagePumpObserver* obs;
+ while ((obs = it.GetNext()) != NULL) {
+ if (obs->WillProcessEvent(xevent))
+ return true;
+ }
+ return false;
+}
+
+void MessagePumpAuraX11::DidProcessXEvent(XEvent* xevent) {
+ FOR_EACH_OBSERVER(MessagePumpObserver, observers(), DidProcessEvent(xevent));
+}
+
+MessagePumpDispatcher* MessagePumpAuraX11::GetDispatcherForXEvent(
+ const NativeEvent& xev) const {
+ ::Window x_window = FindEventTarget(xev);
+ DispatchersMap::const_iterator it = dispatchers_.find(x_window);
+ return it != dispatchers_.end() ? it->second : NULL;
+}
+
+bool MessagePumpAuraX11::Dispatch(const NativeEvent& xev) {
+ // MappingNotify events (meaning that the keyboard or pointer buttons have
+ // been remapped) aren't associated with a window; send them to all
+ // dispatchers.
+ if (xev->type == MappingNotify) {
+ for (DispatchersMap::const_iterator it = dispatchers_.begin();
+ it != dispatchers_.end(); ++it) {
+ it->second->Dispatch(xev);
+ }
+ return true;
+ }
+
+ if (FindEventTarget(xev) == x_root_window_) {
+ FOR_EACH_OBSERVER(MessagePumpDispatcher, root_window_dispatchers_,
+ Dispatch(xev));
+ return true;
+ }
+ MessagePumpDispatcher* dispatcher = GetDispatcherForXEvent(xev);
+ return dispatcher ? dispatcher->Dispatch(xev) : true;
+}
+
+} // namespace base
diff --git a/base/message_loop/message_pump_aurax11.h b/base/message_loop/message_pump_aurax11.h
new file mode 100644
index 0000000..cec6934
--- /dev/null
+++ b/base/message_loop/message_pump_aurax11.h
@@ -0,0 +1,122 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_AURAX11_H
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_AURAX11_H
+
+#include <bitset>
+#include <map>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_pump.h"
+#include "base/message_loop/message_pump_dispatcher.h"
+#include "base/message_loop/message_pump_glib.h"
+#include "base/message_loop/message_pump_observer.h"
+#include "base/observer_list.h"
+
+// It would be nice to include the X11 headers here so that we use Window
+// instead of its typedef of unsigned long, but we can't because everything in
+// chrome includes us through base/message_loop.h, and X11's crappy #define
+// heavy headers muck up half of chrome.
+
+typedef struct _GPollFD GPollFD;
+typedef struct _GSource GSource;
+typedef struct _XDisplay Display;
+
+namespace base {
+
+// This class implements a message-pump for dispatching X events.
+//
+// If there's a current dispatcher given through RunWithDispatcher(), that
+// dispatcher receives events. Otherwise, we route to messages to dispatchers
+// who have subscribed to messages from a specific X11 window.
+class BASE_EXPORT MessagePumpAuraX11 : public MessagePumpGlib,
+ public MessagePumpDispatcher {
+ public:
+ MessagePumpAuraX11();
+
+ // Returns default X Display.
+ static Display* GetDefaultXDisplay();
+
+ // Returns true if the system supports XINPUT2.
+ static bool HasXInput2();
+
+ // Returns the UI message pump.
+ static MessagePumpAuraX11* Current();
+
+ // Adds/Removes |dispatcher| for the |xid|. This will route all messages from
+ // the window |xid| to |dispatcher.
+ void AddDispatcherForWindow(MessagePumpDispatcher* dispatcher,
+ unsigned long xid);
+ void RemoveDispatcherForWindow(unsigned long xid);
+
+ // Adds/Removes |dispatcher| to receive all events sent to the X root
+ // window. A root window can have multiple dispatchers, and events on root
+ // windows will be dispatched to all.
+ void AddDispatcherForRootWindow(MessagePumpDispatcher* dispatcher);
+ void RemoveDispatcherForRootWindow(MessagePumpDispatcher* dispatcher);
+
+ // Internal function. Called by the glib source dispatch function. Processes
+ // all available X events.
+ bool DispatchXEvents();
+
+ // Blocks on the X11 event queue until we receive notification from the
+ // xserver that |w| has been mapped; StructureNotifyMask events on |w| are
+ // pulled out from the queue and dispatched out of order.
+ //
+ // For those that know X11, this is really a wrapper around XWindowEvent
+ // which still makes sure the preempted event is dispatched instead of
+ // dropped on the floor. This method exists because mapping a window is
+ // asynchronous (and we receive an XEvent when mapped), while there are also
+ // functions which require a mapped window.
+ void BlockUntilWindowMapped(unsigned long xid);
+
+ protected:
+ virtual ~MessagePumpAuraX11();
+
+ private:
+ typedef std::map<unsigned long, MessagePumpDispatcher*> DispatchersMap;
+
+ // Initializes the glib event source for X.
+ void InitXSource();
+
+ // Dispatches the XEvent and returns true if we should exit the current loop
+ // of message processing.
+ bool ProcessXEvent(MessagePumpDispatcher* dispatcher, XEvent* event);
+
+ // Sends the event to the observers. If an observer returns true, then it does
+ // not send the event to any other observers and returns true. Returns false
+ // if no observer returns true.
+ bool WillProcessXEvent(XEvent* xevent);
+ void DidProcessXEvent(XEvent* xevent);
+
+ // Returns the Dispatcher based on the event's target window.
+ MessagePumpDispatcher* GetDispatcherForXEvent(const NativeEvent& xev) const;
+
+ // Overridden from MessagePumpDispatcher:
+ virtual bool Dispatch(const NativeEvent& event) OVERRIDE;
+
+ // The event source for X events.
+ GSource* x_source_;
+
+ // The poll attached to |x_source_|.
+ scoped_ptr<GPollFD> x_poll_;
+
+ DispatchersMap dispatchers_;
+
+ // Dispatch calls can cause addition of new dispatchers as we iterate
+ // through them. Use ObserverList to ensure the iterator remains valid across
+ // additions.
+ ObserverList<MessagePumpDispatcher> root_window_dispatchers_;
+
+ unsigned long x_root_window_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessagePumpAuraX11);
+};
+
+typedef MessagePumpAuraX11 MessagePumpForUI;
+
+} // namespace base
+
+#endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_AURAX11_H
diff --git a/base/message_loop/message_pump_default.cc b/base/message_loop/message_pump_default.cc
new file mode 100644
index 0000000..b36ff21
--- /dev/null
+++ b/base/message_loop/message_pump_default.cc
@@ -0,0 +1,85 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_pump_default.h"
+
+#include "base/logging.h"
+#include "base/threading/thread_restrictions.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_nsautorelease_pool.h"
+#endif
+
+namespace base {
+
+MessagePumpDefault::MessagePumpDefault()
+ : keep_running_(true),
+ event_(false, false) {
+}
+
+void MessagePumpDefault::Run(Delegate* delegate) {
+ DCHECK(keep_running_) << "Quit must have been called outside of Run!";
+
+ for (;;) {
+#if defined(OS_MACOSX)
+ mac::ScopedNSAutoreleasePool autorelease_pool;
+#endif
+
+ bool did_work = delegate->DoWork();
+ if (!keep_running_)
+ break;
+
+ did_work |= delegate->DoDelayedWork(&delayed_work_time_);
+ if (!keep_running_)
+ break;
+
+ if (did_work)
+ continue;
+
+ did_work = delegate->DoIdleWork();
+ if (!keep_running_)
+ break;
+
+ if (did_work)
+ continue;
+
+ ThreadRestrictions::ScopedAllowWait allow_wait;
+ if (delayed_work_time_.is_null()) {
+ event_.Wait();
+ } else {
+ TimeDelta delay = delayed_work_time_ - TimeTicks::Now();
+ if (delay > TimeDelta()) {
+ event_.TimedWait(delay);
+ } else {
+ // It looks like delayed_work_time_ indicates a time in the past, so we
+ // need to call DoDelayedWork now.
+ delayed_work_time_ = TimeTicks();
+ }
+ }
+ // Since event_ is auto-reset, we don't need to do anything special here
+ // other than service each delegate method.
+ }
+
+ keep_running_ = true;
+}
+
+void MessagePumpDefault::Quit() {
+ keep_running_ = false;
+}
+
+void MessagePumpDefault::ScheduleWork() {
+ // Since this can be called on any thread, we need to ensure that our Run
+ // loop wakes up.
+ event_.Signal();
+}
+
+void MessagePumpDefault::ScheduleDelayedWork(
+ const TimeTicks& delayed_work_time) {
+ // We know that we can't be blocked on Wait right now since this method can
+ // only be called on the same thread as Run, so we only need to update our
+ // record of how long to sleep when we do sleep.
+ delayed_work_time_ = delayed_work_time;
+}
+
+} // namespace base
diff --git a/base/message_loop/message_pump_default.h b/base/message_loop/message_pump_default.h
new file mode 100644
index 0000000..dd65973
--- /dev/null
+++ b/base/message_loop/message_pump_default.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_DEFAULT_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_DEFAULT_H_
+
+#include "base/message_loop/message_pump.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/time.h"
+
+namespace base {
+
+class MessagePumpDefault : public MessagePump {
+ public:
+ MessagePumpDefault();
+
+ // MessagePump methods:
+ virtual void Run(Delegate* delegate) OVERRIDE;
+ virtual void Quit() OVERRIDE;
+ virtual void ScheduleWork() OVERRIDE;
+ virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) OVERRIDE;
+
+ protected:
+ virtual ~MessagePumpDefault() {}
+
+ private:
+ // This flag is set to false when Run should return.
+ bool keep_running_;
+
+ // Used to sleep until there is more work to do.
+ WaitableEvent event_;
+
+ // The time at which we should call DoDelayedWork.
+ TimeTicks delayed_work_time_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessagePumpDefault);
+};
+
+} // namespace base
+
+#endif // BASE__MESSAGE_LOOPMESSAGE_PUMP_DEFAULT_H_
diff --git a/base/message_loop/message_pump_dispatcher.h b/base/message_loop/message_pump_dispatcher.h
new file mode 100644
index 0000000..e49fa4f
--- /dev/null
+++ b/base/message_loop/message_pump_dispatcher.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_DISPATCHER_H
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_DISPATCHER_H
+
+#include "base/base_export.h"
+#include "base/event_types.h"
+
+namespace base {
+
+// Dispatcher is used during a nested invocation of Run to dispatch events when
+// |RunLoop(dispatcher).Run()| is used. If |RunLoop().Run()| is invoked,
+// MessageLoop does not dispatch events (or invoke TranslateMessage), rather
+// every message is passed to Dispatcher's Dispatch method for dispatch. It is
+// up to the Dispatcher whether or not to dispatch the event.
+//
+// The nested loop is exited by either posting a quit, or returning false
+// from Dispatch.
+class BASE_EXPORT MessagePumpDispatcher {
+ public:
+ virtual ~MessagePumpDispatcher() {}
+
+ // Dispatches the event. If true is returned processing continues as
+ // normal. If false is returned, the nested loop exits immediately.
+ virtual bool Dispatch(const NativeEvent& event) = 0;
+};
+
+} // namespace base
+
+#endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_DISPATCHER_H
diff --git a/base/message_loop/message_pump_glib.cc b/base/message_loop/message_pump_glib.cc
new file mode 100644
index 0000000..de012fd
--- /dev/null
+++ b/base/message_loop/message_pump_glib.cc
@@ -0,0 +1,334 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_pump_glib.h"
+
+#include <fcntl.h>
+#include <math.h>
+
+#include <glib.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+namespace {
+
+// Return a timeout suitable for the glib loop, -1 to block forever,
+// 0 to return right away, or a timeout in milliseconds from now.
+int GetTimeIntervalMilliseconds(const TimeTicks& from) {
+ if (from.is_null())
+ return -1;
+
+ // Be careful here. TimeDelta has a precision of microseconds, but we want a
+ // value in milliseconds. If there are 5.5ms left, should the delay be 5 or
+ // 6? It should be 6 to avoid executing delayed work too early.
+ int delay = static_cast<int>(
+ ceil((from - TimeTicks::Now()).InMillisecondsF()));
+
+ // If this value is negative, then we need to run delayed work soon.
+ return delay < 0 ? 0 : delay;
+}
+
+// A brief refresher on GLib:
+// GLib sources have four callbacks: Prepare, Check, Dispatch and Finalize.
+// On each iteration of the GLib pump, it calls each source's Prepare function.
+// This function should return TRUE if it wants GLib to call its Dispatch, and
+// FALSE otherwise. It can also set a timeout in this case for the next time
+// Prepare should be called again (it may be called sooner).
+// After the Prepare calls, GLib does a poll to check for events from the
+// system. File descriptors can be attached to the sources. The poll may block
+// if none of the Prepare calls returned TRUE. It will block indefinitely, or
+// by the minimum time returned by a source in Prepare.
+// After the poll, GLib calls Check for each source that returned FALSE
+// from Prepare. The return value of Check has the same meaning as for Prepare,
+// making Check a second chance to tell GLib we are ready for Dispatch.
+// Finally, GLib calls Dispatch for each source that is ready. If Dispatch
+// returns FALSE, GLib will destroy the source. Dispatch calls may be recursive
+// (i.e., you can call Run from them), but Prepare and Check cannot.
+// Finalize is called when the source is destroyed.
+// NOTE: It is common for subsytems to want to process pending events while
+// doing intensive work, for example the flash plugin. They usually use the
+// following pattern (recommended by the GTK docs):
+// while (gtk_events_pending()) {
+// gtk_main_iteration();
+// }
+//
+// gtk_events_pending just calls g_main_context_pending, which does the
+// following:
+// - Call prepare on all the sources.
+// - Do the poll with a timeout of 0 (not blocking).
+// - Call check on all the sources.
+// - *Does not* call dispatch on the sources.
+// - Return true if any of prepare() or check() returned true.
+//
+// gtk_main_iteration just calls g_main_context_iteration, which does the whole
+// thing, respecting the timeout for the poll (and block, although it is
+// expected not to if gtk_events_pending returned true), and call dispatch.
+//
+// Thus it is important to only return true from prepare or check if we
+// actually have events or work to do. We also need to make sure we keep
+// internal state consistent so that if prepare/check return true when called
+// from gtk_events_pending, they will still return true when called right
+// after, from gtk_main_iteration.
+//
+// For the GLib pump we try to follow the Windows UI pump model:
+// - Whenever we receive a wakeup event or the timer for delayed work expires,
+// we run DoWork and/or DoDelayedWork. That part will also run in the other
+// event pumps.
+// - We also run DoWork, DoDelayedWork, and possibly DoIdleWork in the main
+// loop, around event handling.
+
+struct WorkSource : public GSource {
+ MessagePumpGlib* pump;
+};
+
+gboolean WorkSourcePrepare(GSource* source,
+ gint* 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) {
+ // Only return TRUE if Dispatch should be called.
+ return static_cast<WorkSource*>(source)->pump->HandleCheck();
+}
+
+gboolean WorkSourceDispatch(GSource* source,
+ GSourceFunc unused_func,
+ gpointer unused_data) {
+
+ static_cast<WorkSource*>(source)->pump->HandleDispatch();
+ // Always return TRUE so our source stays registered.
+ return TRUE;
+}
+
+// I wish these could be const, but g_source_new wants non-const.
+GSourceFuncs WorkSourceFuncs = {
+ WorkSourcePrepare,
+ WorkSourceCheck,
+ WorkSourceDispatch,
+ NULL
+};
+
+} // namespace
+
+struct MessagePumpGlib::RunState {
+ Delegate* delegate;
+ MessagePumpDispatcher* dispatcher;
+
+ // Used to flag that the current Run() invocation should return ASAP.
+ bool should_quit;
+
+ // Used to count how many Run() invocations are on the stack.
+ int run_depth;
+
+ // This keeps the state of whether the pump got signaled that there was new
+ // work to be done. Since we eat the message on the wake up pipe as soon as
+ // we get it, we keep that state here to stay consistent.
+ bool has_work;
+};
+
+MessagePumpGlib::MessagePumpGlib()
+ : state_(NULL),
+ context_(g_main_context_default()),
+ wakeup_gpollfd_(new GPollFD) {
+ // Create our wakeup pipe, which is used to flag when work was scheduled.
+ int fds[2];
+ int ret = pipe(fds);
+ DCHECK_EQ(ret, 0);
+ (void)ret; // Prevent warning in release mode.
+
+ wakeup_pipe_read_ = fds[0];
+ wakeup_pipe_write_ = fds[1];
+ wakeup_gpollfd_->fd = wakeup_pipe_read_;
+ wakeup_gpollfd_->events = G_IO_IN;
+
+ work_source_ = g_source_new(&WorkSourceFuncs, sizeof(WorkSource));
+ static_cast<WorkSource*>(work_source_)->pump = this;
+ g_source_add_poll(work_source_, wakeup_gpollfd_.get());
+ // 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_);
+}
+
+void MessagePumpGlib::RunWithDispatcher(Delegate* delegate,
+ MessagePumpDispatcher* dispatcher) {
+#ifndef NDEBUG
+ // Make sure we only run this on one thread. X/GTK only has one message pump
+ // so we can only have one UI loop per process.
+ static PlatformThreadId thread_id = PlatformThread::CurrentId();
+ DCHECK(thread_id == PlatformThread::CurrentId()) <<
+ "Running MessagePumpGlib on two different threads; "
+ "this is unsupported by GLib!";
+#endif
+
+ RunState state;
+ state.delegate = delegate;
+ state.dispatcher = dispatcher;
+ state.should_quit = false;
+ state.run_depth = state_ ? state_->run_depth + 1 : 1;
+ state.has_work = false;
+
+ 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 RunUntilIdle() works correctly.
+ bool more_work_is_plausible = true;
+
+ // 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?
+ for (;;) {
+ // Don't block if we think we have more work to do.
+ bool block = !more_work_is_plausible;
+
+ more_work_is_plausible = g_main_context_iteration(context_, block);
+ if (state_->should_quit)
+ break;
+
+ more_work_is_plausible |= state_->delegate->DoWork();
+ if (state_->should_quit)
+ break;
+
+ more_work_is_plausible |=
+ state_->delegate->DoDelayedWork(&delayed_work_time_);
+ if (state_->should_quit)
+ break;
+
+ if (more_work_is_plausible)
+ continue;
+
+ more_work_is_plausible = state_->delegate->DoIdleWork();
+ if (state_->should_quit)
+ break;
+ }
+
+ state_ = previous_state;
+}
+
+// Return the timeout we want passed to poll.
+int MessagePumpGlib::HandlePrepare() {
+ // We know we have work, but we haven't called HandleDispatch yet. Don't let
+ // the pump block so that we can do some processing.
+ if (state_ && // state_ may be null during tests.
+ state_->has_work)
+ return 0;
+
+ // 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_);
+}
+
+bool MessagePumpGlib::HandleCheck() {
+ if (!state_) // state_ may be null during tests.
+ return false;
+
+ // We usually have a single message on the wakeup pipe, since we are only
+ // signaled when the queue went from empty to non-empty, but there can be
+ // two messages if a task posted a task, hence we read at most two bytes.
+ // The glib poll will tell us whether there was data, so this read
+ // shouldn't block.
+ if (wakeup_gpollfd_->revents & G_IO_IN) {
+ char msg[2];
+ const int num_bytes = HANDLE_EINTR(read(wakeup_pipe_read_, msg, 2));
+ if (num_bytes < 1) {
+ NOTREACHED() << "Error reading from the wakeup pipe.";
+ }
+ DCHECK((num_bytes == 1 && msg[0] == '!') ||
+ (num_bytes == 2 && msg[0] == '!' && msg[1] == '!'));
+ // Since we ate the message, we need to record that we have more work,
+ // because HandleCheck() may be called without HandleDispatch being called
+ // afterwards.
+ state_->has_work = true;
+ }
+
+ if (state_->has_work)
+ return true;
+
+ if (GetTimeIntervalMilliseconds(delayed_work_time_) == 0) {
+ // The timer has expired. That condition will stay true until we process
+ // that delayed work, so we don't need to record this differently.
+ return true;
+ }
+
+ return false;
+}
+
+void MessagePumpGlib::HandleDispatch() {
+ state_->has_work = false;
+ if (state_->delegate->DoWork()) {
+ // NOTE: on Windows at this point we would call ScheduleWork (see
+ // MessagePumpGlib::HandleWorkMessage in message_pump_win.cc). But here,
+ // instead of posting a message on the wakeup pipe, we can avoid the
+ // syscalls and just signal that we have more work.
+ state_->has_work = true;
+ }
+
+ if (state_->should_quit)
+ return;
+
+ state_->delegate->DoDelayedWork(&delayed_work_time_);
+}
+
+void MessagePumpGlib::AddObserver(MessagePumpObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void MessagePumpGlib::RemoveObserver(MessagePumpObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void MessagePumpGlib::Run(Delegate* delegate) {
+ RunWithDispatcher(delegate, NULL);
+}
+
+void MessagePumpGlib::Quit() {
+ if (state_) {
+ state_->should_quit = true;
+ } else {
+ NOTREACHED() << "Quit called outside Run!";
+ }
+}
+
+void MessagePumpGlib::ScheduleWork() {
+ // This can be called on any thread, so we don't want to touch any state
+ // variables as we would then need locks all over. This ensures that if
+ // we are sleeping in a poll that we will wake up.
+ char msg = '!';
+ if (HANDLE_EINTR(write(wakeup_pipe_write_, &msg, 1)) != 1) {
+ NOTREACHED() << "Could not write to the UI message loop wakeup pipe!";
+ }
+}
+
+void MessagePumpGlib::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
+ // We need to wake up the loop in case the poll timeout needs to be
+ // adjusted. This will cause us to try to do work, but that's ok.
+ delayed_work_time_ = delayed_work_time;
+ ScheduleWork();
+}
+
+MessagePumpGlib::~MessagePumpGlib() {
+ g_source_destroy(work_source_);
+ g_source_unref(work_source_);
+ close(wakeup_pipe_read_);
+ close(wakeup_pipe_write_);
+}
+
+MessagePumpDispatcher* MessagePumpGlib::GetDispatcher() {
+ return state_ ? state_->dispatcher : NULL;
+}
+
+} // namespace base
diff --git a/base/message_loop/message_pump_glib.h b/base/message_loop/message_pump_glib.h
new file mode 100644
index 0000000..e45591b
--- /dev/null
+++ b/base/message_loop/message_pump_glib.h
@@ -0,0 +1,110 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_GLIB_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_GLIB_H_
+
+#include "base/base_export.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_pump.h"
+#include "base/observer_list.h"
+#include "base/time.h"
+
+typedef struct _GMainContext GMainContext;
+typedef struct _GPollFD GPollFD;
+typedef struct _GSource GSource;
+
+namespace base {
+
+// MessagePumpObserver is notified prior to an event being dispatched. As
+// Observers are notified of every change, they have to be FAST! The platform
+// specific implementation of the class is in message_pump_gtk/message_pump_x.
+class MessagePumpObserver;
+
+// MessagePumpDispatcher is used during a nested invocation of Run to dispatch
+// events. If Run is invoked with a non-NULL MessagePumpDispatcher, MessageLoop
+// does not dispatch events (or invoke gtk_main_do_event), rather every event is
+// passed to Dispatcher's Dispatch method for dispatch. It is up to the
+// Dispatcher to dispatch, or not, the event. The platform specific
+// implementation of the class is in message_pump_gtk/message_pump_x.
+class MessagePumpDispatcher;
+
+// This class implements a base MessagePump needed for TYPE_UI MessageLoops on
+// platforms using GLib.
+class BASE_EXPORT MessagePumpGlib : public MessagePump {
+ public:
+ MessagePumpGlib();
+
+ // Like MessagePump::Run, but events are routed through dispatcher.
+ virtual void RunWithDispatcher(Delegate* delegate,
+ MessagePumpDispatcher* dispatcher);
+
+ // Internal methods used for processing the pump callbacks. They are
+ // public for simplicity but should not be used directly. HandlePrepare
+ // is called during the prepare step of glib, and returns a timeout that
+ // will be passed to the poll. HandleCheck is called after the poll
+ // has completed, and returns whether or not HandleDispatch should be called.
+ // HandleDispatch is called if HandleCheck returned true.
+ int HandlePrepare();
+ bool HandleCheck();
+ void HandleDispatch();
+
+ // Adds an Observer, which will start receiving notifications immediately.
+ void AddObserver(MessagePumpObserver* observer);
+
+ // Removes an Observer. It is safe to call this method while an Observer is
+ // receiving a notification callback.
+ void RemoveObserver(MessagePumpObserver* observer);
+
+ // Overridden from MessagePump:
+ virtual void Run(Delegate* delegate) OVERRIDE;
+ virtual void Quit() OVERRIDE;
+ virtual void ScheduleWork() OVERRIDE;
+ virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) OVERRIDE;
+
+ protected:
+ virtual ~MessagePumpGlib();
+
+ // Returns the dispatcher for the current run state (|state_->dispatcher|).
+ MessagePumpDispatcher* GetDispatcher();
+
+ ObserverList<MessagePumpObserver>& observers() { return observers_; }
+
+ private:
+ // We may make recursive calls to Run, so we save state that needs to be
+ // separate between them in this structure type.
+ struct RunState;
+
+ RunState* state_;
+
+ // This is a GLib structure that we can add event sources to. We use the
+ // default GLib context, which is the one to which all GTK events are
+ // dispatched.
+ GMainContext* context_;
+
+ // This is the time when we need to do delayed work.
+ TimeTicks delayed_work_time_;
+
+ // The work source. It is shared by all calls to Run and destroyed when
+ // the message pump is destroyed.
+ GSource* work_source_;
+
+ // We use a wakeup pipe to make sure we'll get out of the glib polling phase
+ // when another thread has scheduled us to do some work. There is a glib
+ // mechanism g_main_context_wakeup, but this won't guarantee that our event's
+ // Dispatch() will be called.
+ int wakeup_pipe_read_;
+ int wakeup_pipe_write_;
+ // Use a scoped_ptr to avoid needing the definition of GPollFD in the header.
+ scoped_ptr<GPollFD> wakeup_gpollfd_;
+
+ // List of observers.
+ ObserverList<MessagePumpObserver> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessagePumpGlib);
+};
+
+} // namespace base
+
+#endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_GLIB_H_
diff --git a/base/message_loop/message_pump_glib_unittest.cc b/base/message_loop/message_pump_glib_unittest.cc
new file mode 100644
index 0000000..cb30bb0
--- /dev/null
+++ b/base/message_loop/message_pump_glib_unittest.cc
@@ -0,0 +1,580 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_pump_glib.h"
+
+#include <glib.h>
+#include <math.h>
+
+#include <algorithm>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop.h"
+#include "base/run_loop.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(TOOLKIT_GTK)
+#include <gtk/gtk.h>
+#endif
+
+namespace base {
+namespace {
+
+// This class injects dummy "events" into the GLib loop. When "handled" these
+// events can run tasks. This is intended to mock gtk events (the corresponding
+// GLib source runs at the same priority).
+class EventInjector {
+ public:
+ EventInjector() : processed_events_(0) {
+ source_ = static_cast<Source*>(g_source_new(&SourceFuncs, sizeof(Source)));
+ source_->injector = this;
+ g_source_attach(source_, NULL);
+ g_source_set_can_recurse(source_, TRUE);
+ }
+
+ ~EventInjector() {
+ g_source_destroy(source_);
+ g_source_unref(source_);
+ }
+
+ int HandlePrepare() {
+ // If the queue is empty, block.
+ if (events_.empty())
+ return -1;
+ TimeDelta delta = events_[0].time - Time::NowFromSystemTime();
+ return std::max(0, static_cast<int>(ceil(delta.InMillisecondsF())));
+ }
+
+ bool HandleCheck() {
+ if (events_.empty())
+ return false;
+ return events_[0].time <= Time::NowFromSystemTime();
+ }
+
+ void HandleDispatch() {
+ if (events_.empty())
+ return;
+ Event event = events_[0];
+ events_.erase(events_.begin());
+ ++processed_events_;
+ if (!event.callback.is_null())
+ event.callback.Run();
+ else if (!event.task.is_null())
+ event.task.Run();
+ }
+
+ // Adds an event to the queue. When "handled", executes |callback|.
+ // delay_ms is relative to the last event if any, or to Now() otherwise.
+ void AddEvent(int delay_ms, const Closure& callback) {
+ AddEventHelper(delay_ms, callback, Closure());
+ }
+
+ void AddDummyEvent(int delay_ms) {
+ AddEventHelper(delay_ms, Closure(), Closure());
+ }
+
+ void AddEventAsTask(int delay_ms, const Closure& task) {
+ AddEventHelper(delay_ms, Closure(), task);
+ }
+
+ void Reset() {
+ processed_events_ = 0;
+ events_.clear();
+ }
+
+ int processed_events() const { return processed_events_; }
+
+ private:
+ struct Event {
+ Time time;
+ Closure callback;
+ Closure task;
+ };
+
+ struct Source : public GSource {
+ EventInjector* injector;
+ };
+
+ void AddEventHelper(
+ int delay_ms, const Closure& callback, const Closure& task) {
+ Time last_time;
+ if (!events_.empty())
+ last_time = (events_.end()-1)->time;
+ else
+ last_time = Time::NowFromSystemTime();
+
+ Time future = last_time + TimeDelta::FromMilliseconds(delay_ms);
+ EventInjector::Event event = {future, callback, task};
+ events_.push_back(event);
+ }
+
+ static gboolean Prepare(GSource* source, gint* timeout_ms) {
+ *timeout_ms = static_cast<Source*>(source)->injector->HandlePrepare();
+ return FALSE;
+ }
+
+ static gboolean Check(GSource* source) {
+ return static_cast<Source*>(source)->injector->HandleCheck();
+ }
+
+ static gboolean Dispatch(GSource* source,
+ GSourceFunc unused_func,
+ gpointer unused_data) {
+ static_cast<Source*>(source)->injector->HandleDispatch();
+ return TRUE;
+ }
+
+ Source* source_;
+ std::vector<Event> events_;
+ int processed_events_;
+ static GSourceFuncs SourceFuncs;
+ DISALLOW_COPY_AND_ASSIGN(EventInjector);
+};
+
+GSourceFuncs EventInjector::SourceFuncs = {
+ EventInjector::Prepare,
+ EventInjector::Check,
+ EventInjector::Dispatch,
+ NULL
+};
+
+void IncrementInt(int *value) {
+ ++*value;
+}
+
+// Checks how many events have been processed by the injector.
+void ExpectProcessedEvents(EventInjector* injector, int count) {
+ EXPECT_EQ(injector->processed_events(), count);
+}
+
+// Posts a task on the current message loop.
+void PostMessageLoopTask(const tracked_objects::Location& from_here,
+ const Closure& task) {
+ MessageLoop::current()->PostTask(from_here, task);
+}
+
+// Test fixture.
+class MessagePumpGLibTest : public testing::Test {
+ public:
+ MessagePumpGLibTest() : loop_(NULL), injector_(NULL) { }
+
+ // Overridden from testing::Test:
+ virtual void SetUp() OVERRIDE {
+ loop_ = new MessageLoop(MessageLoop::TYPE_UI);
+ injector_ = new EventInjector();
+ }
+ virtual void TearDown() OVERRIDE {
+ delete injector_;
+ injector_ = NULL;
+ delete loop_;
+ loop_ = NULL;
+ }
+
+ MessageLoop* loop() const { return loop_; }
+ EventInjector* injector() const { return injector_; }
+
+ private:
+ MessageLoop* loop_;
+ EventInjector* injector_;
+ DISALLOW_COPY_AND_ASSIGN(MessagePumpGLibTest);
+};
+
+} // namespace
+
+TEST_F(MessagePumpGLibTest, TestQuit) {
+ // Checks that Quit works and that the basic infrastructure is working.
+
+ // Quit from a task
+ RunLoop().RunUntilIdle();
+ EXPECT_EQ(0, injector()->processed_events());
+
+ injector()->Reset();
+ // Quit from an event
+ injector()->AddEvent(0, MessageLoop::QuitWhenIdleClosure());
+ loop()->Run();
+ EXPECT_EQ(1, injector()->processed_events());
+}
+
+TEST_F(MessagePumpGLibTest, TestEventTaskInterleave) {
+ // Checks that tasks posted by events are executed before the next event if
+ // the posted task queue is empty.
+ // MessageLoop doesn't make strong guarantees that it is the case, but the
+ // current implementation ensures it and the tests below rely on it.
+ // If changes cause this test to fail, it is reasonable to change it, but
+ // TestWorkWhileWaitingForEvents and TestEventsWhileWaitingForWork have to be
+ // changed accordingly, otherwise they can become flaky.
+ injector()->AddEventAsTask(0, Bind(&DoNothing));
+ Closure check_task =
+ Bind(&ExpectProcessedEvents, Unretained(injector()), 2);
+ Closure posted_task =
+ Bind(&PostMessageLoopTask, FROM_HERE, check_task);
+ injector()->AddEventAsTask(0, posted_task);
+ injector()->AddEventAsTask(0, Bind(&DoNothing));
+ injector()->AddEvent(0, MessageLoop::QuitWhenIdleClosure());
+ loop()->Run();
+ EXPECT_EQ(4, injector()->processed_events());
+
+ injector()->Reset();
+ injector()->AddEventAsTask(0, Bind(&DoNothing));
+ check_task =
+ Bind(&ExpectProcessedEvents, Unretained(injector()), 2);
+ posted_task = Bind(&PostMessageLoopTask, FROM_HERE, check_task);
+ injector()->AddEventAsTask(0, posted_task);
+ injector()->AddEventAsTask(10, Bind(&DoNothing));
+ injector()->AddEvent(0, MessageLoop::QuitWhenIdleClosure());
+ loop()->Run();
+ EXPECT_EQ(4, injector()->processed_events());
+}
+
+TEST_F(MessagePumpGLibTest, TestWorkWhileWaitingForEvents) {
+ int task_count = 0;
+ // Tests that we process tasks while waiting for new events.
+ // The event queue is empty at first.
+ for (int i = 0; i < 10; ++i) {
+ loop()->PostTask(FROM_HERE, Bind(&IncrementInt, &task_count));
+ }
+ // After all the previous tasks have executed, enqueue an event that will
+ // quit.
+ loop()->PostTask(
+ FROM_HERE,
+ Bind(&EventInjector::AddEvent, Unretained(injector()), 0,
+ MessageLoop::QuitWhenIdleClosure()));
+ loop()->Run();
+ ASSERT_EQ(10, task_count);
+ EXPECT_EQ(1, injector()->processed_events());
+
+ // Tests that we process delayed tasks while waiting for new events.
+ injector()->Reset();
+ task_count = 0;
+ for (int i = 0; i < 10; ++i) {
+ loop()->PostDelayedTask(
+ FROM_HERE,
+ Bind(&IncrementInt, &task_count),
+ TimeDelta::FromMilliseconds(10*i));
+ }
+ // After all the previous tasks have executed, enqueue an event that will
+ // quit.
+ // This relies on the fact that delayed tasks are executed in delay order.
+ // That is verified in message_loop_unittest.cc.
+ loop()->PostDelayedTask(
+ FROM_HERE,
+ Bind(&EventInjector::AddEvent, Unretained(injector()), 10,
+ MessageLoop::QuitWhenIdleClosure()),
+ TimeDelta::FromMilliseconds(150));
+ loop()->Run();
+ ASSERT_EQ(10, task_count);
+ EXPECT_EQ(1, injector()->processed_events());
+}
+
+TEST_F(MessagePumpGLibTest, TestEventsWhileWaitingForWork) {
+ // Tests that we process events while waiting for work.
+ // The event queue is empty at first.
+ for (int i = 0; i < 10; ++i) {
+ injector()->AddDummyEvent(0);
+ }
+ // After all the events have been processed, post a task that will check that
+ // the events have been processed (note: the task executes after the event
+ // that posted it has been handled, so we expect 11 at that point).
+ Closure check_task =
+ Bind(&ExpectProcessedEvents, Unretained(injector()), 11);
+ Closure posted_task =
+ Bind(&PostMessageLoopTask, FROM_HERE, check_task);
+ injector()->AddEventAsTask(10, posted_task);
+
+ // And then quit (relies on the condition tested by TestEventTaskInterleave).
+ injector()->AddEvent(10, MessageLoop::QuitWhenIdleClosure());
+ loop()->Run();
+
+ EXPECT_EQ(12, injector()->processed_events());
+}
+
+namespace {
+
+// This class is a helper for the concurrent events / posted tasks test below.
+// It will quit the main loop once enough tasks and events have been processed,
+// while making sure there is always work to do and events in the queue.
+class ConcurrentHelper : public RefCounted<ConcurrentHelper> {
+ public:
+ explicit ConcurrentHelper(EventInjector* injector)
+ : injector_(injector),
+ event_count_(kStartingEventCount),
+ task_count_(kStartingTaskCount) {
+ }
+
+ void FromTask() {
+ if (task_count_ > 0) {
+ --task_count_;
+ }
+ if (task_count_ == 0 && event_count_ == 0) {
+ MessageLoop::current()->QuitWhenIdle();
+ } else {
+ MessageLoop::current()->PostTask(
+ FROM_HERE, Bind(&ConcurrentHelper::FromTask, this));
+ }
+ }
+
+ void FromEvent() {
+ if (event_count_ > 0) {
+ --event_count_;
+ }
+ if (task_count_ == 0 && event_count_ == 0) {
+ MessageLoop::current()->QuitWhenIdle();
+ } else {
+ injector_->AddEventAsTask(
+ 0, Bind(&ConcurrentHelper::FromEvent, this));
+ }
+ }
+
+ int event_count() const { return event_count_; }
+ int task_count() const { return task_count_; }
+
+ private:
+ friend class RefCounted<ConcurrentHelper>;
+
+ ~ConcurrentHelper() {}
+
+ static const int kStartingEventCount = 20;
+ static const int kStartingTaskCount = 20;
+
+ EventInjector* injector_;
+ int event_count_;
+ int task_count_;
+};
+
+} // namespace
+
+TEST_F(MessagePumpGLibTest, TestConcurrentEventPostedTask) {
+ // Tests that posted tasks don't starve events, nor the opposite.
+ // We use the helper class above. We keep both event and posted task queues
+ // full, the helper verifies that both tasks and events get processed.
+ // If that is not the case, either event_count_ or task_count_ will not get
+ // to 0, and MessageLoop::QuitWhenIdle() will never be called.
+ scoped_refptr<ConcurrentHelper> helper = new ConcurrentHelper(injector());
+
+ // Add 2 events to the queue to make sure it is always full (when we remove
+ // the event before processing it).
+ injector()->AddEventAsTask(
+ 0, Bind(&ConcurrentHelper::FromEvent, helper.get()));
+ injector()->AddEventAsTask(
+ 0, Bind(&ConcurrentHelper::FromEvent, helper.get()));
+
+ // Similarly post 2 tasks.
+ loop()->PostTask(
+ FROM_HERE, Bind(&ConcurrentHelper::FromTask, helper.get()));
+ loop()->PostTask(
+ FROM_HERE, Bind(&ConcurrentHelper::FromTask, helper.get()));
+
+ loop()->Run();
+ EXPECT_EQ(0, helper->event_count());
+ EXPECT_EQ(0, helper->task_count());
+}
+
+namespace {
+
+void AddEventsAndDrainGLib(EventInjector* injector) {
+ // Add a couple of dummy events
+ injector->AddDummyEvent(0);
+ injector->AddDummyEvent(0);
+ // Then add an event that will quit the main loop.
+ injector->AddEvent(0, MessageLoop::QuitWhenIdleClosure());
+
+ // Post a couple of dummy tasks
+ MessageLoop::current()->PostTask(FROM_HERE, Bind(&DoNothing));
+ MessageLoop::current()->PostTask(FROM_HERE, Bind(&DoNothing));
+
+ // Drain the events
+ while (g_main_context_pending(NULL)) {
+ g_main_context_iteration(NULL, FALSE);
+ }
+}
+
+} // namespace
+
+TEST_F(MessagePumpGLibTest, TestDrainingGLib) {
+ // Tests that draining events using GLib works.
+ loop()->PostTask(
+ FROM_HERE,
+ Bind(&AddEventsAndDrainGLib, Unretained(injector())));
+ loop()->Run();
+
+ EXPECT_EQ(3, injector()->processed_events());
+}
+
+
+namespace {
+
+#if defined(TOOLKIT_GTK)
+void AddEventsAndDrainGtk(EventInjector* injector) {
+ // Add a couple of dummy events
+ injector->AddDummyEvent(0);
+ injector->AddDummyEvent(0);
+ // Then add an event that will quit the main loop.
+ injector->AddEvent(0, MessageLoop::QuitWhenIdleClosure());
+
+ // Post a couple of dummy tasks
+ MessageLoop::current()->PostTask(FROM_HERE, Bind(&DoNothing));
+ MessageLoop::current()->PostTask(FROM_HERE, Bind(&DoNothing));
+
+ // Drain the events
+ while (gtk_events_pending()) {
+ gtk_main_iteration();
+ }
+}
+#endif
+
+} // namespace
+
+#if defined(TOOLKIT_GTK)
+TEST_F(MessagePumpGLibTest, TestDrainingGtk) {
+ // Tests that draining events using Gtk works.
+ loop()->PostTask(
+ FROM_HERE,
+ Bind(&AddEventsAndDrainGtk, Unretained(injector())));
+ loop()->Run();
+
+ EXPECT_EQ(3, injector()->processed_events());
+}
+#endif
+
+namespace {
+
+// Helper class that lets us run the GLib message loop.
+class GLibLoopRunner : public RefCounted<GLibLoopRunner> {
+ public:
+ GLibLoopRunner() : quit_(false) { }
+
+ void RunGLib() {
+ while (!quit_) {
+ g_main_context_iteration(NULL, TRUE);
+ }
+ }
+
+ void RunLoop() {
+#if defined(TOOLKIT_GTK)
+ while (!quit_) {
+ gtk_main_iteration();
+ }
+#else
+ while (!quit_) {
+ g_main_context_iteration(NULL, TRUE);
+ }
+#endif
+ }
+
+ void Quit() {
+ quit_ = true;
+ }
+
+ void Reset() {
+ quit_ = false;
+ }
+
+ private:
+ friend class RefCounted<GLibLoopRunner>;
+
+ ~GLibLoopRunner() {}
+
+ bool quit_;
+};
+
+void TestGLibLoopInternal(EventInjector* injector) {
+ // Allow tasks to be processed from 'native' event loops.
+ MessageLoop::current()->SetNestableTasksAllowed(true);
+ scoped_refptr<GLibLoopRunner> runner = new GLibLoopRunner();
+
+ int task_count = 0;
+ // Add a couple of dummy events
+ injector->AddDummyEvent(0);
+ injector->AddDummyEvent(0);
+ // Post a couple of dummy tasks
+ MessageLoop::current()->PostTask(
+ FROM_HERE, Bind(&IncrementInt, &task_count));
+ MessageLoop::current()->PostTask(
+ FROM_HERE, Bind(&IncrementInt, &task_count));
+ // Delayed events
+ injector->AddDummyEvent(10);
+ injector->AddDummyEvent(10);
+ // Delayed work
+ MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ Bind(&IncrementInt, &task_count),
+ TimeDelta::FromMilliseconds(30));
+ MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ Bind(&GLibLoopRunner::Quit, runner.get()),
+ TimeDelta::FromMilliseconds(40));
+
+ // Run a nested, straight GLib message loop.
+ runner->RunGLib();
+
+ ASSERT_EQ(3, task_count);
+ EXPECT_EQ(4, injector->processed_events());
+ MessageLoop::current()->QuitWhenIdle();
+}
+
+void TestGtkLoopInternal(EventInjector* injector) {
+ // Allow tasks to be processed from 'native' event loops.
+ MessageLoop::current()->SetNestableTasksAllowed(true);
+ scoped_refptr<GLibLoopRunner> runner = new GLibLoopRunner();
+
+ int task_count = 0;
+ // Add a couple of dummy events
+ injector->AddDummyEvent(0);
+ injector->AddDummyEvent(0);
+ // Post a couple of dummy tasks
+ MessageLoop::current()->PostTask(
+ FROM_HERE, Bind(&IncrementInt, &task_count));
+ MessageLoop::current()->PostTask(
+ FROM_HERE, Bind(&IncrementInt, &task_count));
+ // Delayed events
+ injector->AddDummyEvent(10);
+ injector->AddDummyEvent(10);
+ // Delayed work
+ MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ Bind(&IncrementInt, &task_count),
+ TimeDelta::FromMilliseconds(30));
+ MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ Bind(&GLibLoopRunner::Quit, runner.get()),
+ TimeDelta::FromMilliseconds(40));
+
+ // Run a nested, straight Gtk message loop.
+ runner->RunLoop();
+
+ ASSERT_EQ(3, task_count);
+ EXPECT_EQ(4, injector->processed_events());
+ MessageLoop::current()->QuitWhenIdle();
+}
+
+} // namespace
+
+TEST_F(MessagePumpGLibTest, TestGLibLoop) {
+ // Tests that events and posted tasks are correctly executed if the message
+ // loop is not run by MessageLoop::Run() but by a straight GLib loop.
+ // Note that in this case we don't make strong guarantees about niceness
+ // between events and posted tasks.
+ loop()->PostTask(
+ FROM_HERE,
+ Bind(&TestGLibLoopInternal, Unretained(injector())));
+ loop()->Run();
+}
+
+TEST_F(MessagePumpGLibTest, TestGtkLoop) {
+ // Tests that events and posted tasks are correctly executed if the message
+ // loop is not run by MessageLoop::Run() but by a straight Gtk loop.
+ // Note that in this case we don't make strong guarantees about niceness
+ // between events and posted tasks.
+ loop()->PostTask(
+ FROM_HERE,
+ Bind(&TestGtkLoopInternal, Unretained(injector())));
+ loop()->Run();
+}
+
+} // namespace base
diff --git a/base/message_loop/message_pump_gtk.cc b/base/message_loop/message_pump_gtk.cc
new file mode 100644
index 0000000..8fa8cf2
--- /dev/null
+++ b/base/message_loop/message_pump_gtk.cc
@@ -0,0 +1,114 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_pump_gtk.h"
+
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+
+#include "base/debug/trace_event.h"
+#include "base/profiler/scoped_profile.h"
+
+namespace base {
+
+namespace {
+
+const char* EventToTypeString(const GdkEvent* event) {
+ switch (event->type) {
+ case GDK_NOTHING: return "GDK_NOTHING";
+ case GDK_DELETE: return "GDK_DELETE";
+ case GDK_DESTROY: return "GDK_DESTROY";
+ case GDK_EXPOSE: return "GDK_EXPOSE";
+ case GDK_MOTION_NOTIFY: return "GDK_MOTION_NOTIFY";
+ case GDK_BUTTON_PRESS: return "GDK_BUTTON_PRESS";
+ case GDK_2BUTTON_PRESS: return "GDK_2BUTTON_PRESS";
+ case GDK_3BUTTON_PRESS: return "GDK_3BUTTON_PRESS";
+ case GDK_BUTTON_RELEASE: return "GDK_BUTTON_RELEASE";
+ case GDK_KEY_PRESS: return "GDK_KEY_PRESS";
+ case GDK_KEY_RELEASE: return "GDK_KEY_RELEASE";
+ case GDK_ENTER_NOTIFY: return "GDK_ENTER_NOTIFY";
+ case GDK_LEAVE_NOTIFY: return "GDK_LEAVE_NOTIFY";
+ case GDK_FOCUS_CHANGE: return "GDK_FOCUS_CHANGE";
+ case GDK_CONFIGURE: return "GDK_CONFIGURE";
+ case GDK_MAP: return "GDK_MAP";
+ case GDK_UNMAP: return "GDK_UNMAP";
+ case GDK_PROPERTY_NOTIFY: return "GDK_PROPERTY_NOTIFY";
+ case GDK_SELECTION_CLEAR: return "GDK_SELECTION_CLEAR";
+ case GDK_SELECTION_REQUEST: return "GDK_SELECTION_REQUEST";
+ case GDK_SELECTION_NOTIFY: return "GDK_SELECTION_NOTIFY";
+ case GDK_PROXIMITY_IN: return "GDK_PROXIMITY_IN";
+ case GDK_PROXIMITY_OUT: return "GDK_PROXIMITY_OUT";
+ case GDK_DRAG_ENTER: return "GDK_DRAG_ENTER";
+ case GDK_DRAG_LEAVE: return "GDK_DRAG_LEAVE";
+ case GDK_DRAG_MOTION: return "GDK_DRAG_MOTION";
+ case GDK_DRAG_STATUS: return "GDK_DRAG_STATUS";
+ case GDK_DROP_START: return "GDK_DROP_START";
+ case GDK_DROP_FINISHED: return "GDK_DROP_FINISHED";
+ case GDK_CLIENT_EVENT: return "GDK_CLIENT_EVENT";
+ case GDK_VISIBILITY_NOTIFY: return "GDK_VISIBILITY_NOTIFY";
+ case GDK_NO_EXPOSE: return "GDK_NO_EXPOSE";
+ case GDK_SCROLL: return "GDK_SCROLL";
+ case GDK_WINDOW_STATE: return "GDK_WINDOW_STATE";
+ case GDK_SETTING: return "GDK_SETTING";
+ case GDK_OWNER_CHANGE: return "GDK_OWNER_CHANGE";
+ case GDK_GRAB_BROKEN: return "GDK_GRAB_BROKEN";
+ case GDK_DAMAGE: return "GDK_DAMAGE";
+ default:
+ return "Unknown Gdk Event";
+ }
+}
+
+} // namespace
+
+MessagePumpGtk::MessagePumpGtk() : MessagePumpGlib() {
+ gdk_event_handler_set(&EventDispatcher, this, NULL);
+}
+
+void MessagePumpGtk::DispatchEvents(GdkEvent* event) {
+ UNSHIPPED_TRACE_EVENT1("task", "MessagePumpGtk::DispatchEvents",
+ "type", EventToTypeString(event));
+
+ WillProcessEvent(event);
+
+ MessagePumpDispatcher* dispatcher = GetDispatcher();
+ if (!dispatcher)
+ gtk_main_do_event(event);
+ else if (!dispatcher->Dispatch(event))
+ Quit();
+
+ DidProcessEvent(event);
+}
+
+// static
+Display* MessagePumpGtk::GetDefaultXDisplay() {
+ static GdkDisplay* display = gdk_display_get_default();
+ if (!display) {
+ // GTK / GDK has not been initialized, which is a decision we wish to
+ // support, for example for the GPU process.
+ static Display* xdisplay = XOpenDisplay(NULL);
+ return xdisplay;
+ }
+ return GDK_DISPLAY_XDISPLAY(display);
+}
+
+MessagePumpGtk::~MessagePumpGtk() {
+ gdk_event_handler_set(reinterpret_cast<GdkEventFunc>(gtk_main_do_event),
+ this, NULL);
+}
+
+void MessagePumpGtk::WillProcessEvent(GdkEvent* event) {
+ FOR_EACH_OBSERVER(MessagePumpObserver, observers(), WillProcessEvent(event));
+}
+
+void MessagePumpGtk::DidProcessEvent(GdkEvent* event) {
+ FOR_EACH_OBSERVER(MessagePumpObserver, observers(), DidProcessEvent(event));
+}
+
+// static
+void MessagePumpGtk::EventDispatcher(GdkEvent* event, gpointer data) {
+ MessagePumpGtk* message_pump = reinterpret_cast<MessagePumpGtk*>(data);
+ message_pump->DispatchEvents(event);
+}
+
+} // namespace base
diff --git a/base/message_loop/message_pump_gtk.h b/base/message_loop/message_pump_gtk.h
new file mode 100644
index 0000000..e22e04f
--- /dev/null
+++ b/base/message_loop/message_pump_gtk.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_GTK_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_GTK_H_
+
+#include "base/message_loop/message_pump_glib.h"
+
+typedef union _GdkEvent GdkEvent;
+typedef struct _XDisplay Display;
+
+namespace base {
+
+// The documentation for this class is in message_pump_glib.h
+class MessagePumpObserver {
+ public:
+ // This method is called before processing a message.
+ virtual void WillProcessEvent(GdkEvent* event) = 0;
+
+ // This method is called after processing a message.
+ virtual void DidProcessEvent(GdkEvent* event) = 0;
+
+ protected:
+ virtual ~MessagePumpObserver() {}
+};
+
+// The documentation for this class is in message_pump_glib.h
+//
+// The nested loop is exited by either posting a quit, or returning false
+// from Dispatch.
+class MessagePumpDispatcher {
+ public:
+ // Dispatches the event. If true is returned processing continues as
+ // normal. If false is returned, the nested loop exits immediately.
+ virtual bool Dispatch(GdkEvent* event) = 0;
+
+ protected:
+ virtual ~MessagePumpDispatcher() {}
+};
+
+// This class implements a message-pump for dispatching GTK events.
+class BASE_EXPORT MessagePumpGtk : public MessagePumpGlib {
+ public:
+ MessagePumpGtk();
+
+ // Dispatch an available GdkEvent. Essentially this allows a subclass to do
+ // some task before/after calling the default handler (EventDispatcher).
+ void DispatchEvents(GdkEvent* event);
+
+ // Returns default X Display.
+ static Display* GetDefaultXDisplay();
+
+ protected:
+ virtual ~MessagePumpGtk();
+
+ private:
+ // Invoked from EventDispatcher. Notifies all observers we're about to
+ // process an event.
+ void WillProcessEvent(GdkEvent* event);
+
+ // Invoked from EventDispatcher. Notifies all observers we processed an
+ // event.
+ void DidProcessEvent(GdkEvent* event);
+
+ // Callback prior to gdk dispatching an event.
+ static void EventDispatcher(GdkEvent* event, void* data);
+
+ DISALLOW_COPY_AND_ASSIGN(MessagePumpGtk);
+};
+
+typedef MessagePumpGtk MessagePumpForUI;
+
+} // namespace base
+
+#endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_GTK_H_
diff --git a/base/message_loop/message_pump_io_ios.cc b/base/message_loop/message_pump_io_ios.cc
new file mode 100644
index 0000000..5868195
--- /dev/null
+++ b/base/message_loop/message_pump_io_ios.cc
@@ -0,0 +1,209 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_pump_io_ios.h"
+
+namespace base {
+
+MessagePumpIOSForIO::FileDescriptorWatcher::FileDescriptorWatcher()
+ : is_persistent_(false),
+ fdref_(NULL),
+ callback_types_(0),
+ fd_source_(NULL),
+ pump_(NULL),
+ watcher_(NULL) {
+}
+
+MessagePumpIOSForIO::FileDescriptorWatcher::~FileDescriptorWatcher() {
+ StopWatchingFileDescriptor();
+}
+
+bool MessagePumpIOSForIO::FileDescriptorWatcher::StopWatchingFileDescriptor() {
+ if (fdref_ == NULL)
+ return true;
+
+ CFFileDescriptorDisableCallBacks(fdref_, callback_types_);
+ pump_->RemoveRunLoopSource(fd_source_);
+ fd_source_.reset();
+ fdref_.reset();
+ callback_types_ = 0;
+ pump_ = NULL;
+ watcher_ = NULL;
+ return true;
+}
+
+void MessagePumpIOSForIO::FileDescriptorWatcher::Init(
+ CFFileDescriptorRef fdref,
+ CFOptionFlags callback_types,
+ CFRunLoopSourceRef fd_source,
+ bool is_persistent) {
+ DCHECK(fdref);
+ DCHECK(!fdref_);
+
+ is_persistent_ = is_persistent;
+ fdref_.reset(fdref);
+ callback_types_ = callback_types;
+ fd_source_.reset(fd_source);
+}
+
+void MessagePumpIOSForIO::FileDescriptorWatcher::OnFileCanReadWithoutBlocking(
+ int fd,
+ MessagePumpIOSForIO* pump) {
+ DCHECK(callback_types_ & kCFFileDescriptorReadCallBack);
+ pump->WillProcessIOEvent();
+ watcher_->OnFileCanReadWithoutBlocking(fd);
+ pump->DidProcessIOEvent();
+}
+
+void MessagePumpIOSForIO::FileDescriptorWatcher::OnFileCanWriteWithoutBlocking(
+ int fd,
+ MessagePumpIOSForIO* pump) {
+ DCHECK(callback_types_ & kCFFileDescriptorWriteCallBack);
+ pump->WillProcessIOEvent();
+ watcher_->OnFileCanWriteWithoutBlocking(fd);
+ pump->DidProcessIOEvent();
+}
+
+MessagePumpIOSForIO::MessagePumpIOSForIO() {
+}
+
+MessagePumpIOSForIO::~MessagePumpIOSForIO() {
+}
+
+bool MessagePumpIOSForIO::WatchFileDescriptor(
+ int fd,
+ bool persistent,
+ int mode,
+ FileDescriptorWatcher *controller,
+ Watcher *delegate) {
+ DCHECK_GE(fd, 0);
+ DCHECK(controller);
+ DCHECK(delegate);
+ DCHECK(mode == WATCH_READ || mode == WATCH_WRITE || mode == WATCH_READ_WRITE);
+
+ // WatchFileDescriptor should be called on the pump thread. It is not
+ // threadsafe, and your watcher may never be registered.
+ DCHECK(watch_file_descriptor_caller_checker_.CalledOnValidThread());
+
+ CFFileDescriptorContext source_context = {0};
+ source_context.info = controller;
+
+ CFOptionFlags callback_types = 0;
+ if (mode & WATCH_READ) {
+ callback_types |= kCFFileDescriptorReadCallBack;
+ }
+ if (mode & WATCH_WRITE) {
+ callback_types |= kCFFileDescriptorWriteCallBack;
+ }
+
+ CFFileDescriptorRef fdref = controller->fdref_;
+ if (fdref == NULL) {
+ base::mac::ScopedCFTypeRef<CFFileDescriptorRef> scoped_fdref(
+ CFFileDescriptorCreate(kCFAllocatorDefault, fd, false, HandleFdIOEvent,
+ &source_context));
+ if (scoped_fdref == NULL) {
+ NOTREACHED() << "CFFileDescriptorCreate failed";
+ return false;
+ }
+
+ CFFileDescriptorEnableCallBacks(scoped_fdref, callback_types);
+
+ // TODO(wtc): what should the 'order' argument be?
+ base::mac::ScopedCFTypeRef<CFRunLoopSourceRef> scoped_fd_source(
+ CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault,
+ scoped_fdref,
+ 0));
+ if (scoped_fd_source == NULL) {
+ NOTREACHED() << "CFFileDescriptorCreateRunLoopSource failed";
+ return false;
+ }
+ CFRunLoopAddSource(run_loop(), scoped_fd_source, kCFRunLoopCommonModes);
+
+ // Transfer ownership of scoped_fdref and fd_source to controller.
+ controller->Init(scoped_fdref.release(), callback_types,
+ scoped_fd_source.release(), persistent);
+ } else {
+ // It's illegal to use this function to listen on 2 separate fds with the
+ // same |controller|.
+ if (CFFileDescriptorGetNativeDescriptor(fdref) != fd) {
+ NOTREACHED() << "FDs don't match: "
+ << CFFileDescriptorGetNativeDescriptor(fdref)
+ << " != " << fd;
+ return false;
+ }
+ if (persistent != controller->is_persistent_) {
+ NOTREACHED() << "persistent doesn't match";
+ return false;
+ }
+
+ // Combine old/new event masks.
+ CFFileDescriptorDisableCallBacks(fdref, controller->callback_types_);
+ controller->callback_types_ |= callback_types;
+ CFFileDescriptorEnableCallBacks(fdref, controller->callback_types_);
+ }
+
+ controller->set_watcher(delegate);
+ controller->set_pump(this);
+
+ return true;
+}
+
+void MessagePumpIOSForIO::RemoveRunLoopSource(CFRunLoopSourceRef source) {
+ CFRunLoopRemoveSource(run_loop(), source, kCFRunLoopCommonModes);
+}
+
+void MessagePumpIOSForIO::AddIOObserver(IOObserver *obs) {
+ io_observers_.AddObserver(obs);
+}
+
+void MessagePumpIOSForIO::RemoveIOObserver(IOObserver *obs) {
+ io_observers_.RemoveObserver(obs);
+}
+
+void MessagePumpIOSForIO::WillProcessIOEvent() {
+ FOR_EACH_OBSERVER(IOObserver, io_observers_, WillProcessIOEvent());
+}
+
+void MessagePumpIOSForIO::DidProcessIOEvent() {
+ FOR_EACH_OBSERVER(IOObserver, io_observers_, DidProcessIOEvent());
+}
+
+// static
+void MessagePumpIOSForIO::HandleFdIOEvent(CFFileDescriptorRef fdref,
+ CFOptionFlags callback_types,
+ void* context) {
+ FileDescriptorWatcher* controller =
+ static_cast<FileDescriptorWatcher*>(context);
+ DCHECK_EQ(fdref, controller->fdref_);
+
+ // Ensure that |fdref| will remain live for the duration of this function
+ // call even if |controller| is deleted or |StopWatchingFileDescriptor()| is
+ // called, either of which will cause |fdref| to be released.
+ mac::ScopedCFTypeRef<CFFileDescriptorRef> scoped_fdref(
+ fdref, base::scoped_policy::RETAIN);
+
+ int fd = CFFileDescriptorGetNativeDescriptor(fdref);
+ MessagePumpIOSForIO* pump = controller->pump();
+ if (callback_types & kCFFileDescriptorWriteCallBack)
+ controller->OnFileCanWriteWithoutBlocking(fd, pump);
+
+ // Perform the read callback only if the file descriptor has not been
+ // invalidated in the write callback. As |FileDescriptorWatcher| invalidates
+ // its file descriptor on destruction, the file descriptor being valid also
+ // guarantees that |controller| has not been deleted.
+ if (callback_types & kCFFileDescriptorReadCallBack &&
+ CFFileDescriptorIsValid(fdref)) {
+ DCHECK_EQ(fdref, controller->fdref_);
+ controller->OnFileCanReadWithoutBlocking(fd, pump);
+ }
+
+ // Re-enable callbacks after the read/write if the file descriptor is still
+ // valid and the controller is persistent.
+ if (CFFileDescriptorIsValid(fdref) && controller->is_persistent_) {
+ DCHECK_EQ(fdref, controller->fdref_);
+ CFFileDescriptorEnableCallBacks(fdref, callback_types);
+ }
+}
+
+} // namespace base
diff --git a/base/message_loop/message_pump_io_ios.h b/base/message_loop/message_pump_io_ios.h
new file mode 100644
index 0000000..3aaf037
--- /dev/null
+++ b/base/message_loop/message_pump_io_ios.h
@@ -0,0 +1,142 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_IO_IOS_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_IO_IOS_H_
+
+#include "base/base_export.h"
+#include "base/mac/scoped_cffiledescriptorref.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_pump_mac.h"
+#include "base/observer_list.h"
+
+namespace base {
+
+// This file introduces a class to monitor sockets and issue callbacks when
+// sockets are ready for I/O on iOS.
+class BASE_EXPORT MessagePumpIOSForIO : public MessagePumpNSRunLoop {
+ public:
+ class IOObserver {
+ public:
+ IOObserver() {}
+
+ // An IOObserver is an object that receives IO notifications from the
+ // MessagePump.
+ //
+ // NOTE: An IOObserver implementation should be extremely fast!
+ virtual void WillProcessIOEvent() = 0;
+ virtual void DidProcessIOEvent() = 0;
+
+ protected:
+ virtual ~IOObserver() {}
+ };
+
+ // Used with WatchFileDescriptor to asynchronously monitor the I/O readiness
+ // of a file descriptor.
+ class Watcher {
+ public:
+ // Called from MessageLoop::Run when an FD can be read from/written to
+ // without blocking
+ virtual void OnFileCanReadWithoutBlocking(int fd) = 0;
+ virtual void OnFileCanWriteWithoutBlocking(int fd) = 0;
+
+ protected:
+ virtual ~Watcher() {}
+ };
+
+ // Object returned by WatchFileDescriptor to manage further watching.
+ class FileDescriptorWatcher {
+ public:
+ FileDescriptorWatcher();
+ ~FileDescriptorWatcher(); // Implicitly calls StopWatchingFileDescriptor.
+
+ // NOTE: These methods aren't called StartWatching()/StopWatching() to
+ // avoid confusion with the win32 ObjectWatcher class.
+
+ // Stop watching the FD, always safe to call. No-op if there's nothing
+ // to do.
+ bool StopWatchingFileDescriptor();
+
+ private:
+ friend class MessagePumpIOSForIO;
+ friend class MessagePumpIOSForIOTest;
+
+ // Called by MessagePumpIOSForIO, ownership of |fdref| and |fd_source|
+ // is transferred to this object.
+ void Init(CFFileDescriptorRef fdref,
+ CFOptionFlags callback_types,
+ CFRunLoopSourceRef fd_source,
+ bool is_persistent);
+
+ void set_pump(MessagePumpIOSForIO* pump) { pump_ = pump; }
+ MessagePumpIOSForIO* pump() const { return pump_; }
+
+ void set_watcher(Watcher* watcher) { watcher_ = watcher; }
+
+ void OnFileCanReadWithoutBlocking(int fd, MessagePumpIOSForIO* pump);
+ void OnFileCanWriteWithoutBlocking(int fd, MessagePumpIOSForIO* pump);
+
+ bool is_persistent_; // false if this event is one-shot.
+ base::mac::ScopedCFFileDescriptorRef fdref_;
+ CFOptionFlags callback_types_;
+ base::mac::ScopedCFTypeRef<CFRunLoopSourceRef> fd_source_;
+ scoped_refptr<MessagePumpIOSForIO> pump_;
+ Watcher* watcher_;
+
+ DISALLOW_COPY_AND_ASSIGN(FileDescriptorWatcher);
+ };
+
+ enum Mode {
+ WATCH_READ = 1 << 0,
+ WATCH_WRITE = 1 << 1,
+ WATCH_READ_WRITE = WATCH_READ | WATCH_WRITE
+ };
+
+ MessagePumpIOSForIO();
+
+ // Have the current thread's message loop watch for a a situation in which
+ // reading/writing to the FD can be performed without blocking.
+ // Callers must provide a preallocated FileDescriptorWatcher object which
+ // can later be used to manage the lifetime of this event.
+ // If a FileDescriptorWatcher is passed in which is already attached to
+ // an event, then the effect is cumulative i.e. after the call |controller|
+ // will watch both the previous event and the new one.
+ // If an error occurs while calling this method in a cumulative fashion, the
+ // event previously attached to |controller| is aborted.
+ // Returns true on success.
+ // Must be called on the same thread the message_pump is running on.
+ bool WatchFileDescriptor(int fd,
+ bool persistent,
+ int mode,
+ FileDescriptorWatcher *controller,
+ Watcher *delegate);
+
+ void RemoveRunLoopSource(CFRunLoopSourceRef source);
+
+ void AddIOObserver(IOObserver* obs);
+ void RemoveIOObserver(IOObserver* obs);
+
+ protected:
+ virtual ~MessagePumpIOSForIO();
+
+ private:
+ friend class MessagePumpIOSForIOTest;
+
+ void WillProcessIOEvent();
+ void DidProcessIOEvent();
+
+ static void HandleFdIOEvent(CFFileDescriptorRef fdref,
+ CFOptionFlags callback_types,
+ void* context);
+
+ ObserverList<IOObserver> io_observers_;
+ ThreadChecker watch_file_descriptor_caller_checker_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessagePumpIOSForIO);
+};
+
+} // namespace base
+
+#endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_IO_IOS_H_
diff --git a/base/message_loop/message_pump_io_ios_unittest.cc b/base/message_loop/message_pump_io_ios_unittest.cc
new file mode 100644
index 0000000..9e94c6b
--- /dev/null
+++ b/base/message_loop/message_pump_io_ios_unittest.cc
@@ -0,0 +1,188 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_pump_io_ios.h"
+
+#include <unistd.h>
+
+#include "base/message_loop.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class MessagePumpIOSForIOTest : public testing::Test {
+ protected:
+ MessagePumpIOSForIOTest()
+ : ui_loop_(MessageLoop::TYPE_UI),
+ io_thread_("MessagePumpIOSForIOTestIOThread") {}
+ virtual ~MessagePumpIOSForIOTest() {}
+
+ virtual void SetUp() OVERRIDE {
+ Thread::Options options(MessageLoop::TYPE_IO, 0);
+ ASSERT_TRUE(io_thread_.StartWithOptions(options));
+ ASSERT_EQ(MessageLoop::TYPE_IO, io_thread_.message_loop()->type());
+ int ret = pipe(pipefds_);
+ ASSERT_EQ(0, ret);
+ ret = pipe(alternate_pipefds_);
+ ASSERT_EQ(0, ret);
+ }
+
+ virtual void TearDown() OVERRIDE {
+ if (HANDLE_EINTR(close(pipefds_[0])) < 0)
+ PLOG(ERROR) << "close";
+ if (HANDLE_EINTR(close(pipefds_[1])) < 0)
+ PLOG(ERROR) << "close";
+ }
+
+ MessageLoop* ui_loop() { return &ui_loop_; }
+ MessageLoopForIO* io_loop() const {
+ return static_cast<MessageLoopForIO*>(io_thread_.message_loop());
+ }
+
+ void HandleFdIOEvent(MessageLoopForIO::FileDescriptorWatcher* watcher) {
+ MessagePumpIOSForIO::HandleFdIOEvent(watcher->fdref_,
+ kCFFileDescriptorReadCallBack | kCFFileDescriptorWriteCallBack,
+ watcher);
+ }
+
+ int pipefds_[2];
+ int alternate_pipefds_[2];
+
+ private:
+ MessageLoop ui_loop_;
+ Thread io_thread_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessagePumpIOSForIOTest);
+};
+
+namespace {
+
+// Concrete implementation of MessagePumpIOSForIO::Watcher that does
+// nothing useful.
+class StupidWatcher : public MessagePumpIOSForIO::Watcher {
+ public:
+ virtual ~StupidWatcher() {}
+
+ // base:MessagePumpIOSForIO::Watcher interface
+ virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE {}
+ virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE {}
+};
+
+#if GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
+
+// Test to make sure that we catch calling WatchFileDescriptor off of the
+// wrong thread.
+TEST_F(MessagePumpIOSForIOTest, TestWatchingFromBadThread) {
+ MessagePumpIOSForIO::FileDescriptorWatcher watcher;
+ StupidWatcher delegate;
+
+ ASSERT_DEBUG_DEATH(io_loop()->WatchFileDescriptor(
+ STDOUT_FILENO, false, MessageLoopForIO::WATCH_READ, &watcher, &delegate),
+ "Check failed: "
+ "watch_file_descriptor_caller_checker_.CalledOnValidThread()");
+}
+
+#endif // GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
+
+class BaseWatcher : public MessagePumpIOSForIO::Watcher {
+ public:
+ BaseWatcher(MessagePumpIOSForIO::FileDescriptorWatcher* controller)
+ : controller_(controller) {
+ DCHECK(controller_);
+ }
+ virtual ~BaseWatcher() {}
+
+ // MessagePumpIOSForIO::Watcher interface
+ virtual void OnFileCanReadWithoutBlocking(int /* fd */) OVERRIDE {
+ NOTREACHED();
+ }
+
+ virtual void OnFileCanWriteWithoutBlocking(int /* fd */) OVERRIDE {
+ NOTREACHED();
+ }
+
+ protected:
+ MessagePumpIOSForIO::FileDescriptorWatcher* controller_;
+};
+
+class DeleteWatcher : public BaseWatcher {
+ public:
+ explicit DeleteWatcher(
+ MessagePumpIOSForIO::FileDescriptorWatcher* controller)
+ : BaseWatcher(controller) {}
+
+ virtual ~DeleteWatcher() {
+ DCHECK(!controller_);
+ }
+
+ virtual void OnFileCanWriteWithoutBlocking(int /* fd */) OVERRIDE {
+ DCHECK(controller_);
+ delete controller_;
+ controller_ = NULL;
+ }
+};
+
+TEST_F(MessagePumpIOSForIOTest, DeleteWatcher) {
+ scoped_refptr<MessagePumpIOSForIO> pump(new MessagePumpIOSForIO);
+ MessagePumpIOSForIO::FileDescriptorWatcher* watcher =
+ new MessagePumpIOSForIO::FileDescriptorWatcher;
+ DeleteWatcher delegate(watcher);
+ pump->WatchFileDescriptor(pipefds_[1],
+ false, MessagePumpIOSForIO::WATCH_READ_WRITE, watcher, &delegate);
+
+ // Spoof a callback.
+ HandleFdIOEvent(watcher);
+}
+
+class StopWatcher : public BaseWatcher {
+ public:
+ StopWatcher(MessagePumpIOSForIO::FileDescriptorWatcher* controller,
+ MessagePumpIOSForIO* pump,
+ int fd_to_start_watching = -1)
+ : BaseWatcher(controller),
+ pump_(pump),
+ fd_to_start_watching_(fd_to_start_watching) {}
+
+ virtual ~StopWatcher() {}
+
+ virtual void OnFileCanWriteWithoutBlocking(int /* fd */) OVERRIDE {
+ controller_->StopWatchingFileDescriptor();
+ if (fd_to_start_watching_ >= 0) {
+ pump_->WatchFileDescriptor(fd_to_start_watching_,
+ false, MessagePumpIOSForIO::WATCH_READ_WRITE, controller_, this);
+ }
+ }
+
+ private:
+ MessagePumpIOSForIO* pump_;
+ int fd_to_start_watching_;
+};
+
+TEST_F(MessagePumpIOSForIOTest, StopWatcher) {
+ scoped_refptr<MessagePumpIOSForIO> pump(new MessagePumpIOSForIO);
+ MessagePumpIOSForIO::FileDescriptorWatcher watcher;
+ StopWatcher delegate(&watcher, pump);
+ pump->WatchFileDescriptor(pipefds_[1],
+ false, MessagePumpIOSForIO::WATCH_READ_WRITE, &watcher, &delegate);
+
+ // Spoof a callback.
+ HandleFdIOEvent(&watcher);
+}
+
+TEST_F(MessagePumpIOSForIOTest, StopWatcherAndWatchSomethingElse) {
+ scoped_refptr<MessagePumpIOSForIO> pump(new MessagePumpIOSForIO);
+ MessagePumpIOSForIO::FileDescriptorWatcher watcher;
+ StopWatcher delegate(&watcher, pump, alternate_pipefds_[1]);
+ pump->WatchFileDescriptor(pipefds_[1],
+ false, MessagePumpIOSForIO::WATCH_READ_WRITE, &watcher, &delegate);
+
+ // Spoof a callback.
+ HandleFdIOEvent(&watcher);
+}
+
+} // namespace
+
+} // namespace base
diff --git a/base/message_loop/message_pump_libevent.cc b/base/message_loop/message_pump_libevent.cc
new file mode 100644
index 0000000..8de0db2
--- /dev/null
+++ b/base/message_loop/message_pump_libevent.cc
@@ -0,0 +1,375 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_pump_libevent.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "base/auto_reset.h"
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/observer_list.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/time.h"
+#include "third_party/libevent/event.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_nsautorelease_pool.h"
+#endif
+
+// Lifecycle of struct event
+// Libevent uses two main data structures:
+// struct event_base (of which there is one per message pump), and
+// struct event (of which there is roughly one per socket).
+// The socket's struct event is created in
+// MessagePumpLibevent::WatchFileDescriptor(),
+// is owned by the FileDescriptorWatcher, and is destroyed in
+// StopWatchingFileDescriptor().
+// It is moved into and out of lists in struct event_base by
+// the libevent functions event_add() and event_del().
+//
+// TODO(dkegel):
+// At the moment bad things happen if a FileDescriptorWatcher
+// is active after its MessagePumpLibevent has been destroyed.
+// See MessageLoopTest.FileDescriptorWatcherOutlivesMessageLoop
+// Not clear yet whether that situation occurs in practice,
+// but if it does, we need to fix it.
+
+namespace base {
+
+// Return 0 on success
+// Too small a function to bother putting in a library?
+static int SetNonBlocking(int fd) {
+ int flags = fcntl(fd, F_GETFL, 0);
+ if (flags == -1)
+ flags = 0;
+ return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+}
+
+MessagePumpLibevent::FileDescriptorWatcher::FileDescriptorWatcher()
+ : event_(NULL),
+ pump_(NULL),
+ watcher_(NULL),
+ weak_factory_(this) {
+}
+
+MessagePumpLibevent::FileDescriptorWatcher::~FileDescriptorWatcher() {
+ if (event_) {
+ StopWatchingFileDescriptor();
+ }
+}
+
+bool MessagePumpLibevent::FileDescriptorWatcher::StopWatchingFileDescriptor() {
+ event* e = ReleaseEvent();
+ if (e == NULL)
+ return true;
+
+ // event_del() is a no-op if the event isn't active.
+ int rv = event_del(e);
+ delete e;
+ pump_ = NULL;
+ watcher_ = NULL;
+ return (rv == 0);
+}
+
+void MessagePumpLibevent::FileDescriptorWatcher::Init(event *e) {
+ DCHECK(e);
+ DCHECK(!event_);
+
+ event_ = e;
+}
+
+event *MessagePumpLibevent::FileDescriptorWatcher::ReleaseEvent() {
+ struct event *e = event_;
+ event_ = NULL;
+ return e;
+}
+
+void MessagePumpLibevent::FileDescriptorWatcher::OnFileCanReadWithoutBlocking(
+ int fd, MessagePumpLibevent* pump) {
+ // Since OnFileCanWriteWithoutBlocking() gets called first, it can stop
+ // watching the file descriptor.
+ if (!watcher_)
+ return;
+ pump->WillProcessIOEvent();
+ watcher_->OnFileCanReadWithoutBlocking(fd);
+ pump->DidProcessIOEvent();
+}
+
+void MessagePumpLibevent::FileDescriptorWatcher::OnFileCanWriteWithoutBlocking(
+ int fd, MessagePumpLibevent* pump) {
+ DCHECK(watcher_);
+ pump->WillProcessIOEvent();
+ watcher_->OnFileCanWriteWithoutBlocking(fd);
+ pump->DidProcessIOEvent();
+}
+
+MessagePumpLibevent::MessagePumpLibevent()
+ : keep_running_(true),
+ in_run_(false),
+ processed_io_events_(false),
+ event_base_(event_base_new()),
+ wakeup_pipe_in_(-1),
+ wakeup_pipe_out_(-1) {
+ if (!Init())
+ NOTREACHED();
+}
+
+MessagePumpLibevent::~MessagePumpLibevent() {
+ DCHECK(wakeup_event_);
+ DCHECK(event_base_);
+ event_del(wakeup_event_);
+ delete wakeup_event_;
+ if (wakeup_pipe_in_ >= 0) {
+ if (HANDLE_EINTR(close(wakeup_pipe_in_)) < 0)
+ DPLOG(ERROR) << "close";
+ }
+ if (wakeup_pipe_out_ >= 0) {
+ if (HANDLE_EINTR(close(wakeup_pipe_out_)) < 0)
+ DPLOG(ERROR) << "close";
+ }
+ event_base_free(event_base_);
+}
+
+bool MessagePumpLibevent::WatchFileDescriptor(int fd,
+ bool persistent,
+ int mode,
+ FileDescriptorWatcher *controller,
+ Watcher *delegate) {
+ DCHECK_GE(fd, 0);
+ DCHECK(controller);
+ DCHECK(delegate);
+ DCHECK(mode == WATCH_READ || mode == WATCH_WRITE || mode == WATCH_READ_WRITE);
+ // WatchFileDescriptor should be called on the pump thread. It is not
+ // threadsafe, and your watcher may never be registered.
+ DCHECK(watch_file_descriptor_caller_checker_.CalledOnValidThread());
+
+ int event_mask = persistent ? EV_PERSIST : 0;
+ if (mode & WATCH_READ) {
+ event_mask |= EV_READ;
+ }
+ if (mode & WATCH_WRITE) {
+ event_mask |= EV_WRITE;
+ }
+
+ scoped_ptr<event> evt(controller->ReleaseEvent());
+ if (evt.get() == NULL) {
+ // Ownership is transferred to the controller.
+ evt.reset(new event);
+ } else {
+ // Make sure we don't pick up any funky internal libevent masks.
+ int old_interest_mask = evt.get()->ev_events &
+ (EV_READ | EV_WRITE | EV_PERSIST);
+
+ // Combine old/new event masks.
+ event_mask |= old_interest_mask;
+
+ // Must disarm the event before we can reuse it.
+ event_del(evt.get());
+
+ // It's illegal to use this function to listen on 2 separate fds with the
+ // same |controller|.
+ if (EVENT_FD(evt.get()) != fd) {
+ NOTREACHED() << "FDs don't match" << EVENT_FD(evt.get()) << "!=" << fd;
+ return false;
+ }
+ }
+
+ // Set current interest mask and message pump for this event.
+ event_set(evt.get(), fd, event_mask, OnLibeventNotification, controller);
+
+ // Tell libevent which message pump this socket will belong to when we add it.
+ if (event_base_set(event_base_, evt.get())) {
+ return false;
+ }
+
+ // Add this socket to the list of monitored sockets.
+ if (event_add(evt.get(), NULL)) {
+ return false;
+ }
+
+ // Transfer ownership of evt to controller.
+ controller->Init(evt.release());
+
+ controller->set_watcher(delegate);
+ controller->set_pump(this);
+
+ return true;
+}
+
+void MessagePumpLibevent::AddIOObserver(IOObserver *obs) {
+ io_observers_.AddObserver(obs);
+}
+
+void MessagePumpLibevent::RemoveIOObserver(IOObserver *obs) {
+ io_observers_.RemoveObserver(obs);
+}
+
+// Tell libevent to break out of inner loop.
+static void timer_callback(int fd, short events, void *context)
+{
+ event_base_loopbreak((struct event_base *)context);
+}
+
+// Reentrant!
+void MessagePumpLibevent::Run(Delegate* delegate) {
+ DCHECK(keep_running_) << "Quit must have been called outside of Run!";
+ AutoReset<bool> auto_reset_in_run(&in_run_, true);
+
+ // event_base_loopexit() + EVLOOP_ONCE is leaky, see http://crbug.com/25641.
+ // Instead, make our own timer and reuse it on each call to event_base_loop().
+ scoped_ptr<event> timer_event(new event);
+
+ for (;;) {
+#if defined(OS_MACOSX)
+ mac::ScopedNSAutoreleasePool autorelease_pool;
+#endif
+
+ bool did_work = delegate->DoWork();
+ if (!keep_running_)
+ break;
+
+ event_base_loop(event_base_, EVLOOP_NONBLOCK);
+ did_work |= processed_io_events_;
+ processed_io_events_ = false;
+ if (!keep_running_)
+ break;
+
+ did_work |= delegate->DoDelayedWork(&delayed_work_time_);
+ if (!keep_running_)
+ break;
+
+ if (did_work)
+ continue;
+
+ did_work = delegate->DoIdleWork();
+ if (!keep_running_)
+ break;
+
+ if (did_work)
+ continue;
+
+ // EVLOOP_ONCE tells libevent to only block once,
+ // but to service all pending events when it wakes up.
+ if (delayed_work_time_.is_null()) {
+ event_base_loop(event_base_, EVLOOP_ONCE);
+ } else {
+ TimeDelta delay = delayed_work_time_ - TimeTicks::Now();
+ if (delay > TimeDelta()) {
+ struct timeval poll_tv;
+ poll_tv.tv_sec = delay.InSeconds();
+ poll_tv.tv_usec = delay.InMicroseconds() % Time::kMicrosecondsPerSecond;
+ event_set(timer_event.get(), -1, 0, timer_callback, event_base_);
+ event_base_set(event_base_, timer_event.get());
+ event_add(timer_event.get(), &poll_tv);
+ event_base_loop(event_base_, EVLOOP_ONCE);
+ event_del(timer_event.get());
+ } else {
+ // It looks like delayed_work_time_ indicates a time in the past, so we
+ // need to call DoDelayedWork now.
+ delayed_work_time_ = TimeTicks();
+ }
+ }
+ }
+
+ keep_running_ = true;
+}
+
+void MessagePumpLibevent::Quit() {
+ DCHECK(in_run_);
+ // Tell both libevent and Run that they should break out of their loops.
+ keep_running_ = false;
+ ScheduleWork();
+}
+
+void MessagePumpLibevent::ScheduleWork() {
+ // Tell libevent (in a threadsafe way) that it should break out of its loop.
+ char buf = 0;
+ int nwrite = HANDLE_EINTR(write(wakeup_pipe_in_, &buf, 1));
+ DCHECK(nwrite == 1 || errno == EAGAIN)
+ << "[nwrite:" << nwrite << "] [errno:" << errno << "]";
+}
+
+void MessagePumpLibevent::ScheduleDelayedWork(
+ const TimeTicks& delayed_work_time) {
+ // We know that we can't be blocked on Wait right now since this method can
+ // only be called on the same thread as Run, so we only need to update our
+ // record of how long to sleep when we do sleep.
+ delayed_work_time_ = delayed_work_time;
+}
+
+void MessagePumpLibevent::WillProcessIOEvent() {
+ FOR_EACH_OBSERVER(IOObserver, io_observers_, WillProcessIOEvent());
+}
+
+void MessagePumpLibevent::DidProcessIOEvent() {
+ FOR_EACH_OBSERVER(IOObserver, io_observers_, DidProcessIOEvent());
+}
+
+bool MessagePumpLibevent::Init() {
+ int fds[2];
+ if (pipe(fds)) {
+ DLOG(ERROR) << "pipe() failed, errno: " << errno;
+ return false;
+ }
+ if (SetNonBlocking(fds[0])) {
+ DLOG(ERROR) << "SetNonBlocking for pipe fd[0] failed, errno: " << errno;
+ return false;
+ }
+ if (SetNonBlocking(fds[1])) {
+ DLOG(ERROR) << "SetNonBlocking for pipe fd[1] failed, errno: " << errno;
+ return false;
+ }
+ wakeup_pipe_out_ = fds[0];
+ wakeup_pipe_in_ = fds[1];
+
+ wakeup_event_ = new event;
+ event_set(wakeup_event_, wakeup_pipe_out_, EV_READ | EV_PERSIST,
+ OnWakeup, this);
+ event_base_set(event_base_, wakeup_event_);
+
+ if (event_add(wakeup_event_, 0))
+ return false;
+ return true;
+}
+
+// static
+void MessagePumpLibevent::OnLibeventNotification(int fd, short flags,
+ void* context) {
+ WeakPtr<FileDescriptorWatcher> controller =
+ static_cast<FileDescriptorWatcher*>(context)->weak_factory_.GetWeakPtr();
+ DCHECK(controller.get());
+
+ MessagePumpLibevent* pump = controller->pump();
+ pump->processed_io_events_ = true;
+
+ if (flags & EV_WRITE) {
+ controller->OnFileCanWriteWithoutBlocking(fd, pump);
+ }
+ // Check |controller| in case it's been deleted in
+ // controller->OnFileCanWriteWithoutBlocking().
+ if (controller.get() && flags & EV_READ) {
+ controller->OnFileCanReadWithoutBlocking(fd, pump);
+ }
+}
+
+// Called if a byte is received on the wakeup pipe.
+// static
+void MessagePumpLibevent::OnWakeup(int socket, short flags, void* context) {
+ MessagePumpLibevent* that = static_cast<MessagePumpLibevent*>(context);
+ DCHECK(that->wakeup_pipe_out_ == socket);
+
+ // Remove and discard the wakeup byte.
+ char buf;
+ int nread = HANDLE_EINTR(read(socket, &buf, 1));
+ DCHECK_EQ(nread, 1);
+ that->processed_io_events_ = true;
+ // Tell libevent to break out of inner loop.
+ event_base_loopbreak(that->event_base_);
+}
+
+} // namespace base
diff --git a/base/message_loop/message_pump_libevent.h b/base/message_loop/message_pump_libevent.h
new file mode 100644
index 0000000..a54ef88
--- /dev/null
+++ b/base/message_loop/message_pump_libevent.h
@@ -0,0 +1,179 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_LIBEVENT_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_LIBEVENT_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_pump.h"
+#include "base/observer_list.h"
+#include "base/threading/thread_checker.h"
+#include "base/time.h"
+
+// Declare structs we need from libevent.h rather than including it
+struct event_base;
+struct event;
+
+namespace base {
+
+// Class to monitor sockets and issue callbacks when sockets are ready for I/O
+// TODO(dkegel): add support for background file IO somehow
+class BASE_EXPORT MessagePumpLibevent : public MessagePump {
+ public:
+ class IOObserver {
+ public:
+ IOObserver() {}
+
+ // An IOObserver is an object that receives IO notifications from the
+ // MessagePump.
+ //
+ // NOTE: An IOObserver implementation should be extremely fast!
+ virtual void WillProcessIOEvent() = 0;
+ virtual void DidProcessIOEvent() = 0;
+
+ protected:
+ virtual ~IOObserver() {}
+ };
+
+ // Used with WatchFileDescriptor to asynchronously monitor the I/O readiness
+ // of a file descriptor.
+ class Watcher {
+ public:
+ // Called from MessageLoop::Run when an FD can be read from/written to
+ // without blocking
+ virtual void OnFileCanReadWithoutBlocking(int fd) = 0;
+ virtual void OnFileCanWriteWithoutBlocking(int fd) = 0;
+
+ protected:
+ virtual ~Watcher() {}
+ };
+
+ // Object returned by WatchFileDescriptor to manage further watching.
+ class FileDescriptorWatcher {
+ public:
+ FileDescriptorWatcher();
+ ~FileDescriptorWatcher(); // Implicitly calls StopWatchingFileDescriptor.
+
+ // NOTE: These methods aren't called StartWatching()/StopWatching() to
+ // avoid confusion with the win32 ObjectWatcher class.
+
+ // Stop watching the FD, always safe to call. No-op if there's nothing
+ // to do.
+ bool StopWatchingFileDescriptor();
+
+ private:
+ friend class MessagePumpLibevent;
+ friend class MessagePumpLibeventTest;
+
+ // Called by MessagePumpLibevent, ownership of |e| is transferred to this
+ // object.
+ void Init(event* e);
+
+ // Used by MessagePumpLibevent to take ownership of event_.
+ event* ReleaseEvent();
+
+ void set_pump(MessagePumpLibevent* pump) { pump_ = pump; }
+ MessagePumpLibevent* pump() const { return pump_; }
+
+ void set_watcher(Watcher* watcher) { watcher_ = watcher; }
+
+ void OnFileCanReadWithoutBlocking(int fd, MessagePumpLibevent* pump);
+ void OnFileCanWriteWithoutBlocking(int fd, MessagePumpLibevent* pump);
+
+ event* event_;
+ MessagePumpLibevent* pump_;
+ Watcher* watcher_;
+ WeakPtrFactory<FileDescriptorWatcher> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(FileDescriptorWatcher);
+ };
+
+ enum Mode {
+ WATCH_READ = 1 << 0,
+ WATCH_WRITE = 1 << 1,
+ WATCH_READ_WRITE = WATCH_READ | WATCH_WRITE
+ };
+
+ MessagePumpLibevent();
+
+ // Have the current thread's message loop watch for a a situation in which
+ // reading/writing to the FD can be performed without blocking.
+ // Callers must provide a preallocated FileDescriptorWatcher object which
+ // can later be used to manage the lifetime of this event.
+ // If a FileDescriptorWatcher is passed in which is already attached to
+ // an event, then the effect is cumulative i.e. after the call |controller|
+ // will watch both the previous event and the new one.
+ // If an error occurs while calling this method in a cumulative fashion, the
+ // event previously attached to |controller| is aborted.
+ // Returns true on success.
+ // Must be called on the same thread the message_pump is running on.
+ // TODO(dkegel): switch to edge-triggered readiness notification
+ bool WatchFileDescriptor(int fd,
+ bool persistent,
+ int mode,
+ FileDescriptorWatcher *controller,
+ Watcher *delegate);
+
+ void AddIOObserver(IOObserver* obs);
+ void RemoveIOObserver(IOObserver* obs);
+
+ // MessagePump methods:
+ virtual void Run(Delegate* delegate) OVERRIDE;
+ virtual void Quit() OVERRIDE;
+ virtual void ScheduleWork() OVERRIDE;
+ virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) OVERRIDE;
+
+ protected:
+ virtual ~MessagePumpLibevent();
+
+ private:
+ friend class MessagePumpLibeventTest;
+
+ void WillProcessIOEvent();
+ void DidProcessIOEvent();
+
+ // Risky part of constructor. Returns true on success.
+ bool Init();
+
+ // Called by libevent to tell us a registered FD can be read/written to.
+ static void OnLibeventNotification(int fd, short flags,
+ void* context);
+
+ // Unix pipe used to implement ScheduleWork()
+ // ... callback; called by libevent inside Run() when pipe is ready to read
+ static void OnWakeup(int socket, short flags, void* context);
+
+ // This flag is set to false when Run should return.
+ bool keep_running_;
+
+ // This flag is set when inside Run.
+ bool in_run_;
+
+ // This flag is set if libevent has processed I/O events.
+ bool processed_io_events_;
+
+ // The time at which we should call DoDelayedWork.
+ TimeTicks delayed_work_time_;
+
+ // Libevent dispatcher. Watches all sockets registered with it, and sends
+ // readiness callbacks when a socket is ready for I/O.
+ event_base* event_base_;
+
+ // ... write end; ScheduleWork() writes a single byte to it
+ int wakeup_pipe_in_;
+ // ... read end; OnWakeup reads it and then breaks Run() out of its sleep
+ int wakeup_pipe_out_;
+ // ... libevent wrapper for read end
+ event* wakeup_event_;
+
+ ObserverList<IOObserver> io_observers_;
+ ThreadChecker watch_file_descriptor_caller_checker_;
+ DISALLOW_COPY_AND_ASSIGN(MessagePumpLibevent);
+};
+
+} // namespace base
+
+#endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_LIBEVENT_H_
diff --git a/base/message_loop/message_pump_libevent_unittest.cc b/base/message_loop/message_pump_libevent_unittest.cc
new file mode 100644
index 0000000..657ac7d
--- /dev/null
+++ b/base/message_loop/message_pump_libevent_unittest.cc
@@ -0,0 +1,162 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_pump_libevent.h"
+
+#include <unistd.h>
+
+#include "base/message_loop/message_loop.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/libevent/event.h"
+
+namespace base {
+
+class MessagePumpLibeventTest : public testing::Test {
+ protected:
+ MessagePumpLibeventTest()
+ : ui_loop_(MessageLoop::TYPE_UI),
+ io_thread_("MessagePumpLibeventTestIOThread") {}
+ virtual ~MessagePumpLibeventTest() {}
+
+ virtual void SetUp() OVERRIDE {
+ Thread::Options options(MessageLoop::TYPE_IO, 0);
+ ASSERT_TRUE(io_thread_.StartWithOptions(options));
+ ASSERT_EQ(MessageLoop::TYPE_IO, io_thread_.message_loop()->type());
+ int ret = pipe(pipefds_);
+ ASSERT_EQ(0, ret);
+ }
+
+ virtual void TearDown() OVERRIDE {
+ if (HANDLE_EINTR(close(pipefds_[0])) < 0)
+ PLOG(ERROR) << "close";
+ if (HANDLE_EINTR(close(pipefds_[1])) < 0)
+ PLOG(ERROR) << "close";
+ }
+
+ MessageLoop* ui_loop() { return &ui_loop_; }
+ MessageLoopForIO* io_loop() const {
+ return static_cast<MessageLoopForIO*>(io_thread_.message_loop());
+ }
+
+ void OnLibeventNotification(
+ MessagePumpLibevent* pump,
+ MessagePumpLibevent::FileDescriptorWatcher* controller) {
+ pump->OnLibeventNotification(0, EV_WRITE | EV_READ, controller);
+ }
+
+ int pipefds_[2];
+
+ private:
+ MessageLoop ui_loop_;
+ Thread io_thread_;
+};
+
+namespace {
+
+// Concrete implementation of MessagePumpLibevent::Watcher that does
+// nothing useful.
+class StupidWatcher : public MessagePumpLibevent::Watcher {
+ public:
+ virtual ~StupidWatcher() {}
+
+ // base:MessagePumpLibevent::Watcher interface
+ virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE {}
+ virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE {}
+};
+
+#if GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
+
+// Test to make sure that we catch calling WatchFileDescriptor off of the
+// wrong thread.
+TEST_F(MessagePumpLibeventTest, TestWatchingFromBadThread) {
+ MessagePumpLibevent::FileDescriptorWatcher watcher;
+ StupidWatcher delegate;
+
+ ASSERT_DEATH(io_loop()->WatchFileDescriptor(
+ STDOUT_FILENO, false, MessageLoopForIO::WATCH_READ, &watcher, &delegate),
+ "Check failed: "
+ "watch_file_descriptor_caller_checker_.CalledOnValidThread()");
+}
+
+#endif // GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
+
+class BaseWatcher : public MessagePumpLibevent::Watcher {
+ public:
+ explicit BaseWatcher(MessagePumpLibevent::FileDescriptorWatcher* controller)
+ : controller_(controller) {
+ DCHECK(controller_);
+ }
+ virtual ~BaseWatcher() {}
+
+ // base:MessagePumpLibevent::Watcher interface
+ virtual void OnFileCanReadWithoutBlocking(int /* fd */) OVERRIDE {
+ NOTREACHED();
+ }
+
+ virtual void OnFileCanWriteWithoutBlocking(int /* fd */) OVERRIDE {
+ NOTREACHED();
+ }
+
+ protected:
+ MessagePumpLibevent::FileDescriptorWatcher* controller_;
+};
+
+class DeleteWatcher : public BaseWatcher {
+ public:
+ explicit DeleteWatcher(
+ MessagePumpLibevent::FileDescriptorWatcher* controller)
+ : BaseWatcher(controller) {}
+
+ virtual ~DeleteWatcher() {
+ DCHECK(!controller_);
+ }
+
+ virtual void OnFileCanWriteWithoutBlocking(int /* fd */) OVERRIDE {
+ DCHECK(controller_);
+ delete controller_;
+ controller_ = NULL;
+ }
+};
+
+TEST_F(MessagePumpLibeventTest, DeleteWatcher) {
+ scoped_refptr<MessagePumpLibevent> pump(new MessagePumpLibevent);
+ MessagePumpLibevent::FileDescriptorWatcher* watcher =
+ new MessagePumpLibevent::FileDescriptorWatcher;
+ DeleteWatcher delegate(watcher);
+ pump->WatchFileDescriptor(pipefds_[1],
+ false, MessagePumpLibevent::WATCH_READ_WRITE, watcher, &delegate);
+
+ // Spoof a libevent notification.
+ OnLibeventNotification(pump.get(), watcher);
+}
+
+class StopWatcher : public BaseWatcher {
+ public:
+ explicit StopWatcher(
+ MessagePumpLibevent::FileDescriptorWatcher* controller)
+ : BaseWatcher(controller) {}
+
+ virtual ~StopWatcher() {}
+
+ virtual void OnFileCanWriteWithoutBlocking(int /* fd */) OVERRIDE {
+ controller_->StopWatchingFileDescriptor();
+ }
+};
+
+TEST_F(MessagePumpLibeventTest, StopWatcher) {
+ scoped_refptr<MessagePumpLibevent> pump(new MessagePumpLibevent);
+ MessagePumpLibevent::FileDescriptorWatcher watcher;
+ StopWatcher delegate(&watcher);
+ pump->WatchFileDescriptor(pipefds_[1],
+ false, MessagePumpLibevent::WATCH_READ_WRITE, &watcher, &delegate);
+
+ // Spoof a libevent notification.
+ OnLibeventNotification(pump.get(), &watcher);
+}
+
+} // namespace
+
+} // namespace base
diff --git a/base/message_loop/message_pump_mac.h b/base/message_loop/message_pump_mac.h
new file mode 100644
index 0000000..68c2a3d
--- /dev/null
+++ b/base/message_loop/message_pump_mac.h
@@ -0,0 +1,337 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// The basis for all native run loops on the Mac is the CFRunLoop. It can be
+// used directly, it can be used as the driving force behind the similar
+// Foundation NSRunLoop, and it can be used to implement higher-level event
+// loops such as the NSApplication event loop.
+//
+// This file introduces a basic CFRunLoop-based implementation of the
+// MessagePump interface called CFRunLoopBase. CFRunLoopBase contains all
+// of the machinery necessary to dispatch events to a delegate, but does not
+// implement the specific run loop. Concrete subclasses must provide their
+// own DoRun and Quit implementations.
+//
+// A concrete subclass that just runs a CFRunLoop loop is provided in
+// MessagePumpCFRunLoop. For an NSRunLoop, the similar MessagePumpNSRunLoop
+// is provided.
+//
+// For the application's event loop, an implementation based on AppKit's
+// NSApplication event system is provided in MessagePumpNSApplication.
+//
+// Typically, MessagePumpNSApplication only makes sense on a Cocoa
+// application's main thread. If a CFRunLoop-based message pump is needed on
+// any other thread, one of the other concrete subclasses is preferrable.
+// MessagePumpMac::Create is defined, which returns a new NSApplication-based
+// or NSRunLoop-based MessagePump subclass depending on which thread it is
+// called on.
+
+#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_MAC_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_MAC_H_
+
+#include "base/message_loop/message_pump.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#if !defined(__OBJC__)
+class NSAutoreleasePool;
+#else // !defined(__OBJC__)
+#if defined(OS_IOS)
+#import <Foundation/Foundation.h>
+#else
+#import <AppKit/AppKit.h>
+
+// Clients must subclass NSApplication and implement this protocol if they use
+// MessagePumpMac.
+@protocol CrAppProtocol
+// Must return true if -[NSApplication sendEvent:] is currently on the stack.
+// See the comment for |CreateAutoreleasePool()| in the cc file for why this is
+// necessary.
+- (BOOL)isHandlingSendEvent;
+@end
+#endif // !defined(OS_IOS)
+#endif // !defined(__OBJC__)
+
+namespace base {
+
+class RunLoop;
+class TimeTicks;
+
+class MessagePumpCFRunLoopBase : public MessagePump {
+ // Needs access to CreateAutoreleasePool.
+ friend class MessagePumpScopedAutoreleasePool;
+ public:
+ MessagePumpCFRunLoopBase();
+
+ // Subclasses should implement the work they need to do in MessagePump::Run
+ // in the DoRun method. MessagePumpCFRunLoopBase::Run calls DoRun directly.
+ // This arrangement is used because MessagePumpCFRunLoopBase needs to set
+ // up and tear down things before and after the "meat" of DoRun.
+ virtual void Run(Delegate* delegate) OVERRIDE;
+ virtual void DoRun(Delegate* delegate) = 0;
+
+ virtual void ScheduleWork() OVERRIDE;
+ virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) OVERRIDE;
+
+ protected:
+ virtual ~MessagePumpCFRunLoopBase();
+
+ // Accessors for private data members to be used by subclasses.
+ CFRunLoopRef run_loop() const { return run_loop_; }
+ int nesting_level() const { return nesting_level_; }
+ int run_nesting_level() const { return run_nesting_level_; }
+
+ // Sets this pump's delegate. Signals the appropriate sources if
+ // |delegateless_work_| is true. |delegate| can be NULL.
+ void SetDelegate(Delegate* delegate);
+
+ // Return an autorelease pool to wrap around any work being performed.
+ // In some cases, CreateAutoreleasePool may return nil intentionally to
+ // preventing an autorelease pool from being created, allowing any
+ // objects autoreleased by work to fall into the current autorelease pool.
+ virtual NSAutoreleasePool* CreateAutoreleasePool();
+
+ private:
+ // Timer callback scheduled by ScheduleDelayedWork. This does not do any
+ // work, but it signals work_source_ so that delayed work can be performed
+ // within the appropriate priority constraints.
+ static void RunDelayedWorkTimer(CFRunLoopTimerRef timer, void* info);
+
+ // Perform highest-priority work. This is associated with work_source_
+ // signalled by ScheduleWork or RunDelayedWorkTimer. The static method calls
+ // the instance method; the instance method returns true if it resignalled
+ // work_source_ to be called again from the loop.
+ static void RunWorkSource(void* info);
+ bool RunWork();
+
+ // Perform idle-priority work. This is normally called by PreWaitObserver,
+ // but is also associated with idle_work_source_. When this function
+ // actually does perform idle work, it will resignal that source. The
+ // static method calls the instance method; the instance method returns
+ // true if idle work was done.
+ static void RunIdleWorkSource(void* info);
+ bool RunIdleWork();
+
+ // Perform work that may have been deferred because it was not runnable
+ // within a nested run loop. This is associated with
+ // nesting_deferred_work_source_ and is signalled by
+ // MaybeScheduleNestingDeferredWork when returning from a nested loop,
+ // so that an outer loop will be able to perform the necessary tasks if it
+ // permits nestable tasks.
+ static void RunNestingDeferredWorkSource(void* info);
+ bool RunNestingDeferredWork();
+
+ // Schedules possible nesting-deferred work to be processed before the run
+ // loop goes to sleep, exits, or begins processing sources at the top of its
+ // loop. If this function detects that a nested loop had run since the
+ // previous attempt to schedule nesting-deferred work, it will schedule a
+ // call to RunNestingDeferredWorkSource.
+ void MaybeScheduleNestingDeferredWork();
+
+ // Observer callback responsible for performing idle-priority work, before
+ // the run loop goes to sleep. Associated with idle_work_observer_.
+ static void PreWaitObserver(CFRunLoopObserverRef observer,
+ CFRunLoopActivity activity, void* info);
+
+ // Observer callback called before the run loop processes any sources.
+ // Associated with pre_source_observer_.
+ static void PreSourceObserver(CFRunLoopObserverRef observer,
+ CFRunLoopActivity activity, void* info);
+
+ // Observer callback called when the run loop starts and stops, at the
+ // beginning and end of calls to CFRunLoopRun. This is used to maintain
+ // nesting_level_. Associated with enter_exit_observer_.
+ static void EnterExitObserver(CFRunLoopObserverRef observer,
+ CFRunLoopActivity activity, void* info);
+
+ // Called by EnterExitObserver after performing maintenance on nesting_level_.
+ // This allows subclasses an opportunity to perform additional processing on
+ // the basis of run loops starting and stopping.
+ virtual void EnterExitRunLoop(CFRunLoopActivity activity);
+
+ // The thread's run loop.
+ CFRunLoopRef run_loop_;
+
+ // The timer, sources, and observers are described above alongside their
+ // callbacks.
+ CFRunLoopTimerRef delayed_work_timer_;
+ CFRunLoopSourceRef work_source_;
+ CFRunLoopSourceRef idle_work_source_;
+ CFRunLoopSourceRef nesting_deferred_work_source_;
+ CFRunLoopObserverRef pre_wait_observer_;
+ CFRunLoopObserverRef pre_source_observer_;
+ CFRunLoopObserverRef enter_exit_observer_;
+
+ // (weak) Delegate passed as an argument to the innermost Run call.
+ Delegate* delegate_;
+
+ // The time that delayed_work_timer_ is scheduled to fire. This is tracked
+ // independently of CFRunLoopTimerGetNextFireDate(delayed_work_timer_)
+ // to be able to reset the timer properly after waking from system sleep.
+ // See PowerStateNotification.
+ CFAbsoluteTime delayed_work_fire_time_;
+
+ // The recursion depth of the currently-executing CFRunLoopRun loop on the
+ // run loop's thread. 0 if no run loops are running inside of whatever scope
+ // the object was created in.
+ int nesting_level_;
+
+ // The recursion depth (calculated in the same way as nesting_level_) of the
+ // innermost executing CFRunLoopRun loop started by a call to Run.
+ int run_nesting_level_;
+
+ // The deepest (numerically highest) recursion depth encountered since the
+ // most recent attempt to run nesting-deferred work.
+ int deepest_nesting_level_;
+
+ // "Delegateless" work flags are set when work is ready to be performed but
+ // must wait until a delegate is available to process it. This can happen
+ // when a MessagePumpCFRunLoopBase is instantiated and work arrives without
+ // any call to Run on the stack. The Run method will check for delegateless
+ // work on entry and redispatch it as needed once a delegate is available.
+ bool delegateless_work_;
+ bool delegateless_idle_work_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessagePumpCFRunLoopBase);
+};
+
+class MessagePumpCFRunLoop : public MessagePumpCFRunLoopBase {
+ public:
+ MessagePumpCFRunLoop();
+
+ virtual void DoRun(Delegate* delegate) OVERRIDE;
+ virtual void Quit() OVERRIDE;
+
+ protected:
+ virtual ~MessagePumpCFRunLoop();
+
+ private:
+ virtual void EnterExitRunLoop(CFRunLoopActivity activity) OVERRIDE;
+
+ // True if Quit is called to stop the innermost MessagePump
+ // (innermost_quittable_) but some other CFRunLoopRun loop (nesting_level_)
+ // is running inside the MessagePump's innermost Run call.
+ bool quit_pending_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessagePumpCFRunLoop);
+};
+
+class MessagePumpNSRunLoop : public MessagePumpCFRunLoopBase {
+ public:
+ BASE_EXPORT MessagePumpNSRunLoop();
+
+ virtual void DoRun(Delegate* delegate) OVERRIDE;
+ virtual void Quit() OVERRIDE;
+
+ protected:
+ virtual ~MessagePumpNSRunLoop();
+
+ private:
+ // A source that doesn't do anything but provide something signalable
+ // attached to the run loop. This source will be signalled when Quit
+ // is called, to cause the loop to wake up so that it can stop.
+ CFRunLoopSourceRef quit_source_;
+
+ // False after Quit is called.
+ bool keep_running_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessagePumpNSRunLoop);
+};
+
+#if defined(OS_IOS)
+// This is a fake message pump. It attaches sources to the main thread's
+// CFRunLoop, so PostTask() will work, but it is unable to drive the loop
+// directly, so calling Run() or Quit() are errors.
+class MessagePumpUIApplication : public MessagePumpCFRunLoopBase {
+ public:
+ MessagePumpUIApplication();
+ virtual void DoRun(Delegate* delegate) OVERRIDE;
+ virtual void Quit() OVERRIDE;
+
+ // This message pump can not spin the main message loop directly. Instead,
+ // call |Attach()| to set up a delegate. It is an error to call |Run()|.
+ virtual void Attach(Delegate* delegate);
+
+ protected:
+ virtual ~MessagePumpUIApplication();
+
+ private:
+ RunLoop* run_loop_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessagePumpUIApplication);
+};
+
+#else
+
+class MessagePumpNSApplication : public MessagePumpCFRunLoopBase {
+ public:
+ MessagePumpNSApplication();
+
+ virtual void DoRun(Delegate* delegate) OVERRIDE;
+ virtual void Quit() OVERRIDE;
+
+ protected:
+ virtual ~MessagePumpNSApplication();
+
+ private:
+ // False after Quit is called.
+ bool keep_running_;
+
+ // True if DoRun is managing its own run loop as opposed to letting
+ // -[NSApplication run] handle it. The outermost run loop in the application
+ // is managed by -[NSApplication run], inner run loops are handled by a loop
+ // in DoRun.
+ bool running_own_loop_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessagePumpNSApplication);
+};
+
+class MessagePumpCrApplication : public MessagePumpNSApplication {
+ public:
+ MessagePumpCrApplication();
+
+ protected:
+ virtual ~MessagePumpCrApplication() {}
+
+ // Returns nil if NSApp is currently in the middle of calling
+ // -sendEvent. Requires NSApp implementing CrAppProtocol.
+ virtual NSAutoreleasePool* CreateAutoreleasePool() OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MessagePumpCrApplication);
+};
+#endif // !defined(OS_IOS)
+
+class MessagePumpMac {
+ public:
+ // If not on the main thread, returns a new instance of
+ // MessagePumpNSRunLoop.
+ //
+ // On the main thread, if NSApp exists and conforms to
+ // CrAppProtocol, creates an instances of MessagePumpCrApplication.
+ //
+ // Otherwise creates an instance of MessagePumpNSApplication using a
+ // default NSApplication.
+ static MessagePump* Create();
+
+#if !defined(OS_IOS)
+ // If a pump is created before the required CrAppProtocol is
+ // created, the wrong MessagePump subclass could be used.
+ // UsingCrApp() returns false if the message pump was created before
+ // NSApp was initialized, or if NSApp does not implement
+ // CrAppProtocol. NSApp must be initialized before calling.
+ BASE_EXPORT static bool UsingCrApp();
+
+ // Wrapper to query -[NSApp isHandlingSendEvent] from C++ code.
+ // Requires NSApp to implement CrAppProtocol.
+ BASE_EXPORT static bool IsHandlingSendEvent();
+#endif // !defined(OS_IOS)
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(MessagePumpMac);
+};
+
+} // namespace base
+
+#endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_MAC_H_
diff --git a/base/message_loop/message_pump_mac.mm b/base/message_loop/message_pump_mac.mm
new file mode 100644
index 0000000..a419d48
--- /dev/null
+++ b/base/message_loop/message_pump_mac.mm
@@ -0,0 +1,701 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "base/message_loop/message_pump_mac.h"
+
+#import <Foundation/Foundation.h>
+
+#include <limits>
+
+#include "base/logging.h"
+#include "base/run_loop.h"
+#include "base/time.h"
+
+#if !defined(OS_IOS)
+#import <AppKit/AppKit.h>
+#endif // !defined(OS_IOS)
+
+namespace {
+
+void NoOp(void* info) {
+}
+
+const CFTimeInterval kCFTimeIntervalMax =
+ std::numeric_limits<CFTimeInterval>::max();
+
+#if !defined(OS_IOS)
+// Set to true if MessagePumpMac::Create() is called before NSApp is
+// initialized. Only accessed from the main thread.
+bool g_not_using_cr_app = false;
+#endif
+
+} // namespace
+
+namespace base {
+
+// A scoper for autorelease pools created from message pump run loops.
+// Avoids dirtying up the ScopedNSAutoreleasePool interface for the rare
+// case where an autorelease pool needs to be passed in.
+class MessagePumpScopedAutoreleasePool {
+ public:
+ explicit MessagePumpScopedAutoreleasePool(MessagePumpCFRunLoopBase* pump) :
+ pool_(pump->CreateAutoreleasePool()) {
+ }
+ ~MessagePumpScopedAutoreleasePool() {
+ [pool_ drain];
+ }
+
+ private:
+ NSAutoreleasePool* pool_;
+ DISALLOW_COPY_AND_ASSIGN(MessagePumpScopedAutoreleasePool);
+};
+
+// Must be called on the run loop thread.
+MessagePumpCFRunLoopBase::MessagePumpCFRunLoopBase()
+ : delegate_(NULL),
+ delayed_work_fire_time_(kCFTimeIntervalMax),
+ nesting_level_(0),
+ run_nesting_level_(0),
+ deepest_nesting_level_(0),
+ delegateless_work_(false),
+ delegateless_idle_work_(false) {
+ run_loop_ = CFRunLoopGetCurrent();
+ CFRetain(run_loop_);
+
+ // Set a repeating timer with a preposterous firing time and interval. The
+ // timer will effectively never fire as-is. The firing time will be adjusted
+ // as needed when ScheduleDelayedWork is called.
+ CFRunLoopTimerContext timer_context = CFRunLoopTimerContext();
+ timer_context.info = this;
+ delayed_work_timer_ = CFRunLoopTimerCreate(NULL, // allocator
+ kCFTimeIntervalMax, // fire time
+ kCFTimeIntervalMax, // interval
+ 0, // flags
+ 0, // priority
+ RunDelayedWorkTimer,
+ &timer_context);
+ CFRunLoopAddTimer(run_loop_, delayed_work_timer_, kCFRunLoopCommonModes);
+
+ CFRunLoopSourceContext source_context = CFRunLoopSourceContext();
+ source_context.info = this;
+ source_context.perform = RunWorkSource;
+ work_source_ = CFRunLoopSourceCreate(NULL, // allocator
+ 1, // priority
+ &source_context);
+ CFRunLoopAddSource(run_loop_, work_source_, kCFRunLoopCommonModes);
+
+ source_context.perform = RunIdleWorkSource;
+ idle_work_source_ = CFRunLoopSourceCreate(NULL, // allocator
+ 2, // priority
+ &source_context);
+ CFRunLoopAddSource(run_loop_, idle_work_source_, kCFRunLoopCommonModes);
+
+ source_context.perform = RunNestingDeferredWorkSource;
+ nesting_deferred_work_source_ = CFRunLoopSourceCreate(NULL, // allocator
+ 0, // priority
+ &source_context);
+ CFRunLoopAddSource(run_loop_, nesting_deferred_work_source_,
+ kCFRunLoopCommonModes);
+
+ CFRunLoopObserverContext observer_context = CFRunLoopObserverContext();
+ observer_context.info = this;
+ pre_wait_observer_ = CFRunLoopObserverCreate(NULL, // allocator
+ kCFRunLoopBeforeWaiting,
+ true, // repeat
+ 0, // priority
+ PreWaitObserver,
+ &observer_context);
+ CFRunLoopAddObserver(run_loop_, pre_wait_observer_, kCFRunLoopCommonModes);
+
+ pre_source_observer_ = CFRunLoopObserverCreate(NULL, // allocator
+ kCFRunLoopBeforeSources,
+ true, // repeat
+ 0, // priority
+ PreSourceObserver,
+ &observer_context);
+ CFRunLoopAddObserver(run_loop_, pre_source_observer_, kCFRunLoopCommonModes);
+
+ enter_exit_observer_ = CFRunLoopObserverCreate(NULL, // allocator
+ kCFRunLoopEntry |
+ kCFRunLoopExit,
+ true, // repeat
+ 0, // priority
+ EnterExitObserver,
+ &observer_context);
+ CFRunLoopAddObserver(run_loop_, enter_exit_observer_, kCFRunLoopCommonModes);
+}
+
+// Ideally called on the run loop thread. If other run loops were running
+// lower on the run loop thread's stack when this object was created, the
+// same number of run loops must be running when this object is destroyed.
+MessagePumpCFRunLoopBase::~MessagePumpCFRunLoopBase() {
+ CFRunLoopRemoveObserver(run_loop_, enter_exit_observer_,
+ kCFRunLoopCommonModes);
+ CFRelease(enter_exit_observer_);
+
+ CFRunLoopRemoveObserver(run_loop_, pre_source_observer_,
+ kCFRunLoopCommonModes);
+ CFRelease(pre_source_observer_);
+
+ CFRunLoopRemoveObserver(run_loop_, pre_wait_observer_,
+ kCFRunLoopCommonModes);
+ CFRelease(pre_wait_observer_);
+
+ CFRunLoopRemoveSource(run_loop_, nesting_deferred_work_source_,
+ kCFRunLoopCommonModes);
+ CFRelease(nesting_deferred_work_source_);
+
+ CFRunLoopRemoveSource(run_loop_, idle_work_source_, kCFRunLoopCommonModes);
+ CFRelease(idle_work_source_);
+
+ CFRunLoopRemoveSource(run_loop_, work_source_, kCFRunLoopCommonModes);
+ CFRelease(work_source_);
+
+ CFRunLoopRemoveTimer(run_loop_, delayed_work_timer_, kCFRunLoopCommonModes);
+ CFRelease(delayed_work_timer_);
+
+ CFRelease(run_loop_);
+}
+
+// Must be called on the run loop thread.
+void MessagePumpCFRunLoopBase::Run(Delegate* delegate) {
+ // nesting_level_ will be incremented in EnterExitRunLoop, so set
+ // run_nesting_level_ accordingly.
+ int last_run_nesting_level = run_nesting_level_;
+ run_nesting_level_ = nesting_level_ + 1;
+
+ Delegate* last_delegate = delegate_;
+ SetDelegate(delegate);
+
+ DoRun(delegate);
+
+ // Restore the previous state of the object.
+ SetDelegate(last_delegate);
+ run_nesting_level_ = last_run_nesting_level;
+}
+
+void MessagePumpCFRunLoopBase::SetDelegate(Delegate* delegate) {
+ delegate_ = delegate;
+
+ if (delegate) {
+ // If any work showed up but could not be dispatched for want of a
+ // delegate, set it up for dispatch again now that a delegate is
+ // available.
+ if (delegateless_work_) {
+ CFRunLoopSourceSignal(work_source_);
+ delegateless_work_ = false;
+ }
+ if (delegateless_idle_work_) {
+ CFRunLoopSourceSignal(idle_work_source_);
+ delegateless_idle_work_ = false;
+ }
+ }
+}
+
+// May be called on any thread.
+void MessagePumpCFRunLoopBase::ScheduleWork() {
+ CFRunLoopSourceSignal(work_source_);
+ CFRunLoopWakeUp(run_loop_);
+}
+
+// Must be called on the run loop thread.
+void MessagePumpCFRunLoopBase::ScheduleDelayedWork(
+ const TimeTicks& delayed_work_time) {
+ TimeDelta delta = delayed_work_time - TimeTicks::Now();
+ delayed_work_fire_time_ = CFAbsoluteTimeGetCurrent() + delta.InSecondsF();
+ CFRunLoopTimerSetNextFireDate(delayed_work_timer_, delayed_work_fire_time_);
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::RunDelayedWorkTimer(CFRunLoopTimerRef timer,
+ void* info) {
+ MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+
+ // The timer won't fire again until it's reset.
+ self->delayed_work_fire_time_ = kCFTimeIntervalMax;
+
+ // CFRunLoopTimers fire outside of the priority scheme for CFRunLoopSources.
+ // In order to establish the proper priority in which work and delayed work
+ // are processed one for one, the timer used to schedule delayed work must
+ // signal a CFRunLoopSource used to dispatch both work and delayed work.
+ CFRunLoopSourceSignal(self->work_source_);
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::RunWorkSource(void* info) {
+ MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+ self->RunWork();
+}
+
+// Called by MessagePumpCFRunLoopBase::RunWorkSource.
+bool MessagePumpCFRunLoopBase::RunWork() {
+ if (!delegate_) {
+ // This point can be reached with a NULL delegate_ if Run is not on the
+ // stack but foreign code is spinning the CFRunLoop. Arrange to come back
+ // here when a delegate is available.
+ delegateless_work_ = true;
+ return false;
+ }
+
+ // The NSApplication-based run loop only drains the autorelease pool at each
+ // UI event (NSEvent). The autorelease pool is not drained for each
+ // CFRunLoopSource target that's run. Use a local pool for any autoreleased
+ // objects if the app is not currently handling a UI event to ensure they're
+ // released promptly even in the absence of UI events.
+ MessagePumpScopedAutoreleasePool autorelease_pool(this);
+
+ // Call DoWork and DoDelayedWork once, and if something was done, arrange to
+ // come back here again as long as the loop is still running.
+ bool did_work = delegate_->DoWork();
+ bool resignal_work_source = did_work;
+
+ TimeTicks next_time;
+ delegate_->DoDelayedWork(&next_time);
+ if (!did_work) {
+ // Determine whether there's more delayed work, and if so, if it needs to
+ // be done at some point in the future or if it's already time to do it.
+ // Only do these checks if did_work is false. If did_work is true, this
+ // function, and therefore any additional delayed work, will get another
+ // chance to run before the loop goes to sleep.
+ bool more_delayed_work = !next_time.is_null();
+ if (more_delayed_work) {
+ TimeDelta delay = next_time - TimeTicks::Now();
+ if (delay > TimeDelta()) {
+ // There's more delayed work to be done in the future.
+ ScheduleDelayedWork(next_time);
+ } else {
+ // There's more delayed work to be done, and its time is in the past.
+ // Arrange to come back here directly as long as the loop is still
+ // running.
+ resignal_work_source = true;
+ }
+ }
+ }
+
+ if (resignal_work_source) {
+ CFRunLoopSourceSignal(work_source_);
+ }
+
+ return resignal_work_source;
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::RunIdleWorkSource(void* info) {
+ MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+ self->RunIdleWork();
+}
+
+// Called by MessagePumpCFRunLoopBase::RunIdleWorkSource.
+bool MessagePumpCFRunLoopBase::RunIdleWork() {
+ if (!delegate_) {
+ // This point can be reached with a NULL delegate_ if Run is not on the
+ // stack but foreign code is spinning the CFRunLoop. Arrange to come back
+ // here when a delegate is available.
+ delegateless_idle_work_ = true;
+ return false;
+ }
+
+ // The NSApplication-based run loop only drains the autorelease pool at each
+ // UI event (NSEvent). The autorelease pool is not drained for each
+ // CFRunLoopSource target that's run. Use a local pool for any autoreleased
+ // objects if the app is not currently handling a UI event to ensure they're
+ // released promptly even in the absence of UI events.
+ MessagePumpScopedAutoreleasePool autorelease_pool(this);
+
+ // Call DoIdleWork once, and if something was done, arrange to come back here
+ // again as long as the loop is still running.
+ bool did_work = delegate_->DoIdleWork();
+ if (did_work) {
+ CFRunLoopSourceSignal(idle_work_source_);
+ }
+
+ return did_work;
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::RunNestingDeferredWorkSource(void* info) {
+ MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+ self->RunNestingDeferredWork();
+}
+
+// Called by MessagePumpCFRunLoopBase::RunNestingDeferredWorkSource.
+bool MessagePumpCFRunLoopBase::RunNestingDeferredWork() {
+ if (!delegate_) {
+ // This point can be reached with a NULL delegate_ if Run is not on the
+ // stack but foreign code is spinning the CFRunLoop. There's no sense in
+ // attempting to do any work or signalling the work sources because
+ // without a delegate, work is not possible.
+ return false;
+ }
+
+ // Immediately try work in priority order.
+ if (!RunWork()) {
+ if (!RunIdleWork()) {
+ return false;
+ }
+ } else {
+ // Work was done. Arrange for the loop to try non-nestable idle work on
+ // a subsequent pass.
+ CFRunLoopSourceSignal(idle_work_source_);
+ }
+
+ return true;
+}
+
+// Called before the run loop goes to sleep or exits, or processes sources.
+void MessagePumpCFRunLoopBase::MaybeScheduleNestingDeferredWork() {
+ // deepest_nesting_level_ is set as run loops are entered. If the deepest
+ // level encountered is deeper than the current level, a nested loop
+ // (relative to the current level) ran since the last time nesting-deferred
+ // work was scheduled. When that situation is encountered, schedule
+ // nesting-deferred work in case any work was deferred because nested work
+ // was disallowed.
+ if (deepest_nesting_level_ > nesting_level_) {
+ deepest_nesting_level_ = nesting_level_;
+ CFRunLoopSourceSignal(nesting_deferred_work_source_);
+ }
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::PreWaitObserver(CFRunLoopObserverRef observer,
+ CFRunLoopActivity activity,
+ void* info) {
+ MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+
+ // Attempt to do some idle work before going to sleep.
+ self->RunIdleWork();
+
+ // The run loop is about to go to sleep. If any of the work done since it
+ // started or woke up resulted in a nested run loop running,
+ // nesting-deferred work may have accumulated. Schedule it for processing
+ // if appropriate.
+ self->MaybeScheduleNestingDeferredWork();
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::PreSourceObserver(CFRunLoopObserverRef observer,
+ CFRunLoopActivity activity,
+ void* info) {
+ MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+
+ // The run loop has reached the top of the loop and is about to begin
+ // processing sources. If the last iteration of the loop at this nesting
+ // level did not sleep or exit, nesting-deferred work may have accumulated
+ // if a nested loop ran. Schedule nesting-deferred work for processing if
+ // appropriate.
+ self->MaybeScheduleNestingDeferredWork();
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::EnterExitObserver(CFRunLoopObserverRef observer,
+ CFRunLoopActivity activity,
+ void* info) {
+ MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+
+ switch (activity) {
+ case kCFRunLoopEntry:
+ ++self->nesting_level_;
+ if (self->nesting_level_ > self->deepest_nesting_level_) {
+ self->deepest_nesting_level_ = self->nesting_level_;
+ }
+ break;
+
+ case kCFRunLoopExit:
+ // Not all run loops go to sleep. If a run loop is stopped before it
+ // goes to sleep due to a CFRunLoopStop call, or if the timeout passed
+ // to CFRunLoopRunInMode expires, the run loop may proceed directly from
+ // handling sources to exiting without any sleep. This most commonly
+ // occurs when CFRunLoopRunInMode is passed a timeout of 0, causing it
+ // to make a single pass through the loop and exit without sleep. Some
+ // native loops use CFRunLoop in this way. Because PreWaitObserver will
+ // not be called in these case, MaybeScheduleNestingDeferredWork needs
+ // to be called here, as the run loop exits.
+ //
+ // MaybeScheduleNestingDeferredWork consults self->nesting_level_
+ // to determine whether to schedule nesting-deferred work. It expects
+ // the nesting level to be set to the depth of the loop that is going
+ // to sleep or exiting. It must be called before decrementing the
+ // value so that the value still corresponds to the level of the exiting
+ // loop.
+ self->MaybeScheduleNestingDeferredWork();
+ --self->nesting_level_;
+ break;
+
+ default:
+ break;
+ }
+
+ self->EnterExitRunLoop(activity);
+}
+
+// Called by MessagePumpCFRunLoopBase::EnterExitRunLoop. The default
+// implementation is a no-op.
+void MessagePumpCFRunLoopBase::EnterExitRunLoop(CFRunLoopActivity activity) {
+}
+
+// Base version returns a standard NSAutoreleasePool.
+NSAutoreleasePool* MessagePumpCFRunLoopBase::CreateAutoreleasePool() {
+ return [[NSAutoreleasePool alloc] init];
+}
+
+MessagePumpCFRunLoop::MessagePumpCFRunLoop()
+ : quit_pending_(false) {
+}
+
+MessagePumpCFRunLoop::~MessagePumpCFRunLoop() {}
+
+// Called by MessagePumpCFRunLoopBase::DoRun. If other CFRunLoopRun loops were
+// running lower on the run loop thread's stack when this object was created,
+// the same number of CFRunLoopRun loops must be running for the outermost call
+// to Run. Run/DoRun are reentrant after that point.
+void MessagePumpCFRunLoop::DoRun(Delegate* delegate) {
+ // This is completely identical to calling CFRunLoopRun(), except autorelease
+ // pool management is introduced.
+ int result;
+ do {
+ MessagePumpScopedAutoreleasePool autorelease_pool(this);
+ result = CFRunLoopRunInMode(kCFRunLoopDefaultMode,
+ kCFTimeIntervalMax,
+ false);
+ } while (result != kCFRunLoopRunStopped && result != kCFRunLoopRunFinished);
+}
+
+// Must be called on the run loop thread.
+void MessagePumpCFRunLoop::Quit() {
+ // Stop the innermost run loop managed by this MessagePumpCFRunLoop object.
+ if (nesting_level() == run_nesting_level()) {
+ // This object is running the innermost loop, just stop it.
+ CFRunLoopStop(run_loop());
+ } else {
+ // There's another loop running inside the loop managed by this object.
+ // In other words, someone else called CFRunLoopRunInMode on the same
+ // thread, deeper on the stack than the deepest Run call. Don't preempt
+ // other run loops, just mark this object to quit the innermost Run as
+ // soon as the other inner loops not managed by Run are done.
+ quit_pending_ = true;
+ }
+}
+
+// Called by MessagePumpCFRunLoopBase::EnterExitObserver.
+void MessagePumpCFRunLoop::EnterExitRunLoop(CFRunLoopActivity activity) {
+ if (activity == kCFRunLoopExit &&
+ nesting_level() == run_nesting_level() &&
+ quit_pending_) {
+ // Quit was called while loops other than those managed by this object
+ // were running further inside a run loop managed by this object. Now
+ // that all unmanaged inner run loops are gone, stop the loop running
+ // just inside Run.
+ CFRunLoopStop(run_loop());
+ quit_pending_ = false;
+ }
+}
+
+MessagePumpNSRunLoop::MessagePumpNSRunLoop()
+ : keep_running_(true) {
+ CFRunLoopSourceContext source_context = CFRunLoopSourceContext();
+ source_context.perform = NoOp;
+ quit_source_ = CFRunLoopSourceCreate(NULL, // allocator
+ 0, // priority
+ &source_context);
+ CFRunLoopAddSource(run_loop(), quit_source_, kCFRunLoopCommonModes);
+}
+
+MessagePumpNSRunLoop::~MessagePumpNSRunLoop() {
+ CFRunLoopRemoveSource(run_loop(), quit_source_, kCFRunLoopCommonModes);
+ CFRelease(quit_source_);
+}
+
+void MessagePumpNSRunLoop::DoRun(Delegate* delegate) {
+ while (keep_running_) {
+ // NSRunLoop manages autorelease pools itself.
+ [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
+ beforeDate:[NSDate distantFuture]];
+ }
+
+ keep_running_ = true;
+}
+
+void MessagePumpNSRunLoop::Quit() {
+ keep_running_ = false;
+ CFRunLoopSourceSignal(quit_source_);
+ CFRunLoopWakeUp(run_loop());
+}
+
+#if defined(OS_IOS)
+MessagePumpUIApplication::MessagePumpUIApplication()
+ : run_loop_(NULL) {
+}
+
+MessagePumpUIApplication::~MessagePumpUIApplication() {}
+
+void MessagePumpUIApplication::DoRun(Delegate* delegate) {
+ NOTREACHED();
+}
+
+void MessagePumpUIApplication::Quit() {
+ NOTREACHED();
+}
+
+void MessagePumpUIApplication::Attach(Delegate* delegate) {
+ DCHECK(!run_loop_);
+ run_loop_ = new RunLoop();
+ CHECK(run_loop_->BeforeRun());
+ SetDelegate(delegate);
+}
+
+#else
+
+MessagePumpNSApplication::MessagePumpNSApplication()
+ : keep_running_(true),
+ running_own_loop_(false) {
+}
+
+MessagePumpNSApplication::~MessagePumpNSApplication() {}
+
+void MessagePumpNSApplication::DoRun(Delegate* delegate) {
+ bool last_running_own_loop_ = running_own_loop_;
+
+ // NSApp must be initialized by calling:
+ // [{some class which implements CrAppProtocol} sharedApplication]
+ // Most likely candidates are CrApplication or BrowserCrApplication.
+ // These can be initialized from C++ code by calling
+ // RegisterCrApp() or RegisterBrowserCrApp().
+ CHECK(NSApp);
+
+ if (![NSApp isRunning]) {
+ running_own_loop_ = false;
+ // NSApplication manages autorelease pools itself when run this way.
+ [NSApp run];
+ } else {
+ running_own_loop_ = true;
+ NSDate* distant_future = [NSDate distantFuture];
+ while (keep_running_) {
+ MessagePumpScopedAutoreleasePool autorelease_pool(this);
+ NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask
+ untilDate:distant_future
+ inMode:NSDefaultRunLoopMode
+ dequeue:YES];
+ if (event) {
+ [NSApp sendEvent:event];
+ }
+ }
+ keep_running_ = true;
+ }
+
+ running_own_loop_ = last_running_own_loop_;
+}
+
+void MessagePumpNSApplication::Quit() {
+ if (!running_own_loop_) {
+ [[NSApplication sharedApplication] stop:nil];
+ } else {
+ keep_running_ = false;
+ }
+
+ // Send a fake event to wake the loop up.
+ [NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined
+ location:NSMakePoint(0, 0)
+ modifierFlags:0
+ timestamp:0
+ windowNumber:0
+ context:NULL
+ subtype:0
+ data1:0
+ data2:0]
+ atStart:NO];
+}
+
+MessagePumpCrApplication::MessagePumpCrApplication() {
+}
+
+// Prevents an autorelease pool from being created if the app is in the midst of
+// handling a UI event because various parts of AppKit depend on objects that
+// are created while handling a UI event to be autoreleased in the event loop.
+// An example of this is NSWindowController. When a window with a window
+// controller is closed it goes through a stack like this:
+// (Several stack frames elided for clarity)
+//
+// #0 [NSWindowController autorelease]
+// #1 DoAClose
+// #2 MessagePumpCFRunLoopBase::DoWork()
+// #3 [NSRunLoop run]
+// #4 [NSButton performClick:]
+// #5 [NSWindow sendEvent:]
+// #6 [NSApp sendEvent:]
+// #7 [NSApp run]
+//
+// -performClick: spins a nested run loop. If the pool created in DoWork was a
+// standard NSAutoreleasePool, it would release the objects that were
+// autoreleased into it once DoWork released it. This would cause the window
+// controller, which autoreleased itself in frame #0, to release itself, and
+// possibly free itself. Unfortunately this window controller controls the
+// window in frame #5. When the stack is unwound to frame #5, the window would
+// no longer exists and crashes may occur. Apple gets around this by never
+// releasing the pool it creates in frame #4, and letting frame #7 clean it up
+// when it cleans up the pool that wraps frame #7. When an autorelease pool is
+// released it releases all other pools that were created after it on the
+// autorelease pool stack.
+//
+// CrApplication is responsible for setting handlingSendEvent to true just
+// before it sends the event through the event handling mechanism, and
+// returning it to its previous value once the event has been sent.
+NSAutoreleasePool* MessagePumpCrApplication::CreateAutoreleasePool() {
+ if (MessagePumpMac::IsHandlingSendEvent())
+ return nil;
+ return MessagePumpNSApplication::CreateAutoreleasePool();
+}
+
+// static
+bool MessagePumpMac::UsingCrApp() {
+ DCHECK([NSThread isMainThread]);
+
+ // If NSApp is still not initialized, then the subclass used cannot
+ // be determined.
+ DCHECK(NSApp);
+
+ // The pump was created using MessagePumpNSApplication.
+ if (g_not_using_cr_app)
+ return false;
+
+ return [NSApp conformsToProtocol:@protocol(CrAppProtocol)];
+}
+
+// static
+bool MessagePumpMac::IsHandlingSendEvent() {
+ DCHECK([NSApp conformsToProtocol:@protocol(CrAppProtocol)]);
+ NSObject<CrAppProtocol>* app = static_cast<NSObject<CrAppProtocol>*>(NSApp);
+ return [app isHandlingSendEvent];
+}
+#endif // !defined(OS_IOS)
+
+// static
+MessagePump* MessagePumpMac::Create() {
+ if ([NSThread isMainThread]) {
+#if defined(OS_IOS)
+ return new MessagePumpUIApplication;
+#else
+ if ([NSApp conformsToProtocol:@protocol(CrAppProtocol)])
+ return new MessagePumpCrApplication;
+
+ // The main-thread MessagePump implementations REQUIRE an NSApp.
+ // Executables which have specific requirements for their
+ // NSApplication subclass should initialize appropriately before
+ // creating an event loop.
+ [NSApplication sharedApplication];
+ g_not_using_cr_app = true;
+ return new MessagePumpNSApplication;
+#endif
+ }
+
+ return new MessagePumpNSRunLoop;
+}
+
+} // namespace base
diff --git a/base/message_loop/message_pump_observer.h b/base/message_loop/message_pump_observer.h
new file mode 100644
index 0000000..cb46fa3
--- /dev/null
+++ b/base/message_loop/message_pump_observer.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_OBSERVER_H
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_OBSERVER_H
+
+#include "base/base_export.h"
+#include "base/event_types.h"
+
+namespace base {
+
+enum EventStatus {
+ EVENT_CONTINUE, // The event should be dispatched as normal.
+#if defined(USE_X11)
+ EVENT_HANDLED // The event should not be processed any farther.
+#endif
+};
+
+// A MessagePumpObserver is an object that receives global
+// notifications from the UI MessageLoop with MessagePumpWin or
+// MessagePumpAuraX11.
+//
+// NOTE: An Observer implementation should be extremely fast!
+//
+// For use with MessagePumpAuraX11, please see message_pump_glib.h for more
+// info about how this is invoked in this environment.
+class BASE_EXPORT MessagePumpObserver {
+ public:
+ // This method is called before processing a NativeEvent. If the
+ // method returns EVENT_HANDLED, it indicates the event has already
+ // been handled, so the event is not processed any farther. If the
+ // method returns EVENT_CONTINUE, the event dispatching proceeds as
+ // normal.
+ virtual EventStatus WillProcessEvent(const NativeEvent& event) = 0;
+
+ // This method is called after processing a message. This method
+ // will not be called if WillProcessEvent returns EVENT_HANDLED.
+ virtual void DidProcessEvent(const NativeEvent& event) = 0;
+
+ protected:
+ virtual ~MessagePumpObserver() {}
+};
+
+} // namespace base
+
+#endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_OBSERVER_H
diff --git a/base/message_loop/message_pump_ozone.cc b/base/message_loop/message_pump_ozone.cc
new file mode 100644
index 0000000..5c0bf83
--- /dev/null
+++ b/base/message_loop/message_pump_ozone.cc
@@ -0,0 +1,61 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_pump_ozone.h"
+
+#include "base/logging.h"
+#include "base/message_loop.h"
+
+namespace base {
+
+MessagePumpOzone::MessagePumpOzone()
+ : MessagePumpLibevent() {
+}
+
+MessagePumpOzone::~MessagePumpOzone() {
+}
+
+void MessagePumpOzone::AddObserver(MessagePumpObserver* /* observer */) {
+ NOTIMPLEMENTED();
+}
+
+void MessagePumpOzone::RemoveObserver(MessagePumpObserver* /* observer */) {
+ NOTIMPLEMENTED();
+}
+
+// static
+MessagePumpOzone* MessagePumpOzone::Current() {
+ MessageLoopForUI* loop = MessageLoopForUI::current();
+ return static_cast<MessagePumpOzone*>(loop->pump_ui());
+}
+
+void MessagePumpOzone::AddDispatcherForRootWindow(
+ MessagePumpDispatcher* dispatcher) {
+ // Only one root window is supported.
+ DCHECK(dispatcher_.size() == 0);
+ dispatcher_.insert(dispatcher_.begin(),dispatcher);
+}
+
+void MessagePumpOzone::RemoveDispatcherForRootWindow(
+ MessagePumpDispatcher* dispatcher) {
+ DCHECK(dispatcher_.size() == 1);
+ dispatcher_.pop_back();
+}
+
+bool MessagePumpOzone::Dispatch(const NativeEvent& dev) {
+ if (dispatcher_.size() > 0)
+ return dispatcher_[0]->Dispatch(dev);
+ else
+ return true;
+}
+
+// This code assumes that the caller tracks the lifetime of the |dispatcher|.
+void MessagePumpOzone::RunWithDispatcher(
+ Delegate* delegate, MessagePumpDispatcher* dispatcher) {
+ dispatcher_.push_back(dispatcher);
+ Run(delegate);
+ dispatcher_.pop_back();
+}
+
+} // namespace base
diff --git a/base/message_loop/message_pump_ozone.h b/base/message_loop/message_pump_ozone.h
new file mode 100644
index 0000000..de75ab4
--- /dev/null
+++ b/base/message_loop/message_pump_ozone.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_OZONE_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_OZONE_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/message_loop/message_pump_dispatcher.h"
+#include "base/message_loop/message_pump_libevent.h"
+#include "base/message_loop/message_pump_observer.h"
+#include "base/observer_list.h"
+
+namespace base {
+
+// This class implements a message-pump for processing events from input devices
+// Refer to MessagePump for further documentation.
+class BASE_EXPORT MessagePumpOzone : public MessagePumpLibevent,
+ public MessagePumpDispatcher {
+ public:
+ MessagePumpOzone();
+
+ // Returns the UI message pump.
+ static MessagePumpOzone* Current();
+
+ // Add/Remove the root window dispatcher.
+ void AddDispatcherForRootWindow(MessagePumpDispatcher* dispatcher);
+ void RemoveDispatcherForRootWindow(MessagePumpDispatcher* dispatcher);
+
+ void RunWithDispatcher(Delegate* delegate, MessagePumpDispatcher* dispatcher);
+
+ // Add / remove an Observer, which will start receiving notifications
+ // immediately.
+ void AddObserver(MessagePumpObserver* observer);
+ void RemoveObserver(MessagePumpObserver* observer);
+
+ // Overridden from MessagePumpDispatcher.
+ virtual bool Dispatch(const NativeEvent& event) OVERRIDE;
+
+ private:
+ virtual ~MessagePumpOzone();
+ std::vector<MessagePumpDispatcher*> dispatcher_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessagePumpOzone);
+};
+
+typedef MessagePumpOzone MessagePumpForUI;
+
+} // namespace base
+
+#endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_OZONE_H_
diff --git a/base/message_loop/message_pump_win.cc b/base/message_loop/message_pump_win.cc
new file mode 100644
index 0000000..36a3210
--- /dev/null
+++ b/base/message_loop/message_pump_win.cc
@@ -0,0 +1,686 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_pump_win.h"
+
+#include <math.h>
+
+#include "base/debug/trace_event.h"
+#include "base/message_loop/message_loop.h"
+#include "base/metrics/histogram.h"
+#include "base/process_util.h"
+#include "base/stringprintf.h"
+#include "base/win/wrapped_window_proc.h"
+
+namespace base {
+
+namespace {
+
+enum MessageLoopProblems {
+ MESSAGE_POST_ERROR,
+ COMPLETION_POST_ERROR,
+ SET_TIMER_ERROR,
+ MESSAGE_LOOP_PROBLEM_MAX,
+};
+
+} // namespace
+
+static const wchar_t kWndClassFormat[] = L"Chrome_MessagePumpWindow_%p";
+
+// Message sent to get an additional time slice for pumping (processing) another
+// task (a series of such messages creates a continuous task pump).
+static const int kMsgHaveWork = WM_USER + 1;
+
+//-----------------------------------------------------------------------------
+// MessagePumpWin public:
+
+void MessagePumpWin::AddObserver(MessagePumpObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void MessagePumpWin::RemoveObserver(MessagePumpObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void MessagePumpWin::WillProcessMessage(const MSG& msg) {
+ FOR_EACH_OBSERVER(MessagePumpObserver, observers_, WillProcessEvent(msg));
+}
+
+void MessagePumpWin::DidProcessMessage(const MSG& msg) {
+ FOR_EACH_OBSERVER(MessagePumpObserver, observers_, DidProcessEvent(msg));
+}
+
+void MessagePumpWin::RunWithDispatcher(
+ Delegate* delegate, MessagePumpDispatcher* dispatcher) {
+ RunState s;
+ s.delegate = delegate;
+ s.dispatcher = dispatcher;
+ s.should_quit = false;
+ s.run_depth = state_ ? state_->run_depth + 1 : 1;
+
+ RunState* previous_state = state_;
+ state_ = &s;
+
+ DoRunLoop();
+
+ state_ = previous_state;
+}
+
+void MessagePumpWin::Quit() {
+ DCHECK(state_);
+ state_->should_quit = true;
+}
+
+//-----------------------------------------------------------------------------
+// MessagePumpWin protected:
+
+int MessagePumpWin::GetCurrentDelay() const {
+ if (delayed_work_time_.is_null())
+ return -1;
+
+ // Be careful here. TimeDelta has a precision of microseconds, but we want a
+ // value in milliseconds. If there are 5.5ms left, should the delay be 5 or
+ // 6? It should be 6 to avoid executing delayed work too early.
+ double timeout =
+ ceil((delayed_work_time_ - TimeTicks::Now()).InMillisecondsF());
+
+ // If this value is negative, then we need to run delayed work soon.
+ int delay = static_cast<int>(timeout);
+ if (delay < 0)
+ delay = 0;
+
+ return delay;
+}
+
+//-----------------------------------------------------------------------------
+// MessagePumpForUI public:
+
+MessagePumpForUI::MessagePumpForUI()
+ : atom_(0),
+ message_filter_(new MessageFilter) {
+ InitMessageWnd();
+}
+
+MessagePumpForUI::~MessagePumpForUI() {
+ DestroyWindow(message_hwnd_);
+ UnregisterClass(MAKEINTATOM(atom_),
+ GetModuleFromAddress(&WndProcThunk));
+}
+
+void MessagePumpForUI::ScheduleWork() {
+ if (InterlockedExchange(&have_work_, 1))
+ return; // Someone else continued the pumping.
+
+ // Make sure the MessagePump does some work for us.
+ BOOL ret = PostMessage(message_hwnd_, kMsgHaveWork,
+ reinterpret_cast<WPARAM>(this), 0);
+ if (ret)
+ return; // There was room in the Window Message queue.
+
+ // We have failed to insert a have-work message, so there is a chance that we
+ // will starve tasks/timers while sitting in a nested message loop. Nested
+ // loops only look at Windows Message queues, and don't look at *our* task
+ // queues, etc., so we might not get a time slice in such. :-(
+ // We could abort here, but the fear is that this failure mode is plausibly
+ // common (queue is full, of about 2000 messages), so we'll do a near-graceful
+ // recovery. Nested loops are pretty transient (we think), so this will
+ // probably be recoverable.
+ InterlockedExchange(&have_work_, 0); // Clarify that we didn't really insert.
+ UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", MESSAGE_POST_ERROR,
+ MESSAGE_LOOP_PROBLEM_MAX);
+}
+
+void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
+ //
+ // We would *like* to provide high resolution timers. Windows timers using
+ // SetTimer() have a 10ms granularity. We have to use WM_TIMER as a wakeup
+ // mechanism because the application can enter modal windows loops where it
+ // is not running our MessageLoop; the only way to have our timers fire in
+ // these cases is to post messages there.
+ //
+ // To provide sub-10ms timers, we process timers directly from our run loop.
+ // For the common case, timers will be processed there as the run loop does
+ // its normal work. However, we *also* set the system timer so that WM_TIMER
+ // events fire. This mops up the case of timers not being able to work in
+ // modal message loops. It is possible for the SetTimer to pop and have no
+ // pending timers, because they could have already been processed by the
+ // run loop itself.
+ //
+ // We use a single SetTimer corresponding to the timer that will expire
+ // soonest. As new timers are created and destroyed, we update SetTimer.
+ // Getting a spurrious SetTimer event firing is benign, as we'll just be
+ // processing an empty timer queue.
+ //
+ delayed_work_time_ = delayed_work_time;
+
+ int delay_msec = GetCurrentDelay();
+ DCHECK_GE(delay_msec, 0);
+ if (delay_msec < USER_TIMER_MINIMUM)
+ delay_msec = USER_TIMER_MINIMUM;
+
+ // Create a WM_TIMER event that will wake us up to check for any pending
+ // timers (in case we are running within a nested, external sub-pump).
+ BOOL ret = SetTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this),
+ delay_msec, NULL);
+ if (ret)
+ return;
+ // If we can't set timers, we are in big trouble... but cross our fingers for
+ // now.
+ // TODO(jar): If we don't see this error, use a CHECK() here instead.
+ UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", SET_TIMER_ERROR,
+ MESSAGE_LOOP_PROBLEM_MAX);
+}
+
+void MessagePumpForUI::PumpOutPendingPaintMessages() {
+ // If we are being called outside of the context of Run, then don't try to do
+ // any work.
+ if (!state_)
+ return;
+
+ // Create a mini-message-pump to force immediate processing of only Windows
+ // WM_PAINT messages. Don't provide an infinite loop, but do enough peeking
+ // to get the job done. Actual common max is 4 peeks, but we'll be a little
+ // safe here.
+ const int kMaxPeekCount = 20;
+ int peek_count;
+ for (peek_count = 0; peek_count < kMaxPeekCount; ++peek_count) {
+ MSG msg;
+ if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE | PM_QS_PAINT))
+ break;
+ ProcessMessageHelper(msg);
+ if (state_->should_quit) // Handle WM_QUIT.
+ break;
+ }
+ // Histogram what was really being used, to help to adjust kMaxPeekCount.
+ DHISTOGRAM_COUNTS("Loop.PumpOutPendingPaintMessages Peeks", peek_count);
+}
+
+//-----------------------------------------------------------------------------
+// MessagePumpForUI private:
+
+// static
+LRESULT CALLBACK MessagePumpForUI::WndProcThunk(
+ HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) {
+ switch (message) {
+ case kMsgHaveWork:
+ reinterpret_cast<MessagePumpForUI*>(wparam)->HandleWorkMessage();
+ break;
+ case WM_TIMER:
+ reinterpret_cast<MessagePumpForUI*>(wparam)->HandleTimerMessage();
+ break;
+ }
+ return DefWindowProc(hwnd, message, wparam, lparam);
+}
+
+void MessagePumpForUI::DoRunLoop() {
+ // IF this was just a simple PeekMessage() loop (servicing all possible work
+ // queues), then Windows would try to achieve the following order according
+ // to MSDN documentation about PeekMessage with no filter):
+ // * Sent messages
+ // * Posted messages
+ // * Sent messages (again)
+ // * WM_PAINT messages
+ // * WM_TIMER messages
+ //
+ // Summary: none of the above classes is starved, and sent messages has twice
+ // the chance of being processed (i.e., reduced service time).
+
+ for (;;) {
+ // If we do any work, we may create more messages etc., and more work may
+ // possibly be waiting in another task group. When we (for example)
+ // ProcessNextWindowsMessage(), there is a good chance there are still more
+ // messages waiting. On the other hand, when any of these methods return
+ // having done no work, then it is pretty unlikely that calling them again
+ // quickly will find any work to do. Finally, if they all say they had no
+ // work, then it is a good time to consider sleeping (waiting) for more
+ // work.
+
+ bool more_work_is_plausible = ProcessNextWindowsMessage();
+ if (state_->should_quit)
+ break;
+
+ more_work_is_plausible |= state_->delegate->DoWork();
+ if (state_->should_quit)
+ break;
+
+ more_work_is_plausible |=
+ state_->delegate->DoDelayedWork(&delayed_work_time_);
+ // If we did not process any delayed work, then we can assume that our
+ // existing WM_TIMER if any will fire when delayed work should run. We
+ // don't want to disturb that timer if it is already in flight. However,
+ // if we did do all remaining delayed work, then lets kill the WM_TIMER.
+ if (more_work_is_plausible && delayed_work_time_.is_null())
+ KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this));
+ if (state_->should_quit)
+ break;
+
+ if (more_work_is_plausible)
+ continue;
+
+ more_work_is_plausible = state_->delegate->DoIdleWork();
+ if (state_->should_quit)
+ break;
+
+ if (more_work_is_plausible)
+ continue;
+
+ WaitForWork(); // Wait (sleep) until we have work to do again.
+ }
+}
+
+void MessagePumpForUI::InitMessageWnd() {
+ // Generate a unique window class name.
+ string16 class_name = StringPrintf(kWndClassFormat, this);
+
+ HINSTANCE instance = GetModuleFromAddress(&WndProcThunk);
+ WNDCLASSEX wc = {0};
+ wc.cbSize = sizeof(wc);
+ wc.lpfnWndProc = base::win::WrappedWindowProc<WndProcThunk>;
+ wc.hInstance = instance;
+ wc.lpszClassName = class_name.c_str();
+ atom_ = RegisterClassEx(&wc);
+ DCHECK(atom_);
+
+ message_hwnd_ = CreateWindow(MAKEINTATOM(atom_), 0, 0, 0, 0, 0, 0,
+ HWND_MESSAGE, 0, instance, 0);
+ DCHECK(message_hwnd_);
+}
+
+void MessagePumpForUI::WaitForWork() {
+ // Wait until a message is available, up to the time needed by the timer
+ // manager to fire the next set of timers.
+ int delay = GetCurrentDelay();
+ if (delay < 0) // Negative value means no timers waiting.
+ delay = INFINITE;
+
+ DWORD result;
+ result = MsgWaitForMultipleObjectsEx(0, NULL, delay, QS_ALLINPUT,
+ MWMO_INPUTAVAILABLE);
+
+ if (WAIT_OBJECT_0 == result) {
+ // A WM_* message is available.
+ // If a parent child relationship exists between windows across threads
+ // then their thread inputs are implicitly attached.
+ // This causes the MsgWaitForMultipleObjectsEx API to return indicating
+ // that messages are ready for processing (Specifically, mouse messages
+ // intended for the child window may appear if the child window has
+ // capture).
+ // The subsequent PeekMessages call may fail to return any messages thus
+ // causing us to enter a tight loop at times.
+ // The WaitMessage call below is a workaround to give the child window
+ // some time to process its input messages.
+ MSG msg = {0};
+ DWORD queue_status = GetQueueStatus(QS_MOUSE);
+ if (HIWORD(queue_status) & QS_MOUSE &&
+ !PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE)) {
+ WaitMessage();
+ }
+ return;
+ }
+
+ DCHECK_NE(WAIT_FAILED, result) << GetLastError();
+}
+
+void MessagePumpForUI::HandleWorkMessage() {
+ // If we are being called outside of the context of Run, then don't try to do
+ // any work. This could correspond to a MessageBox call or something of that
+ // sort.
+ if (!state_) {
+ // Since we handled a kMsgHaveWork message, we must still update this flag.
+ InterlockedExchange(&have_work_, 0);
+ return;
+ }
+
+ // Let whatever would have run had we not been putting messages in the queue
+ // run now. This is an attempt to make our dummy message not starve other
+ // messages that may be in the Windows message queue.
+ ProcessPumpReplacementMessage();
+
+ // Now give the delegate a chance to do some work. He'll let us know if he
+ // needs to do more work.
+ if (state_->delegate->DoWork())
+ ScheduleWork();
+}
+
+void MessagePumpForUI::HandleTimerMessage() {
+ KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this));
+
+ // If we are being called outside of the context of Run, then don't do
+ // anything. This could correspond to a MessageBox call or something of
+ // that sort.
+ if (!state_)
+ return;
+
+ state_->delegate->DoDelayedWork(&delayed_work_time_);
+ if (!delayed_work_time_.is_null()) {
+ // A bit gratuitous to set delayed_work_time_ again, but oh well.
+ ScheduleDelayedWork(delayed_work_time_);
+ }
+}
+
+bool MessagePumpForUI::ProcessNextWindowsMessage() {
+ // If there are sent messages in the queue then PeekMessage internally
+ // dispatches the message and returns false. We return true in this
+ // case to ensure that the message loop peeks again instead of calling
+ // MsgWaitForMultipleObjectsEx again.
+ bool sent_messages_in_queue = false;
+ DWORD queue_status = GetQueueStatus(QS_SENDMESSAGE);
+ if (HIWORD(queue_status) & QS_SENDMESSAGE)
+ sent_messages_in_queue = true;
+
+ MSG msg;
+ if (message_filter_->DoPeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+ return ProcessMessageHelper(msg);
+
+ return sent_messages_in_queue;
+}
+
+bool MessagePumpForUI::ProcessMessageHelper(const MSG& msg) {
+ TRACE_EVENT1("base", "MessagePumpForUI::ProcessMessageHelper",
+ "message", msg.message);
+ if (WM_QUIT == msg.message) {
+ // Repost the QUIT message so that it will be retrieved by the primary
+ // GetMessage() loop.
+ state_->should_quit = true;
+ PostQuitMessage(static_cast<int>(msg.wParam));
+ return false;
+ }
+
+ // While running our main message pump, we discard kMsgHaveWork messages.
+ if (msg.message == kMsgHaveWork && msg.hwnd == message_hwnd_)
+ return ProcessPumpReplacementMessage();
+
+ if (CallMsgFilter(const_cast<MSG*>(&msg), kMessageFilterCode))
+ return true;
+
+ WillProcessMessage(msg);
+
+ if (!message_filter_->ProcessMessage(msg)) {
+ if (state_->dispatcher) {
+ if (!state_->dispatcher->Dispatch(msg))
+ state_->should_quit = true;
+ } else {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ DidProcessMessage(msg);
+ return true;
+}
+
+bool MessagePumpForUI::ProcessPumpReplacementMessage() {
+ // When we encounter a kMsgHaveWork message, this method is called to peek
+ // and process a replacement message, such as a WM_PAINT or WM_TIMER. The
+ // goal is to make the kMsgHaveWork as non-intrusive as possible, even though
+ // a continuous stream of such messages are posted. This method carefully
+ // peeks a message while there is no chance for a kMsgHaveWork to be pending,
+ // then resets the have_work_ flag (allowing a replacement kMsgHaveWork to
+ // possibly be posted), and finally dispatches that peeked replacement. Note
+ // that the re-post of kMsgHaveWork may be asynchronous to this thread!!
+
+ bool have_message = false;
+ MSG msg;
+ // We should not process all window messages if we are in the context of an
+ // OS modal loop, i.e. in the context of a windows API call like MessageBox.
+ // This is to ensure that these messages are peeked out by the OS modal loop.
+ if (MessageLoop::current()->os_modal_loop()) {
+ // We only peek out WM_PAINT and WM_TIMER here for reasons mentioned above.
+ have_message = PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE) ||
+ PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE);
+ } else {
+ have_message = !!message_filter_->DoPeekMessage(&msg, NULL, 0, 0,
+ PM_REMOVE);
+ }
+
+ DCHECK(!have_message || kMsgHaveWork != msg.message ||
+ msg.hwnd != message_hwnd_);
+
+ // Since we discarded a kMsgHaveWork message, we must update the flag.
+ int old_have_work = InterlockedExchange(&have_work_, 0);
+ DCHECK(old_have_work);
+
+ // We don't need a special time slice if we didn't have_message to process.
+ if (!have_message)
+ return false;
+
+ // Guarantee we'll get another time slice in the case where we go into native
+ // windows code. This ScheduleWork() may hurt performance a tiny bit when
+ // tasks appear very infrequently, but when the event queue is busy, the
+ // kMsgHaveWork events get (percentage wise) rarer and rarer.
+ ScheduleWork();
+ return ProcessMessageHelper(msg);
+}
+
+void MessagePumpForUI::SetMessageFilter(
+ scoped_ptr<MessageFilter> message_filter) {
+ message_filter_ = message_filter.Pass();
+}
+
+//-----------------------------------------------------------------------------
+// MessagePumpForIO public:
+
+MessagePumpForIO::MessagePumpForIO() {
+ port_.Set(CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 1));
+ DCHECK(port_.IsValid());
+}
+
+void MessagePumpForIO::ScheduleWork() {
+ if (InterlockedExchange(&have_work_, 1))
+ return; // Someone else continued the pumping.
+
+ // Make sure the MessagePump does some work for us.
+ BOOL ret = PostQueuedCompletionStatus(port_, 0,
+ reinterpret_cast<ULONG_PTR>(this),
+ reinterpret_cast<OVERLAPPED*>(this));
+ if (ret)
+ return; // Post worked perfectly.
+
+ // See comment in MessagePumpForUI::ScheduleWork() for this error recovery.
+ InterlockedExchange(&have_work_, 0); // Clarify that we didn't succeed.
+ UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", COMPLETION_POST_ERROR,
+ MESSAGE_LOOP_PROBLEM_MAX);
+}
+
+void MessagePumpForIO::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
+ // We know that we can't be blocked right now since this method can only be
+ // called on the same thread as Run, so we only need to update our record of
+ // how long to sleep when we do sleep.
+ delayed_work_time_ = delayed_work_time;
+}
+
+void MessagePumpForIO::RegisterIOHandler(HANDLE file_handle,
+ IOHandler* handler) {
+ ULONG_PTR key = HandlerToKey(handler, true);
+ HANDLE port = CreateIoCompletionPort(file_handle, port_, key, 1);
+ DPCHECK(port);
+}
+
+bool MessagePumpForIO::RegisterJobObject(HANDLE job_handle,
+ IOHandler* handler) {
+ // Job object notifications use the OVERLAPPED pointer to carry the message
+ // data. Mark the completion key correspondingly, so we will not try to
+ // convert OVERLAPPED* to IOContext*.
+ ULONG_PTR key = HandlerToKey(handler, false);
+ JOBOBJECT_ASSOCIATE_COMPLETION_PORT info;
+ info.CompletionKey = reinterpret_cast<void*>(key);
+ info.CompletionPort = port_;
+ return SetInformationJobObject(job_handle,
+ JobObjectAssociateCompletionPortInformation,
+ &info,
+ sizeof(info)) != FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// MessagePumpForIO private:
+
+void MessagePumpForIO::DoRunLoop() {
+ for (;;) {
+ // If we do any work, we may create more messages etc., and more work may
+ // possibly be waiting in another task group. When we (for example)
+ // WaitForIOCompletion(), there is a good chance there are still more
+ // messages waiting. On the other hand, when any of these methods return
+ // having done no work, then it is pretty unlikely that calling them
+ // again quickly will find any work to do. Finally, if they all say they
+ // had no work, then it is a good time to consider sleeping (waiting) for
+ // more work.
+
+ bool more_work_is_plausible = state_->delegate->DoWork();
+ if (state_->should_quit)
+ break;
+
+ more_work_is_plausible |= WaitForIOCompletion(0, NULL);
+ if (state_->should_quit)
+ break;
+
+ more_work_is_plausible |=
+ state_->delegate->DoDelayedWork(&delayed_work_time_);
+ if (state_->should_quit)
+ break;
+
+ if (more_work_is_plausible)
+ continue;
+
+ more_work_is_plausible = state_->delegate->DoIdleWork();
+ if (state_->should_quit)
+ break;
+
+ if (more_work_is_plausible)
+ continue;
+
+ WaitForWork(); // Wait (sleep) until we have work to do again.
+ }
+}
+
+// Wait until IO completes, up to the time needed by the timer manager to fire
+// the next set of timers.
+void MessagePumpForIO::WaitForWork() {
+ // We do not support nested IO message loops. This is to avoid messy
+ // recursion problems.
+ DCHECK_EQ(1, state_->run_depth) << "Cannot nest an IO message loop!";
+
+ int timeout = GetCurrentDelay();
+ if (timeout < 0) // Negative value means no timers waiting.
+ timeout = INFINITE;
+
+ WaitForIOCompletion(timeout, NULL);
+}
+
+bool MessagePumpForIO::WaitForIOCompletion(DWORD timeout, IOHandler* filter) {
+ IOItem item;
+ if (completed_io_.empty() || !MatchCompletedIOItem(filter, &item)) {
+ // We have to ask the system for another IO completion.
+ if (!GetIOItem(timeout, &item))
+ return false;
+
+ if (ProcessInternalIOItem(item))
+ return true;
+ }
+
+ // If |item.has_valid_io_context| is false then |item.context| does not point
+ // to a context structure, and so should not be dereferenced, although it may
+ // still hold valid non-pointer data.
+ if (!item.has_valid_io_context || item.context->handler) {
+ if (filter && item.handler != filter) {
+ // Save this item for later
+ completed_io_.push_back(item);
+ } else {
+ DCHECK(!item.has_valid_io_context ||
+ (item.context->handler == item.handler));
+ WillProcessIOEvent();
+ item.handler->OnIOCompleted(item.context, item.bytes_transfered,
+ item.error);
+ DidProcessIOEvent();
+ }
+ } else {
+ // The handler must be gone by now, just cleanup the mess.
+ delete item.context;
+ }
+ return true;
+}
+
+// Asks the OS for another IO completion result.
+bool MessagePumpForIO::GetIOItem(DWORD timeout, IOItem* item) {
+ memset(item, 0, sizeof(*item));
+ ULONG_PTR key = NULL;
+ OVERLAPPED* overlapped = NULL;
+ if (!GetQueuedCompletionStatus(port_.Get(), &item->bytes_transfered, &key,
+ &overlapped, timeout)) {
+ if (!overlapped)
+ return false; // Nothing in the queue.
+ item->error = GetLastError();
+ item->bytes_transfered = 0;
+ }
+
+ item->handler = KeyToHandler(key, &item->has_valid_io_context);
+ item->context = reinterpret_cast<IOContext*>(overlapped);
+ return true;
+}
+
+bool MessagePumpForIO::ProcessInternalIOItem(const IOItem& item) {
+ if (this == reinterpret_cast<MessagePumpForIO*>(item.context) &&
+ this == reinterpret_cast<MessagePumpForIO*>(item.handler)) {
+ // This is our internal completion.
+ DCHECK(!item.bytes_transfered);
+ InterlockedExchange(&have_work_, 0);
+ return true;
+ }
+ return false;
+}
+
+// Returns a completion item that was previously received.
+bool MessagePumpForIO::MatchCompletedIOItem(IOHandler* filter, IOItem* item) {
+ DCHECK(!completed_io_.empty());
+ for (std::list<IOItem>::iterator it = completed_io_.begin();
+ it != completed_io_.end(); ++it) {
+ if (!filter || it->handler == filter) {
+ *item = *it;
+ completed_io_.erase(it);
+ return true;
+ }
+ }
+ return false;
+}
+
+void MessagePumpForIO::AddIOObserver(IOObserver *obs) {
+ io_observers_.AddObserver(obs);
+}
+
+void MessagePumpForIO::RemoveIOObserver(IOObserver *obs) {
+ io_observers_.RemoveObserver(obs);
+}
+
+void MessagePumpForIO::WillProcessIOEvent() {
+ FOR_EACH_OBSERVER(IOObserver, io_observers_, WillProcessIOEvent());
+}
+
+void MessagePumpForIO::DidProcessIOEvent() {
+ FOR_EACH_OBSERVER(IOObserver, io_observers_, DidProcessIOEvent());
+}
+
+// static
+ULONG_PTR MessagePumpForIO::HandlerToKey(IOHandler* handler,
+ bool has_valid_io_context) {
+ ULONG_PTR key = reinterpret_cast<ULONG_PTR>(handler);
+
+ // |IOHandler| is at least pointer-size aligned, so the lowest two bits are
+ // always cleared. We use the lowest bit to distinguish completion keys with
+ // and without the associated |IOContext|.
+ DCHECK((key & 1) == 0);
+
+ // Mark the completion key as context-less.
+ if (!has_valid_io_context)
+ key = key | 1;
+ return key;
+}
+
+// static
+MessagePumpForIO::IOHandler* MessagePumpForIO::KeyToHandler(
+ ULONG_PTR key,
+ bool* has_valid_io_context) {
+ *has_valid_io_context = ((key & 1) == 0);
+ return reinterpret_cast<IOHandler*>(key & ~static_cast<ULONG_PTR>(1));
+}
+
+} // namespace base
diff --git a/base/message_loop/message_pump_win.h b/base/message_loop/message_pump_win.h
new file mode 100644
index 0000000..dbb41bd
--- /dev/null
+++ b/base/message_loop/message_pump_win.h
@@ -0,0 +1,396 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_WIN_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_WIN_H_
+
+#include <windows.h>
+
+#include <list>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_pump.h"
+#include "base/message_loop/message_pump_dispatcher.h"
+#include "base/message_loop/message_pump_observer.h"
+#include "base/observer_list.h"
+#include "base/time.h"
+#include "base/win/scoped_handle.h"
+
+namespace base {
+
+// MessagePumpWin serves as the base for specialized versions of the MessagePump
+// for Windows. It provides basic functionality like handling of observers and
+// controlling the lifetime of the message pump.
+class BASE_EXPORT MessagePumpWin : public MessagePump {
+ public:
+ MessagePumpWin() : have_work_(0), state_(NULL) {}
+ virtual ~MessagePumpWin() {}
+
+ // Add an Observer, which will start receiving notifications immediately.
+ void AddObserver(MessagePumpObserver* observer);
+
+ // Remove an Observer. It is safe to call this method while an Observer is
+ // receiving a notification callback.
+ void RemoveObserver(MessagePumpObserver* observer);
+
+ // Give a chance to code processing additional messages to notify the
+ // message loop observers that another message has been processed.
+ void WillProcessMessage(const MSG& msg);
+ void DidProcessMessage(const MSG& msg);
+
+ // Like MessagePump::Run, but MSG objects are routed through dispatcher.
+ void RunWithDispatcher(Delegate* delegate, MessagePumpDispatcher* dispatcher);
+
+ // MessagePump methods:
+ virtual void Run(Delegate* delegate) { RunWithDispatcher(delegate, NULL); }
+ virtual void Quit();
+
+ protected:
+ struct RunState {
+ Delegate* delegate;
+ MessagePumpDispatcher* dispatcher;
+
+ // Used to flag that the current Run() invocation should return ASAP.
+ bool should_quit;
+
+ // Used to count how many Run() invocations are on the stack.
+ int run_depth;
+ };
+
+ virtual void DoRunLoop() = 0;
+ int GetCurrentDelay() const;
+
+ ObserverList<MessagePumpObserver> observers_;
+
+ // The time at which delayed work should run.
+ TimeTicks delayed_work_time_;
+
+ // A boolean value used to indicate if there is a kMsgDoWork message pending
+ // in the Windows Message queue. There is at most one such message, and it
+ // can drive execution of tasks when a native message pump is running.
+ LONG have_work_;
+
+ // State for the current invocation of Run.
+ RunState* state_;
+};
+
+//-----------------------------------------------------------------------------
+// MessagePumpForUI extends MessagePumpWin with methods that are particular to a
+// MessageLoop instantiated with TYPE_UI.
+//
+// MessagePumpForUI implements a "traditional" Windows message pump. It contains
+// a nearly infinite loop that peeks out messages, and then dispatches them.
+// Intermixed with those peeks are callouts to DoWork for pending tasks, and
+// DoDelayedWork for pending timers. When there are no events to be serviced,
+// this pump goes into a wait state. In most cases, this message pump handles
+// all processing.
+//
+// However, when a task, or windows event, invokes on the stack a native dialog
+// box or such, that window typically provides a bare bones (native?) message
+// pump. That bare-bones message pump generally supports little more than a
+// peek of the Windows message queue, followed by a dispatch of the peeked
+// message. MessageLoop extends that bare-bones message pump to also service
+// Tasks, at the cost of some complexity.
+//
+// The basic structure of the extension (refered to as a sub-pump) is that a
+// special message, kMsgHaveWork, is repeatedly injected into the Windows
+// Message queue. Each time the kMsgHaveWork message is peeked, checks are
+// made for an extended set of events, including the availability of Tasks to
+// run.
+//
+// After running a task, the special message kMsgHaveWork is again posted to
+// the Windows Message queue, ensuring a future time slice for processing a
+// future event. To prevent flooding the Windows Message queue, care is taken
+// to be sure that at most one kMsgHaveWork message is EVER pending in the
+// Window's Message queue.
+//
+// There are a few additional complexities in this system where, when there are
+// no Tasks to run, this otherwise infinite stream of messages which drives the
+// sub-pump is halted. The pump is automatically re-started when Tasks are
+// queued.
+//
+// A second complexity is that the presence of this stream of posted tasks may
+// prevent a bare-bones message pump from ever peeking a WM_PAINT or WM_TIMER.
+// Such paint and timer events always give priority to a posted message, such as
+// kMsgHaveWork messages. As a result, care is taken to do some peeking in
+// between the posting of each kMsgHaveWork message (i.e., after kMsgHaveWork
+// is peeked, and before a replacement kMsgHaveWork is posted).
+//
+// NOTE: Although it may seem odd that messages are used to start and stop this
+// flow (as opposed to signaling objects, etc.), it should be understood that
+// the native message pump will *only* respond to messages. As a result, it is
+// an excellent choice. It is also helpful that the starter messages that are
+// placed in the queue when new task arrive also awakens DoRunLoop.
+//
+class BASE_EXPORT MessagePumpForUI : public MessagePumpWin {
+ public:
+ // A MessageFilter implements the common Peek/Translate/Dispatch code to deal
+ // with windows messages.
+ // This abstraction is used to inject TSF message peeking. See
+ // TextServicesMessageFilter.
+ class BASE_EXPORT MessageFilter {
+ public:
+ virtual ~MessageFilter() {}
+ // Implements the functionality exposed by the OS through PeekMessage.
+ virtual BOOL DoPeekMessage(MSG* msg,
+ HWND window_handle,
+ UINT msg_filter_min,
+ UINT msg_filter_max,
+ UINT remove_msg) {
+ return PeekMessage(msg, window_handle, msg_filter_min, msg_filter_max,
+ remove_msg);
+ }
+ // Returns true if |message| was consumed by the filter and no extra
+ // processing is required. If this method returns false, it is the
+ // responsibility of the caller to ensure that normal processing takes
+ // place.
+ // The priority to consume messages is the following:
+ // - Native Windows' message filter (CallMsgFilter).
+ // - MessageFilter::ProcessMessage.
+ // - MessagePumpDispatcher.
+ // - TranslateMessage / DispatchMessage.
+ virtual bool ProcessMessage(const MSG& msg) { return false;}
+ };
+ // The application-defined code passed to the hook procedure.
+ static const int kMessageFilterCode = 0x5001;
+
+ MessagePumpForUI();
+ virtual ~MessagePumpForUI();
+
+ // Sets a new MessageFilter. MessagePumpForUI takes ownership of
+ // |message_filter|. When SetMessageFilter is called, old MessageFilter is
+ // deleted.
+ void SetMessageFilter(scoped_ptr<MessageFilter> message_filter);
+
+ // MessagePump methods:
+ virtual void ScheduleWork();
+ virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time);
+
+ // Applications can call this to encourage us to process all pending WM_PAINT
+ // messages. This method will process all paint messages the Windows Message
+ // queue can provide, up to some fixed number (to avoid any infinite loops).
+ void PumpOutPendingPaintMessages();
+
+ private:
+ static LRESULT CALLBACK WndProcThunk(HWND window_handle,
+ UINT message,
+ WPARAM wparam,
+ LPARAM lparam);
+ virtual void DoRunLoop();
+ void InitMessageWnd();
+ void WaitForWork();
+ void HandleWorkMessage();
+ void HandleTimerMessage();
+ bool ProcessNextWindowsMessage();
+ bool ProcessMessageHelper(const MSG& msg);
+ bool ProcessPumpReplacementMessage();
+
+ // Atom representing the registered window class.
+ ATOM atom_;
+
+ // A hidden message-only window.
+ HWND message_hwnd_;
+
+ scoped_ptr<MessageFilter> message_filter_;
+};
+
+//-----------------------------------------------------------------------------
+// MessagePumpForIO extends MessagePumpWin with methods that are particular to a
+// MessageLoop instantiated with TYPE_IO. This version of MessagePump does not
+// deal with Windows mesagges, and instead has a Run loop based on Completion
+// Ports so it is better suited for IO operations.
+//
+class BASE_EXPORT MessagePumpForIO : public MessagePumpWin {
+ public:
+ struct IOContext;
+
+ // Clients interested in receiving OS notifications when asynchronous IO
+ // operations complete should implement this interface and register themselves
+ // with the message pump.
+ //
+ // Typical use #1:
+ // // Use only when there are no user's buffers involved on the actual IO,
+ // // so that all the cleanup can be done by the message pump.
+ // class MyFile : public IOHandler {
+ // MyFile() {
+ // ...
+ // context_ = new IOContext;
+ // context_->handler = this;
+ // message_pump->RegisterIOHandler(file_, this);
+ // }
+ // ~MyFile() {
+ // if (pending_) {
+ // // By setting the handler to NULL, we're asking for this context
+ // // to be deleted when received, without calling back to us.
+ // context_->handler = NULL;
+ // } else {
+ // delete context_;
+ // }
+ // }
+ // virtual void OnIOCompleted(IOContext* context, DWORD bytes_transfered,
+ // DWORD error) {
+ // pending_ = false;
+ // }
+ // void DoSomeIo() {
+ // ...
+ // // The only buffer required for this operation is the overlapped
+ // // structure.
+ // ConnectNamedPipe(file_, &context_->overlapped);
+ // pending_ = true;
+ // }
+ // bool pending_;
+ // IOContext* context_;
+ // HANDLE file_;
+ // };
+ //
+ // Typical use #2:
+ // class MyFile : public IOHandler {
+ // MyFile() {
+ // ...
+ // message_pump->RegisterIOHandler(file_, this);
+ // }
+ // // Plus some code to make sure that this destructor is not called
+ // // while there are pending IO operations.
+ // ~MyFile() {
+ // }
+ // virtual void OnIOCompleted(IOContext* context, DWORD bytes_transfered,
+ // DWORD error) {
+ // ...
+ // delete context;
+ // }
+ // void DoSomeIo() {
+ // ...
+ // IOContext* context = new IOContext;
+ // // This is not used for anything. It just prevents the context from
+ // // being considered "abandoned".
+ // context->handler = this;
+ // ReadFile(file_, buffer, num_bytes, &read, &context->overlapped);
+ // }
+ // HANDLE file_;
+ // };
+ //
+ // Typical use #3:
+ // Same as the previous example, except that in order to deal with the
+ // requirement stated for the destructor, the class calls WaitForIOCompletion
+ // from the destructor to block until all IO finishes.
+ // ~MyFile() {
+ // while(pending_)
+ // message_pump->WaitForIOCompletion(INFINITE, this);
+ // }
+ //
+ class IOHandler {
+ public:
+ virtual ~IOHandler() {}
+ // This will be called once the pending IO operation associated with
+ // |context| completes. |error| is the Win32 error code of the IO operation
+ // (ERROR_SUCCESS if there was no error). |bytes_transfered| will be zero
+ // on error.
+ virtual void OnIOCompleted(IOContext* context, DWORD bytes_transfered,
+ DWORD error) = 0;
+ };
+
+ // An IOObserver is an object that receives IO notifications from the
+ // MessagePump.
+ //
+ // NOTE: An IOObserver implementation should be extremely fast!
+ class IOObserver {
+ public:
+ IOObserver() {}
+
+ virtual void WillProcessIOEvent() = 0;
+ virtual void DidProcessIOEvent() = 0;
+
+ protected:
+ virtual ~IOObserver() {}
+ };
+
+ // The extended context that should be used as the base structure on every
+ // overlapped IO operation. |handler| must be set to the registered IOHandler
+ // for the given file when the operation is started, and it can be set to NULL
+ // before the operation completes to indicate that the handler should not be
+ // called anymore, and instead, the IOContext should be deleted when the OS
+ // notifies the completion of this operation. Please remember that any buffers
+ // involved with an IO operation should be around until the callback is
+ // received, so this technique can only be used for IO that do not involve
+ // additional buffers (other than the overlapped structure itself).
+ struct IOContext {
+ OVERLAPPED overlapped;
+ IOHandler* handler;
+ };
+
+ MessagePumpForIO();
+ virtual ~MessagePumpForIO() {}
+
+ // MessagePump methods:
+ virtual void ScheduleWork();
+ virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time);
+
+ // Register the handler to be used when asynchronous IO for the given file
+ // completes. The registration persists as long as |file_handle| is valid, so
+ // |handler| must be valid as long as there is pending IO for the given file.
+ void RegisterIOHandler(HANDLE file_handle, IOHandler* handler);
+
+ // Register the handler to be used to process job events. The registration
+ // persists as long as the job object is live, so |handler| must be valid
+ // until the job object is destroyed. Returns true if the registration
+ // succeeded, and false otherwise.
+ bool RegisterJobObject(HANDLE job_handle, IOHandler* handler);
+
+ // Waits for the next IO completion that should be processed by |filter|, for
+ // up to |timeout| milliseconds. Return true if any IO operation completed,
+ // regardless of the involved handler, and false if the timeout expired. If
+ // the completion port received any message and the involved IO handler
+ // matches |filter|, the callback is called before returning from this code;
+ // if the handler is not the one that we are looking for, the callback will
+ // be postponed for another time, so reentrancy problems can be avoided.
+ // External use of this method should be reserved for the rare case when the
+ // caller is willing to allow pausing regular task dispatching on this thread.
+ bool WaitForIOCompletion(DWORD timeout, IOHandler* filter);
+
+ void AddIOObserver(IOObserver* obs);
+ void RemoveIOObserver(IOObserver* obs);
+
+ private:
+ struct IOItem {
+ IOHandler* handler;
+ IOContext* context;
+ DWORD bytes_transfered;
+ DWORD error;
+
+ // In some cases |context| can be a non-pointer value casted to a pointer.
+ // |has_valid_io_context| is true if |context| is a valid IOContext
+ // pointer, and false otherwise.
+ bool has_valid_io_context;
+ };
+
+ virtual void DoRunLoop();
+ void WaitForWork();
+ bool MatchCompletedIOItem(IOHandler* filter, IOItem* item);
+ bool GetIOItem(DWORD timeout, IOItem* item);
+ bool ProcessInternalIOItem(const IOItem& item);
+ void WillProcessIOEvent();
+ void DidProcessIOEvent();
+
+ // Converts an IOHandler pointer to a completion port key.
+ // |has_valid_io_context| specifies whether completion packets posted to
+ // |handler| will have valid OVERLAPPED pointers.
+ static ULONG_PTR HandlerToKey(IOHandler* handler, bool has_valid_io_context);
+
+ // Converts a completion port key to an IOHandler pointer.
+ static IOHandler* KeyToHandler(ULONG_PTR key, bool* has_valid_io_context);
+
+ // The completion port associated with this thread.
+ win::ScopedHandle port_;
+ // This list will be empty almost always. It stores IO completions that have
+ // not been delivered yet because somebody was doing cleanup.
+ std::list<IOItem> completed_io_;
+
+ ObserverList<IOObserver> io_observers_;
+};
+
+} // namespace base
+
+#endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_WIN_H_