From 7c54120ae0a7f4eab73e5bc1f6339e568ca7b330 Mon Sep 17 00:00:00 2001 From: Richard Frith-Macdonald Date: Fri, 5 Jan 2018 09:47:26 +0000 Subject: [PATCH] Add restart functionality --- ChangeLog | 10 ++++++++++ EcProcess.h | 11 +++++++++++ EcProcess.m | 52 ++++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 69 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 79c85a0..dafd6d9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,15 @@ +2018-01-05 Richard Frith-Macdonald + + EcProcess.h: + EcProcess.m: New -ecRestart: method called when we pass the maximum + memory usage limit or when a restart command is issued. The default + implementation calls the -ecQuitFor:status: method using a status of + minus one so that the Command server will restart the program after + it shuts down. + 2018-01-04 Richard Frith-Macdonald + EcProcess.h: Improve comments. EcProcess.m: Avoid warning about unknown connection on shutdown. Rewrite config update code to catch exceptions, ensure that methods are called in the correct order so that -cmdUpdated is always last, diff --git a/EcProcess.h b/EcProcess.h index ab76d1d..5ad05fd 100644 --- a/EcProcess.h +++ b/EcProcess.h @@ -540,6 +540,17 @@ extern NSString* cmdVersion(NSString *ver); */ - (oneway void) ecQuitFor: (NSString*)reason with: (NSInteger)status; +/** This method is designed for handling an orderly restart.
+ * The default implementation calls -ecQuitFor:status: with minus one as + * the status code so that the Command server will start the process + * again.
+ * The method is called automatically when the MemoryMaximum limit is + * exceeded (to gracefully handle memory leaks by restarting).
+ * Subclasses may override this method to allow the shutdown process to be + * handled differently. + */ +- (oneway void) ecRestart: (NSString*)reason; + /** Return the timestamp at which this process started up (when the * receiver was initialised). */ diff --git a/EcProcess.m b/EcProcess.m index a9d05c6..85e7cbd 100644 --- a/EcProcess.m +++ b/EcProcess.m @@ -1104,6 +1104,7 @@ findMode(NSDictionary* d, NSString* s) @interface EcProcess (Private) - (void) cmdMesgrelease: (NSArray*)msg; +- (void) cmdMesgrestart: (NSArray*)msg; - (void) cmdMesgtesting: (NSArray*)msg; - (void) _memCheck; - (NSString*) _moveLog: (NSString*)name to: (NSDate*)when; @@ -1916,7 +1917,7 @@ static BOOL ecDidAwaken = NO; return ecIsQuitting(); } -- (oneway void) ecQuitFor: (NSString*) reason with: (NSInteger)status +- (oneway void) ecQuitFor: (NSString*)reason with: (NSInteger)status { [self ecWillQuit: reason]; if (class_getMethodImplementation([EcProcess class], @selector(cmdQuit:)) @@ -1936,6 +1937,18 @@ static BOOL ecDidAwaken = NO; } } +- (oneway void) ecRestart: (NSString*)reason +{ + if (NO == [NSThread isMainThread]) + { + [self performSelectorOnMainThread: _cmd + withObject: reason + waitUntilDone: NO]; + return; + } + [self ecQuitFor: reason with: -1]; +} + - (void) ecLoggersChanged: (NSNotification*)n { DESTROY(alertLogger); @@ -4789,6 +4802,34 @@ With two parameters ('maximum' and a number),\n\ } } +- (void) cmdMesgrestart: (NSArray*)msg +{ + if ([msg count] == 0) + { + [self cmdPrintf: @"requests a restart"]; + } + else + { + if ([[msg objectAtIndex: 0] caseInsensitiveCompare: @"help"] + == NSOrderedSame) + { + [self cmdPrintf: @"\nThe restart command is used to request a"]; + [self cmdPrintf: @" restart of the process.\n"]; + [self cmdPrintf: @"This is like quitting the process but with"]; + [self cmdPrintf: @" a new process started by the Command\n"]; + [self cmdPrintf: @" server and potentially different shutdown"]; + [self cmdPrintf: @" behavior.\n"]; + } + else + { + [self performSelectorOnMainThread: @selector(ecRestart:) + withObject: @"Console restart command" + waitUntilDone: NO]; + [self cmdPrintf: @"A restart is being requested.\n"]; + } + } +} + - (void) cmdMesgtesting: (NSArray*)msg { if ([msg count] == 0) @@ -4968,13 +5009,16 @@ With two parameters ('maximum' and a number),\n\ } /* If we have a defined maximum memory usage for the process, - * we should shut down with a non-zero status to get a restart. + * we should perform a restart once that limit is passed. */ if (memMaximum > 0 && memPeak > (memMaximum * 1024 * 1024)) { - if (NO == ecIsQuitting()) + static BOOL memRestart = NO; + + if (NO == memRestart) { - [self ecQuitFor: @"memory usage limit reached" with: -1]; + memRestart = YES; + [self ecRestart: @"memory usage limit reached"]; } return; }