From f04f1292a3c31369565e0e1218663a4ae660fdb2 Mon Sep 17 00:00:00 2001 From: Richard Frith-Macdonald Date: Fri, 3 Jul 2020 11:50:25 +0100 Subject: [PATCH] Many fixups/alterations to launch/shutdown of processes. Removed the 'strict' option to enforce a prefix on defaults keys, since it was really never used and just complicated things. --- AlarmTool.m | 6 +---- EcCommand.m | 69 +++++++++++++++++++++++++++++++++--------------- EcHost.m | 3 +-- EcLogger.m | 10 ++++++- EcProcess.h | 27 ++++++++++++++++--- EcProcess.m | 24 ++++++++++------- EcTest.m | 12 +++------ EcUserDefaults.h | 19 ++++--------- EcUserDefaults.m | 41 +++++++++------------------- LogTool.m | 6 +---- Terminate.m | 6 +---- local.make | 6 ----- 12 files changed, 120 insertions(+), 109 deletions(-) diff --git a/AlarmTool.m b/AlarmTool.m index 7d7d395..71d8664 100644 --- a/AlarmTool.m +++ b/AlarmTool.m @@ -32,9 +32,6 @@ #if !defined(EC_DEFAULTS_PREFIX) #define EC_DEFAULTS_PREFIX nil #endif -#if !defined(EC_DEFAULTS_STRICT) -#define EC_DEFAULTS_STRICT NO -#endif #if !defined(EC_EFFECTIVE_USER) #define EC_EFFECTIVE_USER nil #endif @@ -74,8 +71,7 @@ main() { pref = @""; } - defs = [NSUserDefaults userDefaultsWithPrefix: pref - strict: EC_DEFAULTS_STRICT]; + defs = [NSUserDefaults userDefaultsWithPrefix: pref]; dict = [defs dictionaryForKey: @"WellKnownHostNames"]; if (nil != dict) { diff --git a/EcCommand.m b/EcCommand.m index e0c92cc..8a9a95e 100644 --- a/EcCommand.m +++ b/EcCommand.m @@ -204,6 +204,7 @@ desiredName(Desired state) unsigned terminationCount; // Terminations during startup int terminationStatus; // Last exit status NSTimeInterval registrationDate; // Time of process registration + NSTimeInterval awakenedDate; // When the process was awakened NSTimeInterval deferredDate; // Deferred re-launch interval NSTimeInterval queuedDate; // When queued for launch NSTimeInterval stableDate; // Has been running for a while @@ -221,6 +222,7 @@ desiredName(Desired state) + (void) processQueue; + (void) remove: (NSString*)name; - (BOOL) autolaunch; +- (void) awakened; - (BOOL) checkActive; - (BOOL) checkAlive; - (void) clearClient: (EcClientI*)c cleanly: (BOOL)unregisteredOrTransient; @@ -333,6 +335,8 @@ desiredName(Desired state) - (EcClientI*) findIn: (NSArray*)a byObject: (id)s; - (NSString*) host; +- (void) housekeeping: (NSTimer*)t; +- (void) _housekeeping: (NSTimer*)t; - (void) information: (NSString*)inf from: (NSString*)s type: (EcLogType)t; @@ -356,19 +360,19 @@ desiredName(Desired state) - (void) quitAll; - (void) quitAll: (NSDate*)by; - (void) requestConfigFor: (id)c; -- (NSData*) registerClient: (id)c +- (NSData*) registerClient: (id)c + identifier: (int)p name: (NSString*)n transient: (BOOL)t; - (void) reply: (NSString*) msg to: (NSString*)n from: (NSString*)c; - (void) terminate: (NSDate*)by; - (void) _terminate: (NSTimer*)t; -- (void) housekeeping: (NSTimer*)t; -- (void) _housekeeping: (NSTimer*)t; - (NSMutableArray*) unconfiguredClients; - (void) unregisterByObject: (id)obj; - (void) unregisterClient: (EcClientI*)o; - (void) update; - (void) updateConfig: (NSData*)data; +- (void) woken: (id)obj; @end @@ -579,6 +583,11 @@ desiredName(Desired state) return [[conf objectForKey: @"Auto"] boolValue]; } +- (void) awakened +{ + awakenedDate = [NSDate timeIntervalSinceReferenceDate]; +} + /* Check to see if there is an active process connected (or which connects * when we contact it and ask it to). */ @@ -671,7 +680,7 @@ desiredName(Desired state) clientLost = YES; } /* The connection to the client went away, which implies that the process - * was connected/registred and we must either be stopping already or need + * was connected/registered and we must either be stopping already or need * to stop (expect the process to die soon). * So either way we should trigger the -stopping: timeout handler to * check for the end of the process and to ensure that we try again if @@ -1109,14 +1118,15 @@ NSLog(@"startup completed for %@", self); startingTimer = nil; startingDate = 0.0; starting = NO; - if (Dead == desired) - { - /* It is not desired that this process should be running: - * initiate a shutdown. - */ - [self stop]; - } } + if (Dead == desired) + { + /* It is not desired that this process should be running: + * initiate a shutdown. + */ + [self stop]; + } + [self progress]; [LaunchInfo processQueue]; // Maybe we can launch more now } @@ -1584,6 +1594,7 @@ NSLog(@"startup completed for %@", self); [stoppingTimer invalidate]; stoppingTimer = nil; + awakenedDate = 0.0; abortDate = 0.0; stopping = NO; DESTROY(terminateBy); // Termination completed @@ -1655,10 +1666,6 @@ NSLog(@"startup completed for %@", self); { /* Maximum time for clean shutdown has passed. */ - if (client != nil) - { - [self clearClient: client cleanly: NO]; - } [[NSNotificationCenter defaultCenter] removeObserver: self name: NSTaskDidTerminateNotification @@ -1670,7 +1677,15 @@ NSLog(@"startup completed for %@", self); kill(identifier, SIGKILL); identifier = 0; } - [self stopped]; + if (client != nil) + { + [self clearClient: client cleanly: NO]; + } + else + { + [self stopped]; + } + return; } else { @@ -4023,12 +4038,12 @@ NSLog(@"Problem %@", localException); } } -- (NSData*) registerClient: (id)c +- (NSData*) registerClient: (id)c + identifier: (int)p name: (NSString*)n transient: (BOOL)t { LaunchInfo *l = [LaunchInfo existing: n]; - int pid; NSMutableDictionary *dict; EcClientI *obj; EcClientI *old; @@ -4047,11 +4062,9 @@ NSLog(@"Problem %@", localException); errorDescription: 0]; } - pid = [c processIdentifier]; - /* Do we already have this registered? */ - if ([l processIdentifier] == pid && (obj = [l client]) != nil) + if ([l processIdentifier] == p && (obj = [l client]) != nil) { [self logChange: @"re-registered" for: [l name]]; if ([l stable] == YES) @@ -4074,7 +4087,7 @@ NSLog(@"Problem %@", localException); RELEASE(obj); [clients sortUsingSelector: @selector(compare:)]; - [obj setProcessIdentifier: pid]; + [obj setProcessIdentifier: p]; if (nil == l) { @@ -4904,5 +4917,17 @@ NSLog(@"Problem %@", localException); [self newConfig: newConfig]; } +- (void) woken: (id)obj +{ + EcClientI *o = [self findIn: clients byObject: obj]; + + if (o != nil) + { + LaunchInfo *l = [launchInfo objectForKey: [o name]]; + + [l awakened]; + } +} + @end diff --git a/EcHost.m b/EcHost.m index e1ab70d..5d39531 100644 --- a/EcHost.m +++ b/EcHost.m @@ -72,8 +72,7 @@ static NSString *controlName = nil; defs = [NSUserDefaults prefixedDefaults]; if (nil == defs) { - defs = [NSUserDefaults userDefaultsWithPrefix: nil - strict: NO]; + defs = [NSUserDefaults userDefaultsWithPrefix: nil]; } name = [defs stringForKey: @"ControlHost"]; if (nil != name) diff --git a/EcLogger.m b/EcLogger.m index 9866289..4741650 100644 --- a/EcLogger.m +++ b/EcLogger.m @@ -147,7 +147,10 @@ static NSArray *modes; id server; server = (id)[EcProc server: name]; - [server registerClient: self name: cmdLogName() transient: NO]; + [server registerClient: self + identifier: [[NSProcessInfo processInfo] processIdentifier] + name: cmdLogName() + transient: NO]; } /* Should only be called on main thread, but doesn't matter. @@ -210,6 +213,11 @@ static NSArray *modes; return s; } +- (BOOL) ecDidAwaken +{ + return YES; +} + /** * Internal flush operation ... writes data out from us, but * doesn't try any further. Only called in main thread. diff --git a/EcProcess.h b/EcProcess.h index d253732..bdb837e 100644 --- a/EcProcess.h +++ b/EcProcess.h @@ -153,9 +153,21 @@ typedef enum { /** Messages that the Command server may send to clients. */ @protocol CmdClient +/** Passes a property list message to the client (eg from the Console). + */ - (oneway void) cmdMesgData: (in bycopy NSData*)dat from: (NSString*)name; +/** Tells the client to shut down. + */ - (oneway void) cmdQuit: (NSInteger)status; +/** Asks the client for its process identifier. + */ - (int) processIdentifier; +/** Asks the client whether it is awake (-ecAwaken has been called) + */ +- (BOOL) ecDidAwaken; +/** Instructs the client process to connect and re-register with the Command + * server. + */ - (oneway void) ecReconnect; @end @@ -170,9 +182,11 @@ typedef enum { type: (EcLogType)t for: (id)o; - (bycopy NSData*) registerClient: (id)c + identifier: (int)p name: (NSString*)n transient: (BOOL)t; - (void) unregisterByObject: (id)obj; +- (void) woken: (id)obj; @end @protocol Console @@ -180,8 +194,8 @@ typedef enum { @end /** Messages that clients may send to the server. - * NB. The -registerClient:name:transient: method must be sent before - * the -command:to:from: or -reply:to:from: methods. + * NB. The -registerClient:identifier:name:transient: method must be sent + * before the -command:to:from: or -reply:to:from: methods. */ @protocol Command @@ -208,7 +222,8 @@ typedef enum { /** Registers as a client process of the Command server. */ -- (bycopy NSData*) registerClient: (id)c +- (bycopy NSData*) registerClient: (id)c + identifier: (int)p name: (NSString*)n transient: (BOOL)t; @@ -236,6 +251,12 @@ typedef enum { * time your software needs it. */ - (bycopy NSData *) configurationFor: (NSString *)name; + +/** Informs the Command server that a previously registered client considers + * itself to have started up and to now be stable. + */ +- (void) woken: (id)obj; + @end /* diff --git a/EcProcess.m b/EcProcess.m index 8d298f1..21cb169 100644 --- a/EcProcess.m +++ b/EcProcess.m @@ -105,9 +105,6 @@ static NSInteger descriptorsMaximum = 0; #if !defined(EC_DEFAULTS_PREFIX) #define EC_DEFAULTS_PREFIX nil #endif -#if !defined(EC_DEFAULTS_STRICT) -#define EC_DEFAULTS_STRICT NO -#endif #if !defined(EC_EFFECTIVE_USER) #define EC_EFFECTIVE_USER nil #endif @@ -1600,9 +1597,7 @@ findMode(NSDictionary* d, NSString* s) prf = @""; } - ASSIGN(cmdDefs, [NSUserDefaults - userDefaultsWithPrefix: prf - strict: EC_DEFAULTS_STRICT]); + ASSIGN(cmdDefs, [NSUserDefaults userDefaultsWithPrefix: prf]); defs = [EcDefaultRegistration merge: defs]; [cmdDefs registerDefaults: defs]; @@ -1676,9 +1671,7 @@ findMode(NSDictionary* d, NSString* s) NSLog(@"You must be '%@' to run this.", cmdUser); exit(1); } - ASSIGN(cmdDefs, [NSUserDefaults - userDefaultsWithPrefix: prf - strict: EC_DEFAULTS_STRICT]); + ASSIGN(cmdDefs, [NSUserDefaults userDefaultsWithPrefix: prf]); if (defs != nil) { [cmdDefs registerDefaults: defs]; @@ -3466,6 +3459,7 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval); NSData *d; d = [proxy registerClient: self + identifier: [self processIdentifier] name: cmdLogName() transient: cmdIsTransient]; r = [NSPropertyListSerialization @@ -3806,6 +3800,17 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval); [self triggerCmdTimeout]; /* make sure that regular timers run. */ + NS_DURING + [cmdServer woken: self]; + NS_HANDLER + DESTROY(cmdServer); + NS_ENDHANDLER + if (nil == cmdServer) + { + DESTROY(cmdLast); // Allow immediate retry + [self cmdNewServer]; + } + loop = [NSRunLoop currentRunLoop]; future = [NSDate distantFuture]; while (YES == [EcProcConnection isValid]) @@ -3868,6 +3873,7 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval); { NS_DURING [cmdServer registerClient: self + identifier: [self processIdentifier] name: cmdLogName() transient: cmdIsTransient]; NS_HANDLER diff --git a/EcTest.m b/EcTest.m index 827a9c7..91213b0 100644 --- a/EcTest.m +++ b/EcTest.m @@ -32,9 +32,6 @@ #if !defined(EC_DEFAULTS_PREFIX) #define EC_DEFAULTS_PREFIX nil #endif -#if !defined(EC_DEFAULTS_STRICT) -#define EC_DEFAULTS_STRICT NO -#endif #if !defined(EC_EFFECTIVE_USER) #define EC_EFFECTIVE_USER nil #endif @@ -61,8 +58,7 @@ defaults() { pref = @""; } - ASSIGN(defs, [NSUserDefaults userDefaultsWithPrefix: pref - strict: EC_DEFAULTS_STRICT]); + ASSIGN(defs, [NSUserDefaults userDefaultsWithPrefix: pref]); dict = [defs dictionaryForKey: @"WellKnownHostNames"]; if (nil != dict) { @@ -142,10 +138,11 @@ EcTestConnect(NSString *name, NSString *host, NSTimeInterval timeout) { if (YES == [(EcProcess*)proxy cmdIsClient]) { - if (NO == [(EcProcess*)proxy cmdIsConnected]) + if (NO == [(EcProcess*)proxy ecDidAwaken]) { /* We must wait for the connected process to register - * with the Command server and configure itself. + * with the Command server (if it's not transient) and + * configure itself and wake up. */ proxy = nil; [NSThread sleepForTimeInterval: 0.1]; @@ -243,4 +240,3 @@ EcTestShutdown(id process, NSTimeInterval timeout) return YES; } - diff --git a/EcUserDefaults.h b/EcUserDefaults.h index 34b03f1..6c97af1 100644 --- a/EcUserDefaults.h +++ b/EcUserDefaults.h @@ -47,18 +47,14 @@ */ + (void) setDefaultLifetime: (NSTimeInterval)t; -/** Returns a proxy to the shared user defaults instance, which will use +/** Returns a proxy to the shared user defaults instance, which will allow * aPrefix at the start of every key.
* If aPrefix is nil, the string given by the EcUserDefaultsPrefix user * default is used.
- * If the enforcePrefix flag is YES, the prefix is strictly enforced, - * otherwise the system will read defaults using the unprefixed key - * if no value is found for the prefixed key. Similary, when setting - * values, this flag will force the prefix to be prepended to any key - * where it is not already present. + * The proxy will read defaults using the unprefixed key if no value is + * found for the prefixed key. */ -+ (NSUserDefaults*) userDefaultsWithPrefix: (NSString*)aPrefix - strict: (BOOL)enforcePrefix; ++ (NSUserDefaults*) userDefaultsWithPrefix: (NSString*)aPrefix; /** Returns a dictionary listing all the command override keys for which * values are currently set. The values in the dictionary are the timestamps @@ -81,12 +77,7 @@ */ - (NSString*) defaultsPrefix; -/** returns YES if this is a proxy which enforces the use of the prefix on - * defaults keys. - */ -- (BOOL) enforcePrefix; - -/** Convenience method to prepend the pefix to the supplied aKey value +/** Convenience method to prepend the prefix to the supplied aKey value * if it is not already present. */ - (NSString*) key: (NSString*)aKey; diff --git a/EcUserDefaults.m b/EcUserDefaults.m index cc1a4ca..c83ee30 100644 --- a/EcUserDefaults.m +++ b/EcUserDefaults.m @@ -48,9 +48,8 @@ static NSTimeInterval defaultDuration = (72.0 * 60.0 * 60.0); { NSUserDefaults *defs; NSString *prefix; - BOOL enforce; } -- (id) initWithPrefix: (NSString*)p strict: (BOOL)s; +- (id) initWithPrefix: (NSString*)p; - (NSString*) _getKey: (NSString*)baseKey; @end @@ -143,7 +142,7 @@ static NSTimeInterval defaultDuration = (72.0 * 60.0 * 60.0); { aKey = [prefix stringByAppendingString: aKey]; } - if (NO == enforce && nil == [defs objectForKey: aKey]) + if (nil == [defs objectForKey: aKey]) { /* Nothing found for key ... try without the prefix. */ @@ -159,12 +158,11 @@ static NSTimeInterval defaultDuration = (72.0 * 60.0 * 60.0); return nil; } -- (id) initWithPrefix: (NSString*)p strict: (BOOL)s +- (id) initWithPrefix: (NSString*)p { NSMutableArray *list; [lock lock]; - enforce = s; defs = [[NSUserDefaults standardUserDefaults] retain]; if (0 == [p length]) { @@ -238,41 +236,39 @@ static NSTimeInterval defaultDuration = (72.0 * 60.0 * 60.0); - (void) setBool: (BOOL)value forKey: (NSString*)aKey { - [defs setBool: value forKey: (enforce ? [self key: aKey] : aKey)]; + [defs setBool: value forKey: aKey]; } - (BOOL) setCommand: (id)val forKey: (NSString*)key { - return [defs setCommand: val forKey: (enforce ? [self key: key] : key)]; + return [defs setCommand: val forKey: key]; } - (BOOL) setCommand: (id)val forKey: (NSString*)key lifetime: (NSTimeInterval)t { - return [defs setCommand: val - forKey: (enforce ? [self key: key] : key) - lifetime: t]; + return [defs setCommand: val forKey: key lifetime: t]; } - (void) setDouble: (double)value forKey: (NSString*)aKey { - [defs setDouble: value forKey: (enforce ? [self key: aKey] : aKey)]; + [defs setDouble: value forKey: aKey]; } - (void) setFloat: (float)value forKey: (NSString*)aKey { - [defs setFloat: value forKey: (enforce ? [self key: aKey] : aKey)]; + [defs setFloat: value forKey: aKey]; } - (void) setInteger: (NSInteger)value forKey: (NSString*)aKey { - [defs setInteger: value forKey: (enforce ? [self key: aKey] : aKey)]; + [defs setInteger: value forKey: aKey]; } - (void) setObject: (id)anObject forKey: (NSString*)aKey { - [defs setObject: anObject forKey: (enforce ? [self key: aKey] : aKey)]; + [defs setObject: anObject forKey: aKey]; } - (NSArray*) stringArrayForKey: (NSString*)aKey @@ -318,10 +314,9 @@ static NSTimeInterval defaultDuration = (72.0 * 60.0 * 60.0); } + (NSUserDefaults*) userDefaultsWithPrefix: (NSString*)aPrefix - strict: (BOOL)enforcePrefix { - return (NSUserDefaults*)[[[EcUserDefaults alloc] initWithPrefix: - aPrefix strict: enforcePrefix] autorelease]; + return (NSUserDefaults*)[[[EcUserDefaults alloc] + initWithPrefix: aPrefix] autorelease]; } - (NSDictionary*) commandExpiries @@ -354,11 +349,6 @@ static NSTimeInterval defaultDuration = (72.0 * 60.0 * 60.0); return nil; // No prefix in use ... this is not a proxy } -- (BOOL) enforcePrefix -{ - return NO; // No prefix to enforce ... this is not a proxy -} - - (NSString*) key: (NSString*)aKey { NSString *prefix = [self defaultsPrefix]; @@ -441,13 +431,6 @@ static NSTimeInterval defaultDuration = (72.0 * 60.0 * 60.0); BOOL changed = NO; id old; - if (YES == [self enforcePrefix]) - { - /* Make sure prefix is used if we have one set. - */ - key = [self key: key]; - } - [lock lock]; old = [overrides objectForKey: key]; if (old != val && NO == [old isEqual: val]) diff --git a/LogTool.m b/LogTool.m index 626215b..caf7ece 100644 --- a/LogTool.m +++ b/LogTool.m @@ -32,9 +32,6 @@ #if !defined(EC_DEFAULTS_PREFIX) #define EC_DEFAULTS_PREFIX nil #endif -#if !defined(EC_DEFAULTS_STRICT) -#define EC_DEFAULTS_STRICT NO -#endif #if !defined(EC_EFFECTIVE_USER) #define EC_EFFECTIVE_USER nil #endif @@ -68,8 +65,7 @@ main() { pref = @""; } - defs = [NSUserDefaults userDefaultsWithPrefix: pref - strict: EC_DEFAULTS_STRICT]; + defs = [NSUserDefaults userDefaultsWithPrefix: pref]; dict = [defs dictionaryForKey: @"WellKnownHostNames"]; if (nil != dict) { diff --git a/Terminate.m b/Terminate.m index c90f1ad..466e422 100644 --- a/Terminate.m +++ b/Terminate.m @@ -32,9 +32,6 @@ #if !defined(EC_DEFAULTS_PREFIX) #define EC_DEFAULTS_PREFIX nil #endif -#if !defined(EC_DEFAULTS_STRICT) -#define EC_DEFAULTS_STRICT NO -#endif #if !defined(EC_EFFECTIVE_USER) #define EC_EFFECTIVE_USER nil #endif @@ -67,8 +64,7 @@ main() { pref = @""; } - defs = [NSUserDefaults userDefaultsWithPrefix: pref - strict: EC_DEFAULTS_STRICT]; + defs = [NSUserDefaults userDefaultsWithPrefix: pref]; if ([defs boolForKey: @"Help"] || [defs boolForKey: @"help"] || [[[NSProcessInfo processInfo] arguments] containsObject: @"--Help"] diff --git a/local.make b/local.make index 09fcf84..aaead83 100644 --- a/local.make +++ b/local.make @@ -11,11 +11,6 @@ # May be used to define an Objective-C string literal to be used as the # prefix when looking up keys in the defaults/configuration system. # -# EC_DEFAULTS_STRICT -# May be used to define an Objective-C boolean literal to be used to -# control whether configuration keys are used only with the prefix -# or whether values for keys without the prefix are also looked up. -# # EC_EFFECTIVE_USER # May be used to define an Objective-C string literal to be used to # specify the name of the user to run all EcProcess programs. @@ -28,7 +23,6 @@ ECCL_CPPFLAGS += \ '-DEC_DEFAULTS_PREFIX=@"XX"'\ - '-DEC_DEFAULTS_STRICT=NO'\ '-DEC_EFFECTIVE_USER=@"dummy"'\ # Command_CPPFLAGS ...