mirror of
https://github.com/gnustep/libs-ec.git
synced 2025-02-20 18:32:09 +00:00
improve wait time for termination
This commit is contained in:
parent
1f0f34db93
commit
d415fd6479
4 changed files with 142 additions and 55 deletions
|
@ -1,8 +1,15 @@
|
|||
2019-05-14 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* EcProcess.h:
|
||||
* EcCommand.m: Replace -terminate with -terminate: method.
|
||||
* Terminate.m: Extend termination to control the time allowed for the
|
||||
graceful shutdown (default to 30 seconds).
|
||||
|
||||
2019-05-14 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* EcProcess.h:
|
||||
* EcCommand.m: New method to return count of active clients.
|
||||
* terminate.m: New help output and option to wait until Command
|
||||
* Terminate.m: New help output and option to wait until Command
|
||||
server shuts down (printing out number of active clients).
|
||||
|
||||
2019-05-09 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
|
91
EcCommand.m
91
EcCommand.m
|
@ -400,6 +400,7 @@ static NSMutableDictionary *launchInfo = nil;
|
|||
NSMutableDictionary *launching;
|
||||
unsigned pingPosition;
|
||||
NSTimer *terminating;
|
||||
NSDate *terminateBy;
|
||||
NSDate *lastUnanswered;
|
||||
unsigned fwdSequence;
|
||||
unsigned revSequence;
|
||||
|
@ -462,7 +463,8 @@ static NSMutableDictionary *launchInfo = nil;
|
|||
transient: (BOOL)t;
|
||||
- (void) reply: (NSString*) msg to: (NSString*)n from: (NSString*)c;
|
||||
- (NSArray*) restartAll: (NSString*)from;
|
||||
- (void) terminate;
|
||||
- (void) terminate: (NSDate*)by;
|
||||
- (void) _terminate: (NSTimer*)t;
|
||||
- (void) timedOut: (NSTimer*)t;
|
||||
- (void) _timedOut: (NSTimer*)t;
|
||||
- (void) timeoutSoon;
|
||||
|
@ -2087,6 +2089,7 @@ static NSMutableDictionary *launchInfo = nil;
|
|||
RELEASE(launchOrder);
|
||||
RELEASE(environment);
|
||||
RELEASE(lastUnanswered);
|
||||
RELEASE(terminateBy);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
@ -3302,49 +3305,83 @@ static NSMutableDictionary *launchInfo = nil;
|
|||
* Tell all our clients to quit, and wait for them to do so.
|
||||
* If called while already terminating ... force immediate shutdown.
|
||||
*/
|
||||
- (void) terminate: (NSTimer*)t
|
||||
- (void) _terminate: (NSTimer*)t
|
||||
{
|
||||
if (nil == terminating)
|
||||
NSTimeInterval ti = [terminateBy timeIntervalSinceNow];
|
||||
|
||||
if ([clients count] == 0 && [launching count] == 0)
|
||||
{
|
||||
[self information: @"Handling shutdown.\n"
|
||||
[self information: @"Final shutdown."
|
||||
from: nil
|
||||
to: nil
|
||||
type: LT_CONSOLE];
|
||||
[terminating invalidate];
|
||||
terminating = nil;
|
||||
[self cmdQuit: tStatus];
|
||||
}
|
||||
|
||||
if (nil == terminating)
|
||||
else if (ti <= 0.0)
|
||||
{
|
||||
terminating = [NSTimer scheduledTimerWithTimeInterval: 10.0
|
||||
target: self selector: @selector(terminate:)
|
||||
userInfo: [NSDate new]
|
||||
repeats: YES];
|
||||
[[self cmdLogFile: logname] puts: @"Final shutdown.\n"];
|
||||
[terminating invalidate];
|
||||
terminating = nil;
|
||||
[self killAll];
|
||||
[self cmdQuit: tStatus];
|
||||
}
|
||||
|
||||
[self quitAll];
|
||||
|
||||
if (t != nil)
|
||||
else
|
||||
{
|
||||
NSDate *when = (NSDate*)[t userInfo];
|
||||
|
||||
if ([when timeIntervalSinceNow] < -30.0)
|
||||
{
|
||||
[[self cmdLogFile: logname]
|
||||
puts: @"Final shutdown.\n"];
|
||||
[terminating invalidate];
|
||||
terminating = nil;
|
||||
[self killAll];
|
||||
[self cmdQuit: tStatus];
|
||||
}
|
||||
[self quitAll];
|
||||
terminating = [NSTimer scheduledTimerWithTimeInterval: ti
|
||||
target: self
|
||||
selector: _cmd
|
||||
userInfo: nil
|
||||
repeats: NO];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) terminate
|
||||
- (void) terminate: (NSDate*)by
|
||||
{
|
||||
NSTimeInterval ti = 30.0;
|
||||
|
||||
if (nil != terminateBy)
|
||||
{
|
||||
NSString *msg;
|
||||
|
||||
msg = [NSString stringWithFormat: @"Terminate requested,"
|
||||
@" but already terminating by %@", terminateBy];
|
||||
[self information: msg
|
||||
from: nil
|
||||
to: nil
|
||||
type: LT_CONSOLE];
|
||||
return;
|
||||
}
|
||||
if (nil != by)
|
||||
{
|
||||
ti = [by timeIntervalSinceNow];
|
||||
if (ti < 0.5)
|
||||
{
|
||||
ti = 0.5;
|
||||
by = nil;
|
||||
}
|
||||
else if (ti > 900.0)
|
||||
{
|
||||
ti = 900.0;
|
||||
by = nil;
|
||||
}
|
||||
}
|
||||
if (nil == by)
|
||||
{
|
||||
by = [NSDate dateWithTimeIntervalSinceNow: ti];
|
||||
}
|
||||
ASSIGN(terminateBy, by);
|
||||
[self information: @"Terminate initiated.\n"
|
||||
from: nil
|
||||
to: nil
|
||||
type: LT_CONSOLE];
|
||||
[self terminate: nil];
|
||||
terminating = [NSTimer scheduledTimerWithTimeInterval: 0.01
|
||||
target: self
|
||||
selector: @selector(_terminate:)
|
||||
userInfo: nil
|
||||
repeats: NO];
|
||||
}
|
||||
|
||||
- (void) timedOut: (NSTimer*)t
|
||||
|
|
|
@ -139,10 +139,11 @@ typedef enum {
|
|||
from: (NSString*)c;
|
||||
|
||||
/** Shut down the Command server and all its clients.<br />
|
||||
* Clients which fail to shut down gracefully within 30 seconds
|
||||
* may be killed.
|
||||
* Clients which fail to shut down gracefully before the specified timestamp
|
||||
* will be forcibly killed. The timestamp is constrained to be at least half
|
||||
* a second in the future and not more than 15 minutes in the future.
|
||||
*/
|
||||
- (oneway void) terminate;
|
||||
- (oneway void) terminate: (NSDate*)byDate;
|
||||
|
||||
/** This is meant to be used remotely by all sorts of software running
|
||||
* on the machine and which is *not* a full Command client (ie, not a
|
||||
|
|
90
Terminate.m
90
Terminate.m
|
@ -55,6 +55,7 @@ main()
|
|||
NSString *name;
|
||||
id proxy;
|
||||
BOOL any = NO;
|
||||
int res = 0;
|
||||
|
||||
[EcProcess class]; // Force linker to provide library
|
||||
|
||||
|
@ -70,13 +71,21 @@ main()
|
|||
|| [[[NSProcessInfo processInfo] arguments] containsObject: @"--Help"]
|
||||
|| [[[NSProcessInfo processInfo] arguments] containsObject: @"--help"])
|
||||
{
|
||||
printf("Terminate processes and Command server\n");
|
||||
printf("Terminate the Command server and its client processes.\n");
|
||||
printf(" -CommandHost N\tuse alternative Command server host.\n");
|
||||
printf(" -CommandName N\tuse alternative Command server name.\n");
|
||||
printf(" -Wait YES\tWait until termination completes.\n");
|
||||
printf(" -Wait seconds\tWait with completion time limit.\n");
|
||||
printf(" -WellKnownHostNames '{...}'\tprovide a host name map.\n");
|
||||
printf("\n");
|
||||
printf(" By default a 30 second shutdown is requested and the\n");
|
||||
printf(" command finishes without waiting for it to complete.\n");
|
||||
printf(" Possible exit statuses are:\n");
|
||||
printf(" 0 termination requested (completed if -Wait was used).\n");
|
||||
printf(" 1 termination had not completed by end of -Wait timeout.\n");
|
||||
printf(" 2 the Command server was not found (maybe not running).\n");
|
||||
printf(" 3 this help was provided and no termination was requested.\n");
|
||||
fflush(stdout);
|
||||
exit(0);
|
||||
exit(3);
|
||||
}
|
||||
|
||||
dict = [defs dictionaryForKey: @"WellKnownHostNames"];
|
||||
|
@ -116,29 +125,53 @@ main()
|
|||
if (nil == proxy)
|
||||
{
|
||||
NSLog(@"Unable to contact %@ on %@", name, host);
|
||||
res = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
NSConnection *c = [proxy connectionForProxy];
|
||||
unsigned active = [proxy activeCount];
|
||||
NSTimeInterval seconds = [defs doubleForKey: @"Wait"];
|
||||
NSDate *by;
|
||||
|
||||
[(id<Command>)proxy terminate];
|
||||
if ([defs boolForKey: @"Wait"])
|
||||
if (isnan(seconds) || 0.0 == seconds)
|
||||
{
|
||||
NS_DURING
|
||||
by = nil;
|
||||
}
|
||||
else if (seconds < 0.5)
|
||||
{
|
||||
seconds = 0.5;
|
||||
}
|
||||
else if (seconds > 900.0)
|
||||
{
|
||||
seconds = 900.0;
|
||||
}
|
||||
by = [NSDate dateWithTimeIntervalSinceNow: seconds];
|
||||
[(id<Command>)proxy terminate: by];
|
||||
if (nil == [defs objectForKey: @"Wait"])
|
||||
{
|
||||
[c invalidate]; // No waiting
|
||||
}
|
||||
else
|
||||
{
|
||||
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||
|
||||
/* Allow a second more than the requested shutdown time,
|
||||
* so minor timing differences do not cause us to report
|
||||
* the shutdown as having failed.
|
||||
*/
|
||||
while ([c isValid] && [by timeIntervalSinceNow] > -1.0)
|
||||
{
|
||||
NSConnection *c = [proxy connectionForProxy];
|
||||
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||
NSDate *delay;
|
||||
|
||||
while ([c isValid])
|
||||
[pool release];
|
||||
pool = [NSAutoreleasePool new];
|
||||
delay = [NSDate dateWithTimeIntervalSinceNow: 0.2];
|
||||
[[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode
|
||||
beforeDate: delay];
|
||||
if ([c isValid])
|
||||
{
|
||||
NSDate *delay;
|
||||
|
||||
[pool release];
|
||||
pool = [NSAutoreleasePool new];
|
||||
delay = [NSDate dateWithTimeIntervalSinceNow: 0.2];
|
||||
[[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode
|
||||
beforeDate: delay];
|
||||
if ([c isValid])
|
||||
NS_DURING
|
||||
{
|
||||
unsigned remaining = [proxy activeCount];
|
||||
|
||||
|
@ -149,17 +182,26 @@ main()
|
|||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
/* An exception could occur if we lost the connection
|
||||
* while trying to check the active count. In that
|
||||
* case we can assume the Command server terminated.
|
||||
*/
|
||||
[c invalidate];
|
||||
active = 0;
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
}
|
||||
[pool release];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
NSLog(@"%@", localException);
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
[pool release];
|
||||
}
|
||||
if (YES == [c isValid])
|
||||
{
|
||||
res = 1; // Command did not shut down in time.
|
||||
}
|
||||
}
|
||||
RELEASE(arp);
|
||||
return 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue