Skip to content

Commit 2e86ea6

Browse files
authored
BACKPORT: MessagePumpIOSForIO: Fix handling of read+write one-shot events (#7789)
This is a clean backport of https://crrev.com/c/6633541, which fixes a corner case issue in the I/O message pump used by tvOS. Bug: 432824509 --- Original CL description: MessagePumpIOSForIO had the same problem that https://crrev.com/c/6043387 fixed in MessagePumpEpoll: when watching read and write events in one-shot mode, the code was still dispatching both events even though the contract is that only one will fire. Apply the fix from the CL above by taking into account whether we have a persistent watcher or not when deciding whether to fire both events. This fixes IOWatcherFdTest.ReadWriteUnifiedOneShot on tvOS. Change-Id: I0e7adf7e16a04af45b947f15bfc7dd616bb5408e Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6633541 Cr-Commit-Position: refs/heads/main@{#1472485}
1 parent 9330d72 commit 2e86ea6

File tree

1 file changed

+13
-4
lines changed

1 file changed

+13
-4
lines changed

base/message_loop/message_pump_io_ios.cc

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -168,23 +168,32 @@ void MessagePumpIOSForIO::HandleFdIOEvent(CFFileDescriptorRef fdref,
168168
scoped_do_work_item = pump->delegate()->BeginWorkItem();
169169
}
170170

171-
if (callback_types & kCFFileDescriptorWriteCallBack) {
171+
// When the watcher is in one-shot mode (i.e. `is_persistent` is false) and
172+
// the FD watcher is watching both read and write events, the contract is that
173+
// only one will be reported (which one is chosen does not matter).
174+
// This implementation reports writes before reads, so `can_read` is true iff
175+
// the watcher is not in one-shot mode or no write event is being reported.
176+
const bool is_persistent = controller->is_persistent_;
177+
const bool can_write = callback_types & kCFFileDescriptorWriteCallBack;
178+
const bool can_read = callback_types & kCFFileDescriptorReadCallBack &&
179+
(is_persistent || !can_write);
180+
181+
if (can_write) {
172182
controller->OnFileCanWriteWithoutBlocking(fd, pump);
173183
}
174184

175185
// Perform the read callback only if the file descriptor has not been
176186
// invalidated in the write callback. As |FdWatchController| invalidates
177187
// its file descriptor on destruction, the file descriptor being valid also
178188
// guarantees that |controller| has not been deleted.
179-
if (callback_types & kCFFileDescriptorReadCallBack &&
180-
CFFileDescriptorIsValid(fdref)) {
189+
if (can_read && CFFileDescriptorIsValid(fdref)) {
181190
DCHECK_EQ(fdref, controller->fdref_.get());
182191
controller->OnFileCanReadWithoutBlocking(fd, pump);
183192
}
184193

185194
// Re-enable callbacks after the read/write if the file descriptor is still
186195
// valid and the controller is persistent.
187-
if (CFFileDescriptorIsValid(fdref) && controller->is_persistent_) {
196+
if (CFFileDescriptorIsValid(fdref) && is_persistent) {
188197
DCHECK_EQ(fdref, controller->fdref_.get());
189198
CFFileDescriptorEnableCallBacks(fdref, callback_types);
190199
}

0 commit comments

Comments
 (0)