Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(263)

Side by Side Diff: base/message_pump_mac.mm

Issue 7276045: Give a CFRunLoop to the IO message loop type on Mac OS X. Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 9 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698