mirror of
https://github.com/gnustep/libs-ec.git
synced 2025-02-21 02:41:11 +00:00
Improve tolerance (and logging) of re-entrancy in -starting: method.
This commit is contained in:
parent
f54012db83
commit
68b560b62b
1 changed files with 153 additions and 120 deletions
273
EcCommand.m
273
EcCommand.m
|
@ -354,6 +354,10 @@ desiredName(Desired state)
|
||||||
/** Records the alarms currently raised for this process.
|
/** Records the alarms currently raised for this process.
|
||||||
*/
|
*/
|
||||||
NSMutableArray *alarms;
|
NSMutableArray *alarms;
|
||||||
|
|
||||||
|
/* Flag to detect recursive call to -starting:
|
||||||
|
*/
|
||||||
|
BOOL inStarting;
|
||||||
}
|
}
|
||||||
+ (NSString*) description;
|
+ (NSString*) description;
|
||||||
+ (LaunchInfo*) existing: (NSString*)name;
|
+ (LaunchInfo*) existing: (NSString*)name;
|
||||||
|
@ -1833,7 +1837,15 @@ valgrindLog(NSString *name)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NSLog(@"-start called for %@", self);
|
if (startingTimer != nil)
|
||||||
|
{
|
||||||
|
NSLog(@"-start called for %@ with timer already present at %@",
|
||||||
|
self, [NSThread callStackSymbols]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NSLog(@"-start called for %@", self);
|
||||||
|
}
|
||||||
[self resetDelay];
|
[self resetDelay];
|
||||||
startingAlarm = NO;
|
startingAlarm = NO;
|
||||||
startingDate = [NSDate timeIntervalSinceReferenceDate];
|
startingDate = [NSDate timeIntervalSinceReferenceDate];
|
||||||
|
@ -1923,137 +1935,158 @@ valgrindLog(NSString *name)
|
||||||
|
|
||||||
- (void) starting: (NSTimer*)t
|
- (void) starting: (NSTimer*)t
|
||||||
{
|
{
|
||||||
EcCommand *command = (EcCommand*)EcProc;
|
|
||||||
NSTimeInterval ti = 0.0;
|
|
||||||
|
|
||||||
/* On entry t is either a one-shot timer which will automatically
|
/* On entry t is either a one-shot timer which will automatically
|
||||||
* be invalidated after the method completes, or nil (method called
|
* be invalidated after the method completes, or nil (method called
|
||||||
* explicitly, so the timer must be invalidated here).
|
* explicitly, so the timer must be invalidated here).
|
||||||
* Either way the timer is no longer valid and a new one will need
|
* Either way the timer is no longer valid and a new one will need
|
||||||
* to be created unless startup has completed.
|
* to be created unless startup has completed.
|
||||||
*/
|
*/
|
||||||
[startingTimer invalidate];
|
|
||||||
startingTimer = nil;
|
|
||||||
if (NO == [self isStarting])
|
|
||||||
{
|
|
||||||
EcExceptionMajor(nil, @"-starting: when not starting for %@", self);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (client != nil)
|
|
||||||
{
|
|
||||||
EcExceptionMajor(nil, @"-starting: when already registered for %@", self);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ([self checkAbandonedStartup])
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (0 == identifier)
|
|
||||||
{
|
|
||||||
NSString *r = [self reasonToPreventLaunch];
|
|
||||||
|
|
||||||
if (nil == r)
|
if (inStarting)
|
||||||
{
|
{
|
||||||
/* We are able to launch now
|
return; // Re-entrant call ignored.
|
||||||
*/
|
}
|
||||||
[launchQueue removeObject: self];
|
inStarting = YES;
|
||||||
queuedDate = 0.0;
|
NS_DURING
|
||||||
terminationDate = 0.0;
|
{
|
||||||
terminationStatusKnown = NO;
|
EcCommand *command = (EcCommand*)EcProc;
|
||||||
if (NO == [self launch])
|
NSTimeInterval ti = 0.0;
|
||||||
{
|
|
||||||
ti = [self delay]; // delay between launch attempts
|
|
||||||
[launchQueue addObject: self];
|
|
||||||
queuedDate = [NSDate timeIntervalSinceReferenceDate];
|
|
||||||
[command logChange: @"queued (launch failed)" for: name];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (client != nil)
|
|
||||||
{
|
|
||||||
return; // Connection established.
|
|
||||||
}
|
|
||||||
ti = 0.0; // Calculate the time to wait below
|
|
||||||
[command logChange: @"launched" for: name];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
BOOL alreadyQueued = [launchQueue containsObject: self];
|
|
||||||
NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
|
|
||||||
|
|
||||||
if (deferredDate > 0.0 && now < deferredDate)
|
|
||||||
{
|
|
||||||
/* We are waiting for a retry at a specific time.
|
|
||||||
* If we are not already queued, add to queue.
|
|
||||||
*/
|
|
||||||
ti = deferredDate - now;
|
|
||||||
if (NO == alreadyQueued)
|
|
||||||
{
|
|
||||||
[launchQueue addObject: self];
|
|
||||||
queuedDate = [NSDate timeIntervalSinceReferenceDate];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Launching is prevented for a non-time-based reason,
|
|
||||||
* so we reset the time from which we count launching as
|
|
||||||
* started and specify a timer for checking again.
|
|
||||||
*/
|
|
||||||
startingDate = [NSDate timeIntervalSinceReferenceDate];
|
|
||||||
ti = 1.0;
|
|
||||||
if (NO == alreadyQueued)
|
|
||||||
{
|
|
||||||
[launchQueue addObject: self];
|
|
||||||
queuedDate = [NSDate timeIntervalSinceReferenceDate];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (NO == alreadyQueued)
|
|
||||||
{
|
|
||||||
r = [NSString stringWithFormat: @"queued (%@)", r];
|
|
||||||
[command logChange: r for: name];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (0.0 == ti && startingDate > 0.0)
|
|
||||||
{
|
|
||||||
ti = [NSDate timeIntervalSinceReferenceDate];
|
|
||||||
if (ti - startingDate < 30.0)
|
|
||||||
{
|
|
||||||
/* We need to raise an alarm if it takes longer than 30 seconds
|
|
||||||
* to start up the process.
|
|
||||||
*/
|
|
||||||
ti = 30.0 - (ti - startingDate);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (NO == startingAlarm)
|
|
||||||
{
|
|
||||||
startingAlarm = YES;
|
|
||||||
[command alarmCode: ACLaunchFailed
|
|
||||||
procName: name
|
|
||||||
addText: @"Client not active after launch attempt"];
|
|
||||||
}
|
|
||||||
ti = 60.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (nil != startingTimer)
|
|
||||||
{
|
|
||||||
[startingTimer invalidate];
|
[startingTimer invalidate];
|
||||||
EcExceptionMajor(nil, @"startingTimer reset %@", self);
|
startingTimer = nil;
|
||||||
|
if (NO == [self isStarting])
|
||||||
|
{
|
||||||
|
EcExceptionMajor(nil, @"-starting: when not starting for %@", self);
|
||||||
|
inStarting = NO;
|
||||||
|
NS_VOIDRETURN;
|
||||||
|
}
|
||||||
|
if (client != nil)
|
||||||
|
{
|
||||||
|
EcExceptionMajor(nil, @"-starting: after registered for %@", self);
|
||||||
|
inStarting = NO;
|
||||||
|
NS_VOIDRETURN;
|
||||||
|
}
|
||||||
|
if ([self checkAbandonedStartup])
|
||||||
|
{
|
||||||
|
inStarting = NO;
|
||||||
|
NS_VOIDRETURN;
|
||||||
|
}
|
||||||
|
if (0 == identifier)
|
||||||
|
{
|
||||||
|
NSString *r = [self reasonToPreventLaunch];
|
||||||
|
|
||||||
|
if (nil == r)
|
||||||
|
{
|
||||||
|
/* We are able to launch now
|
||||||
|
*/
|
||||||
|
[launchQueue removeObject: self];
|
||||||
|
queuedDate = 0.0;
|
||||||
|
terminationDate = 0.0;
|
||||||
|
terminationStatusKnown = NO;
|
||||||
|
if (NO == [self launch])
|
||||||
|
{
|
||||||
|
ti = [self delay]; // delay between launch attempts
|
||||||
|
[launchQueue addObject: self];
|
||||||
|
queuedDate = [NSDate timeIntervalSinceReferenceDate];
|
||||||
|
[command logChange: @"queued (launch failed)" for: name];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (client != nil)
|
||||||
|
{
|
||||||
|
inStarting = NO;
|
||||||
|
NS_VOIDRETURN; // Connection established.
|
||||||
|
}
|
||||||
|
ti = 0.0; // Calculate the time to wait below
|
||||||
|
[command logChange: @"launched" for: name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BOOL alreadyQueued;
|
||||||
|
NSTimeInterval now;
|
||||||
|
|
||||||
|
alreadyQueued = [launchQueue containsObject: self];
|
||||||
|
now = [NSDate timeIntervalSinceReferenceDate];
|
||||||
|
if (deferredDate > 0.0 && now < deferredDate)
|
||||||
|
{
|
||||||
|
/* We are waiting for a retry at a specific time.
|
||||||
|
* If we are not already queued, add to queue.
|
||||||
|
*/
|
||||||
|
ti = deferredDate - now;
|
||||||
|
if (NO == alreadyQueued)
|
||||||
|
{
|
||||||
|
[launchQueue addObject: self];
|
||||||
|
queuedDate = [NSDate timeIntervalSinceReferenceDate];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Launching is prevented for a non-time-based reason,
|
||||||
|
* so we reset the time from which we count launching as
|
||||||
|
* started and specify a timer for checking again.
|
||||||
|
*/
|
||||||
|
startingDate = [NSDate timeIntervalSinceReferenceDate];
|
||||||
|
ti = 1.0;
|
||||||
|
if (NO == alreadyQueued)
|
||||||
|
{
|
||||||
|
[launchQueue addObject: self];
|
||||||
|
queuedDate = [NSDate timeIntervalSinceReferenceDate];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (NO == alreadyQueued)
|
||||||
|
{
|
||||||
|
r = [NSString stringWithFormat: @"queued (%@)", r];
|
||||||
|
[command logChange: r for: name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (0.0 == ti && startingDate > 0.0)
|
||||||
|
{
|
||||||
|
ti = [NSDate timeIntervalSinceReferenceDate];
|
||||||
|
if (ti - startingDate < 30.0)
|
||||||
|
{
|
||||||
|
/* We need to raise an alarm if it takes longer than 30 seconds
|
||||||
|
* to start up the process.
|
||||||
|
*/
|
||||||
|
ti = 30.0 - (ti - startingDate);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (NO == startingAlarm)
|
||||||
|
{
|
||||||
|
startingAlarm = YES;
|
||||||
|
[command alarmCode: ACLaunchFailed
|
||||||
|
procName: name
|
||||||
|
addText: @"Client not active after launch attempt"];
|
||||||
|
}
|
||||||
|
ti = 60.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nil != startingTimer)
|
||||||
|
{
|
||||||
|
[startingTimer invalidate];
|
||||||
|
EcExceptionMajor(nil, @"startingTimer reset %@", self);
|
||||||
|
}
|
||||||
|
if (startingDate > 0.0)
|
||||||
|
{
|
||||||
|
startingTimer = [NSTimer scheduledTimerWithTimeInterval: ti
|
||||||
|
target: self
|
||||||
|
selector: _cmd
|
||||||
|
userInfo: name
|
||||||
|
repeats: NO];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NSLog(@"Startup cancelled in -starting: for %@", self);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (startingDate > 0.0)
|
NS_HANDLER
|
||||||
{
|
{
|
||||||
startingTimer = [NSTimer scheduledTimerWithTimeInterval: ti
|
EcExceptionMajor(localException, @"Problem -starting: %@", self);
|
||||||
target: self
|
|
||||||
selector: _cmd
|
|
||||||
userInfo: name
|
|
||||||
repeats: NO];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
NSLog(@"Startup cancelled in -starting: for %@", self);
|
|
||||||
}
|
}
|
||||||
|
NS_ENDHANDLER
|
||||||
|
inStarting = NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSDate*) startingDate
|
- (NSDate*) startingDate
|
||||||
|
|
Loading…
Reference in a new issue