Monotone-Parent: 5bcd57a0e5cbbcf8047ad1d76568d8c74ced2932
Monotone-Revision: be431bdd93e6d75500bc17889aba62d9c2c91105 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2010-02-19T00:38:34 Monotone-Branch: ca.inverse.sogomaint-2.0.2
parent
f20478142f
commit
93a566cf9b
|
@ -5409,7 +5409,7 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
||||||
#if defined(__CYGWIN32__) || defined(__MINGW32__)
|
#if defined(__CYGWIN32__) || defined(__MINGW32__)
|
||||||
|
|
||||||
int WOWatchDogApplicationMain
|
int WOWatchDogApplicationMain
|
||||||
@@ -39,201 +60,911 @@
|
@@ -39,201 +60,875 @@
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
@ -5458,10 +5458,10 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
||||||
+@interface WOWatchDogChild : NSObject <RunLoopEvents>
|
+@interface WOWatchDogChild : NSObject <RunLoopEvents>
|
||||||
+{
|
+{
|
||||||
+ int pid;
|
+ int pid;
|
||||||
+ int SIGCHLDStatus;
|
|
||||||
+ int counter;
|
+ int counter;
|
||||||
+ NGActiveSocket *controlSocket;
|
+ NGActiveSocket *controlSocket;
|
||||||
+ WOChildStatus status;
|
+ WOChildStatus status;
|
||||||
|
+ NSTimer *killTimer;
|
||||||
+ WOWatchDog *watchDog;
|
+ WOWatchDog *watchDog;
|
||||||
+ NSCalendarDate *lastSpawn;
|
+ NSCalendarDate *lastSpawn;
|
||||||
+ BOOL loggedNotRespawn;
|
+ BOOL loggedNotRespawn;
|
||||||
|
@ -5472,9 +5472,7 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
||||||
+- (void) setPid: (int) newPid;
|
+- (void) setPid: (int) newPid;
|
||||||
+- (int) pid;
|
+- (int) pid;
|
||||||
+
|
+
|
||||||
+- (void) setSIGCHLDStatus: (int) newSIGCHLDStatus;
|
+- (void) handleProcessStatus: (int) status;
|
||||||
+- (int) SIGCHLDStatus;
|
|
||||||
+- (void) handleSIGCHLDStatus;
|
|
||||||
+
|
+
|
||||||
+- (void) setControlSocket: (NGActiveSocket *) newSocket;
|
+- (void) setControlSocket: (NGActiveSocket *) newSocket;
|
||||||
+- (NGActiveSocket *) controlSocket;
|
+- (NGActiveSocket *) controlSocket;
|
||||||
|
@ -5500,10 +5498,10 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
||||||
+ int argc;
|
+ int argc;
|
||||||
+ const char **argv;
|
+ const char **argv;
|
||||||
+
|
+
|
||||||
|
+ NSTimer *loopTimer;
|
||||||
+ BOOL terminate;
|
+ BOOL terminate;
|
||||||
+ BOOL willTerminate;
|
+ BOOL willTerminate;
|
||||||
+ NSNumber *terminationSignal;
|
+ NSNumber *terminationSignal;
|
||||||
+ int pendingSIGCHLD;
|
|
||||||
+ int pendingSIGHUP;
|
+ int pendingSIGHUP;
|
||||||
+
|
+
|
||||||
+ NGPassiveSocket *listeningSocket;
|
+ NGPassiveSocket *listeningSocket;
|
||||||
|
@ -5543,8 +5541,8 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
||||||
+ {
|
+ {
|
||||||
+ pid = -1;
|
+ pid = -1;
|
||||||
+ controlSocket = nil;
|
+ controlSocket = nil;
|
||||||
+ SIGCHLDStatus = -1;
|
|
||||||
+ status = WOChildStatusDown;
|
+ status = WOChildStatusDown;
|
||||||
|
+ killTimer = nil;
|
||||||
+ counter = 0;
|
+ counter = 0;
|
||||||
+ lastSpawn = nil;
|
+ lastSpawn = nil;
|
||||||
+ loggedNotRespawn = NO;
|
+ loggedNotRespawn = NO;
|
||||||
|
@ -5571,6 +5569,7 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
||||||
+
|
+
|
||||||
+- (void) dealloc
|
+- (void) dealloc
|
||||||
+{
|
+{
|
||||||
|
+ [killTimer invalidate];
|
||||||
+ [self setControlSocket: nil];
|
+ [self setControlSocket: nil];
|
||||||
+ [lastSpawn release];
|
+ [lastSpawn release];
|
||||||
+ [super dealloc];
|
+ [super dealloc];
|
||||||
|
@ -5591,31 +5590,22 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
||||||
+ return pid;
|
+ return pid;
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+- (void) setSIGCHLDStatus: (int) newSIGCHLDStatus
|
+- (void) handleProcessStatus: (int) processStatus
|
||||||
+{
|
|
||||||
+ SIGCHLDStatus = newSIGCHLDStatus;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+- (int) SIGCHLDStatus
|
|
||||||
+{
|
|
||||||
+ return SIGCHLDStatus;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+- (void) handleSIGCHLDStatus
|
|
||||||
+{
|
+{
|
||||||
+ int code;
|
+ int code;
|
||||||
+
|
+
|
||||||
+ [self logWithFormat: @"received SIGCHLD from pid %d", pid];
|
+ code = WEXITSTATUS (processStatus);
|
||||||
+ code = WEXITSTATUS (SIGCHLDStatus);
|
+ if (code == 0)
|
||||||
+ if (code != 0)
|
+ [self logWithFormat: @"child %d exited", pid];
|
||||||
|
+ else
|
||||||
+ [self logWithFormat: @"child %d exited with code %i", pid, code];
|
+ [self logWithFormat: @"child %d exited with code %i", pid, code];
|
||||||
+ if (WIFSIGNALED (SIGCHLDStatus))
|
+ if (WIFSIGNALED (processStatus))
|
||||||
+ [self logWithFormat: @" (terminated due to signal %i%@)",
|
+ [self logWithFormat: @" (terminated due to signal %i%@)",
|
||||||
+ WTERMSIG (SIGCHLDStatus),
|
+ WTERMSIG (processStatus),
|
||||||
+ WCOREDUMP (SIGCHLDStatus) ? @", coredump" : @""];
|
+ WCOREDUMP (processStatus) ? @", coredump" : @""];
|
||||||
+ if (WIFSTOPPED (SIGCHLDStatus))
|
+ if (WIFSTOPPED (processStatus))
|
||||||
+ [self logWithFormat: @" (stopped due to signal %i)", WSTOPSIG (SIGCHLDStatus)];
|
+ [self logWithFormat: @" (stopped due to signal %i)",
|
||||||
+ SIGCHLDStatus = -1;
|
+ WSTOPSIG (processStatus)];
|
||||||
+ [self setStatus: WOChildStatusDown];
|
+ [self setStatus: WOChildStatusDown];
|
||||||
+ [self setControlSocket: nil];
|
+ [self setControlSocket: nil];
|
||||||
+}
|
+}
|
||||||
|
@ -5682,34 +5672,14 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
||||||
}
|
}
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+- (BOOL) readMessage
|
+- (void) _killKill
|
||||||
+{
|
+{
|
||||||
+ WOChildMessage message;
|
+ if (status != WOChildStatusDown) {
|
||||||
+ BOOL rc;
|
+ [self warnWithFormat: @"safety belt -- sending KILL signal to pid %d",
|
||||||
+
|
+ pid];
|
||||||
+ if ([controlSocket readBytes: &message
|
+ kill (pid, SIGKILL);
|
||||||
+ count: sizeof (WOChildMessage)] == NGStreamError) {
|
+ killTimer = nil;
|
||||||
+ rc = NO;
|
|
||||||
+ [self errorWithFormat: @"FAILURE receiving status for child %d", pid];
|
|
||||||
+ [self errorWithFormat: @" socket: %@", controlSocket];
|
|
||||||
}
|
}
|
||||||
+ else {
|
|
||||||
+ rc = YES;
|
|
||||||
+ if (message == WOChildMessageAccept) {
|
|
||||||
+ status = WOChildStatusBusy;
|
|
||||||
+ }
|
|
||||||
+ else if (message == WOChildMessageReady) {
|
|
||||||
+ status = WOChildStatusReady;
|
|
||||||
+ [watchDog declareChildReady: self];
|
|
||||||
+ }
|
|
||||||
+ // else if (message == WOChildMessageShutdown) {
|
|
||||||
+ // status = WOChildStatusDown;
|
|
||||||
+ // [watchDog declareChildDown: self];
|
|
||||||
+ // }
|
|
||||||
+ // [self logStatus];
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
-static void _writePid(NSString *pidFile) {
|
-static void _writePid(NSString *pidFile) {
|
||||||
|
@ -5720,38 +5690,63 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
||||||
- fprintf(pf, "%i\n", getpid());
|
- fprintf(pf, "%i\n", getpid());
|
||||||
- fflush(pf);
|
- fflush(pf);
|
||||||
- fclose(pf);
|
- fclose(pf);
|
||||||
+- (BOOL) _sendMessage: (WOChildMessage) message
|
|
||||||
+{
|
|
||||||
+ return ([controlSocket writeBytes: &message
|
|
||||||
+ count: sizeof (WOChildMessage)] != NGStreamError
|
|
||||||
+ && [self readMessage]);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+- (void) _killKill
|
|
||||||
+{
|
|
||||||
+ if (status != WOChildStatusDown) {
|
|
||||||
+ [self warnWithFormat: @"sending KILL signal to pid %d", pid];
|
|
||||||
+ kill (pid, SIGKILL);
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+- (void) _kill
|
+- (void) _kill
|
||||||
+{
|
+{
|
||||||
+ if (status != WOChildStatusDown) {
|
+ if (status != WOChildStatusDown) {
|
||||||
+ [self logWithFormat: @"sending terminate signal to pid %d", pid];
|
+ [self logWithFormat: @"sending terminate signal to pid %d", pid];
|
||||||
+ status = WOChildStatusTerminating;
|
+ status = WOChildStatusTerminating;
|
||||||
+ kill (pid, SIGTERM);
|
+ kill (pid, SIGTERM);
|
||||||
+ /* We hardcode a 5 minutes delay before ensuring that all children are
|
|
||||||
+ terminated. This enables long requests to finish properly while
|
|
||||||
+ avoiding 100% CPU usage for deadlocked children. */
|
|
||||||
+ [NSTimer scheduledTimerWithTimeInterval: 5.0 * 60
|
|
||||||
+ target: self
|
|
||||||
+ selector: @selector (_killKill)
|
|
||||||
+ userInfo: nil
|
|
||||||
+ repeats: NO];
|
|
||||||
+ }
|
+ }
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
|
+- (BOOL) readMessage
|
||||||
|
+{
|
||||||
|
+ WOChildMessage message;
|
||||||
|
+ BOOL rc;
|
||||||
|
+
|
||||||
|
+ if ([controlSocket readBytes: &message
|
||||||
|
+ count: sizeof (WOChildMessage)] == NGStreamError) {
|
||||||
|
+ rc = NO;
|
||||||
|
+ [self errorWithFormat: @"FAILURE receiving status for child %d", pid];
|
||||||
|
+ [self errorWithFormat: @" socket: %@", controlSocket];
|
||||||
|
+ [self _kill];
|
||||||
|
+ }
|
||||||
|
+ else {
|
||||||
|
+ rc = YES;
|
||||||
|
+ if (message == WOChildMessageAccept) {
|
||||||
|
+ status = WOChildStatusBusy;
|
||||||
|
+ /* We schedule a 10 minutes grace period while the child is processing
|
||||||
|
+ the request. This enables long requests to complete while providing a
|
||||||
|
+ safety belt for children gone rogue. */
|
||||||
|
+ killTimer
|
||||||
|
+ = [NSTimer scheduledTimerWithTimeInterval: 10.0 * 60
|
||||||
|
+ target: self
|
||||||
|
+ selector: @selector (_killKill)
|
||||||
|
+ userInfo: nil
|
||||||
|
+ repeats: NO];
|
||||||
|
}
|
||||||
|
+ else if (message == WOChildMessageReady) {
|
||||||
|
+ status = WOChildStatusReady;
|
||||||
|
+ [killTimer invalidate];
|
||||||
|
+ killTimer = nil;
|
||||||
|
+ [watchDog declareChildReady: self];
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ return rc;
|
||||||
|
}
|
||||||
|
-static void _delPid(void) {
|
||||||
|
- if ([pidFile length] > 0) {
|
||||||
|
- if (unlink([pidFile cString]) == 0)
|
||||||
|
- pidFile = nil;
|
||||||
|
+
|
||||||
|
+- (BOOL) _sendMessage: (WOChildMessage) message
|
||||||
|
+{
|
||||||
|
+ return ([controlSocket writeBytes: &message
|
||||||
|
+ count: sizeof (WOChildMessage)] != NGStreamError
|
||||||
|
+ && [self readMessage]);
|
||||||
|
+}
|
||||||
|
+
|
||||||
+- (void) notify
|
+- (void) notify
|
||||||
+{
|
+{
|
||||||
+ WOChildMessage message;
|
+ WOChildMessage message;
|
||||||
|
@ -5761,9 +5756,12 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
||||||
+ if (![self _sendMessage: message]) {
|
+ if (![self _sendMessage: message]) {
|
||||||
+ [self errorWithFormat: @"FAILURE notifying child %d", pid];
|
+ [self errorWithFormat: @"FAILURE notifying child %d", pid];
|
||||||
+ [self _kill];
|
+ [self _kill];
|
||||||
+ }
|
}
|
||||||
+}
|
}
|
||||||
+
|
|
||||||
|
-static void exitWatchdog(void) {
|
||||||
|
- killChild();
|
||||||
|
- _delPid();
|
||||||
+- (void) terminate
|
+- (void) terminate
|
||||||
+{
|
+{
|
||||||
+ if (status == WOChildStatusDown) {
|
+ if (status == WOChildStatusDown) {
|
||||||
|
@ -5772,8 +5770,17 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
||||||
+ [self setControlSocket: nil];
|
+ [self setControlSocket: nil];
|
||||||
+ [self _kill];
|
+ [self _kill];
|
||||||
+ }
|
+ }
|
||||||
+}
|
}
|
||||||
+
|
|
||||||
|
-static void wsignalHandler(int _signal) {
|
||||||
|
- switch (_signal) {
|
||||||
|
- case SIGINT:
|
||||||
|
- /* Control-C */
|
||||||
|
- fprintf(stderr, "[%i]: watchdog handling signal ctrl-c ..\n", getpid());
|
||||||
|
- killChild();
|
||||||
|
- exit(0);
|
||||||
|
- /* shouldn't get here */
|
||||||
|
- abort();
|
||||||
+- (void) receivedEvent: (void*)data
|
+- (void) receivedEvent: (void*)data
|
||||||
+ type: (RunLoopEventType)type
|
+ type: (RunLoopEventType)type
|
||||||
+ extra: (void*)extra
|
+ extra: (void*)extra
|
||||||
|
@ -5791,174 +5798,6 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
||||||
+ [self setControlSocket: nil];
|
+ [self setControlSocket: nil];
|
||||||
+ }
|
+ }
|
||||||
+}
|
+}
|
||||||
+
|
|
||||||
+@end
|
|
||||||
+
|
|
||||||
+@implementation WOWatchDog
|
|
||||||
+
|
|
||||||
++ (id) sharedWatchDog
|
|
||||||
+{
|
|
||||||
+ static WOWatchDog *sharedWatchDog = nil;
|
|
||||||
+
|
|
||||||
+ if (!sharedWatchDog)
|
|
||||||
+ sharedWatchDog = [self new];
|
|
||||||
+
|
|
||||||
+ return sharedWatchDog;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+- (id) init
|
|
||||||
+{
|
|
||||||
+ if ((self = [super init]))
|
|
||||||
+ {
|
|
||||||
+ listeningSocket = nil;
|
|
||||||
+ terminate = NO;
|
|
||||||
+ willTerminate = NO;
|
|
||||||
+ terminationSignal = nil;
|
|
||||||
+ pendingSIGCHLD = 0;
|
|
||||||
+ pendingSIGHUP = 0;
|
|
||||||
+
|
|
||||||
+ numberOfChildren = 0;
|
|
||||||
+ children = [[NSMutableArray alloc] initWithCapacity: 10];
|
|
||||||
+ readyChildren = [[NSMutableArray alloc] initWithCapacity: 10];
|
|
||||||
+ downChildren = [[NSMutableArray alloc] initWithCapacity: 10];
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+ return self;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+- (void) _releaseListeningSocket
|
|
||||||
+{
|
|
||||||
+ if (listeningSocket) {
|
|
||||||
+ [[NSRunLoop currentRunLoop] removeEvent: (void *) [listeningSocket fileDescriptor]
|
|
||||||
+ type: ET_RDESC
|
|
||||||
+ forMode: NSDefaultRunLoopMode
|
|
||||||
+ all: YES];
|
|
||||||
+ [listeningSocket close];
|
|
||||||
+ [listeningSocket release];
|
|
||||||
+ listeningSocket = nil;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-static void _delPid(void) {
|
|
||||||
- if ([pidFile length] > 0) {
|
|
||||||
- if (unlink([pidFile cString]) == 0)
|
|
||||||
- pidFile = nil;
|
|
||||||
+
|
|
||||||
+- (void) dealloc
|
|
||||||
+{
|
|
||||||
+ [self _releaseListeningSocket];
|
|
||||||
+ [terminationSignal release];
|
|
||||||
+ [appName release];
|
|
||||||
+ [children release];
|
|
||||||
+ [super dealloc];
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+- (void) _runChildWithControlSocket: (NGActiveSocket *) controlSocket
|
|
||||||
+{
|
|
||||||
+ WOApplication *app;
|
|
||||||
+ extern char **environ;
|
|
||||||
+
|
|
||||||
+ [NSProcessInfo initializeWithArguments: (char **) argv
|
|
||||||
+ count: argc
|
|
||||||
+ environment: environ];
|
|
||||||
+ NGInitTextStdio();
|
|
||||||
+ app = [NSClassFromString(appName) new];
|
|
||||||
+ [app autorelease];
|
|
||||||
+ [app setListeningSocket: listeningSocket];
|
|
||||||
+ [app setControlSocket: controlSocket];
|
|
||||||
+ [app run];
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+- (void) receivedEvent: (void*)data
|
|
||||||
+ type: (RunLoopEventType)type
|
|
||||||
+ extra: (void*)extra
|
|
||||||
+ forMode: (NSString*)mode
|
|
||||||
+{
|
|
||||||
+ int nextId;
|
|
||||||
+ WOWatchDogChild *child;
|
|
||||||
+
|
|
||||||
+ // NSLog (@"have a child accept the connection");
|
|
||||||
+ nextId = [readyChildren count] - 1;
|
|
||||||
+ if (nextId > -1)
|
|
||||||
+ {
|
|
||||||
+ child = [readyChildren objectAtIndex: nextId];
|
|
||||||
+ [readyChildren removeObjectAtIndex: nextId];
|
|
||||||
+ [child notify];
|
|
||||||
+ }
|
|
||||||
+ // else
|
|
||||||
+ // NSLog (@"all children busy");
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+- (void) _cleanupSignalAndEventHandlers
|
|
||||||
+{
|
|
||||||
+ int count;
|
|
||||||
+ NSRunLoop *runLoop;
|
|
||||||
+
|
|
||||||
+ [[UnixSignalHandler sharedHandler] removeObserver: self];
|
|
||||||
+
|
|
||||||
+ runLoop = [NSRunLoop currentRunLoop];
|
|
||||||
+ [runLoop removeEvent: (void *) [listeningSocket fileDescriptor]
|
|
||||||
+ type: ET_RDESC
|
|
||||||
+ forMode: NSDefaultRunLoopMode
|
|
||||||
+ all: YES];
|
|
||||||
+
|
|
||||||
+ for (count = 0; count < numberOfChildren; count++) {
|
|
||||||
+ [[children objectAtIndex: count] setControlSocket: nil];
|
|
||||||
+ // controlSocket = [[children objectAtIndex: count] controlSocket];
|
|
||||||
+ // if (controlSocket)
|
|
||||||
+ // [runLoop removeEvent: (void *) [controlSocket fileDescriptor]
|
|
||||||
+ // type: ET_RDESC
|
|
||||||
+ // forMode: NSDefaultRunLoopMode
|
|
||||||
+ // all: YES];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-static void exitWatchdog(void) {
|
|
||||||
- killChild();
|
|
||||||
- _delPid();
|
|
||||||
+- (BOOL) _spawnChild: (WOWatchDogChild *) child
|
|
||||||
+{
|
|
||||||
+ NGActiveSocket *pair[2];
|
|
||||||
+ BOOL isChild;
|
|
||||||
+ int childPid;
|
|
||||||
+ extern char **environ;
|
|
||||||
+
|
|
||||||
+ isChild = NO;
|
|
||||||
+
|
|
||||||
+ if ([NGActiveSocket socketPair: pair]) {
|
|
||||||
+ childPid = fork ();
|
|
||||||
+ if (childPid == 0) {
|
|
||||||
+ setsid ();
|
|
||||||
+ isChild = YES;
|
|
||||||
+ [self _cleanupSignalAndEventHandlers];
|
|
||||||
+ [self _runChildWithControlSocket: pair[0]];
|
|
||||||
+ } else if (childPid > 0) {
|
|
||||||
+ [self logWithFormat: @"child spawned with pid %d", childPid];
|
|
||||||
+ [child setPid: childPid];
|
|
||||||
+ [child setStatus: WOChildStatusSpawning];
|
|
||||||
+ [child setControlSocket: pair[1]];
|
|
||||||
+ [child setLastSpawn: [NSCalendarDate date]];
|
|
||||||
+ // [self logWithFormat: @"parent ready for child: %d", childPid];
|
|
||||||
+ } else {
|
|
||||||
+ perror ("fork");
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return isChild;
|
|
||||||
}
|
|
||||||
|
|
||||||
-static void wsignalHandler(int _signal) {
|
|
||||||
- switch (_signal) {
|
|
||||||
- case SIGINT:
|
|
||||||
- /* Control-C */
|
|
||||||
- fprintf(stderr, "[%i]: watchdog handling signal ctrl-c ..\n", getpid());
|
|
||||||
- killChild();
|
|
||||||
- exit(0);
|
|
||||||
- /* shouldn't get here */
|
|
||||||
- abort();
|
|
||||||
+- (void) _ensureNumberOfChildren
|
|
||||||
+{
|
|
||||||
+ int currentNumber, delta, count, min, max;
|
|
||||||
+ WOWatchDogChild *child;
|
|
||||||
|
|
||||||
- case SIGSEGV:
|
- case SIGSEGV:
|
||||||
- /* Coredump ! */
|
- /* Coredump ! */
|
||||||
|
@ -5970,31 +5809,7 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
||||||
- exit(123);
|
- exit(123);
|
||||||
- /* shouldn't get here */
|
- /* shouldn't get here */
|
||||||
- abort();
|
- abort();
|
||||||
+ currentNumber = [children count];
|
+@end
|
||||||
+ if (currentNumber < numberOfChildren) {
|
|
||||||
+ delta = numberOfChildren - currentNumber;
|
|
||||||
+ for (count = 0; count < delta; count++) {
|
|
||||||
+ child = [WOWatchDogChild watchDogChild];
|
|
||||||
+ [child setWatchDog: self];
|
|
||||||
+ [children addObject: child];
|
|
||||||
+ [downChildren addObject: child];
|
|
||||||
+ }
|
|
||||||
+ [self logWithFormat: @"preparing %d children", delta];
|
|
||||||
+ }
|
|
||||||
+ else if (currentNumber > numberOfChildren) {
|
|
||||||
+ delta = currentNumber - numberOfChildren;
|
|
||||||
+ max = [downChildren count];
|
|
||||||
+ if (max > delta)
|
|
||||||
+ min = max - delta;
|
|
||||||
+ else
|
|
||||||
+ min = 0;
|
|
||||||
+ for (count = max - 1; count >= min; count--) {
|
|
||||||
+ child = [downChildren objectAtIndex: count];
|
|
||||||
+ [downChildren removeObjectAtIndex: count];
|
|
||||||
+ [children removeObject: child];
|
|
||||||
+ delta--;
|
|
||||||
+ [self logWithFormat: @"%d processes purged from pool", delta];
|
|
||||||
+ }
|
|
||||||
|
|
||||||
- case SIGTERM:
|
- case SIGTERM:
|
||||||
- /* TERM signal (kill 'pid') */
|
- /* TERM signal (kill 'pid') */
|
||||||
|
@ -6019,17 +5834,47 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
||||||
- fprintf(stderr, "[%i]: watchdog handling signal %i ..\n",
|
- fprintf(stderr, "[%i]: watchdog handling signal %i ..\n",
|
||||||
- getpid(), _signal);
|
- getpid(), _signal);
|
||||||
- break;
|
- break;
|
||||||
+ max = [readyChildren count];
|
+@implementation WOWatchDog
|
||||||
+ if (max > delta)
|
+
|
||||||
+ max -= delta;
|
++ (id) sharedWatchDog
|
||||||
+ for (count = max - 1; count > -1; count--) {
|
+{
|
||||||
+ child = [readyChildren objectAtIndex: count];
|
+ static WOWatchDog *sharedWatchDog = nil;
|
||||||
+ [readyChildren removeObjectAtIndex: count];
|
+
|
||||||
+ [child terminate];
|
+ if (!sharedWatchDog)
|
||||||
+ [child setStatus: WOChildStatusExcessive];
|
+ sharedWatchDog = [self new];
|
||||||
+ delta--;
|
+
|
||||||
|
+ return sharedWatchDog;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+- (id) init
|
||||||
|
+{
|
||||||
|
+ if ((self = [super init]))
|
||||||
|
+ {
|
||||||
|
+ listeningSocket = nil;
|
||||||
|
+ terminate = NO;
|
||||||
|
+ willTerminate = NO;
|
||||||
|
+ terminationSignal = nil;
|
||||||
|
+ pendingSIGHUP = 0;
|
||||||
|
+
|
||||||
|
+ numberOfChildren = 0;
|
||||||
|
+ children = [[NSMutableArray alloc] initWithCapacity: 10];
|
||||||
|
+ readyChildren = [[NSMutableArray alloc] initWithCapacity: 10];
|
||||||
|
+ downChildren = [[NSMutableArray alloc] initWithCapacity: 10];
|
||||||
+ }
|
+ }
|
||||||
+ [self logWithFormat: @"%d processes left to terminate", delta];
|
+
|
||||||
|
+ return self;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+- (void) _releaseListeningSocket
|
||||||
|
+{
|
||||||
|
+ if (listeningSocket) {
|
||||||
|
+ [[NSRunLoop currentRunLoop] removeEvent: (void *) [listeningSocket fileDescriptor]
|
||||||
|
+ type: ET_RDESC
|
||||||
|
+ forMode: NSDefaultRunLoopMode
|
||||||
|
+ all: YES];
|
||||||
|
+ [listeningSocket close];
|
||||||
|
+ [listeningSocket release];
|
||||||
|
+ listeningSocket = nil;
|
||||||
}
|
}
|
||||||
- fflush(stderr);
|
- fflush(stderr);
|
||||||
-
|
-
|
||||||
|
@ -6072,6 +5917,140 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
||||||
-
|
-
|
||||||
- fprintf(stderr, "\n");
|
- fprintf(stderr, "\n");
|
||||||
- fflush(stderr);
|
- fflush(stderr);
|
||||||
|
+- (void) dealloc
|
||||||
|
+{
|
||||||
|
+ [self _releaseListeningSocket];
|
||||||
|
+ [terminationSignal release];
|
||||||
|
+ [appName release];
|
||||||
|
+ [children release];
|
||||||
|
+ [super dealloc];
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+- (void) _runChildWithControlSocket: (NGActiveSocket *) controlSocket
|
||||||
|
+{
|
||||||
|
+ WOApplication *app;
|
||||||
|
+ extern char **environ;
|
||||||
|
+
|
||||||
|
+ [NSProcessInfo initializeWithArguments: (char **) argv
|
||||||
|
+ count: argc
|
||||||
|
+ environment: environ];
|
||||||
|
+ NGInitTextStdio();
|
||||||
|
+ app = [NSClassFromString(appName) new];
|
||||||
|
+ [app autorelease];
|
||||||
|
+ [app setListeningSocket: listeningSocket];
|
||||||
|
+ [app setControlSocket: controlSocket];
|
||||||
|
+ [app run];
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+- (void) receivedEvent: (void*)data
|
||||||
|
+ type: (RunLoopEventType)type
|
||||||
|
+ extra: (void*)extra
|
||||||
|
+ forMode: (NSString*)mode
|
||||||
|
+{
|
||||||
|
+ int nextId;
|
||||||
|
+ WOWatchDogChild *child;
|
||||||
|
+
|
||||||
|
+ nextId = [readyChildren count] - 1;
|
||||||
|
+ if (nextId > -1) {
|
||||||
|
+ child = [readyChildren objectAtIndex: nextId];
|
||||||
|
+ [readyChildren removeObjectAtIndex: nextId];
|
||||||
|
+ [child notify];
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+- (void) _cleanupSignalAndEventHandlers
|
||||||
|
+{
|
||||||
|
+ int count;
|
||||||
|
+ NSRunLoop *runLoop;
|
||||||
|
+
|
||||||
|
+ [[UnixSignalHandler sharedHandler] removeObserver: self];
|
||||||
|
+ [loopTimer invalidate];
|
||||||
|
+ loopTimer = nil;
|
||||||
|
+ runLoop = [NSRunLoop currentRunLoop];
|
||||||
|
+ [runLoop removeEvent: (void *) [listeningSocket fileDescriptor]
|
||||||
|
+ type: ET_RDESC
|
||||||
|
+ forMode: NSDefaultRunLoopMode
|
||||||
|
+ all: YES];
|
||||||
|
+
|
||||||
|
+ for (count = 0; count < numberOfChildren; count++)
|
||||||
|
+ [[children objectAtIndex: count] setControlSocket: nil];
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+- (BOOL) _spawnChild: (WOWatchDogChild *) child
|
||||||
|
+{
|
||||||
|
+ NGActiveSocket *pair[2];
|
||||||
|
+ BOOL isChild;
|
||||||
|
+ int childPid;
|
||||||
|
+ extern char **environ;
|
||||||
|
+
|
||||||
|
+ isChild = NO;
|
||||||
|
+
|
||||||
|
+ if ([NGActiveSocket socketPair: pair]) {
|
||||||
|
+ childPid = fork ();
|
||||||
|
+ if (childPid == 0) {
|
||||||
|
+ setsid ();
|
||||||
|
+ isChild = YES;
|
||||||
|
+ [self _cleanupSignalAndEventHandlers];
|
||||||
|
+ [self _runChildWithControlSocket: pair[0]];
|
||||||
|
+ } else if (childPid > 0) {
|
||||||
|
+ [self logWithFormat: @"child spawned with pid %d", childPid];
|
||||||
|
+ [child setPid: childPid];
|
||||||
|
+ [child setStatus: WOChildStatusSpawning];
|
||||||
|
+ [child setControlSocket: pair[1]];
|
||||||
|
+ [child setLastSpawn: [NSCalendarDate date]];
|
||||||
|
+ } else {
|
||||||
|
+ perror ("fork");
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return isChild;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+- (void) _ensureNumberOfChildren
|
||||||
|
+{
|
||||||
|
+ int currentNumber, delta, count, min, max;
|
||||||
|
+ WOWatchDogChild *child;
|
||||||
|
+
|
||||||
|
+ currentNumber = [children count];
|
||||||
|
+ if (currentNumber < numberOfChildren) {
|
||||||
|
+ delta = numberOfChildren - currentNumber;
|
||||||
|
+ for (count = 0; count < delta; count++) {
|
||||||
|
+ child = [WOWatchDogChild watchDogChild];
|
||||||
|
+ [child setWatchDog: self];
|
||||||
|
+ [children addObject: child];
|
||||||
|
+ [downChildren addObject: child];
|
||||||
|
+ }
|
||||||
|
+ [self logWithFormat: @"preparing %d children", delta];
|
||||||
|
+ }
|
||||||
|
+ else if (currentNumber > numberOfChildren) {
|
||||||
|
+ delta = currentNumber - numberOfChildren;
|
||||||
|
+ max = [downChildren count];
|
||||||
|
+ if (max > delta)
|
||||||
|
+ min = max - delta;
|
||||||
|
+ else
|
||||||
|
+ min = 0;
|
||||||
|
+ for (count = max - 1; count >= min; count--) {
|
||||||
|
+ child = [downChildren objectAtIndex: count];
|
||||||
|
+ [downChildren removeObjectAtIndex: count];
|
||||||
|
+ [children removeObject: child];
|
||||||
|
+ delta--;
|
||||||
|
+ [self logWithFormat: @"%d processes purged from pool", delta];
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ max = [readyChildren count];
|
||||||
|
+ if (max > delta)
|
||||||
|
+ max -= delta;
|
||||||
|
+ for (count = max - 1; count > -1; count--) {
|
||||||
|
+ child = [readyChildren objectAtIndex: count];
|
||||||
|
+ [readyChildren removeObjectAtIndex: count];
|
||||||
|
+ [child terminate];
|
||||||
|
+ [child setStatus: WOChildStatusExcessive];
|
||||||
|
+ delta--;
|
||||||
|
+ }
|
||||||
|
+ [self logWithFormat: @"%d processes left to terminate", delta];
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
+- (void) _noop
|
+- (void) _noop
|
||||||
+{
|
+{
|
||||||
+}
|
+}
|
||||||
|
@ -6141,6 +6120,7 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
||||||
+ NGInternetSocketAddress *listeningAddress;
|
+ NGInternetSocketAddress *listeningAddress;
|
||||||
+ NSUserDefaults *ud;
|
+ NSUserDefaults *ud;
|
||||||
+ id port, allow;
|
+ id port, allow;
|
||||||
|
+ static BOOL warnedAboutAllow = NO;
|
||||||
+
|
+
|
||||||
+ listeningAddress = nil;
|
+ listeningAddress = nil;
|
||||||
+
|
+
|
||||||
|
@ -6153,8 +6133,12 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
||||||
}
|
}
|
||||||
- signal(_signal, signalHandler);
|
- signal(_signal, signalHandler);
|
||||||
+ allow = [ud objectForKey:@"WOHttpAllowHost"];
|
+ allow = [ud objectForKey:@"WOHttpAllowHost"];
|
||||||
+ if (allow)
|
+ if (allow && !warnedAboutAllow) {
|
||||||
+ [self warnWithFormat: @"'WOHttpAllowHost' is ignored in watchdog mode, use a real firewall instead"];
|
+ [self warnWithFormat: @"'WOHttpAllowHost' is ignored in watchdog mode,"
|
||||||
|
+ @" use a real firewall instead"];
|
||||||
|
+ warnedAboutAllow = YES;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
+ if ([port isKindOfClass: [NSString class]]) {
|
+ if ([port isKindOfClass: [NSString class]]) {
|
||||||
+ if ([port isEqualToString: @"auto"]) {
|
+ if ([port isEqualToString: @"auto"]) {
|
||||||
+ listeningAddress
|
+ listeningAddress
|
||||||
|
@ -6211,7 +6195,6 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
||||||
+ rc = YES;
|
+ rc = YES;
|
||||||
+ }
|
+ }
|
||||||
+ NS_HANDLER {
|
+ NS_HANDLER {
|
||||||
+ // [self logWithFormat:@"failure listening on address 127.0.0.1:%d", port];
|
|
||||||
+ rc = NO;
|
+ rc = NO;
|
||||||
+ }
|
+ }
|
||||||
+ NS_ENDHANDLER;
|
+ NS_ENDHANDLER;
|
||||||
|
@ -6235,20 +6218,7 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+- (void) _handleSIGPIPE:(NSNumber *)_signal {
|
+- (void) _handleSIGPIPE:(NSNumber *)_signal {
|
||||||
+ [self logWithFormat: @"received SIGPIPE (unhandled)"];
|
+ [self logWithFormat: @"received SIGPIPE (ignored)"];
|
||||||
+}
|
|
||||||
+
|
|
||||||
+- (void) _handleSIGCHLD:(NSNumber *)_signal {
|
|
||||||
+ WOWatchDogChild *child;
|
|
||||||
+ pid_t childPid;
|
|
||||||
+ int status;
|
|
||||||
+
|
|
||||||
+ childPid = wait (&status);
|
|
||||||
+ if (childPid > -1) {
|
|
||||||
+ pendingSIGCHLD++;
|
|
||||||
+ child = [self _childWithPID: childPid];
|
|
||||||
+ [child setSIGCHLDStatus: status];
|
|
||||||
+ }
|
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+- (void) _handleTermination:(NSNumber *)_signal {
|
+- (void) _handleTermination:(NSNumber *)_signal {
|
||||||
|
@ -6271,14 +6241,10 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
||||||
+ us = [UnixSignalHandler sharedHandler];
|
+ us = [UnixSignalHandler sharedHandler];
|
||||||
+ [us addObserver:self selector:@selector(_handleSIGPIPE:)
|
+ [us addObserver:self selector:@selector(_handleSIGPIPE:)
|
||||||
+ forSignal:SIGPIPE immediatelyNotifyOnSignal:YES];
|
+ forSignal:SIGPIPE immediatelyNotifyOnSignal:YES];
|
||||||
+ [us addObserver:self selector:@selector(_handleSIGCHLD:)
|
|
||||||
+ forSignal:SIGCHLD immediatelyNotifyOnSignal:YES];
|
|
||||||
+ [us addObserver:self selector:@selector(_handleTermination:)
|
+ [us addObserver:self selector:@selector(_handleTermination:)
|
||||||
+ forSignal:SIGINT immediatelyNotifyOnSignal:YES];
|
+ forSignal:SIGINT immediatelyNotifyOnSignal:YES];
|
||||||
+ [us addObserver:self selector:@selector(_handleTermination:)
|
+ [us addObserver:self selector:@selector(_handleTermination:)
|
||||||
+ forSignal:SIGTERM immediatelyNotifyOnSignal:YES];
|
+ forSignal:SIGTERM immediatelyNotifyOnSignal:YES];
|
||||||
+ // [us addObserver:self selector:@selector(_handleSIGKILL:)
|
|
||||||
+ // forSignal:SIGKILL immediatelyNotifyOnSignal:YES];
|
|
||||||
+ [us addObserver:self selector:@selector(_handleSIGHUP:)
|
+ [us addObserver:self selector:@selector(_handleSIGHUP:)
|
||||||
+ forSignal:SIGHUP immediatelyNotifyOnSignal:YES];
|
+ forSignal:SIGHUP immediatelyNotifyOnSignal:YES];
|
||||||
+#endif
|
+#endif
|
||||||
|
@ -6336,22 +6302,19 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
||||||
+ willTerminate = YES;
|
+ willTerminate = YES;
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+- (void) _handlePostSIGCHLDStatus
|
+- (void) _checkProcessesStatus
|
||||||
+{
|
+{
|
||||||
+ int status, count;
|
+ int status;
|
||||||
|
+ pid_t childPid;
|
||||||
+ WOWatchDogChild *child;
|
+ WOWatchDogChild *child;
|
||||||
+
|
+
|
||||||
+ for (count = 0; pendingSIGCHLD && count < numberOfChildren; count++) {
|
+ while ((childPid = waitpid (-1, &status, WNOHANG)) > 0) {
|
||||||
+ child = [children objectAtIndex: count];
|
+ child = [self _childWithPID: childPid];
|
||||||
+ status = [child SIGCHLDStatus];
|
+ [child handleProcessStatus: status];
|
||||||
+ if (status != -1) {
|
+ [self declareChildDown: child];
|
||||||
+ [child handleSIGCHLDStatus];
|
+ if (willTerminate && [downChildren count] == numberOfChildren) {
|
||||||
+ pendingSIGCHLD--;
|
+ [self logWithFormat: @"all children exited. We now terminate."];
|
||||||
+ [self declareChildDown: child];
|
+ terminate = YES;
|
||||||
+ if (willTerminate && [downChildren count] == numberOfChildren) {
|
|
||||||
+ [self logWithFormat: @"all children exited. We now terminate."];
|
|
||||||
+ terminate = YES;
|
|
||||||
+ }
|
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+}
|
+}
|
||||||
|
@ -6407,11 +6370,11 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
||||||
+
|
+
|
||||||
+ /* This timer ensures the looping of the runloop at reasonable intervals
|
+ /* This timer ensures the looping of the runloop at reasonable intervals
|
||||||
+ for correct processing of signal handlers. */
|
+ for correct processing of signal handlers. */
|
||||||
+ [NSTimer scheduledTimerWithTimeInterval: 0.5
|
+ loopTimer = [NSTimer scheduledTimerWithTimeInterval: 0.5
|
||||||
+ target: self
|
+ target: self
|
||||||
+ selector: @selector (_noop)
|
+ selector: @selector (_noop)
|
||||||
+ userInfo: nil
|
+ userInfo: nil
|
||||||
+ repeats: YES];
|
+ repeats: YES];
|
||||||
+ terminate = NO;
|
+ terminate = NO;
|
||||||
+ while (!terminate) {
|
+ while (!terminate) {
|
||||||
+ pool = [NSAutoreleasePool new];
|
+ pool = [NSAutoreleasePool new];
|
||||||
|
@ -6440,12 +6403,13 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
||||||
+ if (!terminate) {
|
+ if (!terminate) {
|
||||||
+ if (terminationSignal)
|
+ if (terminationSignal)
|
||||||
+ [self _handlePostTerminationSignal];
|
+ [self _handlePostTerminationSignal];
|
||||||
+ while (pendingSIGCHLD)
|
+ [self _checkProcessesStatus];
|
||||||
+ [self _handlePostSIGCHLDStatus];
|
|
||||||
+ }
|
+ }
|
||||||
|
+
|
||||||
+ [pool release];
|
+ [pool release];
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
|
+ [loopTimer invalidate];
|
||||||
+ [[UnixSignalHandler sharedHandler] removeObserver: self];
|
+ [[UnixSignalHandler sharedHandler] removeObserver: self];
|
||||||
+ }
|
+ }
|
||||||
+ else
|
+ else
|
||||||
|
@ -6473,7 +6437,7 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
||||||
NSAutoreleasePool *pool;
|
NSAutoreleasePool *pool;
|
||||||
NSUserDefaults *ud;
|
NSUserDefaults *ud;
|
||||||
+ NSString *logFile, *nsPidFile;
|
+ NSString *logFile, *nsPidFile;
|
||||||
+ int rc, stdErrNo;
|
+ int rc;
|
||||||
+ pid_t childPid;
|
+ pid_t childPid;
|
||||||
+ NSProcessInfo *processInfo;
|
+ NSProcessInfo *processInfo;
|
||||||
|
|
||||||
|
@ -6482,7 +6446,7 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
||||||
#if LIB_FOUNDATION_LIBRARY || defined(GS_PASS_ARGUMENTS)
|
#if LIB_FOUNDATION_LIBRARY || defined(GS_PASS_ARGUMENTS)
|
||||||
{
|
{
|
||||||
extern char **environ;
|
extern char **environ;
|
||||||
@@ -241,179 +972,68 @@
|
@@ -241,179 +936,59 @@
|
||||||
environment:(void*)environ];
|
environment:(void*)environ];
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -6508,9 +6472,8 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
||||||
+ [processInfo processName],
|
+ [processInfo processName],
|
||||||
+ [processInfo processName]];
|
+ [processInfo processName]];
|
||||||
+ if (![logFile isEqualToString: @"-"]) {
|
+ if (![logFile isEqualToString: @"-"]) {
|
||||||
+ stdErrNo = dup(fileno(stderr));
|
+ freopen([logFile cString], "a", stdout);
|
||||||
+ stdout = freopen([logFile cString], "a", stdout);
|
+ freopen([logFile cString], "a", stderr);
|
||||||
+ stderr = freopen([logFile cString], "a", stderr);
|
|
||||||
}
|
}
|
||||||
-
|
-
|
||||||
- /* watch dog */
|
- /* watch dog */
|
||||||
|
@ -6557,34 +6520,8 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
||||||
- else {
|
- else {
|
||||||
- sleep(1);
|
- sleep(1);
|
||||||
- }
|
- }
|
||||||
+ if (stdout && stderr) {
|
- }
|
||||||
+ if ([ud boolForKey: @"WONoDetach"])
|
- else {
|
||||||
+ childPid = 0;
|
|
||||||
+ else
|
|
||||||
+ childPid = fork();
|
|
||||||
+
|
|
||||||
+ if (childPid) {
|
|
||||||
+ rc = 0;
|
|
||||||
+ }
|
|
||||||
+ else {
|
|
||||||
+ nsPidFile = [ud objectForKey: @"WOPidFile"];
|
|
||||||
+ if (!nsPidFile)
|
|
||||||
+ nsPidFile = [NSString stringWithFormat: @"/var/run/%@/%@.pid",
|
|
||||||
+ [processInfo processName],
|
|
||||||
+ [processInfo processName]];
|
|
||||||
+ pidFile = [nsPidFile UTF8String];
|
|
||||||
+ if (_writePid(nsPidFile)) {
|
|
||||||
+ respawnDelay = [ud integerForKey: @"WORespawnDelay"];
|
|
||||||
+ if (!respawnDelay)
|
|
||||||
+ respawnDelay = 5;
|
|
||||||
+ /* default is to use the watch dog! */
|
|
||||||
+ if ([ud objectForKey:@"WOUseWatchDog"] != nil
|
|
||||||
+ && ![ud boolForKey:@"WOUseWatchDog"])
|
|
||||||
+ rc = WOApplicationMain(appName, argc, argv);
|
|
||||||
+ else
|
|
||||||
+ rc = [[WOWatchDog sharedWatchDog] run: appName argc: argc argv: argv];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
- if (child == 0) {
|
- if (child == 0) {
|
||||||
- /* child process */
|
- /* child process */
|
||||||
- signal(SIGPIPE, SIG_DFL);
|
- signal(SIGPIPE, SIG_DFL);
|
||||||
|
@ -6595,7 +6532,11 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
||||||
-
|
-
|
||||||
- if (isVerbose)
|
- if (isVerbose)
|
||||||
- fprintf(stderr, "starting child %i ..\n", getpid());
|
- fprintf(stderr, "starting child %i ..\n", getpid());
|
||||||
-
|
+ if ([ud boolForKey: @"WONoDetach"])
|
||||||
|
+ childPid = 0;
|
||||||
|
+ else
|
||||||
|
+ childPid = fork();
|
||||||
|
|
||||||
- pidFile = [pidFile stringByAppendingPathExtension:@"child"];
|
- pidFile = [pidFile stringByAppendingPathExtension:@"child"];
|
||||||
- _writePid(pidFile);
|
- _writePid(pidFile);
|
||||||
-
|
-
|
||||||
|
@ -6635,7 +6576,33 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
||||||
- child, forkCount, strerror(errno));
|
- child, forkCount, strerror(errno));
|
||||||
- continue;
|
- continue;
|
||||||
- }
|
- }
|
||||||
-
|
+ if (childPid) {
|
||||||
|
+ rc = 0;
|
||||||
|
+ }
|
||||||
|
+ else {
|
||||||
|
+ nsPidFile = [ud objectForKey: @"WOPidFile"];
|
||||||
|
+ if (!nsPidFile)
|
||||||
|
+ nsPidFile = [NSString stringWithFormat: @"/var/run/%@/%@.pid",
|
||||||
|
+ [processInfo processName],
|
||||||
|
+ [processInfo processName]];
|
||||||
|
+ pidFile = [nsPidFile UTF8String];
|
||||||
|
+ if (_writePid(nsPidFile)) {
|
||||||
|
+ respawnDelay = [ud integerForKey: @"WORespawnDelay"];
|
||||||
|
+ if (!respawnDelay)
|
||||||
|
+ respawnDelay = 5;
|
||||||
|
+ /* default is to use the watch dog! */
|
||||||
|
+ if ([ud objectForKey:@"WOUseWatchDog"] != nil
|
||||||
|
+ && ![ud boolForKey:@"WOUseWatchDog"])
|
||||||
|
+ rc = WOApplicationMain(appName, argc, argv);
|
||||||
|
+ else
|
||||||
|
+ rc = [[WOWatchDog sharedWatchDog] run: appName argc: argc argv: argv];
|
||||||
|
+ }
|
||||||
|
+ else {
|
||||||
|
+ [ud errorWithFormat: @"unable to open pid file: %@", pidFile];
|
||||||
|
+ rc = -1;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
|
||||||
- clientStopTime = time(NULL);
|
- clientStopTime = time(NULL);
|
||||||
- uptime = clientStopTime - clientStartTime;
|
- uptime = clientStopTime - clientStartTime;
|
||||||
-
|
-
|
||||||
|
@ -6655,7 +6622,8 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
||||||
- time_t now;
|
- time_t now;
|
||||||
-
|
-
|
||||||
- now = time(NULL);
|
- now = time(NULL);
|
||||||
-
|
+ [pool release];
|
||||||
|
|
||||||
- if (uptime < 3) {
|
- if (uptime < 3) {
|
||||||
- if (failExitCount > 0) {
|
- if (failExitCount > 0) {
|
||||||
- unsigned secsSinceLastFail;
|
- unsigned secsSinceLastFail;
|
||||||
|
@ -6698,26 +6666,15 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
||||||
- child, forkCount, status);
|
- child, forkCount, status);
|
||||||
- }
|
- }
|
||||||
- }
|
- }
|
||||||
+ [ud errorWithFormat: @"unable to open pid file: %@", pidFile];
|
- }
|
||||||
+ rc = -1;
|
- }
|
||||||
}
|
|
||||||
}
|
|
||||||
- return 0;
|
- return 0;
|
||||||
}
|
- }
|
||||||
+ else {
|
|
||||||
+ stdout = fdopen(stdErrNo, "a");
|
|
||||||
+ stderr = fdopen(stdErrNo, "a");
|
|
||||||
+ fprintf(stderr, "failed to redirect output channels to log file '%s'\n",
|
|
||||||
+ [logFile cString]);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ [pool release];
|
|
||||||
+
|
|
||||||
+ return rc;
|
+ return rc;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -421,8 +1041,8 @@
|
@@ -421,8 +996,8 @@
|
||||||
|
|
||||||
@interface NSUserDefaults(ServerDefaults)
|
@interface NSUserDefaults(ServerDefaults)
|
||||||
+ (id)hackInServerDefaults:(NSUserDefaults *)_ud
|
+ (id)hackInServerDefaults:(NSUserDefaults *)_ud
|
||||||
|
@ -6728,7 +6685,7 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
||||||
@end
|
@end
|
||||||
|
|
||||||
int WOWatchDogApplicationMainWithServerDefaults
|
int WOWatchDogApplicationMainWithServerDefaults
|
||||||
@@ -437,7 +1057,7 @@
|
@@ -437,7 +1012,7 @@
|
||||||
{
|
{
|
||||||
extern char **environ;
|
extern char **environ;
|
||||||
[NSProcessInfo initializeWithArguments:(void*)argv count:argc
|
[NSProcessInfo initializeWithArguments:(void*)argv count:argc
|
||||||
|
@ -6737,7 +6694,7 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -446,8 +1066,8 @@
|
@@ -446,8 +1021,8 @@
|
||||||
|
|
||||||
ud = [NSUserDefaults standardUserDefaults];
|
ud = [NSUserDefaults standardUserDefaults];
|
||||||
sd = [defClass hackInServerDefaults:ud
|
sd = [defClass hackInServerDefaults:ud
|
||||||
|
@ -6970,7 +6927,21 @@ Index: sope-appserver/NGObjWeb/ChangeLog
|
||||||
===================================================================
|
===================================================================
|
||||||
--- sope-appserver/NGObjWeb/ChangeLog (revision 1664)
|
--- sope-appserver/NGObjWeb/ChangeLog (revision 1664)
|
||||||
+++ sope-appserver/NGObjWeb/ChangeLog (working copy)
|
+++ sope-appserver/NGObjWeb/ChangeLog (working copy)
|
||||||
@@ -1,3 +1,163 @@
|
@@ -1,3 +1,177 @@
|
||||||
|
+2010-02-18 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||||
|
+
|
||||||
|
+ * WOWatchDogApplicationMain.m (-run:argc:argv:): we assign the
|
||||||
|
+ loop timer to an ivar so that it can be invalidated when a child
|
||||||
|
+ process is spawned. Child processes are check at each loop, since
|
||||||
|
+ receiving SIGCHILD is not guaranteed and we deadlock
|
||||||
|
+ when all remaining processes are zombies.
|
||||||
|
+ (-_setupSignals): SIGCHILD is no longer trapped.
|
||||||
|
+ (-readMessage): we now setup a 10 minutes timer when the child
|
||||||
|
+ accepts the request up to the moment its done with it. This
|
||||||
|
+ provides a supplemental safety for deadlocked children.
|
||||||
|
+ (WOWatchDogApplicationMain): we no longer care about the return
|
||||||
|
+ values for fdreopen since this is useless and is not portable.
|
||||||
|
+
|
||||||
+2010-02-03 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
+2010-02-03 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||||
+
|
+
|
||||||
+ * WOCookie.m (-stringValue): pass an minimal english locale
|
+ * WOCookie.m (-stringValue): pass an minimal english locale
|
||||||
|
|
Loading…
Reference in New Issue