* 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
returnedMessage:(NSString**)retMessage;
- (void) workerThreadWillExit:(GSWWorkerThread*) thread;
// GSW only
- (void) workerThreadFinished:(GSWWorkerThread*) thread;
-(void)stop;
-(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]]);
if ((_workerThreadCountMax <1) || (_isMultiThreadEnabled == NO)) {
_workerThreadCountMax = 1;
_workerThreadCountMax = 0;
_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;
}
@ -187,18 +199,16 @@ void _queueWorkOnHandle(NSFileHandle* handle, NSMutableArray* waitingThreadArray
atIndex: [waitingThreadArray count]];
}
// never called if single threaded.
- (void) workerThreadWillExit:(GSWWorkerThread*) thread
- (void) workerThreadFinished:(GSWWorkerThread*) thread
{
[_selfLock lock];
[thread retain];
[_threads removeObject: thread];
if ([_waitingThreads count]) {
_workOnHandle([_waitingThreads objectAtIndex:0], self, _threads, _isMultiThreadEnabled);
[_waitingThreads removeObjectAtIndex:0];
}
[thread autorelease];
if ([_waitingThreads count]) {
[thread setServerSocket:[_waitingThreads objectAtIndex:0]];
[_waitingThreads removeObjectAtIndex:0];
}
[_selfLock unlock];
}
//PRIVATE!
@ -268,44 +278,54 @@ void _queueWorkOnHandle(NSFileHandle* handle, NSMutableArray* waitingThreadArray
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
{
NSFileHandle *listenHandle=nil;
NSFileHandle *inStream = nil;
NSString* connRefusedMessage=nil;
// requestTS=GSWTime_now();
listenHandle=[notification object];
inStream = [[notification userInfo] objectForKey:@"NSFileHandleNotificationFileHandleItem"];
// we want future Notifications.
[listenHandle acceptConnectionInBackgroundAndNotify];
if (![self isConnectionAllowedWithHandle:inStream
returnedMessage:&connRefusedMessage]) {
// don't waste any time
[inStream closeFile];
return;
}
// SYNCHRONIZED(_selfLock)
{
[_selfLock lock];
int count = [_threads count];
if (count < _workerThreadCountMax) {
_workOnHandle(inStream,self, _threads, _isMultiThreadEnabled);
GSWWorkerThread * thread = nil;
if (_isMultiThreadEnabled) {
thread = [self _nextFreeThread];
if (thread) {
[thread setServerSocket:inStream];
} else {
_queueWorkOnHandle(inStream, _waitingThreads);
_queueWorkOnHandle(inStream, _waitingThreads);
}
[_selfLock unlock];
} else {
_workOnHandle(inStream,self, _threads, _isMultiThreadEnabled);
}
// END_SYNCHRONIZED;
[_selfLock unlock];
}
-(NSFileHandle*)fileHandle
@ -414,7 +434,7 @@ void _queueWorkOnHandle(NSFileHandle* handle, NSMutableArray* waitingThreadArray
// CHECKME: find out if we really need this. -- dw
-(id)workerThreadCountMax
{
return [NSNumber numberWithInt:1000];
return [NSNumber numberWithInt:_workerThreadCountMax];
}
// 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
-(void) dealloc
{
DESTROY(_storageDict);
[super dealloc];
}
+ (instancetype) dictionary
{
return AUTORELEASE([[self alloc] init]);

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

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

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

@ -32,16 +32,12 @@
#include <sys/socket.h>
#include "GSWWOCompatibility.h"
#include "GSWWorkerThread.h"
#include "GSWPrivate.h"
#include "GSWDefines.h"
#include "GSWConstants.h"
#include "GSWUtils.h"
#include "GSWDebug.h"
#include "GSWRequest.h"
#include "GSWApplication.h"
#include "GSWAdaptor.h"
@ -49,28 +45,31 @@
#include "GSWResponse.h"
#include "GSWHTTPIO.h"
//static NSData* lineFeedData=nil;
static NSString *REQUEST_ID = @"x-webobjects-request-id";
@interface NSThread (WeKnowWhatWeDo)
- (void)run;
@end
@implementation GSWWorkerThread
+ (void) initialize
{
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
{
// TODO: add vars!
DESTROY(_serverSocket);
DESTROY(_currentSocket);
DESTROY(_queueCondition);
_app = nil;
_mtAdaptor = nil;
@ -82,40 +81,37 @@ static NSString *REQUEST_ID = @"x-webobjects-request-id";
adaptor:(GSWAdaptor*)adaptor
stream:(NSFileHandle*)stream
{
if ((self = [self init])) {
_app = application;
_mtAdaptor = (GSWDefaultAdaptor*)adaptor;
ASSIGN(_serverSocket,stream);
_keepAlive=NO;
_maxSocketIdleTime=900; // 300 ms
_isMultiThreadEnabled = [adaptor isMultiThreadEnabled];
if (_isMultiThreadEnabled) {
_t = [[NSThread alloc] initWithTarget:self
selector:@selector(runOnce)
object:nil];
[[NSNotificationCenter defaultCenter] addObserver: self
selector:@selector(threadWillExit:)
name:NSThreadWillExitNotification
object: _t];
_runFlag = YES;
[_t start];
[_t autorelease];
} else {
_runFlag = YES;
_pool = [[NSAutoreleasePool alloc] init];
[self runOnce];
DESTROY(_pool);
}
if ((self = [self init])) {
_runFlag = NO;
_app = application;
_mtAdaptor = (GSWDefaultAdaptor*)adaptor;
ASSIGN(_serverSocket,stream);
_keepAlive=NO;
_maxSocketIdleTime=900; // 300 ms
_isMultiThreadEnabled = [adaptor isMultiThreadEnabled];
if (_isMultiThreadEnabled) {
_queueCondition = [[NSCondition alloc] init];
_t = [[NSThread alloc] initWithTarget:self
selector:@selector(checkForWork)
object:nil];
[_t start];
[_t autorelease];
} else {
_runFlag = YES;
_pool = [[NSAutoreleasePool alloc] init];
[self runOnce];
DESTROY(_pool);
}
return self;
}
return self;
}
- (void)threadWillExit:(NSNotification*)notification
{
[_mtAdaptor workerThreadWillExit:self];
_mtAdaptor = nil;
[[NSNotificationCenter defaultCenter] removeObserver: self];
}
@ -130,70 +126,91 @@ static NSString *REQUEST_ID = @"x-webobjects-request-id";
_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
{
GSWRequest *request = nil;
struct timeval timeout;
GSWResponse *response;
GSWRequest *request = nil;
struct timeval timeout;
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)) {
return;
request = [GSWHTTPIO readRequestFromFromHandle: _serverSocket];
} 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 {
setsockopt([_serverSocket fileDescriptor], SOL_SOCKET, SO_RCVTIMEO, &timeout,sizeof(timeout));
request = [GSWHTTPIO readRequestFromFromHandle: _serverSocket];
[GSWHTTPIO sendResponse:response
toHandle: _serverSocket
request:request];
} NS_HANDLER {
_errorOnRead = YES;
NSLog(@"%s -- dropping connection reason: %@",__PRETTY_FUNCTION__, [localException reason]);
NSLog(@"%s -- Exception while sending response: %@",
__PRETTY_FUNCTION__, [localException description]);
} 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:
[self _closeSocket];
_processingRequest = NO;
[self _closeSocket];
_processingRequest = NO;
_runFlag = NO;
}
@ -209,9 +226,14 @@ done:
- (NSString*) description
{
return [NSString stringWithFormat:@"<%s %p socket:%@ >",
return [NSString stringWithFormat:@"<%s %p socket:%@ isWorking:%s>",
object_getClassName(self),
(void*)self, _serverSocket];
(void*)self, _serverSocket, _runFlag ? "YES" : "NO"];
}
-(BOOL)isWorking
{
return _runFlag;
}
@end