I'm running into a bit of a conundrum with the following code snippet. The purpose of this code is to read bytes from an NSInputStream and process them accordingly. However, we have noticed that sometimes, the inputStream.read() function can block indefinitely.
In order to address this, we implemented a timeout mechanism, shown below. We know the read is occurring because we get the log line that says "Reading Stream", which occurs after the dispatch_sync() block, but it will still continue to indefinitely hang at times and the timeout block, which was scheduled on the main thread, is never firing. Why is this not working as intended?
When the inputStream.read() function doesn't block indefinitely, the following code snippet works perfectly, and the timeout block is cancelled before it fires. Also, other independent dispatch_after() blocks get called elsewhere in our code, and the syntax is exactly the same as those areas that do work, so I'm wondering why this timeout pattern isn't working.
- (void)readStreamData:(nonnull NSInputStream*)stream {
NSUInteger fileDataSize = self.fileDataSize;
__weak typeof(self) weakSelf = self;
dispatch_async(self.streamQueue, ^{
@autoreleasepool {
if(weakSelf == nil) return;
NSMutableData* buffer = [[NSMutableData alloc] initWithLength:fileDataSize];
// Timeout Read if it does not return within 5 seconds
__block BOOL timeout = YES;
dispatch_sync(dispatch_get_main_queue(), ^{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if(timeout) {
[weakSelf.delegate objectTransferService:weakSelf error:[NSError errorWithDomain:PBObjectTransferServiceErrorDomain
code:-weakSelf.transferState
userInfo:@{NSLocalizedDescriptionKey : @"Reading Stream Timed Out"}]];
}
timeout = NO;
});
});
if(!weakSelf.readStreamLog) {
PBLogWeakDebug(@"Reading Stream");
weakSelf.readStreamLog = YES;
}
NSInteger read = [stream read:buffer.mutableBytes maxLength:buffer.length];
dispatch_async(dispatch_get_main_queue(), ^{
if (timeout) {
PBLogWeakVerbose(@"Cancelling Read Stream Timeout");
timeout = NO;
if(weakSelf == nil) return;
// Do some additional Non-blocking WORK
// Non-blocking WORK
// Non-blocking WORK
});
}
});
}