Use dispatch_after for delayed destroy of channel

pull/16190/head
Muxi Yan 7 years ago
parent 67a4eb6623
commit ac211b4214
  1. 87
      src/objective-c/GRPCClient/private/GRPCChannel.m

@ -57,14 +57,13 @@ NSTimeInterval kChannelDestroyDelay = 30;
@implementation GRPCChannelRef {
NSTimeInterval _destroyDelay;
// We use dispatch queue for this purpose since timer invalidation must happen on the same
// thread which issued the timer.
dispatch_queue_t _dispatchQueue;
void (^_destroyChannelCallback)();
NSUInteger _refCount;
NSTimer *_timer;
BOOL _disconnected;
dispatch_queue_t _dispatchQueue;
dispatch_queue_t _timerQueue;
NSDate *_lastDispatch;
}
- (instancetype)initWithDestroyDelay:(NSTimeInterval)destroyDelay
@ -74,57 +73,65 @@ NSTimeInterval kChannelDestroyDelay = 30;
_destroyChannelCallback = destroyChannelCallback;
_refCount = 1;
_timer = nil;
_disconnected = NO;
if (@available(iOS 8.0, *)) {
_dispatchQueue = dispatch_queue_create(NULL, dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, -1));
_timerQueue = dispatch_queue_create(NULL, dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_CONCURRENT, QOS_CLASS_DEFAULT, -1));
} else {
_dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
_timerQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT);
}
_lastDispatch = nil;
}
return self;
}
// This function is protected by channel dispatch queue.
- (void)refChannel {
if (!_disconnected) {
_refCount++;
[_timer invalidate];
_timer = nil;
}
dispatch_async(_dispatchQueue, ^{
if (!self->_disconnected) {
self->_refCount++;
self->_lastDispatch = nil;
}
});
}
// This function is protected by channel dispatch queue.
- (void)unrefChannel {
if (!_disconnected) {
_refCount--;
if (_refCount == 0) {
[_timer invalidate];
_timer = [NSTimer scheduledTimerWithTimeInterval:_destroyDelay
target:self
selector:@selector(timerFire:)
userInfo:nil
repeats:NO];
dispatch_async(_dispatchQueue, ^{
if (!self->_disconnected) {
self->_refCount--;
if (self->_refCount == 0) {
self->_lastDispatch = [NSDate date];
dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, (int64_t)kChannelDestroyDelay * 1e9);
dispatch_after(delay, self->_timerQueue, ^{
[self timerFire];
});
}
}
}
});
}
// This function is protected by channel dispatch queue.
- (void)disconnect {
if (!_disconnected) {
[_timer invalidate];
_timer = nil;
_disconnected = YES;
// Break retain loop
_destroyChannelCallback = nil;
}
dispatch_async(_dispatchQueue, ^{
if (!self->_disconnected) {
self->_lastDispatch = nil;
self->_disconnected = YES;
// Break retain loop
self->_destroyChannelCallback = nil;
}
});
}
// This function is protected by channel dispatch queue.
- (void)timerFire:(NSTimer *)timer {
if (_disconnected || _timer == nil || _timer != timer) {
return;
}
_timer = nil;
_destroyChannelCallback();
// Break retain loop
_destroyChannelCallback = nil;
_disconnected = YES;
- (void)timerFire {
dispatch_async(_dispatchQueue, ^{
if (self->_disconnected || self->_lastDispatch == nil || -[self->_lastDispatch timeIntervalSinceNow] < -kChannelDestroyDelay) {
return;
}
self->_lastDispatch = nil;
self->_disconnected = YES;
self->_destroyChannelCallback();
// Break retain loop
self->_destroyChannelCallback = nil;
});
}
@end

Loading…
Cancel
Save