Monotone-Parent: ac9fdaf585c4ef94cbc22bcacdf8a0bef4ccd28a
Monotone-Revision: 2b8f8f20ddcc05375d6fc621de6d97b49198722a Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2009-12-07T20:39:00 Monotone-Branch: ca.inverse.sogomaint-2.0.2
parent
36fdb452e1
commit
7b774b19c1
|
@ -4579,7 +4579,7 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
#if defined(__CYGWIN32__) || defined(__MINGW32__)
|
||||
|
||||
int WOWatchDogApplicationMain
|
||||
@@ -39,199 +60,795 @@
|
||||
@@ -39,201 +60,845 @@
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
|
||||
|
@ -4618,6 +4618,7 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
+ WOChildStatusReady,
|
||||
+ WOChildStatusBusy,
|
||||
+ WOChildStatusExcessive,
|
||||
+ WOChildStatusTerminating,
|
||||
+ WOChildStatusMax
|
||||
+} WOChildStatus;
|
||||
+
|
||||
|
@ -4631,6 +4632,7 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
+ WOChildStatus status;
|
||||
+ WOWatchDog *watchDog;
|
||||
+ NSCalendarDate *lastSpawn;
|
||||
+ BOOL loggedNotRespawn;
|
||||
+}
|
||||
+
|
||||
+- (void) setWatchDog: (WOWatchDog *) newWatchDog;
|
||||
|
@ -4646,6 +4648,8 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
+
|
||||
+- (void) setLastSpawn: (NSCalendarDate *) newLastSpawn;
|
||||
+- (NSCalendarDate *) lastSpawn;
|
||||
+- (NSCalendarDate *) nextSpawn;
|
||||
+- (void) logNotRespawn;
|
||||
+
|
||||
+- (BOOL) readMessage;
|
||||
+
|
||||
|
@ -4703,6 +4707,7 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
+ status = WOChildStatusDown;
|
||||
+ counter = 0;
|
||||
+ lastSpawn = nil;
|
||||
+ loggedNotRespawn = NO;
|
||||
}
|
||||
- else if (kill(child, SIGKILL)) {
|
||||
- waitpid(child, &status, 0);
|
||||
|
@ -4728,12 +4733,14 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
+{
|
||||
+ NSRunLoop *runLoop;
|
||||
+
|
||||
+ runLoop = [NSRunLoop currentRunLoop];
|
||||
+ [runLoop removeEvent: (void *) [controlSocket fileDescriptor]
|
||||
+ type: ET_RDESC
|
||||
+ forMode: NSDefaultRunLoopMode
|
||||
+ all: YES];
|
||||
+ [controlSocket release];
|
||||
+ if (controlSocket) {
|
||||
+ runLoop = [NSRunLoop currentRunLoop];
|
||||
+ [runLoop removeEvent: (void *) [controlSocket fileDescriptor]
|
||||
+ type: ET_RDESC
|
||||
+ forMode: NSDefaultRunLoopMode
|
||||
+ all: YES];
|
||||
+ [controlSocket release];
|
||||
+ }
|
||||
+ [lastSpawn release];
|
||||
+ [super dealloc];
|
||||
+}
|
||||
|
@ -4763,6 +4770,7 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
+ type: ET_RDESC
|
||||
+ forMode: NSDefaultRunLoopMode
|
||||
+ all: YES];
|
||||
+ [controlSocket close];
|
||||
+ ASSIGN (controlSocket, newSocket);
|
||||
+ if (controlSocket)
|
||||
+ [runLoop addEvent: (void *) [controlSocket fileDescriptor]
|
||||
|
@ -4788,7 +4796,8 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
+
|
||||
+- (void) setLastSpawn: (NSCalendarDate *) newLastSpawn
|
||||
+{
|
||||
+ ASSIGN(lastSpawn, newLastSpawn);
|
||||
+ ASSIGN (lastSpawn, newLastSpawn);
|
||||
+ loggedNotRespawn = NO;
|
||||
+}
|
||||
+
|
||||
+- (NSCalendarDate *) lastSpawn
|
||||
|
@ -4796,16 +4805,22 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
+ return lastSpawn;
|
||||
+}
|
||||
+
|
||||
+// - (void) logStatus
|
||||
+// {
|
||||
+// NSLog (@"%d served %d requests", pid, counter);
|
||||
+// if (status == WOChildStatusBusy)
|
||||
+// NSLog (@"child (%d) is busy", pid);
|
||||
+// else if (status == WOChildStatusReady)
|
||||
+// NSLog (@"child (%d) is ready", pid);
|
||||
+// else if (status == WOChildStatusDown)
|
||||
+// NSLog (@"child (%d) has shutdown", pid);
|
||||
+// }
|
||||
+- (NSCalendarDate *) nextSpawn
|
||||
+{
|
||||
+ return [lastSpawn addYear: 0 month: 0 day: 0
|
||||
+ hour: 0 minute: 0
|
||||
+ second: respawnDelay];
|
||||
+}
|
||||
+
|
||||
+- (void) logNotRespawn
|
||||
+{
|
||||
+ if (!loggedNotRespawn)
|
||||
+ {
|
||||
+ [self logWithFormat:
|
||||
+ @"avoiding to respawn child before %@", [self nextSpawn]];
|
||||
+ loggedNotRespawn = YES;
|
||||
}
|
||||
+}
|
||||
+
|
||||
+- (BOOL) readMessage
|
||||
+{
|
||||
|
@ -4815,24 +4830,24 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
+ if ([controlSocket readBytes: &message
|
||||
+ count: sizeof (WOChildMessage)] == NGStreamError) {
|
||||
+ rc = NO;
|
||||
+ NSLog (@"FAILURE receiving status for child %d", pid);
|
||||
+ }
|
||||
+ [self errorWithFormat: @"FAILURE receiving status for child %d", pid];
|
||||
}
|
||||
+ 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];
|
||||
+ }
|
||||
+ // else if (message == WOChildMessageShutdown) {
|
||||
+ // status = WOChildStatusDown;
|
||||
+ // [watchDog declareChildDown: self];
|
||||
+ // }
|
||||
+ // NSLog (@"message read status (%d):", pid);
|
||||
+ // [self logStatus];
|
||||
}
|
||||
+ }
|
||||
+
|
||||
+ return rc;
|
||||
}
|
||||
|
@ -4852,13 +4867,29 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
+ && [self readMessage]);
|
||||
+}
|
||||
+
|
||||
+- (void) _killKill
|
||||
+{
|
||||
+ if (status != WOChildStatusDown) {
|
||||
+ [self warnWithFormat: @"sending KILL signal to child %d", pid];
|
||||
+ kill (pid, SIGKILL);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+- (void) _kill
|
||||
+{
|
||||
+ NSLog (@"we send a terminate signal to child %d", pid);
|
||||
+ status = WOChildStatusDown;
|
||||
+ kill (pid, SIGTERM);
|
||||
+ [NSThread sleepForTimeInterval: 1];
|
||||
+ kill (pid, SIGKILL);
|
||||
+ if (status != WOChildStatusDown) {
|
||||
+ [self logWithFormat: @"sending terminate signal to child %d", pid];
|
||||
+ status = WOChildStatusTerminating;
|
||||
+ 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];
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+- (void) notify
|
||||
|
@ -4868,7 +4899,7 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
+ counter++;
|
||||
+ message = WOChildMessageAccept;
|
||||
+ if (![self _sendMessage: message]) {
|
||||
+ NSLog (@"FAILURE notifying child %d", pid);
|
||||
+ [self errorWithFormat: @"FAILURE notifying child %d", pid];
|
||||
+ [self _kill];
|
||||
+ }
|
||||
+}
|
||||
|
@ -4878,23 +4909,12 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
+ WOChildMessage message;
|
||||
+
|
||||
+ if (status == WOChildStatusDown) {
|
||||
+ NSLog (@"child is already down");
|
||||
+ [self logWithFormat: @"child is already down"];
|
||||
+ } else {
|
||||
+ // NSLog (@"terminating child %d", pid);
|
||||
+ [controlSocket setSendTimeout: 1.0];
|
||||
+ [controlSocket setReceiveTimeout: 4.0];
|
||||
+
|
||||
+ message = WOChildMessageShutdown;
|
||||
+ if (!([self _sendMessage: message])) {
|
||||
+ NSLog (@"FAILURE terminating child %d", pid);
|
||||
+ [self _kill];
|
||||
}
|
||||
}
|
||||
}
|
||||
-static void _delPid(void) {
|
||||
- if ([pidFile length] > 0) {
|
||||
- if (unlink([pidFile cString]) == 0)
|
||||
- pidFile = nil;
|
||||
+ [self setControlSocket: nil];
|
||||
+ [self _kill];
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+- (void) delayedTerminate
|
||||
+{
|
||||
|
@ -4941,7 +4961,7 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
+ children = [[NSMutableArray alloc] initWithCapacity: 10];
|
||||
+ readyChildren = [[NSMutableArray alloc] initWithCapacity: 10];
|
||||
+ downChildren = [[NSMutableArray alloc] initWithCapacity: 10];
|
||||
+ }
|
||||
}
|
||||
+
|
||||
+ return self;
|
||||
+}
|
||||
|
@ -4953,46 +4973,29 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
+ type: ET_RDESC
|
||||
+ forMode: NSDefaultRunLoopMode
|
||||
+ all: YES];
|
||||
+ [listeningSocket close];
|
||||
+ [listeningSocket release];
|
||||
+ listeningSocket = nil;
|
||||
}
|
||||
}
|
||||
|
||||
-static void exitWatchdog(void) {
|
||||
- killChild();
|
||||
- _delPid();
|
||||
-static void _delPid(void) {
|
||||
- if ([pidFile length] > 0) {
|
||||
- if (unlink([pidFile cString]) == 0)
|
||||
- pidFile = nil;
|
||||
+
|
||||
+- (void) dealloc
|
||||
+{
|
||||
+ [self _releaseListeningSocket];
|
||||
+ [appName release];
|
||||
+ [children release];
|
||||
+ [super dealloc];
|
||||
}
|
||||
|
||||
-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) _runChildWithControlSocket: (NGActiveSocket *) controlSocket
|
||||
+{
|
||||
+ WOApplication *app;
|
||||
+ extern char **environ;
|
||||
|
||||
- case SIGSEGV:
|
||||
- /* Coredump ! */
|
||||
- fprintf(stderr,
|
||||
- "[%i]: watchdog handling segmentation fault "
|
||||
- "(SERIOUS PROBLEM) ..\n",
|
||||
- getpid());
|
||||
- killChild();
|
||||
- exit(123);
|
||||
- /* shouldn't get here */
|
||||
- abort();
|
||||
+
|
||||
+ [NSProcessInfo initializeWithArguments: (char **) argv
|
||||
+ count: argc
|
||||
+ environment: environ];
|
||||
|
@ -5003,30 +5006,7 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
+ [app setControlSocket: controlSocket];
|
||||
+ [app run];
|
||||
+}
|
||||
|
||||
- case SIGTERM:
|
||||
- /* TERM signal (kill 'pid') */
|
||||
- fprintf(stderr, "[%i]: watchdog handling SIGTERM ..\n", getpid());
|
||||
- killChild();
|
||||
- exit(0);
|
||||
- /* shouldn't get here */
|
||||
- abort();
|
||||
-
|
||||
- case SIGHUP:
|
||||
- /* HUP signal (restart children) */
|
||||
- fprintf(stderr, "[%i]: watchdog handling SIGHUP ..\n", getpid());
|
||||
- killChild();
|
||||
- killedChild = YES;
|
||||
- signal(_signal, wsignalHandler);
|
||||
- return;
|
||||
-
|
||||
- case SIGCHLD:
|
||||
- break;
|
||||
-
|
||||
- default:
|
||||
- fprintf(stderr, "[%i]: watchdog handling signal %i ..\n",
|
||||
- getpid(), _signal);
|
||||
- break;
|
||||
+
|
||||
+- (void) receivedEvent: (void*)data
|
||||
+ type: (RunLoopEventType)type
|
||||
+ extra: (void*)extra
|
||||
|
@ -5069,6 +5049,127 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
+ 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:
|
||||
- /* Coredump ! */
|
||||
- fprintf(stderr,
|
||||
- "[%i]: watchdog handling segmentation fault "
|
||||
- "(SERIOUS PROBLEM) ..\n",
|
||||
- getpid());
|
||||
- killChild();
|
||||
- exit(123);
|
||||
- /* shouldn't get here */
|
||||
- abort();
|
||||
+ 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];
|
||||
+ }
|
||||
|
||||
- case SIGTERM:
|
||||
- /* TERM signal (kill 'pid') */
|
||||
- fprintf(stderr, "[%i]: watchdog handling SIGTERM ..\n", getpid());
|
||||
- killChild();
|
||||
- exit(0);
|
||||
- /* shouldn't get here */
|
||||
- abort();
|
||||
-
|
||||
- case SIGHUP:
|
||||
- /* HUP signal (restart children) */
|
||||
- fprintf(stderr, "[%i]: watchdog handling SIGHUP ..\n", getpid());
|
||||
- killChild();
|
||||
- killedChild = YES;
|
||||
- signal(_signal, wsignalHandler);
|
||||
- return;
|
||||
-
|
||||
- case SIGCHLD:
|
||||
- break;
|
||||
-
|
||||
- default:
|
||||
- fprintf(stderr, "[%i]: watchdog handling signal %i ..\n",
|
||||
- getpid(), _signal);
|
||||
- break;
|
||||
+ 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];
|
||||
}
|
||||
- fflush(stderr);
|
||||
-
|
||||
- switch (_signal) {
|
||||
|
@ -5110,84 +5211,6 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
-
|
||||
- fprintf(stderr, "\n");
|
||||
- fflush(stderr);
|
||||
+- (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 ();
|
||||
+ // stdin = freopen ("/dev/null", "w+", stdin);
|
||||
+ // stderr = freopen ("/dev/null", "w+", stderr);
|
||||
+ 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;
|
||||
+}
|
||||
+
|
||||
+- (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
|
||||
+{
|
||||
+}
|
||||
|
@ -5212,15 +5235,12 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
+ [children removeObject: child];
|
||||
+ else {
|
||||
+ now = [NSCalendarDate date];
|
||||
+ nextSpawn = [[child lastSpawn] addYear: 0 month: 0 day: 0
|
||||
+ hour: 0 minute: 0
|
||||
+ second: respawnDelay];
|
||||
+ nextSpawn = [child nextSpawn];
|
||||
+ if ([nextSpawn earlierDate: now] == nextSpawn)
|
||||
+ isChild = [self _spawnChild: child];
|
||||
+ else {
|
||||
+ delayed = YES;
|
||||
+ [self logWithFormat:
|
||||
+ @"avoiding to respawn child before %@", nextSpawn];
|
||||
+ [child logNotRespawn];
|
||||
+ [NSTimer
|
||||
+ scheduledTimerWithTimeInterval: respawnDelay
|
||||
+ target: self
|
||||
|
@ -5268,9 +5288,11 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
+
|
||||
+ listeningAddress = nil;
|
||||
+
|
||||
+ port = [NSClassFromString (appName) port];
|
||||
+ if (!port)
|
||||
+ port = @"auto";
|
||||
+ allow
|
||||
+ = [[NSUserDefaults standardUserDefaults] objectForKey:@"WOHttpAllowHost"];
|
||||
+ port = [NSClassFromString(appName) port];
|
||||
+ if ([port isKindOfClass: [NSString class]]) {
|
||||
+ if ([port isEqualToString: @"auto"]) {
|
||||
+ listeningAddress
|
||||
|
@ -5284,8 +5306,9 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
+ if (allow)
|
||||
+ listeningAddress =
|
||||
+ [NGInternetSocketAddress wildcardAddressWithPort:[port intValue]];
|
||||
+ else
|
||||
+ else {
|
||||
+ port = [NSString stringWithFormat: @"127.0.0.1:%@", port];
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (!listeningAddress)
|
||||
|
@ -5297,11 +5320,13 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
+- (BOOL) _prepareListeningSocket
|
||||
+{
|
||||
+ NGInternetSocketAddress *addr;
|
||||
+ NSString *address;
|
||||
+ BOOL rc;
|
||||
+ int backlog;
|
||||
+
|
||||
+ addr = [self _listeningAddress];
|
||||
+ NS_DURING {
|
||||
+ [listeningSocket release];
|
||||
+ listeningSocket = [[NGPassiveSocket alloc] initWithDomain: [addr domain]];
|
||||
+ [listeningSocket bindToAddress: addr];
|
||||
+ backlog = [[NSUserDefaults standardUserDefaults]
|
||||
|
@ -5309,7 +5334,10 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
+ if (!backlog)
|
||||
+ backlog = 5;
|
||||
+ [listeningSocket listenWithBacklog: backlog];
|
||||
+ [self logWithFormat: @"listening on %@:%d", [addr address], [addr port]];
|
||||
+ address = [addr address];
|
||||
+ if (!address)
|
||||
+ address = @"*";
|
||||
+ [self logWithFormat: @"listening on %@:%d", address, [addr port]];
|
||||
+ [[NSRunLoop currentRunLoop] addEvent: (void *) [listeningSocket fileDescriptor]
|
||||
+ type: ET_RDESC
|
||||
+ watcher: self
|
||||
|
@ -5341,42 +5369,39 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
+}
|
||||
+
|
||||
+- (void) _handleSIGPIPE:(NSNumber *)_signal {
|
||||
+ // NSLog (@"received SIGPIPE");
|
||||
+ [self logWithFormat: @"received SIGPIPE (unhandled)"];
|
||||
+}
|
||||
+
|
||||
+/* BUG:
|
||||
+ - when relying only on SIGCHLD, we miss some of them (signal blocking?)
|
||||
+ - when relying on [WOWatchDogChild terminate], we exit before all processes
|
||||
+ are down, this is the least worse of the two. */
|
||||
+- (void) _handleSIGCHLD:(NSNumber *)_signal {
|
||||
+ WOWatchDogChild *child;
|
||||
+ pid_t childPid;
|
||||
+ int status, code;
|
||||
+
|
||||
+ // NSLog (@"received SIGCHLD");
|
||||
+ childPid = wait(&status);
|
||||
+ childPid = wait (&status);
|
||||
+ [self logWithFormat: @"received SIGCHLD: %d", childPid];
|
||||
+ if (childPid > -1) {
|
||||
+ code = WEXITSTATUS(status);
|
||||
+ if (code != 0)
|
||||
+ NSLog (@"child %d exited with code %i", childPid, code);
|
||||
+ [self logWithFormat: @"child %d exited with code %i", childPid, code];
|
||||
+ if (WIFSIGNALED(status))
|
||||
+ NSLog (@" (terminated due to signal %i%@)",
|
||||
+ WTERMSIG(status),
|
||||
+ WCOREDUMP(status) ? @", coredump" : @"");
|
||||
+ [self logWithFormat: @" (terminated due to signal %i%@)",
|
||||
+ WTERMSIG(status),
|
||||
+ WCOREDUMP(status) ? @", coredump" : @""];
|
||||
+ if (WIFSTOPPED(status))
|
||||
+ NSLog (@" (stopped due to signal %i)", WSTOPSIG(status));
|
||||
+ [self logWithFormat: @" (stopped due to signal %i)", WSTOPSIG(status)];
|
||||
+ child = [self _childWithPID: childPid];
|
||||
+ if (child) {
|
||||
+ [child setStatus: WOChildStatusDown];
|
||||
+ [self declareChildDown: child];
|
||||
+ [child setControlSocket: nil];
|
||||
+ if (willTerminate && [downChildren count] == numberOfChildren) {
|
||||
+ NSLog (@"all child exited");
|
||||
+ [self logWithFormat: @"all child exited"];
|
||||
+ terminate = YES;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ NSLog (@"no pid received");
|
||||
+ [self errorWithFormat: @"no pid received"];
|
||||
+}
|
||||
+
|
||||
+- (void) _handleTermination:(NSNumber *)_signal {
|
||||
|
@ -5384,13 +5409,14 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
+ int count, max;
|
||||
+
|
||||
+ if (!willTerminate) {
|
||||
+ NSLog (@"Terminating with signal %@", _signal);
|
||||
+ [self logWithFormat: @"Terminating with signal %@", _signal];
|
||||
+ [self _releaseListeningSocket];
|
||||
+ willTerminate = YES;
|
||||
+ max = [children count];
|
||||
+ for (count = 0; count < max; count++) {
|
||||
+ child = [children objectAtIndex: count];
|
||||
+ if ([child status] != WOChildStatusDown)
|
||||
+ if ([child status] != WOChildStatusDown
|
||||
+ && [child status] != WOChildStatusTerminating)
|
||||
+ [child delayedTerminate];
|
||||
+ }
|
||||
+ }
|
||||
|
@ -5472,24 +5498,41 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
+- (int) run: (NSString *) newAppName
|
||||
+ argc: (int) newArgC argv: (const char **) newArgV
|
||||
+{
|
||||
+ NSAutoreleasePool *pool;
|
||||
+ NSRunLoop *runLoop;
|
||||
+ NSDate *limitDate;
|
||||
+ BOOL listening;
|
||||
+ int retries;
|
||||
+
|
||||
+ willTerminate = NO;
|
||||
+
|
||||
+ ASSIGN(appName, newAppName);
|
||||
+ ASSIGN (appName, newAppName);
|
||||
+ argc = newArgC;
|
||||
+ argv = newArgV;
|
||||
+
|
||||
+ [self _processArguments];
|
||||
+ if ([self _prepareListeningSocket]) {
|
||||
+
|
||||
+ listening = NO;
|
||||
+ retries = 0;
|
||||
+ while (!listening && retries < 5) {
|
||||
+ listening = [self _prepareListeningSocket];
|
||||
+ retries++;
|
||||
+ if (!listening) {
|
||||
+ [self warnWithFormat: @"listening socket: attempt %d failed", retries];
|
||||
+ [NSThread sleepForTimeInterval: 1.0];
|
||||
+ }
|
||||
+ }
|
||||
+ if (listening) {
|
||||
+ [self _setupSignals];
|
||||
+ [self _ensureWorkersCount];
|
||||
+
|
||||
+ // NSLog (@"ready to process requests");
|
||||
+ runLoop = [NSRunLoop currentRunLoop];
|
||||
+ terminate = NO;
|
||||
+
|
||||
+ while (!terminate) {
|
||||
+ pool = [NSAutoreleasePool new];
|
||||
+
|
||||
+ // [self logWithFormat: @"watchdog loop"];
|
||||
+ NS_DURING {
|
||||
+ terminate = [self _ensureChildren];
|
||||
|
@ -5504,10 +5547,14 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
+ @"an exception occured in runloop %@", localException];
|
||||
+ }
|
||||
+ NS_ENDHANDLER;
|
||||
+ [pool release];
|
||||
+ }
|
||||
+
|
||||
+ [[UnixSignalHandler sharedHandler] removeObserver: self];
|
||||
+ }
|
||||
+ else
|
||||
+ [self errorWithFormat: @"unable to listen on specified port,"
|
||||
+ @" check that no other process is already using it"];
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
|
@ -5535,8 +5582,11 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
+ NSProcessInfo *processInfo;
|
||||
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
+
|
||||
#if LIB_FOUNDATION_LIBRARY || defined(GS_PASS_ARGUMENTS)
|
||||
@@ -241,179 +858,61 @@
|
||||
{
|
||||
extern char **environ;
|
||||
@@ -241,179 +906,67 @@
|
||||
environment:(void*)environ];
|
||||
}
|
||||
#endif
|
||||
|
@ -5549,7 +5599,18 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
- if ([ud objectForKey:@"WOUseWatchDog"] != nil) {
|
||||
- if (![ud boolForKey:@"WOUseWatchDog"])
|
||||
- return WOApplicationMain(appName, argc, argv);
|
||||
- }
|
||||
+ processInfo = [NSProcessInfo processInfo];
|
||||
+
|
||||
+ logFile = [ud objectForKey: @"WOLogFile"];
|
||||
+ if (!logFile)
|
||||
+ logFile = [NSString stringWithFormat: @"/var/log/%@/%@.log",
|
||||
+ [processInfo processName],
|
||||
+ [processInfo processName]];
|
||||
+ if (![logFile isEqualToString: @"-"]) {
|
||||
+ stdErrNo = dup(fileno(stderr));
|
||||
+ stdout = freopen([logFile cString], "a", stdout);
|
||||
+ stderr = freopen([logFile cString], "a", stderr);
|
||||
}
|
||||
-
|
||||
- /* watch dog */
|
||||
- {
|
||||
|
@ -5607,7 +5668,11 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
-
|
||||
- if (isVerbose)
|
||||
- fprintf(stderr, "starting child %i ..\n", getpid());
|
||||
+ processInfo = [NSProcessInfo processInfo];
|
||||
+ if (stdout && stderr) {
|
||||
+ /* This invocation forces the class initialization of WOCoreApplication,
|
||||
+ which causes the NSUserDefaults to be initialized as well with
|
||||
+ Defaults.plist. */
|
||||
+ [NSClassFromString (appName) port];
|
||||
|
||||
- pidFile = [pidFile stringByAppendingPathExtension:@"child"];
|
||||
- _writePid(pidFile);
|
||||
|
@ -5648,15 +5713,6 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
- child, forkCount, strerror(errno));
|
||||
- continue;
|
||||
- }
|
||||
+ logFile = [ud objectForKey: @"WOLogFile"];
|
||||
+ if (!logFile)
|
||||
+ logFile = [NSString stringWithFormat: @"/var/log/%@/%@.log",
|
||||
+ [processInfo processName],
|
||||
+ [processInfo processName]];
|
||||
+ stdErrNo = dup(fileno(stderr));
|
||||
+ stdout = freopen([logFile cString], "a", stdout);
|
||||
+ stderr = freopen([logFile cString], "a", stderr);
|
||||
+ if (stdout && stderr) {
|
||||
+ if ([ud boolForKey: @"WONoDetach"])
|
||||
+ childPid = 0;
|
||||
+ else
|
||||
|
@ -5738,7 +5794,6 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
+ if (!respawnDelay)
|
||||
+ respawnDelay = 5;
|
||||
+ /* default is to use the watch dog! */
|
||||
+ /* Note: the Defaults.plist is not yet loaded at this stage! */
|
||||
+ if ([ud objectForKey:@"WOUseWatchDog"] != nil
|
||||
+ && ![ud boolForKey:@"WOUseWatchDog"])
|
||||
+ rc = WOApplicationMain(appName, argc, argv);
|
||||
|
@ -5746,7 +5801,7 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
+ rc = [[WOWatchDog sharedWatchDog] run: appName argc: argc argv: argv];
|
||||
}
|
||||
+ else {
|
||||
+ NSLog (@"unable to open pid file: %@", pidFile);
|
||||
+ [ud errorWithFormat: @"unable to open pid file: %@", pidFile];
|
||||
+ rc = -1;
|
||||
+ }
|
||||
}
|
||||
|
@ -5765,7 +5820,7 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
}
|
||||
#endif
|
||||
|
||||
@@ -421,8 +920,8 @@
|
||||
@@ -421,8 +974,8 @@
|
||||
|
||||
@interface NSUserDefaults(ServerDefaults)
|
||||
+ (id)hackInServerDefaults:(NSUserDefaults *)_ud
|
||||
|
@ -5776,7 +5831,7 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
@end
|
||||
|
||||
int WOWatchDogApplicationMainWithServerDefaults
|
||||
@@ -437,7 +936,7 @@
|
||||
@@ -437,7 +990,7 @@
|
||||
{
|
||||
extern char **environ;
|
||||
[NSProcessInfo initializeWithArguments:(void*)argv count:argc
|
||||
|
@ -5785,7 +5840,7 @@ Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
|
|||
}
|
||||
#endif
|
||||
|
||||
@@ -446,8 +945,8 @@
|
||||
@@ -446,8 +999,8 @@
|
||||
|
||||
ud = [NSUserDefaults standardUserDefaults];
|
||||
sd = [defClass hackInServerDefaults:ud
|
||||
|
@ -5845,7 +5900,22 @@ Index: sope-appserver/NGObjWeb/ChangeLog
|
|||
===================================================================
|
||||
--- sope-appserver/NGObjWeb/ChangeLog (revision 1660)
|
||||
+++ sope-appserver/NGObjWeb/ChangeLog (working copy)
|
||||
@@ -1,3 +1,56 @@
|
||||
@@ -1,3 +1,71 @@
|
||||
+2009-12-07 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
+
|
||||
+ * WOCoreApplication.m (+initialize): we invoke
|
||||
+ "registerUserDefaults" from here now. This enables Defaults.plist
|
||||
+ to be registered as soon as the watchdog is active.
|
||||
+
|
||||
+ * WOWatchDogApplicationMain.m (-terminate): we use a SIGTERM to
|
||||
+ terminate the children instead of passing a message. We also setup
|
||||
+ a timer that will send a SIGKILL after 5 minutes.
|
||||
+ (-_releaseListeningSocket): we close the socket here so that other
|
||||
+ processes can start listening.
|
||||
+ (WOWatchDogApplicationMain): we accept "-" as argument to
|
||||
+ "WOLogFile" so that we avoid redirecting the output and the error
|
||||
+ channels.
|
||||
+
|
||||
+2009-11-11 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
+
|
||||
+ * WOCoreApplication.m (-setControlSocket, -controlSocket)
|
||||
|
@ -6939,7 +7009,93 @@ Index: sope-appserver/NGObjWeb/WOCoreApplication.m
|
|||
===================================================================
|
||||
--- sope-appserver/NGObjWeb/WOCoreApplication.m (revision 1660)
|
||||
+++ sope-appserver/NGObjWeb/WOCoreApplication.m (working copy)
|
||||
@@ -190,6 +190,9 @@
|
||||
@@ -75,6 +75,43 @@
|
||||
NGObjWeb_DECLARE id WOApp = nil;
|
||||
static NSMutableArray *activeApps = nil; // THREAD
|
||||
|
||||
++ (void)registerUserDefaults {
|
||||
+ NSDictionary *owDefaults = nil;
|
||||
+ NSString *apath;
|
||||
+
|
||||
+ apath = [[self class] findNGObjWebResource:@"Defaults" ofType:@"plist"];
|
||||
+ if (apath == nil)
|
||||
+ [self errorWithFormat:@"Cannot find Defaults.plist resource of "
|
||||
+ @"NGObjWeb library!"];
|
||||
+#if HEAVY_DEBUG
|
||||
+ else
|
||||
+ [self debugWithFormat:@"Note: loading default defaults: %@", apath];
|
||||
+#endif
|
||||
+
|
||||
+ owDefaults = [NSDictionary dictionaryWithContentsOfFile:apath];
|
||||
+ if (owDefaults) {
|
||||
+ [[NSUserDefaults standardUserDefaults] registerDefaults:owDefaults];
|
||||
+#if HEAVY_DEBUG
|
||||
+ [self debugWithFormat:@"did register NGObjWeb defaults: %@\n%@",
|
||||
+ apath, owDefaults];
|
||||
+#endif
|
||||
+ }
|
||||
+ else {
|
||||
+ [self errorWithFormat:@"could not load NGObjWeb defaults: '%@'",
|
||||
+ apath];
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
++ (void)initialize
|
||||
+{
|
||||
+ static BOOL initialized = NO;
|
||||
+
|
||||
+ if (!initialized) {
|
||||
+ [self registerUserDefaults];
|
||||
+ initialized = YES;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+ (id)application {
|
||||
if (WOApp == nil) {
|
||||
[self warnWithFormat:@"%s: some code called +application without an "
|
||||
@@ -115,33 +152,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
-- (void)registerUserDefaults {
|
||||
- NSDictionary *owDefaults = nil;
|
||||
- NSString *apath;
|
||||
-
|
||||
- apath = [[self class] findNGObjWebResource:@"Defaults" ofType:@"plist"];
|
||||
- if (apath == nil)
|
||||
- [self errorWithFormat:@"Cannot find Defaults.plist resource of "
|
||||
- @"NGObjWeb library!"];
|
||||
-#if HEAVY_DEBUG
|
||||
- else
|
||||
- [self debugWithFormat:@"Note: loading default defaults: %@", apath];
|
||||
-#endif
|
||||
-
|
||||
- owDefaults = [NSDictionary dictionaryWithContentsOfFile:apath];
|
||||
- if (owDefaults) {
|
||||
- [[NSUserDefaults standardUserDefaults] registerDefaults:owDefaults];
|
||||
-#if HEAVY_DEBUG
|
||||
- [self debugWithFormat:@"did register NGObjWeb defaults: %@\n%@",
|
||||
- apath, owDefaults];
|
||||
-#endif
|
||||
- }
|
||||
- else {
|
||||
- [self errorWithFormat:@"could not load NGObjWeb defaults: '%@'",
|
||||
- apath];
|
||||
- }
|
||||
-}
|
||||
-
|
||||
- (id)init {
|
||||
#if COCOA_Foundation_LIBRARY
|
||||
/*
|
||||
@@ -157,7 +167,6 @@
|
||||
NSUserDefaults *ud;
|
||||
NGLoggerManager *lm;
|
||||
|
||||
- [self registerUserDefaults];
|
||||
ud = [NSUserDefaults standardUserDefaults];
|
||||
lm = [NGLoggerManager defaultLoggerManager];
|
||||
logger = [lm loggerForClass:[self class]];
|
||||
@@ -190,6 +199,9 @@
|
||||
forSignal:SIGHUP immediatelyNotifyOnSignal:NO];
|
||||
}
|
||||
#endif
|
||||
|
@ -6949,7 +7105,7 @@ Index: sope-appserver/NGObjWeb/WOCoreApplication.m
|
|||
}
|
||||
return self;
|
||||
}
|
||||
@@ -202,9 +205,32 @@
|
||||
@@ -202,9 +214,32 @@
|
||||
[self->adaptors release];
|
||||
[self->requestLock release];
|
||||
[self->lock release];
|
||||
|
@ -6982,7 +7138,15 @@ Index: sope-appserver/NGObjWeb/WOCoreApplication.m
|
|||
/* NGLogging */
|
||||
|
||||
+ (id)logger {
|
||||
@@ -786,7 +812,9 @@
|
||||
@@ -225,6 +260,7 @@
|
||||
/* STDIO is forbidden in signal handlers !!! no malloc !!! */
|
||||
#if 1
|
||||
self->cappFlags.isTerminating = 1;
|
||||
+ [self->listeningSocket close];
|
||||
#else
|
||||
static int termCount = 0;
|
||||
unsigned pid;
|
||||
@@ -786,7 +822,9 @@
|
||||
id woport;
|
||||
id addr;
|
||||
|
||||
|
|
Loading…
Reference in New Issue