* 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;

58
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);
[thread setServerSocket:[_waitingThreads objectAtIndex:0]];
[_waitingThreads removeObjectAtIndex:0];
}
[thread autorelease];
[_selfLock unlock];
}
//PRIVATE!
@ -268,6 +278,16 @@ 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
{
@ -275,15 +295,12 @@ void _queueWorkOnHandle(NSFileHandle* handle, NSMutableArray* waitingThreadArray
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
@ -291,20 +308,23 @@ void _queueWorkOnHandle(NSFileHandle* handle, NSMutableArray* waitingThreadArray
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);
}
[_selfLock unlock];
}
// END_SYNCHRONIZED;
} else {
_workOnHandle(inStream,self, _threads, _isMultiThreadEnabled);
}
[_selfLock unlock];
}
@ -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

64
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;
@ -83,6 +82,7 @@ static NSString *REQUEST_ID = @"x-webobjects-request-id";
stream:(NSFileHandle*)stream
{
if ((self = [self init])) {
_runFlag = NO;
_app = application;
_mtAdaptor = (GSWDefaultAdaptor*)adaptor;
ASSIGN(_serverSocket,stream);
@ -91,15 +91,12 @@ static NSString *REQUEST_ID = @"x-webobjects-request-id";
_isMultiThreadEnabled = [adaptor isMultiThreadEnabled];
if (_isMultiThreadEnabled) {
_queueCondition = [[NSCondition alloc] init];
_t = [[NSThread alloc] initWithTarget:self
selector:@selector(runOnce)
selector:@selector(checkForWork)
object:nil];
[[NSNotificationCenter defaultCenter] addObserver: self
selector:@selector(threadWillExit:)
name:NSThreadWillExitNotification
object: _t];
_runFlag = YES;
[_t start];
[_t autorelease];
} else {
@ -115,7 +112,6 @@ static NSString *REQUEST_ID = @"x-webobjects-request-id";
- (void)threadWillExit:(NSNotification*)notification
{
[_mtAdaptor workerThreadWillExit:self];
_mtAdaptor = nil;
[[NSNotificationCenter defaultCenter] removeObserver: self];
}
@ -130,6 +126,27 @@ 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;
@ -140,13 +157,11 @@ static NSString *REQUEST_ID = @"x-webobjects-request-id";
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));
@ -194,6 +209,8 @@ done:
[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