* GSWeb/GSWDictionary.m

added - dealloc
    * GSWeb/GSWDefaultAdaptor.h
    * GSWeb/GSWDefaultAdaptor.m
    * GSWeb/GSWWorkerThread.h
    * GSWeb/GSWWorkerThread.m
      pooling NSThreads now to make GSW able to handle multiple threads.
This commit is contained in:
David Wetzel 2017-12-29 00:24:04 -05:00
parent 143b590b70
commit e108560e37
5 changed files with 181 additions and 128 deletions

3
GSWeb/GSWDefaultAdaptor.h Normal file → Executable file
View file

@ -95,7 +95,8 @@ GSWEB_EXPORT int iBlock;
-(BOOL)isConnectionAllowedWithHandle:(NSFileHandle*)handle -(BOOL)isConnectionAllowedWithHandle:(NSFileHandle*)handle
returnedMessage:(NSString**)retMessage; returnedMessage:(NSString**)retMessage;
- (void) workerThreadWillExit:(GSWWorkerThread*) thread; // GSW only
- (void) workerThreadFinished:(GSWWorkerThread*) thread;
-(void)stop; -(void)stop;
-(void)run; -(void)run;

78
GSWeb/GSWDefaultAdaptor.m Normal file → Executable file
View file

@ -104,9 +104,21 @@ static GSWResponse * static_lastDitchErrorResponse = nil;
ASSIGN(_adaptorHost,[arguments objectForKey:GSWOPT_AdaptorHost[GSWebNamingConv]]); ASSIGN(_adaptorHost,[arguments objectForKey:GSWOPT_AdaptorHost[GSWebNamingConv]]);
if ((_workerThreadCountMax <1) || (_isMultiThreadEnabled == NO)) { if ((_workerThreadCountMax <1) || (_isMultiThreadEnabled == NO)) {
_workerThreadCountMax = 1; _workerThreadCountMax = 0;
_isMultiThreadEnabled = NO; _isMultiThreadEnabled = NO;
} }
if (_isMultiThreadEnabled) {
for (int i=0; i < _workerThreadCountMax; i++) {
GSWWorkerThread * thread = [GSWWorkerThread alloc];
thread = [thread initWithApp:GSWApp
adaptor:self
stream:nil];
[_threads addObject: thread];
[thread release];
}
}
} }
return self; return self;
} }
@ -187,18 +199,16 @@ void _queueWorkOnHandle(NSFileHandle* handle, NSMutableArray* waitingThreadArray
atIndex: [waitingThreadArray count]]; atIndex: [waitingThreadArray count]];
} }
// never called if single threaded.
- (void) workerThreadWillExit:(GSWWorkerThread*) thread - (void) workerThreadFinished:(GSWWorkerThread*) thread
{ {
[_selfLock lock]; [_selfLock lock];
[thread retain]; if ([_waitingThreads count]) {
[_threads removeObject: thread]; [thread setServerSocket:[_waitingThreads objectAtIndex:0]];
if ([_waitingThreads count]) { [_waitingThreads removeObjectAtIndex:0];
_workOnHandle([_waitingThreads objectAtIndex:0], self, _threads, _isMultiThreadEnabled); }
[_waitingThreads removeObjectAtIndex:0];
}
[thread autorelease];
[_selfLock unlock]; [_selfLock unlock];
} }
//PRIVATE! //PRIVATE!
@ -268,44 +278,54 @@ void _queueWorkOnHandle(NSFileHandle* handle, NSMutableArray* waitingThreadArray
return GSWIntNumber(_workerThreadCount); return GSWIntNumber(_workerThreadCount);
} }
// Use locked only
- (GSWWorkerThread*) _nextFreeThread
{
for (GSWWorkerThread *thread in _threads) {
if ([thread isWorking] == NO) {
return thread;
}
}
return nil;
}
-(void)announceNewConnection:(NSNotification*)notification -(void)announceNewConnection:(NSNotification*)notification
{ {
NSFileHandle *listenHandle=nil; NSFileHandle *listenHandle=nil;
NSFileHandle *inStream = nil; NSFileHandle *inStream = nil;
NSString* connRefusedMessage=nil; NSString* connRefusedMessage=nil;
// requestTS=GSWTime_now();
listenHandle=[notification object]; listenHandle=[notification object];
inStream = [[notification userInfo] objectForKey:@"NSFileHandleNotificationFileHandleItem"]; inStream = [[notification userInfo] objectForKey:@"NSFileHandleNotificationFileHandleItem"];
// we want future Notifications. // we want future Notifications.
[listenHandle acceptConnectionInBackgroundAndNotify]; [listenHandle acceptConnectionInBackgroundAndNotify];
if (![self isConnectionAllowedWithHandle:inStream if (![self isConnectionAllowedWithHandle:inStream
returnedMessage:&connRefusedMessage]) { returnedMessage:&connRefusedMessage]) {
// don't waste any time // don't waste any time
[inStream closeFile]; [inStream closeFile];
return; return;
} }
// SYNCHRONIZED(_selfLock)
{
[_selfLock lock]; [_selfLock lock];
int count = [_threads count];
GSWWorkerThread * thread = nil;
if (count < _workerThreadCountMax) {
_workOnHandle(inStream,self, _threads, _isMultiThreadEnabled); if (_isMultiThreadEnabled) {
thread = [self _nextFreeThread];
if (thread) {
[thread setServerSocket:inStream];
} else { } else {
_queueWorkOnHandle(inStream, _waitingThreads); _queueWorkOnHandle(inStream, _waitingThreads);
} }
[_selfLock unlock];
} else {
_workOnHandle(inStream,self, _threads, _isMultiThreadEnabled);
} }
[_selfLock unlock];
// END_SYNCHRONIZED;
} }
-(NSFileHandle*)fileHandle -(NSFileHandle*)fileHandle
@ -414,7 +434,7 @@ void _queueWorkOnHandle(NSFileHandle* handle, NSMutableArray* waitingThreadArray
// CHECKME: find out if we really need this. -- dw // CHECKME: find out if we really need this. -- dw
-(id)workerThreadCountMax -(id)workerThreadCountMax
{ {
return [NSNumber numberWithInt:1000]; return [NSNumber numberWithInt:_workerThreadCountMax];
} }
// CHECKME: find out if we really need this. -- dw // CHECKME: find out if we really need this. -- dw

7
GSWeb/GSWDictionary.m Normal file → Executable file
View file

@ -35,6 +35,13 @@
@implementation GSWDictionary @implementation GSWDictionary
-(void) dealloc
{
DESTROY(_storageDict);
[super dealloc];
}
+ (instancetype) dictionary + (instancetype) dictionary
{ {
return AUTORELEASE([[self alloc] init]); return AUTORELEASE([[self alloc] init]);

5
GSWeb/GSWWorkerThread.h Normal file → Executable file
View file

@ -71,15 +71,18 @@
// int _inputBufferIndex; // int _inputBufferIndex;
// BOOL _keepAlive; // BOOL _keepAlive;
// BOOL _errorOnRead; // BOOL _errorOnRead;
// BOOL _runFlag; NSCondition * _queueCondition;
} }
- (void)setServerSocket:(NSFileHandle*)stream;
-(id)initWithApp:(GSWApplication*)application -(id)initWithApp:(GSWApplication*)application
adaptor:(GSWAdaptor*)adaptor adaptor:(GSWAdaptor*)adaptor
stream:(NSFileHandle*)stream; stream:(NSFileHandle*)stream;
-(void)runOnce; -(void)runOnce;
-(BOOL)isWorking;
@end @end

216
GSWeb/GSWWorkerThread.m Normal file → Executable file
View file

@ -32,16 +32,12 @@
#include <sys/socket.h> #include <sys/socket.h>
#include "GSWWOCompatibility.h" #include "GSWWOCompatibility.h"
#include "GSWWorkerThread.h" #include "GSWWorkerThread.h"
#include "GSWPrivate.h" #include "GSWPrivate.h"
#include "GSWDefines.h" #include "GSWDefines.h"
#include "GSWConstants.h" #include "GSWConstants.h"
#include "GSWUtils.h" #include "GSWUtils.h"
#include "GSWDebug.h" #include "GSWDebug.h"
#include "GSWRequest.h" #include "GSWRequest.h"
#include "GSWApplication.h" #include "GSWApplication.h"
#include "GSWAdaptor.h" #include "GSWAdaptor.h"
@ -49,28 +45,31 @@
#include "GSWResponse.h" #include "GSWResponse.h"
#include "GSWHTTPIO.h" #include "GSWHTTPIO.h"
//static NSData* lineFeedData=nil;
static NSString *REQUEST_ID = @"x-webobjects-request-id"; static NSString *REQUEST_ID = @"x-webobjects-request-id";
@interface NSThread (WeKnowWhatWeDo)
- (void)run;
@end
@implementation GSWWorkerThread @implementation GSWWorkerThread
+ (void) initialize + (void) initialize
{ {
if (self == [GSWWorkerThread class]) if (self == [GSWWorkerThread class])
{ {
// ASSIGN(lineFeedData,([[NSString stringWithString:@"\n"] dataUsingEncoding:NSASCIIStringEncoding]));
} }
} }
- (void)setServerSocket:(NSFileHandle*)stream
{
[_queueCondition lock];
ASSIGN(_serverSocket,stream);
[_queueCondition signal];
[_queueCondition unlock];
}
-(void)dealloc -(void)dealloc
{ {
// TODO: add vars! // TODO: add vars!
DESTROY(_serverSocket); DESTROY(_serverSocket);
DESTROY(_currentSocket); DESTROY(_currentSocket);
DESTROY(_queueCondition);
_app = nil; _app = nil;
_mtAdaptor = nil; _mtAdaptor = nil;
@ -82,40 +81,37 @@ static NSString *REQUEST_ID = @"x-webobjects-request-id";
adaptor:(GSWAdaptor*)adaptor adaptor:(GSWAdaptor*)adaptor
stream:(NSFileHandle*)stream stream:(NSFileHandle*)stream
{ {
if ((self = [self init])) { if ((self = [self init])) {
_app = application; _runFlag = NO;
_mtAdaptor = (GSWDefaultAdaptor*)adaptor; _app = application;
ASSIGN(_serverSocket,stream); _mtAdaptor = (GSWDefaultAdaptor*)adaptor;
_keepAlive=NO; ASSIGN(_serverSocket,stream);
_maxSocketIdleTime=900; // 300 ms _keepAlive=NO;
_isMultiThreadEnabled = [adaptor isMultiThreadEnabled]; _maxSocketIdleTime=900; // 300 ms
_isMultiThreadEnabled = [adaptor isMultiThreadEnabled];
if (_isMultiThreadEnabled) {
_t = [[NSThread alloc] initWithTarget:self if (_isMultiThreadEnabled) {
selector:@selector(runOnce) _queueCondition = [[NSCondition alloc] init];
object:nil];
_t = [[NSThread alloc] initWithTarget:self
[[NSNotificationCenter defaultCenter] addObserver: self selector:@selector(checkForWork)
selector:@selector(threadWillExit:) object:nil];
name:NSThreadWillExitNotification
object: _t]; [_t start];
_runFlag = YES; [_t autorelease];
[_t start]; } else {
[_t autorelease]; _runFlag = YES;
} else { _pool = [[NSAutoreleasePool alloc] init];
_runFlag = YES; [self runOnce];
_pool = [[NSAutoreleasePool alloc] init]; DESTROY(_pool);
[self runOnce];
DESTROY(_pool);
}
} }
return self;
}
return self;
} }
- (void)threadWillExit:(NSNotification*)notification - (void)threadWillExit:(NSNotification*)notification
{ {
[_mtAdaptor workerThreadWillExit:self];
_mtAdaptor = nil; _mtAdaptor = nil;
[[NSNotificationCenter defaultCenter] removeObserver: self]; [[NSNotificationCenter defaultCenter] removeObserver: self];
} }
@ -130,70 +126,91 @@ static NSString *REQUEST_ID = @"x-webobjects-request-id";
_currentSocket = nil; _currentSocket = nil;
} }
- (void) checkForWork
{
while (![[NSThread currentThread] isCancelled]) {
[_queueCondition lock];
[_queueCondition wait];
if (_serverSocket == nil) {
[_queueCondition unlock];
continue;
} else {
_runFlag = YES;
}
[_queueCondition unlock];
_pool = [[NSAutoreleasePool alloc] init];
[self runOnce];
DESTROY(_pool);
DESTROY(_serverSocket);
[_mtAdaptor workerThreadFinished:self];
}
}
-(void)runOnce -(void)runOnce
{ {
GSWRequest *request = nil; GSWRequest *request = nil;
struct timeval timeout; struct timeval timeout;
GSWResponse *response; GSWResponse *response;
if ((!_runFlag) || (_serverSocket == nil)) {
return;
}
_errorOnRead = NO;
// _maxSocketIdleTime is milisecs!
timeout.tv_sec = 0;
timeout.tv_usec = _maxSocketIdleTime * 1000;
NS_DURING {
setsockopt([_serverSocket fileDescriptor], SOL_SOCKET, SO_RCVTIMEO, &timeout,sizeof(timeout));
if ((!_runFlag) || (_serverSocket == nil)) { request = [GSWHTTPIO readRequestFromFromHandle: _serverSocket];
return; } NS_HANDLER {
_errorOnRead = YES;
NSLog(@"%s -- dropping connection reason: %@",__PRETTY_FUNCTION__, [localException reason]);
} NS_ENDHANDLER;
// "womp" is the request handler key used by the WOTaskD contacing your app
if ((_errorOnRead || (request == nil)) ||
((([[_app class] isDirectConnectEnabled] == NO) && ([request isUsingWebServer] == NO)) &&
([@"womp" isEqual:[request requestHandlerKey]] == NO))) {
goto done;
}
_processingRequest = YES;
_dispatchError = NO;
NS_DURING {
response = [_app dispatchRequest:request];
} NS_HANDLER {
NSLog(@"%s -- Exception occurred while responding to client: %@",
__PRETTY_FUNCTION__, [localException description]);
_dispatchError = YES;
response = [GSWDefaultAdaptor _lastDitchErrorResponse];
} NS_ENDHANDLER;
if (response) {
NSString * reqid = [request headerForKey:REQUEST_ID];
if (reqid) {
[response setHeader:reqid forKey:REQUEST_ID];
} }
_errorOnRead = NO;
// _maxSocketIdleTime is milisecs!
timeout.tv_sec = 0;
timeout.tv_usec = _maxSocketIdleTime * 1000;
NS_DURING { NS_DURING {
setsockopt([_serverSocket fileDescriptor], SOL_SOCKET, SO_RCVTIMEO, &timeout,sizeof(timeout)); [GSWHTTPIO sendResponse:response
toHandle: _serverSocket
request = [GSWHTTPIO readRequestFromFromHandle: _serverSocket]; request:request];
} NS_HANDLER { } NS_HANDLER {
_errorOnRead = YES; NSLog(@"%s -- Exception while sending response: %@",
NSLog(@"%s -- dropping connection reason: %@",__PRETTY_FUNCTION__, [localException reason]); __PRETTY_FUNCTION__, [localException description]);
} NS_ENDHANDLER; } NS_ENDHANDLER;
}
// "womp" is the request handler key used by the WOTaskD contacing your app
if ((_errorOnRead || (request == nil)) ||
((([[_app class] isDirectConnectEnabled] == NO) && ([request isUsingWebServer] == NO)) &&
([@"womp" isEqual:[request requestHandlerKey]] == NO))) {
goto done;
}
_processingRequest = YES;
_dispatchError = NO;
NS_DURING {
response = [_app dispatchRequest:request];
} NS_HANDLER {
NSLog(@"%s -- Exception occurred while responding to client: %@",
__PRETTY_FUNCTION__, [localException description]);
_dispatchError = YES;
response = [GSWDefaultAdaptor _lastDitchErrorResponse];
} NS_ENDHANDLER;
if (response) {
NSString * reqid = [request headerForKey:REQUEST_ID];
if (reqid) {
[response setHeader:reqid forKey:REQUEST_ID];
}
NS_DURING {
[GSWHTTPIO sendResponse:response
toHandle: _serverSocket
request:request];
} NS_HANDLER {
NSLog(@"%s -- Exception while sending response: %@",
__PRETTY_FUNCTION__, [localException description]);
} NS_ENDHANDLER;
}
done: done:
[self _closeSocket]; [self _closeSocket];
_processingRequest = NO; _processingRequest = NO;
_runFlag = NO;
} }
@ -209,9 +226,14 @@ done:
- (NSString*) description - (NSString*) description
{ {
return [NSString stringWithFormat:@"<%s %p socket:%@ >", return [NSString stringWithFormat:@"<%s %p socket:%@ isWorking:%s>",
object_getClassName(self), object_getClassName(self),
(void*)self, _serverSocket]; (void*)self, _serverSocket, _runFlag ? "YES" : "NO"];
}
-(BOOL)isWorking
{
return _runFlag;
} }
@end @end