mirror of
https://github.com/gnustep/libs-gsweb.git
synced 2025-02-19 10:01:05 +00:00
* 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:
parent
143b590b70
commit
e108560e37
5 changed files with 181 additions and 128 deletions
3
GSWeb/GSWDefaultAdaptor.h
Normal file → Executable file
3
GSWeb/GSWDefaultAdaptor.h
Normal file → Executable 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
78
GSWeb/GSWDefaultAdaptor.m
Normal file → Executable 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
7
GSWeb/GSWDictionary.m
Normal file → Executable 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
5
GSWeb/GSWWorkerThread.h
Normal file → Executable 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
216
GSWeb/GSWWorkerThread.m
Normal file → Executable 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
|
||||
|
|
Loading…
Reference in a new issue