diff options
author | mark@chromium.org <mark@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-09-23 21:08:28 +0000 |
---|---|---|
committer | mark@chromium.org <mark@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-09-23 21:08:28 +0000 |
commit | 96c9ea12f042a0c12f4de097c86e3be27a458bd2 (patch) | |
tree | 38d6199b0d20963fcaae13986fd1a1bc75992be9 | |
parent | 0aaaa256de3da10ffdb145bfd12dc0d51933c4bb (diff) | |
download | chromium_src-96c9ea12f042a0c12f4de097c86e3be27a458bd2.zip chromium_src-96c9ea12f042a0c12f4de097c86e3be27a458bd2.tar.gz chromium_src-96c9ea12f042a0c12f4de097c86e3be27a458bd2.tar.bz2 |
Mac-specific CFRunLoop-based MessagePump implementation
Review URL: http://codereview.chromium.org/444
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@2521 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | base/base.xcodeproj/project.pbxproj | 14 | ||||
-rw-r--r-- | base/message_loop.cc | 12 | ||||
-rw-r--r-- | base/message_pump_mac.h | 181 | ||||
-rw-r--r-- | base/message_pump_mac.mm | 363 | ||||
-rw-r--r-- | net/net.xcodeproj/project.pbxproj | 10 |
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; |