xref: /aosp_15_r20/external/cronet/base/message_loop/message_pump_io_ios.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/message_loop/message_pump_io_ios.h"
6 
7 #include "base/notreached.h"
8 
9 namespace base {
10 
FdWatchController(const Location & from_here)11 MessagePumpIOSForIO::FdWatchController::FdWatchController(
12     const Location& from_here)
13     : FdWatchControllerInterface(from_here) {}
14 
~FdWatchController()15 MessagePumpIOSForIO::FdWatchController::~FdWatchController() {
16   StopWatchingFileDescriptor();
17 }
18 
StopWatchingFileDescriptor()19 bool MessagePumpIOSForIO::FdWatchController::StopWatchingFileDescriptor() {
20   if (fdref_ == NULL)
21     return true;
22 
23   CFFileDescriptorDisableCallBacks(fdref_.get(), callback_types_);
24   if (pump_)
25     pump_->RemoveRunLoopSource(fd_source_);
26   fd_source_.reset();
27   fdref_.reset();
28   callback_types_ = 0;
29   pump_.reset();
30   watcher_ = NULL;
31   return true;
32 }
33 
Init(CFFileDescriptorRef fdref,CFOptionFlags callback_types,CFRunLoopSourceRef fd_source,bool is_persistent)34 void MessagePumpIOSForIO::FdWatchController::Init(CFFileDescriptorRef fdref,
35                                                   CFOptionFlags callback_types,
36                                                   CFRunLoopSourceRef fd_source,
37                                                   bool is_persistent) {
38   DCHECK(fdref);
39   DCHECK(!fdref_.is_valid());
40 
41   is_persistent_ = is_persistent;
42   fdref_.reset(fdref);
43   callback_types_ = callback_types;
44   fd_source_.reset(fd_source);
45 }
46 
OnFileCanReadWithoutBlocking(int fd,MessagePumpIOSForIO * pump)47 void MessagePumpIOSForIO::FdWatchController::OnFileCanReadWithoutBlocking(
48     int fd,
49     MessagePumpIOSForIO* pump) {
50   DCHECK(callback_types_ & kCFFileDescriptorReadCallBack);
51   watcher_->OnFileCanReadWithoutBlocking(fd);
52 }
53 
OnFileCanWriteWithoutBlocking(int fd,MessagePumpIOSForIO * pump)54 void MessagePumpIOSForIO::FdWatchController::OnFileCanWriteWithoutBlocking(
55     int fd,
56     MessagePumpIOSForIO* pump) {
57   DCHECK(callback_types_ & kCFFileDescriptorWriteCallBack);
58   watcher_->OnFileCanWriteWithoutBlocking(fd);
59 }
60 
MessagePumpIOSForIO()61 MessagePumpIOSForIO::MessagePumpIOSForIO() : weak_factory_(this) {
62 }
63 
~MessagePumpIOSForIO()64 MessagePumpIOSForIO::~MessagePumpIOSForIO() {
65 }
66 
WatchFileDescriptor(int fd,bool persistent,int mode,FdWatchController * controller,FdWatcher * delegate)67 bool MessagePumpIOSForIO::WatchFileDescriptor(int fd,
68                                               bool persistent,
69                                               int mode,
70                                               FdWatchController* controller,
71                                               FdWatcher* delegate) {
72   DCHECK_GE(fd, 0);
73   DCHECK(controller);
74   DCHECK(delegate);
75   DCHECK(mode == WATCH_READ || mode == WATCH_WRITE || mode == WATCH_READ_WRITE);
76 
77   // WatchFileDescriptor should be called on the pump thread. It is not
78   // threadsafe, and your watcher may never be registered.
79   DCHECK(watch_file_descriptor_caller_checker_.CalledOnValidThread());
80 
81   CFFileDescriptorContext source_context = {0};
82   source_context.info = controller;
83 
84   CFOptionFlags callback_types = 0;
85   if (mode & WATCH_READ) {
86     callback_types |= kCFFileDescriptorReadCallBack;
87   }
88   if (mode & WATCH_WRITE) {
89     callback_types |= kCFFileDescriptorWriteCallBack;
90   }
91 
92   CFFileDescriptorRef fdref = controller->fdref_.get();
93   if (fdref == NULL) {
94     apple::ScopedCFTypeRef<CFFileDescriptorRef> scoped_fdref(
95         CFFileDescriptorCreate(kCFAllocatorDefault, fd, false, HandleFdIOEvent,
96                                &source_context));
97     if (scoped_fdref == NULL) {
98       NOTREACHED() << "CFFileDescriptorCreate failed";
99       return false;
100     }
101 
102     CFFileDescriptorEnableCallBacks(scoped_fdref, callback_types);
103 
104     // TODO(wtc): what should the 'order' argument be?
105     apple::ScopedCFTypeRef<CFRunLoopSourceRef> scoped_fd_source(
106         CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, scoped_fdref,
107                                             0));
108     if (scoped_fd_source == NULL) {
109       NOTREACHED() << "CFFileDescriptorCreateRunLoopSource failed";
110       return false;
111     }
112     CFRunLoopAddSource(run_loop(), scoped_fd_source, kCFRunLoopCommonModes);
113 
114     // Transfer ownership of scoped_fdref and fd_source to controller.
115     controller->Init(scoped_fdref.release(), callback_types,
116                      scoped_fd_source.release(), persistent);
117   } else {
118     // It's illegal to use this function to listen on 2 separate fds with the
119     // same |controller|.
120     if (CFFileDescriptorGetNativeDescriptor(fdref) != fd) {
121       NOTREACHED() << "FDs don't match: "
122                    << CFFileDescriptorGetNativeDescriptor(fdref)
123                    << " != " << fd;
124       return false;
125     }
126     if (persistent != controller->is_persistent_) {
127       NOTREACHED() << "persistent doesn't match";
128       return false;
129     }
130 
131     // Combine old/new event masks.
132     CFFileDescriptorDisableCallBacks(fdref, controller->callback_types_);
133     controller->callback_types_ |= callback_types;
134     CFFileDescriptorEnableCallBacks(fdref, controller->callback_types_);
135   }
136 
137   controller->set_watcher(delegate);
138   controller->set_pump(weak_factory_.GetWeakPtr());
139 
140   return true;
141 }
142 
RemoveRunLoopSource(CFRunLoopSourceRef source)143 void MessagePumpIOSForIO::RemoveRunLoopSource(CFRunLoopSourceRef source) {
144   CFRunLoopRemoveSource(run_loop(), source, kCFRunLoopCommonModes);
145 }
146 
147 // static
HandleFdIOEvent(CFFileDescriptorRef fdref,CFOptionFlags callback_types,void * context)148 void MessagePumpIOSForIO::HandleFdIOEvent(CFFileDescriptorRef fdref,
149                                           CFOptionFlags callback_types,
150                                           void* context) {
151   FdWatchController* controller = static_cast<FdWatchController*>(context);
152   DCHECK_EQ(fdref, controller->fdref_.get());
153 
154   // Ensure that |fdref| will remain live for the duration of this function
155   // call even if |controller| is deleted or |StopWatchingFileDescriptor()| is
156   // called, either of which will cause |fdref| to be released.
157   apple::ScopedCFTypeRef<CFFileDescriptorRef> scoped_fdref(
158       fdref, base::scoped_policy::RETAIN);
159 
160   int fd = CFFileDescriptorGetNativeDescriptor(fdref);
161   MessagePumpIOSForIO* pump = controller->pump().get();
162   DCHECK(pump);
163 
164   // Inform ThreadController of this native work item for tracking and tracing
165   // purposes.
166   Delegate::ScopedDoWorkItem scoped_do_work_item;
167   if (pump->delegate()) {
168     scoped_do_work_item = pump->delegate()->BeginWorkItem();
169   }
170 
171   if (callback_types & kCFFileDescriptorWriteCallBack)
172     controller->OnFileCanWriteWithoutBlocking(fd, pump);
173 
174   // Perform the read callback only if the file descriptor has not been
175   // invalidated in the write callback. As |FdWatchController| invalidates
176   // its file descriptor on destruction, the file descriptor being valid also
177   // guarantees that |controller| has not been deleted.
178   if (callback_types & kCFFileDescriptorReadCallBack &&
179       CFFileDescriptorIsValid(fdref)) {
180     DCHECK_EQ(fdref, controller->fdref_.get());
181     controller->OnFileCanReadWithoutBlocking(fd, pump);
182   }
183 
184   // Re-enable callbacks after the read/write if the file descriptor is still
185   // valid and the controller is persistent.
186   if (CFFileDescriptorIsValid(fdref) && controller->is_persistent_) {
187     DCHECK_EQ(fdref, controller->fdref_.get());
188     CFFileDescriptorEnableCallBacks(fdref, callback_types);
189   }
190 }
191 
192 }  // namespace base
193