message_pump_mac.h (11782B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 // Copyright (c) 2008 The Chromium Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style license that can be 5 // found in the LICENSE file. 6 7 // The basis for all native run loops on the Mac is the CFRunLoop. It can be 8 // used directly, it can be used as the driving force behind the similar 9 // Foundation NSRunLoop, and it can be used to implement higher-level event 10 // loops such as the NSApplication event loop. 11 // 12 // This file introduces a basic CFRunLoop-based implementation of the 13 // MessagePump interface called CFRunLoopBase. CFRunLoopBase contains all 14 // of the machinery necessary to dispatch events to a delegate, but does not 15 // implement the specific run loop. Concrete subclasses must provide their 16 // own DoRun and Quit implementations. 17 // 18 // A concrete subclass that just runs a CFRunLoop loop is provided in 19 // MessagePumpCFRunLoop. For an NSRunLoop, the similar MessagePumpNSRunLoop 20 // is provided. 21 // 22 // For the application's event loop, an implementation based on AppKit's 23 // NSApplication event system is provided in MessagePumpNSApplication. 24 // 25 // Typically, MessagePumpNSApplication only makes sense on a Cocoa 26 // application's main thread. If a CFRunLoop-based message pump is needed on 27 // any other thread, one of the other concrete subclasses is preferrable. 28 // MessagePumpMac::Create is defined, which returns a new NSApplication-based 29 // or NSRunLoop-based MessagePump subclass depending on which thread it is 30 // called on. 31 32 #ifndef BASE_MESSAGE_PUMP_MAC_H_ 33 #define BASE_MESSAGE_PUMP_MAC_H_ 34 35 #include "base/message_pump.h" 36 37 #include "base/basictypes.h" 38 39 #include <CoreFoundation/CoreFoundation.h> 40 #include <IOKit/IOKitLib.h> 41 42 #if defined(__OBJC__) 43 @class NSAutoreleasePool; 44 #else // defined(__OBJC__) 45 class NSAutoreleasePool; 46 #endif // defined(__OBJC__) 47 48 namespace base { 49 50 class TimeTicks; 51 52 class MessagePumpCFRunLoopBase : public MessagePump { 53 // Needs access to CreateAutoreleasePool. 54 friend class MessagePumpScopedAutoreleasePool; 55 56 public: 57 MessagePumpCFRunLoopBase(); 58 virtual ~MessagePumpCFRunLoopBase(); 59 60 // Subclasses should implement the work they need to do in MessagePump::Run 61 // in the DoRun method. MessagePumpCFRunLoopBase::Run calls DoRun directly. 62 // This arrangement is used because MessagePumpCFRunLoopBase needs to set 63 // up and tear down things before and after the "meat" of DoRun. 64 virtual void Run(Delegate* delegate); 65 virtual void DoRun(Delegate* delegate) = 0; 66 67 virtual void ScheduleWork(); 68 virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time); 69 70 protected: 71 // Accessors for private data members to be used by subclasses. 72 CFRunLoopRef run_loop() const { return run_loop_; } 73 int nesting_level() const { return nesting_level_; } 74 int run_nesting_level() const { return run_nesting_level_; } 75 76 // Return an autorelease pool to wrap around any work being performed. 77 // In some cases, CreateAutoreleasePool may return nil intentionally to 78 // preventing an autorelease pool from being created, allowing any 79 // objects autoreleased by work to fall into the current autorelease pool. 80 virtual NSAutoreleasePool* CreateAutoreleasePool(); 81 82 private: 83 // Timer callback scheduled by ScheduleDelayedWork. This does not do any 84 // work, but it signals delayed_work_source_ so that delayed work can be 85 // performed within the appropriate priority constraints. 86 static void RunDelayedWorkTimer(CFRunLoopTimerRef timer, void* info); 87 88 // Perform highest-priority work. This is associated with work_source_ 89 // signalled by ScheduleWork. The static method calls the instance method; 90 // the instance method returns true if work was done. 91 static void RunWorkSource(void* info); 92 bool RunWork(); 93 94 // Perform delayed-priority work. This is associated with 95 // delayed_work_source_ signalled by RunDelayedWorkTimer, and is responsible 96 // for calling ScheduleDelayedWork again if appropriate. The static method 97 // calls the instance method; the instance method returns true if more 98 // delayed work is available. 99 static void RunDelayedWorkSource(void* info); 100 bool RunDelayedWork(); 101 102 // Perform idle-priority work. This is normally called by PreWaitObserver, 103 // but is also associated with idle_work_source_. When this function 104 // actually does perform idle work, it will resignal that source. The 105 // static method calls the instance method; the instance method returns 106 // true if idle work was done. 107 static void RunIdleWorkSource(void* info); 108 bool RunIdleWork(); 109 110 // Perform work that may have been deferred because it was not runnable 111 // within a nested run loop. This is associated with 112 // nesting_deferred_work_source_ and is signalled by 113 // MaybeScheduleNestingDeferredWork when returning from a nested loop, 114 // so that an outer loop will be able to perform the necessary tasks if it 115 // permits nestable tasks. 116 static void RunNestingDeferredWorkSource(void* info); 117 bool RunNestingDeferredWork(); 118 119 // Schedules possible nesting-deferred work to be processed before the run 120 // loop goes to sleep, exits, or begins processing sources at the top of its 121 // loop. If this function detects that a nested loop had run since the 122 // previous attempt to schedule nesting-deferred work, it will schedule a 123 // call to RunNestingDeferredWorkSource. 124 void MaybeScheduleNestingDeferredWork(); 125 126 // Observer callback responsible for performing idle-priority work, before 127 // the run loop goes to sleep. Associated with idle_work_observer_. 128 static void PreWaitObserver(CFRunLoopObserverRef observer, 129 CFRunLoopActivity activity, void* info); 130 131 // Observer callback called before the run loop processes any sources. 132 // Associated with pre_source_observer_. 133 static void PreSourceObserver(CFRunLoopObserverRef observer, 134 CFRunLoopActivity activity, void* info); 135 136 // Observer callback called when the run loop starts and stops, at the 137 // beginning and end of calls to CFRunLoopRun. This is used to maintain 138 // nesting_level_. Associated with enter_exit_observer_. 139 static void EnterExitObserver(CFRunLoopObserverRef observer, 140 CFRunLoopActivity activity, void* info); 141 142 // Called by EnterExitObserver after performing maintenance on nesting_level_. 143 // This allows subclasses an opportunity to perform additional processing on 144 // the basis of run loops starting and stopping. 145 virtual void EnterExitRunLoop(CFRunLoopActivity activity); 146 147 #if !defined(XP_IOS) 148 // IOKit power state change notification callback, called when the system 149 // enters and leaves the sleep state. 150 static void PowerStateNotification(void* info, io_service_t service, 151 uint32_t message_type, 152 void* message_argument); 153 #endif 154 155 // The thread's run loop. 156 CFRunLoopRef run_loop_; 157 158 // The timer, sources, and observers are described above alongside their 159 // callbacks. 160 CFRunLoopTimerRef delayed_work_timer_; 161 CFRunLoopSourceRef work_source_; 162 CFRunLoopSourceRef delayed_work_source_; 163 CFRunLoopSourceRef idle_work_source_; 164 CFRunLoopSourceRef nesting_deferred_work_source_; 165 CFRunLoopObserverRef pre_wait_observer_; 166 CFRunLoopObserverRef pre_source_observer_; 167 CFRunLoopObserverRef enter_exit_observer_; 168 169 // Objects used for power state notification. See PowerStateNotification. 170 io_connect_t root_power_domain_; 171 IONotificationPortRef power_notification_port_; 172 io_object_t power_notification_object_; 173 174 // (weak) Delegate passed as an argument to the innermost Run call. 175 Delegate* delegate_; 176 177 // The time that delayed_work_timer_ is scheduled to fire. This is tracked 178 // independently of CFRunLoopTimerGetNextFireDate(delayed_work_timer_) 179 // to be able to reset the timer properly after waking from system sleep. 180 // See PowerStateNotification. 181 CFAbsoluteTime delayed_work_fire_time_; 182 183 // The recursion depth of the currently-executing CFRunLoopRun loop on the 184 // run loop's thread. 0 if no run loops are running inside of whatever scope 185 // the object was created in. 186 int nesting_level_; 187 188 // The recursion depth (calculated in the same way as nesting_level_) of the 189 // innermost executing CFRunLoopRun loop started by a call to Run. 190 int run_nesting_level_; 191 192 // The deepest (numerically highest) recursion depth encountered since the 193 // most recent attempt to run nesting-deferred work. 194 int deepest_nesting_level_; 195 196 // "Delegateless" work flags are set when work is ready to be performed but 197 // must wait until a delegate is available to process it. This can happen 198 // when a MessagePumpCFRunLoopBase is instantiated and work arrives without 199 // any call to Run on the stack. The Run method will check for delegateless 200 // work on entry and redispatch it as needed once a delegate is available. 201 bool delegateless_work_; 202 bool delegateless_delayed_work_; 203 bool delegateless_idle_work_; 204 205 DISALLOW_COPY_AND_ASSIGN(MessagePumpCFRunLoopBase); 206 }; 207 208 class MessagePumpCFRunLoop : public MessagePumpCFRunLoopBase { 209 public: 210 MessagePumpCFRunLoop(); 211 212 virtual void DoRun(Delegate* delegate); 213 virtual void Quit(); 214 215 private: 216 virtual void EnterExitRunLoop(CFRunLoopActivity activity); 217 218 // True if Quit is called to stop the innermost MessagePump 219 // (innermost_quittable_) but some other CFRunLoopRun loop (nesting_level_) 220 // is running inside the MessagePump's innermost Run call. 221 bool quit_pending_; 222 223 DISALLOW_COPY_AND_ASSIGN(MessagePumpCFRunLoop); 224 }; 225 226 class MessagePumpNSRunLoop : public MessagePumpCFRunLoopBase { 227 public: 228 MessagePumpNSRunLoop(); 229 virtual ~MessagePumpNSRunLoop(); 230 231 virtual void DoRun(Delegate* delegate); 232 virtual void Quit(); 233 234 private: 235 // A source that doesn't do anything but provide something signalable 236 // attached to the run loop. This source will be signalled when Quit 237 // is called, to cause the loop to wake up so that it can stop. 238 CFRunLoopSourceRef quit_source_; 239 240 // False after Quit is called. 241 bool keep_running_; 242 243 DISALLOW_COPY_AND_ASSIGN(MessagePumpNSRunLoop); 244 }; 245 246 #if defined(XP_IOS) 247 // This is a fake message pump. It attaches sources to the main thread's 248 // CFRunLoop, so PostTask() will work, but it is unable to drive the loop 249 // directly, so calling Run() or Quit() are errors. 250 class MessagePumpUIApplication : public MessagePumpCFRunLoopBase { 251 public: 252 MessagePumpUIApplication() {} 253 254 void DoRun(Delegate* delegate) override; 255 void Quit() override; 256 257 private: 258 DISALLOW_COPY_AND_ASSIGN(MessagePumpUIApplication); 259 }; 260 261 #else 262 263 class MessagePumpNSApplication : public MessagePumpCFRunLoopBase { 264 public: 265 MessagePumpNSApplication(); 266 267 virtual void DoRun(Delegate* delegate); 268 virtual void Quit(); 269 270 protected: 271 // Returns nil if NSApp is currently in the middle of calling -sendEvent. 272 virtual NSAutoreleasePool* CreateAutoreleasePool(); 273 274 private: 275 // False after Quit is called. 276 bool keep_running_; 277 278 // True if DoRun is managing its own run loop as opposed to letting 279 // -[NSApplication run] handle it. The outermost run loop in the application 280 // is managed by -[NSApplication run], inner run loops are handled by a loop 281 // in DoRun. 282 bool running_own_loop_; 283 284 DISALLOW_COPY_AND_ASSIGN(MessagePumpNSApplication); 285 }; 286 #endif 287 288 class MessagePumpMac { 289 public: 290 // Returns a new instance of MessagePumpNSApplication if called on the main 291 // thread. Otherwise, returns a new instance of MessagePumpNSRunLoop. 292 static MessagePump* Create(); 293 294 private: 295 DISALLOW_IMPLICIT_CONSTRUCTORS(MessagePumpMac); 296 }; 297 298 } // namespace base 299 300 #endif // BASE_MESSAGE_PUMP_MAC_H_