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
|
#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 () {
|
@interface GCDWebServerHandler () {
|
||||||
@private
|
@private
|
||||||
GCDWebServerMatchBlock _matchBlock;
|
GCDWebServerMatchBlock _matchBlock;
|
||||||
@ -129,9 +144,10 @@ static void _SignalHandler(int signal) {
|
|||||||
dispatch_queue_t _syncQueue;
|
dispatch_queue_t _syncQueue;
|
||||||
dispatch_semaphore_t _sourceSemaphore;
|
dispatch_semaphore_t _sourceSemaphore;
|
||||||
NSMutableArray* _handlers;
|
NSMutableArray* _handlers;
|
||||||
NSInteger _activeConnections; // Accessed only with _syncQueue
|
NSInteger _activeConnections; // Accessed through _syncQueue only
|
||||||
BOOL _connected;
|
BOOL _connected; // Accessed on main thread only
|
||||||
CFRunLoopTimerRef _connectedTimer;
|
BOOL _disconnecting; // Accessed on main thread only
|
||||||
|
CFRunLoopTimerRef _disconnectTimer; // Accessed on main thread only
|
||||||
|
|
||||||
NSDictionary* _options;
|
NSDictionary* _options;
|
||||||
NSString* _serverName;
|
NSString* _serverName;
|
||||||
@ -175,10 +191,13 @@ static void _SignalHandler(int signal) {
|
|||||||
GCDWebServerInitializeFunctions();
|
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 {
|
@autoreleasepool {
|
||||||
[(ARC_BRIDGE GCDWebServer*)info _didDisconnect];
|
[server _didDisconnect];
|
||||||
}
|
}
|
||||||
|
server->_disconnecting = NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)init {
|
- (instancetype)init {
|
||||||
@ -187,8 +206,8 @@ static void _ConnectedTimerCallBack(CFRunLoopTimerRef timer, void* info) {
|
|||||||
_sourceSemaphore = dispatch_semaphore_create(0);
|
_sourceSemaphore = dispatch_semaphore_create(0);
|
||||||
_handlers = [[NSMutableArray alloc] init];
|
_handlers = [[NSMutableArray alloc] init];
|
||||||
CFRunLoopTimerContext context = {0, (ARC_BRIDGE void*)self, NULL, NULL, NULL};
|
CFRunLoopTimerContext context = {0, (ARC_BRIDGE void*)self, NULL, NULL, NULL};
|
||||||
_connectedTimer = CFRunLoopTimerCreate(kCFAllocatorDefault, HUGE_VAL, HUGE_VAL, 0, 0, _ConnectedTimerCallBack, &context);
|
_disconnectTimer = CFRunLoopTimerCreate(kCFAllocatorDefault, HUGE_VAL, HUGE_VAL, 0, 0, _DisconnectTimerCallBack, &context);
|
||||||
CFRunLoopAddTimer(CFRunLoopGetMain(), _connectedTimer, kCFRunLoopCommonModes);
|
CFRunLoopAddTimer(CFRunLoopGetMain(), _disconnectTimer, kCFRunLoopCommonModes);
|
||||||
#if TARGET_OS_IPHONE
|
#if TARGET_OS_IPHONE
|
||||||
_backgroundTask = UIBackgroundTaskInvalid;
|
_backgroundTask = UIBackgroundTaskInvalid;
|
||||||
#endif
|
#endif
|
||||||
@ -201,8 +220,8 @@ static void _ConnectedTimerCallBack(CFRunLoopTimerRef timer, void* info) {
|
|||||||
DCHECK(_activeConnections == 0);
|
DCHECK(_activeConnections == 0);
|
||||||
DCHECK(_options == nil); // The server can never be dealloc'ed while running because of the retain-cycle with the dispatch source
|
DCHECK(_options == nil); // The server can never be dealloc'ed while running because of the retain-cycle with the dispatch source
|
||||||
|
|
||||||
CFRunLoopTimerInvalidate(_connectedTimer);
|
CFRunLoopTimerInvalidate(_disconnectTimer);
|
||||||
CFRelease(_connectedTimer);
|
CFRelease(_disconnectTimer);
|
||||||
ARC_RELEASE(_handlers);
|
ARC_RELEASE(_handlers);
|
||||||
ARC_DISPATCH_RELEASE(_sourceSemaphore);
|
ARC_DISPATCH_RELEASE(_sourceSemaphore);
|
||||||
ARC_DISPATCH_RELEASE(_syncQueue);
|
ARC_DISPATCH_RELEASE(_syncQueue);
|
||||||
@ -252,8 +271,9 @@ static void _ConnectedTimerCallBack(CFRunLoopTimerRef timer, void* info) {
|
|||||||
DCHECK(_activeConnections >= 0);
|
DCHECK(_activeConnections >= 0);
|
||||||
if (_activeConnections == 0) {
|
if (_activeConnections == 0) {
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
if (_disconnectDelay > 0.0) {
|
if (_disconnecting) {
|
||||||
CFRunLoopTimerSetNextFireDate(_connectedTimer, HUGE_VAL);
|
CFRunLoopTimerSetNextFireDate(_disconnectTimer, HUGE_VAL);
|
||||||
|
_disconnecting = NO;
|
||||||
}
|
}
|
||||||
if (_connected == NO) {
|
if (_connected == NO) {
|
||||||
[self _didConnect];
|
[self _didConnect];
|
||||||
@ -307,7 +327,8 @@ static void _ConnectedTimerCallBack(CFRunLoopTimerRef timer, void* info) {
|
|||||||
if (_activeConnections == 0) {
|
if (_activeConnections == 0) {
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
if ((_disconnectDelay > 0.0) && (_source != NULL)) {
|
if ((_disconnectDelay > 0.0) && (_source != NULL)) {
|
||||||
CFRunLoopTimerSetNextFireDate(_connectedTimer, CFAbsoluteTimeGetCurrent() + _disconnectDelay);
|
CFRunLoopTimerSetNextFireDate(_disconnectTimer, CFAbsoluteTimeGetCurrent() + _disconnectDelay);
|
||||||
|
_disconnecting = YES;
|
||||||
} else {
|
} else {
|
||||||
[self _didDisconnect];
|
[self _didDisconnect];
|
||||||
}
|
}
|
||||||
@ -531,6 +552,14 @@ static inline NSString* _EncodeBase64(NSString* string) {
|
|||||||
ARC_RELEASE(_authenticationDigestAccounts);
|
ARC_RELEASE(_authenticationDigestAccounts);
|
||||||
_authenticationDigestAccounts = nil;
|
_authenticationDigestAccounts = nil;
|
||||||
|
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
if (_disconnecting) {
|
||||||
|
CFRunLoopTimerSetNextFireDate(_disconnectTimer, HUGE_VAL);
|
||||||
|
_disconnecting = NO;
|
||||||
|
[self _didDisconnect];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
LOG_INFO(@"%@ stopped", [self class]);
|
LOG_INFO(@"%@ stopped", [self class]);
|
||||||
if ([_delegate respondsToSelector:@selector(webServerDidStop:)]) {
|
if ([_delegate respondsToSelector:@selector(webServerDidStop:)]) {
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
@ -674,11 +703,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
|
|||||||
[self stop];
|
[self stop];
|
||||||
success = YES;
|
success = YES;
|
||||||
}
|
}
|
||||||
while (1) {
|
_ExecuteMainThreadRunLoopSources();
|
||||||
if (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, true) == kCFRunLoopRunTimedOut) { // Ensure pending scheduled callbacks have been executed
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
signal(SIGINT, intHandler);
|
signal(SIGINT, intHandler);
|
||||||
signal(SIGTERM, termHandler);
|
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
|
NSArray* ignoredHeaders = @[@"Date", @"Etag"]; // Dates are always different by definition and ETags depend on file system node IDs
|
||||||
NSInteger result = -1;
|
NSInteger result = -1;
|
||||||
if ([self startWithOptions:options error:NULL]) {
|
if ([self startWithOptions:options error:NULL]) {
|
||||||
|
_ExecuteMainThreadRunLoopSources();
|
||||||
|
|
||||||
result = 0;
|
result = 0;
|
||||||
NSArray* files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:NULL];
|
NSArray* files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:NULL];
|
||||||
@ -1073,15 +1099,12 @@ static void _LogResult(NSString* format, ...) {
|
|||||||
++result;
|
++result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_ExecuteMainThreadRunLoopSources();
|
||||||
}
|
}
|
||||||
|
|
||||||
[self stop];
|
[self stop];
|
||||||
|
|
||||||
while (1) {
|
_ExecuteMainThreadRunLoopSources();
|
||||||
if (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, true) == kCFRunLoopRunTimedOut) { // Ensure pending scheduled callbacks have been executed
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user