mirror of
https://github.com/swisspol/GCDWebServer.git
synced 2024-10-07 08:32:16 +08:00
Ensure connected state is updated immediately after calling -stop
This commit is contained in:
parent
c193860468
commit
40ea252ad6
@ -95,6 +95,21 @@ static void _SignalHandler(int signal) {
|
||||
|
||||
#endif
|
||||
|
||||
#if !TARGET_OS_IPHONE || defined(__GCDWEBSERVER_ENABLE_TESTING__)
|
||||
|
||||
// This utility function is used to ensure scheduled callbacks on the main thread are called when running the server synchronously
|
||||
// https://developer.apple.com/library/mac/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html
|
||||
// The main queue works with the application’s run loop to interleave the execution of queued tasks with the execution of other event sources attached to the run loop
|
||||
// TODO: Ensure all scheduled blocks on the main queue are also executed
|
||||
static void _ExecuteMainThreadRunLoopSources() {
|
||||
SInt32 result;
|
||||
do {
|
||||
result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.0, true);
|
||||
} while (result == kCFRunLoopRunHandledSource);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@interface GCDWebServerHandler () {
|
||||
@private
|
||||
GCDWebServerMatchBlock _matchBlock;
|
||||
@ -129,9 +144,10 @@ static void _SignalHandler(int signal) {
|
||||
dispatch_queue_t _syncQueue;
|
||||
dispatch_semaphore_t _sourceSemaphore;
|
||||
NSMutableArray* _handlers;
|
||||
NSInteger _activeConnections; // Accessed only with _syncQueue
|
||||
BOOL _connected;
|
||||
CFRunLoopTimerRef _connectedTimer;
|
||||
NSInteger _activeConnections; // Accessed through _syncQueue only
|
||||
BOOL _connected; // Accessed on main thread only
|
||||
BOOL _disconnecting; // Accessed on main thread only
|
||||
CFRunLoopTimerRef _disconnectTimer; // Accessed on main thread only
|
||||
|
||||
NSDictionary* _options;
|
||||
NSString* _serverName;
|
||||
@ -175,10 +191,13 @@ static void _SignalHandler(int signal) {
|
||||
GCDWebServerInitializeFunctions();
|
||||
}
|
||||
|
||||
static void _ConnectedTimerCallBack(CFRunLoopTimerRef timer, void* info) {
|
||||
static void _DisconnectTimerCallBack(CFRunLoopTimerRef timer, void* info) {
|
||||
DCHECK([NSThread isMainThread]);
|
||||
GCDWebServer* server = (ARC_BRIDGE GCDWebServer*)info;
|
||||
@autoreleasepool {
|
||||
[(ARC_BRIDGE GCDWebServer*)info _didDisconnect];
|
||||
[server _didDisconnect];
|
||||
}
|
||||
server->_disconnecting = NO;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
@ -187,8 +206,8 @@ static void _ConnectedTimerCallBack(CFRunLoopTimerRef timer, void* info) {
|
||||
_sourceSemaphore = dispatch_semaphore_create(0);
|
||||
_handlers = [[NSMutableArray alloc] init];
|
||||
CFRunLoopTimerContext context = {0, (ARC_BRIDGE void*)self, NULL, NULL, NULL};
|
||||
_connectedTimer = CFRunLoopTimerCreate(kCFAllocatorDefault, HUGE_VAL, HUGE_VAL, 0, 0, _ConnectedTimerCallBack, &context);
|
||||
CFRunLoopAddTimer(CFRunLoopGetMain(), _connectedTimer, kCFRunLoopCommonModes);
|
||||
_disconnectTimer = CFRunLoopTimerCreate(kCFAllocatorDefault, HUGE_VAL, HUGE_VAL, 0, 0, _DisconnectTimerCallBack, &context);
|
||||
CFRunLoopAddTimer(CFRunLoopGetMain(), _disconnectTimer, kCFRunLoopCommonModes);
|
||||
#if TARGET_OS_IPHONE
|
||||
_backgroundTask = UIBackgroundTaskInvalid;
|
||||
#endif
|
||||
@ -201,8 +220,8 @@ static void _ConnectedTimerCallBack(CFRunLoopTimerRef timer, void* info) {
|
||||
DCHECK(_activeConnections == 0);
|
||||
DCHECK(_options == nil); // The server can never be dealloc'ed while running because of the retain-cycle with the dispatch source
|
||||
|
||||
CFRunLoopTimerInvalidate(_connectedTimer);
|
||||
CFRelease(_connectedTimer);
|
||||
CFRunLoopTimerInvalidate(_disconnectTimer);
|
||||
CFRelease(_disconnectTimer);
|
||||
ARC_RELEASE(_handlers);
|
||||
ARC_DISPATCH_RELEASE(_sourceSemaphore);
|
||||
ARC_DISPATCH_RELEASE(_syncQueue);
|
||||
@ -252,8 +271,9 @@ static void _ConnectedTimerCallBack(CFRunLoopTimerRef timer, void* info) {
|
||||
DCHECK(_activeConnections >= 0);
|
||||
if (_activeConnections == 0) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (_disconnectDelay > 0.0) {
|
||||
CFRunLoopTimerSetNextFireDate(_connectedTimer, HUGE_VAL);
|
||||
if (_disconnecting) {
|
||||
CFRunLoopTimerSetNextFireDate(_disconnectTimer, HUGE_VAL);
|
||||
_disconnecting = NO;
|
||||
}
|
||||
if (_connected == NO) {
|
||||
[self _didConnect];
|
||||
@ -307,7 +327,8 @@ static void _ConnectedTimerCallBack(CFRunLoopTimerRef timer, void* info) {
|
||||
if (_activeConnections == 0) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if ((_disconnectDelay > 0.0) && (_source != NULL)) {
|
||||
CFRunLoopTimerSetNextFireDate(_connectedTimer, CFAbsoluteTimeGetCurrent() + _disconnectDelay);
|
||||
CFRunLoopTimerSetNextFireDate(_disconnectTimer, CFAbsoluteTimeGetCurrent() + _disconnectDelay);
|
||||
_disconnecting = YES;
|
||||
} else {
|
||||
[self _didDisconnect];
|
||||
}
|
||||
@ -531,6 +552,14 @@ static inline NSString* _EncodeBase64(NSString* string) {
|
||||
ARC_RELEASE(_authenticationDigestAccounts);
|
||||
_authenticationDigestAccounts = nil;
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (_disconnecting) {
|
||||
CFRunLoopTimerSetNextFireDate(_disconnectTimer, HUGE_VAL);
|
||||
_disconnecting = NO;
|
||||
[self _didDisconnect];
|
||||
}
|
||||
});
|
||||
|
||||
LOG_INFO(@"%@ stopped", [self class]);
|
||||
if ([_delegate respondsToSelector:@selector(webServerDidStop:)]) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
@ -674,11 +703,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
|
||||
[self stop];
|
||||
success = YES;
|
||||
}
|
||||
while (1) {
|
||||
if (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, true) == kCFRunLoopRunTimedOut) { // Ensure pending scheduled callbacks have been executed
|
||||
break;
|
||||
}
|
||||
}
|
||||
_ExecuteMainThreadRunLoopSources();
|
||||
signal(SIGINT, intHandler);
|
||||
signal(SIGTERM, termHandler);
|
||||
}
|
||||
@ -971,6 +996,7 @@ static void _LogResult(NSString* format, ...) {
|
||||
NSArray* ignoredHeaders = @[@"Date", @"Etag"]; // Dates are always different by definition and ETags depend on file system node IDs
|
||||
NSInteger result = -1;
|
||||
if ([self startWithOptions:options error:NULL]) {
|
||||
_ExecuteMainThreadRunLoopSources();
|
||||
|
||||
result = 0;
|
||||
NSArray* files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:NULL];
|
||||
@ -1073,15 +1099,12 @@ static void _LogResult(NSString* format, ...) {
|
||||
++result;
|
||||
}
|
||||
}
|
||||
_ExecuteMainThreadRunLoopSources();
|
||||
}
|
||||
|
||||
[self stop];
|
||||
|
||||
while (1) {
|
||||
if (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, true) == kCFRunLoopRunTimedOut) { // Ensure pending scheduled callbacks have been executed
|
||||
break;
|
||||
}
|
||||
}
|
||||
_ExecuteMainThreadRunLoopSources();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user