OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/message_pump_mac.h" | 5 #include "base/message_pump_mac.h" |
6 | 6 |
7 #import <AppKit/AppKit.h> | 7 #import <AppKit/AppKit.h> |
8 #import <Foundation/Foundation.h> | 8 #import <Foundation/Foundation.h> |
9 | 9 |
10 #include <limits> | 10 #include <limits> |
11 | 11 |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/mac/scoped_cftyperef.h" |
13 #include "base/time.h" | 14 #include "base/time.h" |
14 | 15 |
15 namespace { | 16 namespace { |
16 | 17 |
17 void NoOp(void* info) { | 18 void NoOp(void* info) { |
18 } | 19 } |
19 | 20 |
20 const CFTimeInterval kCFTimeIntervalMax = | 21 const CFTimeInterval kCFTimeIntervalMax = |
21 std::numeric_limits<CFTimeInterval>::max(); | 22 std::numeric_limits<CFTimeInterval>::max(); |
22 | 23 |
23 } // namespace | 24 } // namespace |
24 | 25 |
25 namespace base { | 26 namespace base { |
26 | 27 |
| 28 MessagePumpCFRunLoopBase::FileDescriptorWatcher::FileDescriptorWatcher() |
| 29 : is_persistent_(false), |
| 30 fdref_(NULL), |
| 31 callback_types_(0), |
| 32 fd_source_(NULL), |
| 33 pump_(NULL), |
| 34 watcher_(NULL) { |
| 35 } |
| 36 |
| 37 MessagePumpCFRunLoopBase::FileDescriptorWatcher::~FileDescriptorWatcher() { |
| 38 if (fdref_) { |
| 39 StopWatchingFileDescriptor(); |
| 40 } |
| 41 } |
| 42 |
| 43 bool MessagePumpCFRunLoopBase:: |
| 44 FileDescriptorWatcher::StopWatchingFileDescriptor() { |
| 45 CFFileDescriptorRef fdref = ReleaseCFFileDescriptor(); |
| 46 if (fdref == NULL) |
| 47 return true; |
| 48 |
| 49 CFFileDescriptorDisableCallBacks(fdref, callback_types_); |
| 50 pump_->RemoveRunLoopSource(fd_source_); |
| 51 CFRelease(fd_source_); |
| 52 fd_source_ = NULL; |
| 53 CFFileDescriptorInvalidate(fdref); |
| 54 CFRelease(fdref); |
| 55 callback_types_ = 0; |
| 56 pump_ = NULL; |
| 57 watcher_ = NULL; |
| 58 return true; |
| 59 } |
| 60 |
| 61 void MessagePumpCFRunLoopBase::FileDescriptorWatcher::Init( |
| 62 CFFileDescriptorRef fdref, |
| 63 CFOptionFlags callback_types, |
| 64 CFRunLoopSourceRef fd_source, |
| 65 bool is_persistent) { |
| 66 DCHECK(fdref); |
| 67 DCHECK(!fdref_); |
| 68 |
| 69 is_persistent_ = is_persistent; |
| 70 fdref_ = fdref; |
| 71 callback_types_ = callback_types; |
| 72 fd_source_ = fd_source; |
| 73 } |
| 74 |
| 75 CFFileDescriptorRef |
| 76 MessagePumpCFRunLoopBase::FileDescriptorWatcher::ReleaseCFFileDescriptor() { |
| 77 CFFileDescriptorRef fdref = fdref_; |
| 78 fdref_ = NULL; |
| 79 return fdref; |
| 80 } |
| 81 |
| 82 void MessagePumpCFRunLoopBase:: |
| 83 FileDescriptorWatcher::OnFileCanReadWithoutBlocking( |
| 84 int fd, |
| 85 MessagePumpCFRunLoopBase* pump) { |
| 86 pump->WillProcessIOEvent(); |
| 87 watcher_->OnFileCanReadWithoutBlocking(fd); |
| 88 pump->DidProcessIOEvent(); |
| 89 } |
| 90 |
| 91 void MessagePumpCFRunLoopBase:: |
| 92 FileDescriptorWatcher::OnFileCanWriteWithoutBlocking( |
| 93 int fd, |
| 94 MessagePumpCFRunLoopBase* pump) { |
| 95 pump->WillProcessIOEvent(); |
| 96 watcher_->OnFileCanWriteWithoutBlocking(fd); |
| 97 pump->DidProcessIOEvent(); |
| 98 } |
| 99 |
27 // A scoper for autorelease pools created from message pump run loops. | 100 // A scoper for autorelease pools created from message pump run loops. |
28 // Avoids dirtying up the ScopedNSAutoreleasePool interface for the rare | 101 // Avoids dirtying up the ScopedNSAutoreleasePool interface for the rare |
29 // case where an autorelease pool needs to be passed in. | 102 // case where an autorelease pool needs to be passed in. |
30 class MessagePumpScopedAutoreleasePool { | 103 class MessagePumpScopedAutoreleasePool { |
31 public: | 104 public: |
32 explicit MessagePumpScopedAutoreleasePool(MessagePumpCFRunLoopBase* pump) : | 105 explicit MessagePumpScopedAutoreleasePool(MessagePumpCFRunLoopBase* pump) : |
33 pool_(pump->CreateAutoreleasePool()) { | 106 pool_(pump->CreateAutoreleasePool()) { |
34 } | 107 } |
35 ~MessagePumpScopedAutoreleasePool() { | 108 ~MessagePumpScopedAutoreleasePool() { |
36 [pool_ drain]; | 109 [pool_ drain]; |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
141 | 214 |
142 CFRunLoopRemoveSource(run_loop_, work_source_, kCFRunLoopCommonModes); | 215 CFRunLoopRemoveSource(run_loop_, work_source_, kCFRunLoopCommonModes); |
143 CFRelease(work_source_); | 216 CFRelease(work_source_); |
144 | 217 |
145 CFRunLoopRemoveTimer(run_loop_, delayed_work_timer_, kCFRunLoopCommonModes); | 218 CFRunLoopRemoveTimer(run_loop_, delayed_work_timer_, kCFRunLoopCommonModes); |
146 CFRelease(delayed_work_timer_); | 219 CFRelease(delayed_work_timer_); |
147 | 220 |
148 CFRelease(run_loop_); | 221 CFRelease(run_loop_); |
149 } | 222 } |
150 | 223 |
| 224 // static |
| 225 void MessagePumpCFRunLoopBase::HandleFdIOEvent(CFFileDescriptorRef fdref, |
| 226 CFOptionFlags callback_types, |
| 227 void* info) { |
| 228 int fd = CFFileDescriptorGetNativeDescriptor(fdref); |
| 229 |
| 230 FileDescriptorWatcher* controller = |
| 231 static_cast<FileDescriptorWatcher*>(info); |
| 232 |
| 233 CHECK_EQ(fdref, controller->fdref_); |
| 234 bool persistent = controller->is_persistent_; |
| 235 |
| 236 MessagePumpCFRunLoopBase* pump = controller->pump(); |
| 237 |
| 238 if (callback_types & kCFFileDescriptorWriteCallBack) { |
| 239 controller->OnFileCanWriteWithoutBlocking(fd, pump); |
| 240 } |
| 241 if (callback_types & kCFFileDescriptorReadCallBack) { |
| 242 controller->OnFileCanReadWithoutBlocking(fd, pump); |
| 243 } |
| 244 |
| 245 // Must read/write from the fd before re-enabling the callbacks. |
| 246 // |controller| may have been deleted, and |fdref| may have been |
| 247 // invalidated. |
| 248 if (CFFileDescriptorIsValid(fdref) && persistent) |
| 249 CFFileDescriptorEnableCallBacks(fdref, callback_types); |
| 250 } |
| 251 |
| 252 bool MessagePumpCFRunLoopBase::WatchFileDescriptor( |
| 253 int fd, |
| 254 bool persistent, |
| 255 Mode mode, |
| 256 FileDescriptorWatcher *controller, |
| 257 Watcher *delegate) { |
| 258 DCHECK_GE(fd, 0); |
| 259 DCHECK(controller); |
| 260 DCHECK(delegate); |
| 261 DCHECK(mode == WATCH_READ || mode == WATCH_WRITE || mode == WATCH_READ_WRITE); |
| 262 // WatchFileDescriptor should be called on the pump thread. It is not |
| 263 // threadsafe, and your watcher may never be registered. |
| 264 DCHECK(watch_file_descriptor_caller_checker_.CalledOnValidThread()); |
| 265 |
| 266 CFFileDescriptorContext source_context = CFFileDescriptorContext(); |
| 267 source_context.version = 0; |
| 268 source_context.info = controller; |
| 269 |
| 270 CFOptionFlags callback_types = 0; |
| 271 if ((mode & WATCH_READ) != 0) { |
| 272 callback_types |= kCFFileDescriptorReadCallBack; |
| 273 } |
| 274 if ((mode & WATCH_WRITE) != 0) { |
| 275 callback_types |= kCFFileDescriptorWriteCallBack; |
| 276 } |
| 277 |
| 278 base::mac::ScopedCFTypeRef<CFFileDescriptorRef> fdref( |
| 279 controller->ReleaseCFFileDescriptor()); |
| 280 if (fdref == NULL) { |
| 281 // Ownership is transferred to the controller. |
| 282 fdref.reset(CFFileDescriptorCreate(kCFAllocatorDefault, |
| 283 fd, false, |
| 284 HandleFdIOEvent, |
| 285 &source_context)); |
| 286 if (fdref == NULL) { |
| 287 NOTREACHED() << "CFFileDescriptorCreate failed"; |
| 288 return false; |
| 289 } |
| 290 CFFileDescriptorEnableCallBacks(fdref, callback_types); |
| 291 |
| 292 // TODO(wtc): what should the 'order' argument be? |
| 293 CFRunLoopSourceRef fd_source = CFFileDescriptorCreateRunLoopSource( |
| 294 kCFAllocatorDefault, fdref, 0); |
| 295 if (fd_source == NULL) { |
| 296 NOTREACHED() << "CFFileDescriptorCreateRunLoopSource failed"; |
| 297 return false; |
| 298 } |
| 299 CFRunLoopAddSource(run_loop_, fd_source, kCFRunLoopCommonModes); |
| 300 |
| 301 // Transfer ownership of fdref to controller. |
| 302 controller->Init(fdref.release(), callback_types, fd_source, persistent); |
| 303 } else { |
| 304 // It's illegal to use this function to listen on 2 separate fds with the |
| 305 // same |controller|. |
| 306 if (CFFileDescriptorGetNativeDescriptor(fdref) != fd) { |
| 307 NOTREACHED() << "FDs don't match" |
| 308 << CFFileDescriptorGetNativeDescriptor(fdref)<< "!=" << fd; |
| 309 return false; |
| 310 } |
| 311 if (persistent != controller->is_persistent_) { |
| 312 NOTREACHED() << "persistent don't match"; |
| 313 return false; |
| 314 } |
| 315 |
| 316 // Combine old/new event masks. |
| 317 CFFileDescriptorDisableCallBacks(fdref, controller->callback_types_); |
| 318 controller->callback_types_ |= callback_types; |
| 319 CFFileDescriptorEnableCallBacks(fdref, controller->callback_types_); |
| 320 controller->fdref_ = fdref.release(); |
| 321 } |
| 322 |
| 323 controller->set_watcher(delegate); |
| 324 controller->set_pump(this); |
| 325 |
| 326 return true; |
| 327 } |
| 328 |
| 329 void MessagePumpCFRunLoopBase::RemoveRunLoopSource( |
| 330 CFRunLoopSourceRef source) { |
| 331 CFRunLoopRemoveSource(run_loop_, source, kCFRunLoopCommonModes); |
| 332 } |
| 333 |
| 334 void MessagePumpCFRunLoopBase::AddIOObserver(IOObserver *obs) { |
| 335 io_observers_.AddObserver(obs); |
| 336 } |
| 337 |
| 338 void MessagePumpCFRunLoopBase::RemoveIOObserver(IOObserver *obs) { |
| 339 io_observers_.RemoveObserver(obs); |
| 340 } |
| 341 |
151 // Must be called on the run loop thread. | 342 // Must be called on the run loop thread. |
152 void MessagePumpCFRunLoopBase::Run(Delegate* delegate) { | 343 void MessagePumpCFRunLoopBase::Run(Delegate* delegate) { |
153 // nesting_level_ will be incremented in EnterExitRunLoop, so set | 344 // nesting_level_ will be incremented in EnterExitRunLoop, so set |
154 // run_nesting_level_ accordingly. | 345 // run_nesting_level_ accordingly. |
155 int last_run_nesting_level = run_nesting_level_; | 346 int last_run_nesting_level = run_nesting_level_; |
156 run_nesting_level_ = nesting_level_ + 1; | 347 run_nesting_level_ = nesting_level_ + 1; |
157 | 348 |
158 Delegate* last_delegate = delegate_; | 349 Delegate* last_delegate = delegate_; |
159 delegate_ = delegate; | 350 delegate_ = delegate; |
160 | 351 |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
206 exploded.day_of_month, | 397 exploded.day_of_month, |
207 exploded.hour, | 398 exploded.hour, |
208 exploded.minute, | 399 exploded.minute, |
209 seconds | 400 seconds |
210 }; | 401 }; |
211 delayed_work_fire_time_ = CFGregorianDateGetAbsoluteTime(gregorian, NULL); | 402 delayed_work_fire_time_ = CFGregorianDateGetAbsoluteTime(gregorian, NULL); |
212 | 403 |
213 CFRunLoopTimerSetNextFireDate(delayed_work_timer_, delayed_work_fire_time_); | 404 CFRunLoopTimerSetNextFireDate(delayed_work_timer_, delayed_work_fire_time_); |
214 } | 405 } |
215 | 406 |
| 407 void MessagePumpCFRunLoopBase::WillProcessIOEvent() { |
| 408 FOR_EACH_OBSERVER(IOObserver, io_observers_, WillProcessIOEvent()); |
| 409 } |
| 410 |
| 411 void MessagePumpCFRunLoopBase::DidProcessIOEvent() { |
| 412 FOR_EACH_OBSERVER(IOObserver, io_observers_, DidProcessIOEvent()); |
| 413 } |
| 414 |
216 // Called from the run loop. | 415 // Called from the run loop. |
217 // static | 416 // static |
218 void MessagePumpCFRunLoopBase::RunDelayedWorkTimer(CFRunLoopTimerRef timer, | 417 void MessagePumpCFRunLoopBase::RunDelayedWorkTimer(CFRunLoopTimerRef timer, |
219 void* info) { | 418 void* info) { |
220 MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info); | 419 MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info); |
221 | 420 |
222 // The timer won't fire again until it's reset. | 421 // The timer won't fire again until it's reset. |
223 self->delayed_work_fire_time_ = kCFTimeIntervalMax; | 422 self->delayed_work_fire_time_ = kCFTimeIntervalMax; |
224 | 423 |
225 // CFRunLoopTimers fire outside of the priority scheme for CFRunLoopSources. | 424 // CFRunLoopTimers fire outside of the priority scheme for CFRunLoopSources. |
(...skipping 408 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
634 // static | 833 // static |
635 MessagePump* MessagePumpMac::Create() { | 834 MessagePump* MessagePumpMac::Create() { |
636 if ([NSThread isMainThread]) { | 835 if ([NSThread isMainThread]) { |
637 return new MessagePumpNSApplication; | 836 return new MessagePumpNSApplication; |
638 } | 837 } |
639 | 838 |
640 return new MessagePumpNSRunLoop; | 839 return new MessagePumpNSRunLoop; |
641 } | 840 } |
642 | 841 |
643 } // namespace base | 842 } // namespace base |
OLD | NEW |