Skip to content

Commit 1e41b4c

Browse files
Fix part of the TSAN flakiness of ChannelTests.
#### How does the flakiness happen? If a Dispatch I/O instance has pending dispatch_io_read, the dispatch_io_close waits for the dispatch_io_read to be completed before releasing resources. However, `[EDOSocketChannel -receiveDataWithHandler:]` does two consecutive dispatch_io_read, so the second dispatch_io_read may corrupt dispatch_io_close when TSAN is enabled. #### Proposed Fix In `[EDOSocketChannel -receiveDataWithHandler:]`, before performing the second dispatch_io_read, it first checks if the Dispatch I/O is still valid. PiperOrigin-RevId: 326086302
1 parent 61a4ad8 commit 1e41b4c

File tree

1 file changed

+23
-2
lines changed

1 file changed

+23
-2
lines changed

Channel/Sources/EDOSocketChannel.m

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,9 @@ - (void)receiveDataWithHandler:(EDOChannelReceiveHandler)handler {
154154
size_t payloadSize = EDOGetPayloadSizeFromFrameData(data);
155155
if (payloadSize > 0) {
156156
remainingDataSize = payloadSize;
157-
dispatch_io_read(channel, 0, payloadSize, handlerQueue, dataHandler);
157+
if (![self readDispatchIOWithDataSize:remainingDataSize handler:dataHandler] && handler) {
158+
handler(self, nil, nil);
159+
}
158160
} else {
159161
// Close the channel on errors and closed sockets.
160162
if (error != 0 || payloadSize == 0) {
@@ -170,7 +172,7 @@ - (void)receiveDataWithHandler:(EDOChannelReceiveHandler)handler {
170172
}
171173
};
172174

173-
dispatch_io_read(channel, 0, EDOGetPayloadHeaderSize(), handlerQueue, frameHandler);
175+
[self readDispatchIOWithDataSize:EDOGetPayloadHeaderSize() handler:frameHandler];
174176
}
175177

176178
/** @see -[EDOChannel isValid] */
@@ -190,4 +192,23 @@ - (void)invalidate {
190192
}
191193
}
192194

195+
#pragma mark - Private
196+
197+
/**
198+
* Atomically checks the validity of the socket channel and calls dispatch_io_read if it's valid.
199+
*
200+
* @param dataSize The number of bytes to be read through dispatch_io_read.
201+
* @param handler The handler to process the data read by dispatch_io_read.
202+
*
203+
* @return @c YES if dispatch_io_read is called; @c NO otherwise.
204+
*/
205+
- (BOOL)readDispatchIOWithDataSize:(size_t)dataSize handler:(dispatch_io_handler_t)handler {
206+
@synchronized(self) {
207+
if (_channel) {
208+
dispatch_io_read(_channel, 0, dataSize, _handlerQueue, handler);
209+
}
210+
return _channel != NULL;
211+
}
212+
}
213+
193214
@end

0 commit comments

Comments
 (0)