mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-23 00:41:02 +00:00
NSURLSession: optimized timout timer and fixed memory management
This commit is contained in:
parent
cb6c53b84d
commit
15499e1017
6 changed files with 108 additions and 143 deletions
|
@ -155,7 +155,7 @@ curl_debug_function(CURL *handle, curl_infotype type, char *data,
|
|||
text = [NSString stringWithUTF8String: data];
|
||||
}
|
||||
|
||||
NSLog(@"%p %lu %d %@", o, [task taskIdentifier], type, text);
|
||||
NSLog(@"%p %lu %d %@", o, (unsigned long)[task taskIdentifier], type, text);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -234,17 +234,7 @@ curl_socket_function(void *userdata, curl_socket_t fd, curlsocktype type)
|
|||
|
||||
- (void) resetTimer
|
||||
{
|
||||
// simply create a new timer with the same queue, timeout and handler
|
||||
// this must cancel the old handler and reset the timer
|
||||
if (_timeoutTimer)
|
||||
{
|
||||
GSTimeoutSource *oldTimer = _timeoutTimer;
|
||||
[oldTimer cancel];
|
||||
_timeoutTimer = [[GSTimeoutSource alloc] initWithQueue: [oldTimer queue]
|
||||
milliseconds: [oldTimer milliseconds]
|
||||
handler: [oldTimer handler]];
|
||||
RELEASE(oldTimer);
|
||||
}
|
||||
[_timeoutTimer setTimeout: [_timeoutTimer timeout]];
|
||||
}
|
||||
|
||||
- (void) setupCallbacks
|
||||
|
@ -415,7 +405,7 @@ curl_socket_function(void *userdata, curl_socket_t fd, curlsocktype type)
|
|||
else
|
||||
{
|
||||
value = [NSString stringWithFormat: @"%@:%lu:%@",
|
||||
originHost, port, host];
|
||||
originHost, (unsigned long)port, host];
|
||||
}
|
||||
|
||||
struct curl_slist *connect_to = NULL;
|
||||
|
|
|
@ -605,7 +605,6 @@ parseArgumentPart(NSString *part, NSString *name)
|
|||
GSTimeoutSource *timeoutTimer;
|
||||
|
||||
timeoutTimer = [[GSTimeoutSource alloc] initWithQueue: [task workQueue]
|
||||
milliseconds: timeoutInterval
|
||||
handler:
|
||||
^{
|
||||
NSError *urlError;
|
||||
|
@ -622,6 +621,7 @@ parseArgumentPart(NSString *part, NSString *name)
|
|||
[client URLProtocol: self didFailWithError: urlError];
|
||||
}
|
||||
}];
|
||||
[timeoutTimer setTimeout: timeoutInterval];
|
||||
[_easyHandle setTimeoutTimer: timeoutTimer];
|
||||
RELEASE(timeoutTimer);
|
||||
|
||||
|
|
|
@ -77,12 +77,10 @@ typedef NS_ENUM(NSUInteger, GSSocketRegisterActionType) {
|
|||
socket: (curl_socket_t)socket
|
||||
queue: (dispatch_queue_t)queue
|
||||
handler: (dispatch_block_t)handler;
|
||||
- (void) createReadSourceWithSocket: (curl_socket_t)socket
|
||||
queue: (dispatch_queue_t)queue
|
||||
handler: (dispatch_block_t)handler;
|
||||
- (void) createWriteSourceWithSocket: (curl_socket_t)socket
|
||||
queue: (dispatch_queue_t)queue
|
||||
handler: (dispatch_block_t)handler;
|
||||
- (dispatch_source_t) createSourceWithType: (dispatch_source_type_t)type
|
||||
socket: (curl_socket_t)socket
|
||||
queue: (dispatch_queue_t)queue
|
||||
handler: (dispatch_block_t)handler;
|
||||
|
||||
+ (instancetype) from: (void*)socketSourcePtr;
|
||||
|
||||
|
|
|
@ -10,8 +10,7 @@
|
|||
#import "Foundation/NSURLSession.h"
|
||||
|
||||
@interface GSMultiHandle ()
|
||||
- (void) performActionForSocket: (int)socket;
|
||||
- (void) readAndWriteAvailableDataOnSocket: (int)socket;
|
||||
- (void) readAndWriteAvailableDataOnSocket: (curl_socket_t)socket;
|
||||
- (void) readMessages;
|
||||
- (void) completedTransferForEasyHandle: (CURL*)rawEasyHandle
|
||||
easyCode: (int)easyCode;
|
||||
|
@ -196,44 +195,27 @@ static int curl_timer_function(CURL *easyHandle, int timeout, void *userdata) {
|
|||
// of milliseconds.
|
||||
if (-1 == value)
|
||||
{
|
||||
[_timeoutSource cancel];
|
||||
DESTROY(_timeoutSource);
|
||||
}
|
||||
else if (0 == value)
|
||||
{
|
||||
[_timeoutSource cancel];
|
||||
DESTROY(_timeoutSource);
|
||||
dispatch_async(_queue,
|
||||
^{
|
||||
[self timeoutTimerFired];
|
||||
});
|
||||
}
|
||||
[_timeoutSource suspend];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nil == _timeoutSource || value != [_timeoutSource milliseconds])
|
||||
if (!_timeoutSource)
|
||||
{
|
||||
[_timeoutSource cancel];
|
||||
DESTROY(_timeoutSource);
|
||||
_timeoutSource = [[GSTimeoutSource alloc] initWithQueue: _queue
|
||||
milliseconds: value
|
||||
handler: ^{
|
||||
[self timeoutTimerFired];
|
||||
}];
|
||||
}
|
||||
}
|
||||
}
|
||||
[_timeoutSource setTimeout: value];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) performActionForSocket: (int)socket
|
||||
{
|
||||
[self readAndWriteAvailableDataOnSocket: socket];
|
||||
}
|
||||
|
||||
- (void)timeoutTimerFired
|
||||
- (void) timeoutTimerFired
|
||||
{
|
||||
[self readAndWriteAvailableDataOnSocket: CURL_SOCKET_TIMEOUT];
|
||||
}
|
||||
|
||||
- (void) readAndWriteAvailableDataOnSocket: (int)socket
|
||||
- (void) readAndWriteAvailableDataOnSocket: (curl_socket_t)socket
|
||||
{
|
||||
int runningHandlesCount = 0;
|
||||
|
||||
|
@ -312,7 +294,7 @@ static int curl_timer_function(CURL *easyHandle, int timeout, void *userdata) {
|
|||
[handle transferCompletedWithError: err];
|
||||
}
|
||||
|
||||
- (int32_t) registerWithSocket: (curl_socket_t)socket
|
||||
- (int32_t) registerWithSocket: (curl_socket_t)socket
|
||||
what: (int)what
|
||||
socketSourcePtr: (void *)socketSourcePtr
|
||||
{
|
||||
|
@ -342,6 +324,7 @@ static int curl_timer_function(CURL *easyHandle, int timeout, void *userdata) {
|
|||
&& GSSocketRegisterActionTypeUnregister == [action type])
|
||||
{
|
||||
DESTROY(socketSources);
|
||||
curl_multi_assign(_rawHandle, socket, NULL);
|
||||
}
|
||||
|
||||
if (nil != socketSources)
|
||||
|
@ -350,7 +333,7 @@ static int curl_timer_function(CURL *easyHandle, int timeout, void *userdata) {
|
|||
socket: socket
|
||||
queue: _queue
|
||||
handler: ^{
|
||||
[self performActionForSocket: socket];
|
||||
[self readAndWriteAvailableDataOnSocket: socket];
|
||||
}];
|
||||
}
|
||||
|
||||
|
@ -400,16 +383,11 @@ static int curl_timer_function(CURL *easyHandle, int timeout, void *userdata) {
|
|||
{
|
||||
switch (self.type)
|
||||
{
|
||||
case GSSocketRegisterActionTypeNone:
|
||||
return false;
|
||||
case GSSocketRegisterActionTypeRegisterRead:
|
||||
return true;
|
||||
case GSSocketRegisterActionTypeRegisterWrite:
|
||||
return false;
|
||||
case GSSocketRegisterActionTypeRegisterReadAndWrite:
|
||||
return true;
|
||||
case GSSocketRegisterActionTypeUnregister:
|
||||
return false;
|
||||
return YES;
|
||||
default:
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -417,16 +395,11 @@ static int curl_timer_function(CURL *easyHandle, int timeout, void *userdata) {
|
|||
{
|
||||
switch (self.type)
|
||||
{
|
||||
case GSSocketRegisterActionTypeNone:
|
||||
return false;
|
||||
case GSSocketRegisterActionTypeRegisterRead:
|
||||
return false;
|
||||
case GSSocketRegisterActionTypeRegisterWrite:
|
||||
return true;
|
||||
case GSSocketRegisterActionTypeRegisterReadAndWrite:
|
||||
return true;
|
||||
case GSSocketRegisterActionTypeUnregister:
|
||||
return false;
|
||||
return YES;
|
||||
default:
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -444,16 +417,15 @@ static int curl_timer_function(CURL *easyHandle, int timeout, void *userdata) {
|
|||
if (_readSource)
|
||||
{
|
||||
dispatch_source_cancel(_readSource);
|
||||
dispatch_release(_readSource);
|
||||
}
|
||||
_readSource = NULL;
|
||||
|
||||
if (_writeSource)
|
||||
{
|
||||
dispatch_source_cancel(_writeSource);
|
||||
dispatch_release(_writeSource);
|
||||
}
|
||||
_writeSource = NULL;
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
@ -462,50 +434,40 @@ static int curl_timer_function(CURL *easyHandle, int timeout, void *userdata) {
|
|||
queue: (dispatch_queue_t)queue
|
||||
handler: (dispatch_block_t)handler
|
||||
{
|
||||
if ([action needsReadSource])
|
||||
if (!_readSource && [action needsReadSource])
|
||||
{
|
||||
[self createReadSourceWithSocket: socket queue: queue handler: handler];
|
||||
_readSource = [self createSourceWithType: DISPATCH_SOURCE_TYPE_READ
|
||||
socket: socket
|
||||
queue: queue
|
||||
handler: handler];
|
||||
}
|
||||
|
||||
if ([action needsWriteSource])
|
||||
if (!_writeSource && [action needsWriteSource])
|
||||
{
|
||||
[self createWriteSourceWithSocket: socket queue: queue handler: handler];
|
||||
_writeSource = [self createSourceWithType: DISPATCH_SOURCE_TYPE_WRITE
|
||||
socket: socket
|
||||
queue: queue
|
||||
handler: handler];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) createReadSourceWithSocket: (curl_socket_t)socket
|
||||
queue: (dispatch_queue_t)queue
|
||||
handler: (dispatch_block_t)handler
|
||||
- (dispatch_source_t) createSourceWithType: (dispatch_source_type_t)type
|
||||
socket: (curl_socket_t)socket
|
||||
queue: (dispatch_queue_t)queue
|
||||
handler: (dispatch_block_t)handler
|
||||
{
|
||||
dispatch_source_t s;
|
||||
dispatch_source_t source;
|
||||
|
||||
if (_readSource)
|
||||
{
|
||||
return;
|
||||
}
|
||||
source = dispatch_source_create(type, socket, 0, queue);
|
||||
dispatch_source_set_event_handler(source, handler);
|
||||
dispatch_source_set_cancel_handler(source, ^{
|
||||
dispatch_release(source);
|
||||
});
|
||||
dispatch_resume(source);
|
||||
|
||||
s = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, socket, 0, queue);
|
||||
dispatch_source_set_event_handler(s, handler);
|
||||
_readSource = s;
|
||||
dispatch_resume(s);
|
||||
return source;
|
||||
}
|
||||
|
||||
- (void) createWriteSourceWithSocket: (curl_socket_t)socket
|
||||
queue: (dispatch_queue_t)queue
|
||||
handler: (dispatch_block_t)handler
|
||||
{
|
||||
dispatch_source_t s;
|
||||
|
||||
if (_writeSource)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
s = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, socket, 0, queue);
|
||||
dispatch_source_set_event_handler(s, handler);
|
||||
_writeSource = s;
|
||||
dispatch_resume(s);
|
||||
}
|
||||
|
||||
+ (instancetype) from: (void*)socketSourcePtr
|
||||
{
|
||||
|
|
|
@ -11,24 +11,22 @@
|
|||
*/
|
||||
@interface GSTimeoutSource : NSObject
|
||||
{
|
||||
dispatch_source_t _rawSource;
|
||||
NSInteger _milliseconds;
|
||||
dispatch_queue_t _queue;
|
||||
dispatch_block_t _handler;
|
||||
dispatch_source_t _timer;
|
||||
NSInteger _timeoutMs;
|
||||
bool _isSuspended;
|
||||
}
|
||||
|
||||
- (void) cancel;
|
||||
|
||||
- (NSInteger) milliseconds;
|
||||
|
||||
- (dispatch_queue_t) queue;
|
||||
|
||||
- (dispatch_block_t) handler;
|
||||
|
||||
- (instancetype) initWithQueue: (dispatch_queue_t)queue
|
||||
milliseconds: (NSInteger)milliseconds
|
||||
handler: (dispatch_block_t)handler;
|
||||
|
||||
- (NSInteger) timeout;
|
||||
- (void) setTimeout: (NSInteger)timeoutMs;
|
||||
|
||||
- (void) suspend;
|
||||
|
||||
- (void) cancel;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3,23 +3,19 @@
|
|||
@implementation GSTimeoutSource
|
||||
|
||||
- (instancetype) initWithQueue: (dispatch_queue_t)queue
|
||||
milliseconds: (NSInteger)milliseconds
|
||||
handler: (dispatch_block_t)handler
|
||||
{
|
||||
if (nil != (self = [super init]))
|
||||
{
|
||||
_queue = queue;
|
||||
_handler = Block_copy(handler);
|
||||
_milliseconds = milliseconds;
|
||||
_rawSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, _queue);
|
||||
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
|
||||
dispatch_source_set_event_handler(timer, handler);
|
||||
dispatch_source_set_cancel_handler(timer, ^{
|
||||
dispatch_release(timer);
|
||||
});
|
||||
|
||||
uint64_t delay = MAX(1, milliseconds - 1);
|
||||
|
||||
dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, delay * NSEC_PER_MSEC);
|
||||
|
||||
dispatch_source_set_timer(_rawSource, start, delay * NSEC_PER_MSEC, _milliseconds == 1 ? 1 * NSEC_PER_USEC : 1 * NSEC_PER_MSEC);
|
||||
dispatch_source_set_event_handler(_rawSource, _handler);
|
||||
dispatch_resume(_rawSource);
|
||||
_timer = timer;
|
||||
_timeoutMs = -1;
|
||||
_isSuspended = YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
@ -27,33 +23,54 @@
|
|||
- (void) dealloc
|
||||
{
|
||||
[self cancel];
|
||||
Block_release(_handler);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSInteger) timeout
|
||||
{
|
||||
return _timeoutMs;
|
||||
}
|
||||
|
||||
- (void) setTimeout: (NSInteger)timeoutMs
|
||||
{
|
||||
if (timeoutMs >= 0)
|
||||
{
|
||||
_timeoutMs = timeoutMs;
|
||||
|
||||
dispatch_source_set_timer(_timer,
|
||||
dispatch_time(DISPATCH_TIME_NOW, timeoutMs * NSEC_PER_MSEC),
|
||||
DISPATCH_TIME_FOREVER, // don't repeat
|
||||
timeoutMs * 0.05); // 5% leeway
|
||||
|
||||
if (_isSuspended)
|
||||
{
|
||||
_isSuspended = NO;
|
||||
dispatch_resume(_timer);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
[self suspend];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)suspend
|
||||
{
|
||||
if (!_isSuspended)
|
||||
{
|
||||
_isSuspended = YES;
|
||||
_timeoutMs = -1;
|
||||
dispatch_suspend(_timer);
|
||||
}
|
||||
}
|
||||
|
||||
- (void) cancel
|
||||
{
|
||||
if (_rawSource)
|
||||
if (_timer)
|
||||
{
|
||||
dispatch_source_cancel(_rawSource);
|
||||
dispatch_release(_rawSource);
|
||||
_rawSource = NULL;
|
||||
dispatch_source_cancel(_timer);
|
||||
_timer = NULL; // released in cancel handler
|
||||
}
|
||||
}
|
||||
|
||||
- (NSInteger) milliseconds
|
||||
{
|
||||
return _milliseconds;
|
||||
}
|
||||
|
||||
- (dispatch_queue_t) queue
|
||||
{
|
||||
return _queue;
|
||||
}
|
||||
|
||||
- (dispatch_block_t) handler
|
||||
{
|
||||
return _handler;
|
||||
}
|
||||
|
||||
@end
|
Loading…
Reference in a new issue