summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/base.xcodeproj/project.pbxproj14
-rw-r--r--base/message_loop.cc12
-rw-r--r--base/message_pump_mac.h181
-rw-r--r--base/message_pump_mac.mm363
-rw-r--r--net/net.xcodeproj/project.pbxproj10
5 files changed, 573 insertions, 7 deletions
diff --git a/base/base.xcodeproj/project.pbxproj b/base/base.xcodeproj/project.pbxproj
index 8971af4..01b8333 100644
--- a/base/base.xcodeproj/project.pbxproj
+++ b/base/base.xcodeproj/project.pbxproj
@@ -80,6 +80,8 @@
7B8505D90E5B445100730B43 /* libbase_gfx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 825403B10D92D2E50006B936 /* libbase_gfx.a */; };
7B85062A0E5B556900730B43 /* libpng.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B165D5E0E55081400185273 /* libpng.a */; };
7B85062F0E5B559A00730B43 /* libzlib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B165D6E0E55081400185273 /* libzlib.a */; };
+ 7BA355EB0E898C100023C8B9 /* message_pump_mac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7BA355EA0E898C100023C8B9 /* message_pump_mac.mm */; };
+ 7BA3562C0E898F880023C8B9 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7BA3562B0E898F7B0023C8B9 /* AppKit.framework */; };
7BAE30E50E6D939F00C3F750 /* atomicops_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BAE30E10E6D939800C3F750 /* atomicops_unittest.cc */; };
7BAE30E60E6D939F00C3F750 /* simple_thread_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BAE30E40E6D939800C3F750 /* simple_thread_unittest.cc */; };
7BAE30E70E6D93A300C3F750 /* simple_thread.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BAE30E20E6D939800C3F750 /* simple_thread.cc */; };
@@ -237,14 +239,14 @@
isa = PBXContainerItemProxy;
containerPortal = 7B26301F0E82F1E6001CE27F /* libevent.xcodeproj */;
proxyType = 2;
- remoteGlobalIDString = 7B262E840E82E5D7001CE27F /* libevent.a */;
+ remoteGlobalIDString = 7B262E840E82E5D7001CE27F;
remoteInfo = libevent;
};
7B2630250E82F1EF001CE27F /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 7B26301F0E82F1E6001CE27F /* libevent.xcodeproj */;
proxyType = 1;
- remoteGlobalIDString = 7B262E830E82E5D7001CE27F /* libevent */;
+ remoteGlobalIDString = 7B262E830E82E5D7001CE27F;
remoteInfo = libevent;
};
7B4DF5310E5B6A4B004D7619 /* PBXContainerItemProxy */ = {
@@ -379,6 +381,9 @@
7B8505A50E5B3FBE00730B43 /* skia_utils.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = skia_utils.cc; sourceTree = "<group>"; };
7B8505A60E5B3FBE00730B43 /* skia_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = skia_utils.h; sourceTree = "<group>"; };
7B8505A80E5B3FBE00730B43 /* vector_canvas_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = vector_canvas_unittest.cc; sourceTree = "<group>"; };
+ 7BA355E90E898C100023C8B9 /* message_pump_mac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = message_pump_mac.h; sourceTree = "<group>"; };
+ 7BA355EA0E898C100023C8B9 /* message_pump_mac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = message_pump_mac.mm; sourceTree = "<group>"; };
+ 7BA3562B0E898F7B0023C8B9 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = "<group>"; };
7BAE30E10E6D939800C3F750 /* atomicops_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = atomicops_unittest.cc; sourceTree = "<group>"; };
7BAE30E20E6D939800C3F750 /* simple_thread.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = simple_thread.cc; sourceTree = "<group>"; };
7BAE30E30E6D939800C3F750 /* simple_thread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = simple_thread.h; sourceTree = "<group>"; };
@@ -660,6 +665,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 7BA3562C0E898F880023C8B9 /* AppKit.framework in Frameworks */,
ABE1BA2A0E7574D1009041DA /* ApplicationServices.framework in Frameworks */,
7B78D40E0E54FE8000609465 /* Foundation.framework in Frameworks */,
7B78D38C0E54FDEC00609465 /* libbase.a in Frameworks */,
@@ -870,6 +876,8 @@
93611ADD0E5A7FC500F9405D /* message_pump_default.h */,
7B26302D0E82F218001CE27F /* message_pump_libevent.cc */,
7B26302E0E82F218001CE27F /* message_pump_libevent.h */,
+ 7BA355E90E898C100023C8B9 /* message_pump_mac.h */,
+ 7BA355EA0E898C100023C8B9 /* message_pump_mac.mm */,
7BF8828F0E719389000BAF8A /* non_thread_safe.cc */,
7BF882900E719389000BAF8A /* non_thread_safe.h */,
825403390D92D2210006B936 /* observer_list.h */,
@@ -1066,6 +1074,7 @@
829E2FA80DBFD7D500819EBF /* Frameworks */ = {
isa = PBXGroup;
children = (
+ 7BA3562B0E898F7B0023C8B9 /* AppKit.framework */,
ABE1BA290E7574D1009041DA /* ApplicationServices.framework */,
7B78D40D0E54FE8000609465 /* Foundation.framework */,
);
@@ -1317,6 +1326,7 @@
93611AE10E5A7FE200F9405D /* message_loop.cc in Sources */,
93611ADF0E5A7FC500F9405D /* message_pump_default.cc in Sources */,
7B26302F0E82F218001CE27F /* message_pump_libevent.cc in Sources */,
+ 7BA355EB0E898C100023C8B9 /* message_pump_mac.mm in Sources */,
7BF882910E719389000BAF8A /* non_thread_safe.cc in Sources */,
ABF4B9B50DC2BC9F00A6E319 /* path_service.cc in Sources */,
824654A60DC25CD7007C2BAA /* pickle.cc in Sources */,
diff --git a/base/message_loop.cc b/base/message_loop.cc
index ccd6d3e..91c40d3 100644
--- a/base/message_loop.cc
+++ b/base/message_loop.cc
@@ -13,6 +13,9 @@
#include "base/string_util.h"
#include "base/thread_local.h"
+#if defined(OS_MACOSX)
+#include "base/message_pump_mac.h"
+#endif
#if defined(OS_POSIX)
#include "base/message_pump_libevent.h"
#endif
@@ -83,14 +86,19 @@ MessageLoop::MessageLoop(Type type)
pump_ = new base::MessagePumpWin();
}
#elif defined(OS_POSIX)
+#if defined(OS_MACOSX)
+ if (type_ == TYPE_UI) {
+ pump_ = base::MessagePumpMac::Create();
+ } else
+#endif // OS_MACOSX
if (type_ == TYPE_IO) {
pump_ = new base::MessagePumpLibevent();
} else {
pump_ = new base::MessagePumpDefault();
}
-#else
+#else // OS_POSIX
pump_ = new base::MessagePumpDefault();
-#endif
+#endif // OS_POSIX
}
MessageLoop::~MessageLoop() {
diff --git a/base/message_pump_mac.h b/base/message_pump_mac.h
new file mode 100644
index 0000000..20b4a0e
--- /dev/null
+++ b/base/message_pump_mac.h
@@ -0,0 +1,181 @@
+// Copyright (c) 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.
+
+// 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_PUMP_MAC_H_
+#define BASE_MESSAGE_PUMP_MAC_H_
+
+#include "base/message_pump.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#include "base/time.h"
+
+namespace base {
+
+class MessagePumpCFRunLoopBase : public MessagePump {
+ public:
+ MessagePumpCFRunLoopBase();
+ virtual ~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);
+ virtual void DoRun(Delegate* delegate) = 0;
+
+ virtual void ScheduleWork();
+ virtual void ScheduleDelayedWork(const Time& delayed_work_time);
+
+ protected:
+ // The thread's run loop.
+ CFRunLoopRef run_loop_;
+
+ private:
+ // Timer callback scheduled by ScheduleDelayedWork. This does not do any
+ // work, but it signals delayed_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.
+ static void RunWork(void* info);
+
+ // Perform delayed-priority work. This is associated with
+ // delayed_work_source_ signalled by RunDelayedWorkTimer, and is responsible
+ // for calling ScheduleDelayedWork again if appropriate.
+ static void RunDelayedWork(void* info);
+
+ // Observer callback responsible for performing idle-priority work, before
+ // the run loop goes to sleep. Associated with idle_work_observer_.
+ static void RunIdleWork(CFRunLoopObserverRef observer,
+ CFRunLoopActivity activity, void* info);
+
+ // The timer, sources, and observer are described above alongside their
+ // callbacks.
+ CFRunLoopTimerRef delayed_work_timer_;
+ CFRunLoopSourceRef work_source_;
+ CFRunLoopSourceRef delayed_work_source_;
+ CFRunLoopObserverRef idle_work_observer_;
+
+ // (weak) Delegate passed as an argument to the innermost Run call.
+ Delegate* delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessagePumpCFRunLoopBase);
+};
+
+class MessagePumpCFRunLoop : public MessagePumpCFRunLoopBase {
+ public:
+ MessagePumpCFRunLoop();
+ virtual ~MessagePumpCFRunLoop();
+
+ virtual void DoRun(Delegate* delegate);
+ virtual void Quit();
+
+ private:
+ // 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_ and to handle deferred loop quits. Associated with
+ // enter_exit_observer_.
+ static void EnterExitRunLoop(CFRunLoopObserverRef observer,
+ CFRunLoopActivity activity, void* info);
+
+ // Observer for EnterExitRunLoop.
+ CFRunLoopObserverRef enter_exit_observer_;
+
+ // 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 innermost_quittable_;
+
+ // 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:
+ MessagePumpNSRunLoop();
+ virtual ~MessagePumpNSRunLoop();
+
+ virtual void DoRun(Delegate* delegate);
+ virtual void Quit();
+
+ 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);
+};
+
+class MessagePumpNSApplication : public MessagePumpCFRunLoopBase {
+ public:
+ MessagePumpNSApplication();
+
+ virtual void DoRun(Delegate* delegate);
+ virtual void Quit();
+
+ 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 MessagePumpMac {
+ public:
+ // Returns a new instance of MessagePumpNSApplication if called on the main
+ // thread. Otherwise, returns a new instance of MessagePumpNSRunLoop.
+ static MessagePump* Create();
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(MessagePumpMac);
+};
+
+} // namespace base
+
+#endif // BASE_MESSAGE_PUMP_MAC_H_
diff --git a/base/message_pump_mac.mm b/base/message_pump_mac.mm
new file mode 100644
index 0000000..495f828
--- /dev/null
+++ b/base/message_pump_mac.mm
@@ -0,0 +1,363 @@
+// Copyright (c) 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_pump_mac.h"
+
+#import <AppKit/AppKit.h>
+#import <Foundation/Foundation.h>
+#include <float.h>
+
+namespace {
+
+void NoOp(void* info) {
+}
+
+} // namespace
+
+namespace base {
+
+// Must be called on the run loop thread.
+MessagePumpCFRunLoopBase::MessagePumpCFRunLoopBase()
+ : delegate_(NULL) {
+ 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
+ DBL_MAX, // fire time
+ DBL_MAX, // interval
+ 0, // flags (ignored)
+ 0, // priority (ignored)
+ RunDelayedWorkTimer,
+ &timer_context);
+ CFRunLoopAddTimer(run_loop_, delayed_work_timer_, kCFRunLoopCommonModes);
+
+ CFRunLoopSourceContext source_context = CFRunLoopSourceContext();
+ source_context.info = this;
+ source_context.perform = RunWork;
+ work_source_ = CFRunLoopSourceCreate(NULL, // allocator
+ 0, // priority
+ &source_context);
+ CFRunLoopAddSource(run_loop_, work_source_, kCFRunLoopCommonModes);
+
+ source_context.perform = RunDelayedWork;
+ delayed_work_source_ = CFRunLoopSourceCreate(NULL, // allocator
+ 1, // priority
+ &source_context);
+ CFRunLoopAddSource(run_loop_, delayed_work_source_, kCFRunLoopCommonModes);
+
+ CFRunLoopObserverContext observer_context = CFRunLoopObserverContext();
+ observer_context.info = this;
+ idle_work_observer_ = CFRunLoopObserverCreate(NULL, // allocator
+ kCFRunLoopBeforeWaiting,
+ true, // repeat
+ 0, // priority
+ RunIdleWork,
+ &observer_context);
+ CFRunLoopAddObserver(run_loop_, idle_work_observer_, kCFRunLoopCommonModes);
+}
+
+// Ideally called on the run loop thread.
+MessagePumpCFRunLoopBase::~MessagePumpCFRunLoopBase() {
+ CFRunLoopRemoveObserver(run_loop_, idle_work_observer_,
+ kCFRunLoopCommonModes);
+ CFRelease(idle_work_observer_);
+
+ CFRunLoopRemoveSource(run_loop_, delayed_work_source_, kCFRunLoopCommonModes);
+ CFRelease(delayed_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) {
+ Delegate* last_delegate = delegate_;
+ delegate_ = delegate;
+
+ DoRun(delegate);
+
+ delegate_ = last_delegate;
+}
+
+// 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 Time& delayed_work_time) {
+ Time::Exploded exploded;
+ delayed_work_time.UTCExplode(&exploded);
+ double seconds = exploded.second +
+ (static_cast<double>((delayed_work_time.ToInternalValue()) %
+ Time::kMicrosecondsPerSecond) /
+ Time::kMicrosecondsPerSecond);
+ CFGregorianDate gregorian = {
+ exploded.year,
+ exploded.month,
+ exploded.day_of_month,
+ exploded.hour,
+ exploded.minute,
+ seconds
+ };
+ CFAbsoluteTime fire_time = CFGregorianDateGetAbsoluteTime(gregorian, NULL);
+
+ CFRunLoopTimerSetNextFireDate(delayed_work_timer_, fire_time);
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::RunDelayedWorkTimer(CFRunLoopTimerRef timer,
+ void* info) {
+ MessagePumpCFRunLoop* self = static_cast<MessagePumpCFRunLoop*>(info);
+
+ // CFRunLoopTimers fire outside of the priority scheme for CFRunLoopSources.
+ // In order to establish the proper priority where delegate_->DoDelayedWork
+ // can only be called if delegate_->DoWork returns false, the timer used
+ // to schedule delayed work must signal a CFRunLoopSource set at a lower
+ // priority than the one used for delegate_->DoWork.
+ CFRunLoopSourceSignal(self->delayed_work_source_);
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::RunWork(void* info) {
+ MessagePumpCFRunLoop* self = static_cast<MessagePumpCFRunLoop*>(info);
+
+ // Call DoWork once, and if something was done, arrange to come back here
+ // again as long as the loop is still running.
+ if (self->delegate_->DoWork()) {
+ CFRunLoopSourceSignal(self->work_source_);
+ }
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::RunDelayedWork(void* info) {
+ MessagePumpCFRunLoop* self = static_cast<MessagePumpCFRunLoop*>(info);
+
+ Time next_time;
+ self->delegate_->DoDelayedWork(&next_time);
+ if (!next_time.is_null()) {
+ TimeDelta delay = next_time - Time::Now();
+ if (delay > TimeDelta()) {
+ // There's more delayed work to be done in the future.
+ self->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.
+ CFRunLoopSourceSignal(self->delayed_work_source_);
+ }
+ }
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::RunIdleWork(CFRunLoopObserverRef observer,
+ CFRunLoopActivity activity,
+ void* info) {
+ MessagePumpCFRunLoop* self = static_cast<MessagePumpCFRunLoop*>(info);
+
+ if (self->delegate_->DoIdleWork()) {
+ // If idle work was done, don't let the loop go to sleep. More idle work
+ // might be waiting.
+ CFRunLoopWakeUp(self->run_loop_);
+ }
+}
+
+// Must be called on the run loop thread.
+MessagePumpCFRunLoop::MessagePumpCFRunLoop()
+ : nesting_level_(0),
+ innermost_quittable_(0),
+ quit_pending_(false) {
+ CFRunLoopObserverContext observer_context = CFRunLoopObserverContext();
+ observer_context.info = this;
+ enter_exit_observer_ = CFRunLoopObserverCreate(NULL, // allocator
+ kCFRunLoopEntry |
+ kCFRunLoopExit,
+ true, // repeat
+ 0, // priority
+ EnterExitRunLoop,
+ &observer_context);
+ CFRunLoopAddObserver(run_loop_, enter_exit_observer_, kCFRunLoopCommonModes);
+}
+
+// Ideally called on the run loop thread. 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 when this object is
+// destroyed.
+MessagePumpCFRunLoop::~MessagePumpCFRunLoop() {
+ CFRunLoopRemoveObserver(run_loop_, enter_exit_observer_,
+ kCFRunLoopCommonModes);
+ CFRelease(enter_exit_observer_);
+}
+
+// Called by CFRunLoopBase::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) {
+ // nesting_level_ will be incremented in EnterExitRunLoop, so set
+ // innermost_quittable_ accordingly.
+ int last_innermost_quittable = innermost_quittable_;
+ innermost_quittable_ = nesting_level_ + 1;
+
+ CFRunLoopRun();
+
+ // Restore the previous state of the object.
+ innermost_quittable_ = last_innermost_quittable;
+}
+
+// Must be called on the run loop thread.
+void MessagePumpCFRunLoop::Quit() {
+ // Stop the innermost run loop managed by this MessagePumpCFRunLoop object.
+ if (nesting_level_ == innermost_quittable_) {
+ // 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 CFRunLoopRun on the same thread,
+ // higher on the stack than our highest Run call. Don't preempt other
+ // run loops, just mark the object to quit our innermost run loop as soon
+ // as the other inner loops we don't manage are done.
+ quit_pending_ = true;
+ }
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoop::EnterExitRunLoop(CFRunLoopObserverRef observer,
+ CFRunLoopActivity activity,
+ void* info) {
+ MessagePumpCFRunLoop* self = static_cast<MessagePumpCFRunLoop*>(info);
+
+ switch (activity) {
+ case kCFRunLoopEntry:
+ // If the run loop was entered by a call to Run, this will properly
+ // balance the decrement done in Run before entering the loop.
+ ++self->nesting_level_;
+ break;
+ case kCFRunLoopExit:
+ if (--self->nesting_level_ == self->innermost_quittable_ &&
+ self->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(self->run_loop_);
+ self->quit_pending_ = false;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+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_);
+}
+
+MessagePumpNSApplication::MessagePumpNSApplication()
+ : keep_running_(true),
+ running_own_loop_(false) {
+}
+
+void MessagePumpNSApplication::DoRun(Delegate* delegate) {
+ bool last_running_own_loop_ = running_own_loop_;
+
+ [NSApplication sharedApplication];
+
+ if (![NSApp isRunning]) {
+ running_own_loop_ = false;
+ // NSApplication manages autorelease pools itself when run this way.
+ [NSApp run];
+ } else {
+ running_own_loop_ = true;
+ while (keep_running_) {
+ NSAutoreleasePool* autorelease_pool = [[NSAutoreleasePool alloc] init];
+ NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask
+ untilDate:[NSDate distantFuture]
+ inMode:NSDefaultRunLoopMode
+ dequeue:YES];
+ if (event) {
+ [NSApp sendEvent:event];
+ }
+ [autorelease_pool drain];
+ }
+ keep_running_ = true;
+ }
+
+ running_own_loop_ = last_running_own_loop_;
+}
+
+void MessagePumpNSApplication::Quit() {
+ if (!running_own_loop_) {
+ [NSApp 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];
+}
+
+// static
+MessagePump* MessagePumpMac::Create() {
+ if ([NSThread isMainThread]) {
+ return new MessagePumpNSApplication;
+ }
+
+ return new MessagePumpNSRunLoop;
+}
+
+} // namespace base
diff --git a/net/net.xcodeproj/project.pbxproj b/net/net.xcodeproj/project.pbxproj
index 0b6311b..49bb933 100644
--- a/net/net.xcodeproj/project.pbxproj
+++ b/net/net.xcodeproj/project.pbxproj
@@ -100,6 +100,7 @@
7BA0169E0E5A1EAE00044150 /* libzlib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7BA016980E5A1E8700044150 /* libzlib.a */; };
7BA016A30E5A1EE900044150 /* gzip_header.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED32B70E5A181C00A747DB /* gzip_header.cc */; };
7BA0172F0E5A244D00044150 /* bzip2_filter.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED32750E5A181C00A747DB /* bzip2_filter.cc */; };
+ 7BA359120E89903B0023C8B9 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7BA357A60E8990260023C8B9 /* AppKit.framework */; };
7BD8F70C0E65DCD800034DE9 /* block_files_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED32F90E5A190600A747DB /* block_files_unittest.cc */; };
7BD8F70D0E65DCE000034DE9 /* disk_cache_test_base.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED32D50E5A190600A747DB /* disk_cache_test_base.cc */; };
7BD8F70E0E65DCE500034DE9 /* disk_cache_test_util.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED32FA0E5A190600A747DB /* disk_cache_test_util.cc */; };
@@ -370,6 +371,7 @@
7BA0157A0E5A1C9100044150 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = "<group>"; };
7BA016870E5A1E6E00044150 /* bzip2.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = bzip2.xcodeproj; path = third_party/bzip2/bzip2.xcodeproj; sourceTree = "<group>"; };
7BA016930E5A1E8700044150 /* zlib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = zlib.xcodeproj; path = third_party/zlib/zlib.xcodeproj; sourceTree = "<group>"; };
+ 7BA357A60E8990260023C8B9 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = "<group>"; };
7BED316E0E5A145200A747DB /* common.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = common.xcconfig; sourceTree = "<group>"; };
7BED316F0E5A145200A747DB /* debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = debug.xcconfig; sourceTree = "<group>"; };
7BED31700E5A145200A747DB /* executable.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = executable.xcconfig; sourceTree = "<group>"; };
@@ -590,9 +592,9 @@
7BED33BA0E5A198600A747DB /* url_request_file_job.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = url_request_file_job.h; sourceTree = "<group>"; };
7BED33BB0E5A198600A747DB /* url_request_inet_job.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = url_request_inet_job.cc; sourceTree = "<group>"; };
7BED33BC0E5A198600A747DB /* url_request_http_job.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = url_request_http_job.h; sourceTree = "<group>"; };
- 8200F2020E5F741E005A3C44 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = /System/Library/Frameworks/CoreServices.framework; sourceTree = "<absolute>"; };
+ 8200F2020E5F741E005A3C44 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = "<group>"; };
82113A1C0E8434EE00E3848F /* x509_certificate_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = x509_certificate_unittest.cc; sourceTree = "<group>"; };
- 82113A270E84360200E3848F /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = /System/Library/Frameworks/Security.framework; sourceTree = "<absolute>"; };
+ 82113A270E84360200E3848F /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = "<group>"; };
E47E933E0E8924DC00CA613E /* tcp_client_socket_libevent.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tcp_client_socket_libevent.cc; sourceTree = "<group>"; };
E49DD2E80E892F8C003C7A87 /* sdch_manager.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sdch_manager.cc; sourceTree = "<group>"; };
E49DD2E90E892F8C003C7A87 /* sdch_manager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sdch_manager.h; sourceTree = "<group>"; };
@@ -619,6 +621,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 7BA359120E89903B0023C8B9 /* AppKit.framework in Frameworks */,
8200F2030E5F741E005A3C44 /* CoreServices.framework in Frameworks */,
7BA015FA0E5A1CA600044150 /* Foundation.framework in Frameworks */,
7BED34450E5A1A9600A747DB /* libbase.a in Frameworks */,
@@ -732,9 +735,10 @@
7BED31A20E5A15DD00A747DB /* Frameworks */ = {
isa = PBXGroup;
children = (
- 82113A270E84360200E3848F /* Security.framework */,
+ 7BA357A60E8990260023C8B9 /* AppKit.framework */,
8200F2020E5F741E005A3C44 /* CoreServices.framework */,
7BA0157A0E5A1C9100044150 /* Foundation.framework */,
+ 82113A270E84360200E3848F /* Security.framework */,
);
name = Frameworks;
sourceTree = SDKROOT;