diff --git a/ChangeLog b/ChangeLog index 7b4794d6d..268c6991e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,34 @@ +Wed Apr 1 18:45:00 1998 Richard Frith-Macdonald + + * Tools/gdomap.m: Modified code so that we make sure we have at least + one valid route to any gdomap process which has probed us. This is + to cope with machines which send out info about all their interfaces + when one or more of the interfaces is not working. + + * src/checks/nstask.m: added test for environment setting. + + * src/NSCalendarDate.m: Fixed bug in initialisation where daylight + savings time is in operation - was adjusting in wrong direction. + + * src/NSRunLoop.m: Added NSObject catagory for the methods - + ([NSObject +cancelPreviousPerformRequestsWithTarget:selector:object:]), + ([NSObject -performSelector:withObject:afterDelay:]), and + ([NSObject -performSelector:withObject:afterDelay:inModes:]) + + * src/NSTask.m: Various bug fixes as a result of running the test + suite. All seems to work ok now. + + * src/NSDate.h: Changed order of declaractions so this can be included + within NSObject.h + + * src/NSObject.h: Added run-loop integration methods - + ([NSObject +cancelPreviousPerformRequestsWithTarget:selector:object:]), + ([NSObject -performSelector:withObject:afterDelay:]), and + ([NSObject -performSelector:withObject:afterDelay:inModes:]) + + * src/NSRunLoop.h: Added an instance variable to keep track of + queued delayed actions to be performed on objects. + Tue Mar 31 11:32:03 1998 Adam Fedor * aclocal.m4 (OBJC_CON_AUTOLOAD): Improved test. Check nm output diff --git a/Headers/gnustep/base/NSDate.h b/Headers/gnustep/base/NSDate.h index 4936224fc..88bd993c4 100644 --- a/Headers/gnustep/base/NSDate.h +++ b/Headers/gnustep/base/NSDate.h @@ -21,11 +21,11 @@ #ifndef __NSDate_h_GNUSTEP_BASE_INCLUDE #define __NSDate_h_GNUSTEP_BASE_INCLUDE -#include - /* Time interval difference between two dates, in seconds. */ typedef double NSTimeInterval; +#include + @class NSArray; @class NSCalendarDate; @class NSDictionary; diff --git a/Headers/gnustep/base/NSObject.h b/Headers/gnustep/base/NSObject.h index 3bdcdd102..0934a97e9 100644 --- a/Headers/gnustep/base/NSObject.h +++ b/Headers/gnustep/base/NSObject.h @@ -30,6 +30,7 @@ #include @class NSArchiver; +@class NSArray; @class NSCoder; @class NSPortCoder; @class NSMethodSignature; @@ -164,4 +165,19 @@ enum {NSNotFound = 0x7fffffff}; - performSelector: (SEL)aSelector withObject: object1 withObject: object2; @end + +#include +@interface NSObject (TimedPerformers) ++ (void) cancelPreviousPerformRequestsWithTarget: (id)obj + selector: (SEL)s + object: (id)arg; +- (void) performSelector: (SEL)s + withObject: (id)arg + afterDelay: (NSTimeInterval)seconds; +- (void) performSelector: (SEL)s + withObject: (id)arg + afterDelay: (NSTimeInterval)seconds + inModes: (NSArray*)modes; +@end + #endif /* __NSObject_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Headers/gnustep/base/NSRunLoop.h b/Headers/gnustep/base/NSRunLoop.h index b617bfc9b..2cb355eb8 100644 --- a/Headers/gnustep/base/NSRunLoop.h +++ b/Headers/gnustep/base/NSRunLoop.h @@ -38,6 +38,7 @@ extern id NSDefaultRunLoopMode; @private NSMapTable *_mode_2_timers; @private NSMapTable *_mode_2_watchers; @private NSMutableArray *_performers; + @private NSMutableArray *_timedPerformers; } + (NSRunLoop*) currentRunLoop; diff --git a/Source/NSCalendarDate.m b/Source/NSCalendarDate.m index 274ea4cc6..39a18e1cb 100644 --- a/Source/NSCalendarDate.m +++ b/Source/NSCalendarDate.m @@ -525,7 +525,7 @@ static id long_day[7] = {@"Sunday", oldOffset = [time_zone timeZoneSecondsFromGMT]; time_zone = z; newOffset = [time_zone timeZoneSecondsFromGMT]; - s += oldOffset - newOffset; + s += newOffset - oldOffset; } else { diff --git a/Source/NSRunLoop.m b/Source/NSRunLoop.m index 40eb95870..c395ef535 100644 --- a/Source/NSRunLoop.m +++ b/Source/NSRunLoop.m @@ -271,6 +271,18 @@ static int debug_run_loop = 0; @end + +@interface NSRunLoop (TimedPerformers) +- (NSMutableArray*) _timedPerformers; +@end + +@implementation NSRunLoop (TimedPerformers) +- (NSMutableArray*) _timedPerformers +{ + return _timedPerformers; +} +@end + /* * The RunLoopPerformer class is used to hold information about * messages which are due to be sent to objects once a particular @@ -282,7 +294,8 @@ static int debug_run_loop = 0; id target; id argument; unsigned order; - NSArray* modes; + NSArray *modes; + NSTimer *timer; } - (void) fire; @@ -296,12 +309,14 @@ static int debug_run_loop = 0; argument: anArgument; - (NSArray*) modes; - (unsigned int) order; +- (void) setTimer: (NSTimer*)timer; @end @implementation RunLoopPerformer - (void) dealloc { + [timer invalidate]; [target release]; [argument release]; [modes release]; @@ -310,7 +325,13 @@ static int debug_run_loop = 0; - (void)fire { - [target perform:selector withObject:argument]; + if (timer != nil) { + timer = nil; + [[self retain] autorelease]; + [[[NSRunLoop currentInstance] _timedPerformers] + removeObjectIdenticalTo: self]; + } + [target perform: selector withObject: argument]; } - initWithSelector: (SEL)aSelector @@ -351,6 +372,91 @@ static int debug_run_loop = 0; return order; } +- (void) setTimer: (NSTimer*)t +{ + timer = t; +} +@end + +@implementation NSObject (TimedPerformers) + ++ (void) cancelPreviousPerformRequestsWithTarget: (id)target + selector: (SEL)aSelector + object: (id)arg +{ + NSMutableArray *array; + int i; + + [target retain]; + [arg retain]; + array = [[NSRunLoop currentInstance] _timedPerformers]; + for (i = [array count]; i > 0; i--) { + if ([[array objectAtIndex: i-1] matchesSelector: aSelector + target: target + argument: arg]) { + [array removeObjectAtIndex: i-1]; + } + } + [arg release]; + [target release]; +} + +- (void) performSelector: (SEL)aSelector + withObject: (id)argument + afterDelay: (NSTimeInterval)seconds +{ + NSMutableArray *array; + RunLoopPerformer *item; + + array = [[NSRunLoop currentInstance] _timedPerformers]; + item = [[RunLoopPerformer alloc] initWithSelector: aSelector + target: self + argument: argument + order: 0 + modes: nil]; + [array addObject: item]; + [item setTimer: [NSTimer scheduledTimerWithTimeInterval: seconds + target: item + selector: @selector(fire) + userInfo: nil + repeats: NO]]; + [item release]; +} + +- (void) performSelector: (SEL)aSelector + withObject: (id)argument + afterDelay: (NSTimeInterval)seconds + inModes: (NSArray*)modes +{ + NSRunLoop *loop; + NSMutableArray *array; + RunLoopPerformer *item; + NSTimer *timer; + int i; + + if (modes == nil || [modes count] == 0) { + return; + } + loop = [NSRunLoop currentInstance]; + array = [loop _timedPerformers]; + item = [[RunLoopPerformer alloc] initWithSelector: aSelector + target: self + argument: argument + order: 0 + modes: nil]; + [array addObject: item]; + timer = [NSTimer timerWithTimeInterval: seconds + target: item + selector: @selector(fire) + userInfo: nil + repeats: NO]; + [item setTimer: timer]; + [item release]; + for (i = 0; i < [modes count]; i++) { + [loop addTimer: timer forMode: [modes objectAtIndex: i]]; + } +} + @end @@ -362,6 +468,7 @@ static int debug_run_loop = 0; - (RunLoopWatcher*) _getWatcher: (void*)data type: (RunLoopEventType)type forMode: (NSString*)mode; +- (NSMutableArray*) _performers; - (void) _removeWatcher: (void*)data type: (RunLoopEventType)type forMode: (NSString*)mode; @@ -430,17 +537,20 @@ static int debug_run_loop = 0; - (void) _checkPerformers { RunLoopPerformer *item; - int count = [_performers count]; + NSArray *array = [NSArray arrayWithArray: _performers]; + int count = [array count]; + unsigned pos; int i; - for (i = count; i > 0; i++) { - item = (RunLoopPerformer*)[_performers objectAtIndex:(i-1)]; + for (i = 0; i < count; i++) { + item = (RunLoopPerformer*)[array objectAtIndex: i]; - if ([[item modes] containsObject: _current_mode]) { - [item retain]; - [_performers removeObjectAtIndex:(i-1)]; - [item fire]; - [item release]; + pos = [_performers indexOfObjectIdenticalTo: item]; + if (pos != NSNotFound) { + if ([[item modes] containsObject: _current_mode]) { + [_performers removeObjectAtIndex: pos]; + [item fire]; + } } } } @@ -640,6 +750,7 @@ static int debug_run_loop = 0; _mode_2_watchers = NSCreateMapTable (NSObjectMapKeyCallBacks, NSObjectMapValueCallBacks, 0); _performers = [[NSMutableArray arrayWithCapacity:8] retain]; + _timedPerformers = [[NSMutableArray arrayWithCapacity:8] retain]; return self; } @@ -648,6 +759,7 @@ static int debug_run_loop = 0; NSFreeMapTable(_mode_2_timers); NSFreeMapTable(_mode_2_watchers); [_performers release]; + [_timedPerformers release]; [super dealloc]; } @@ -1159,6 +1271,8 @@ id NSDefaultRunLoopMode = @"NSDefaultRunLoopMode"; int count = [_performers count]; int i; + [target retain]; + [argument retain]; for (i = count; i > 0; i++) { item = (RunLoopPerformer*)[_performers objectAtIndex:(i-1)]; @@ -1166,6 +1280,8 @@ id NSDefaultRunLoopMode = @"NSDefaultRunLoopMode"; [_performers removeObjectAtIndex:(i-1)]; } } + [argument release]; + [target release]; } - (void) configureAsServer diff --git a/Source/NSTask.m b/Source/NSTask.m index 31b3bd78c..db8471ace 100644 --- a/Source/NSTask.m +++ b/Source/NSTask.m @@ -218,7 +218,7 @@ NSString *NSTaskDidTerminateNotification = @"NSTaskDidTerminateNotification"; if (hasCollected == NO) { [self _collectChild]; } - if (hasTerminated == NO) return NO; + if (hasTerminated == YES) return NO; return YES; } @@ -231,7 +231,7 @@ NSString *NSTaskDidTerminateNotification = @"NSTaskDidTerminateNotification"; if (hasCollected == NO) { [self _collectChild]; } - if (hasTerminated) { + if (hasTerminated == NO) { [NSException raise: NSInvalidArgumentException format: @"NSTask - task has not yet terminated"]; } @@ -259,7 +259,7 @@ NSString *NSTaskDidTerminateNotification = @"NSTaskDidTerminateNotification"; int ec = [e count]; int ac = [a count]; const char *args[ac+2]; - const char *envp[ec+1]; + const char *envl[ec+1]; int i; if (hasLaunched) { @@ -287,12 +287,18 @@ NSString *NSTaskDidTerminateNotification = @"NSTaskDidTerminateNotification"; for (i = 0; i < ec; i++) { NSString *s; id key = [k objectAtIndex: i]; - id val = [e objectForKey: k]; + id val = [e objectForKey: key]; - s = [NSString stringWithFormat: @"%s=%s", [key cString], [val cString]]; - envp[i] = [s cString]; + if (val) { + s = [NSString stringWithFormat: @"%s=%s", + [key cString], [val cString]]; + } + else { + s = [NSString stringWithFormat: @"%s=", [key cString]]; + } + envl[i] = [s cString]; } - envp[ec] = 0; + envl[ec] = 0; path = [[self currentDirectoryPath] cString]; idesc = [[self standardInput] fileDescriptor]; @@ -309,7 +315,7 @@ NSString *NSTaskDidTerminateNotification = @"NSTaskDidTerminateNotification"; if (odesc != 1) dup2(odesc, 1); if (edesc != 2) dup2(edesc, 2); chdir(path); - execve(executable, args, envp); + execve(executable, args, envl); exit(-1); } else { @@ -358,10 +364,13 @@ NSString *NSTaskDidTerminateNotification = @"NSTaskDidTerminateNotification"; { if (hasCollected == NO) { if (waitpid(taskId, &terminationStatus, WNOHANG) == taskId) { - hasCollected = YES; - hasTerminated = YES; - if (hasNotified == NO) { - [self _sendNotification]; + if (WIFEXITED(terminationStatus)) { + terminationStatus = WEXITSTATUS(terminationStatus); + hasCollected = YES; + hasTerminated = YES; + if (hasNotified == NO) { + [self _sendNotification]; + } } } } diff --git a/Testing/nstask.m b/Testing/nstask.m index db3d1548b..bc45a577a 100644 --- a/Testing/nstask.m +++ b/Testing/nstask.m @@ -1,10 +1,12 @@ #include +#include #include int main() { id pool; + NSDictionary *env; NSTask *task; pool = [[NSAutoreleasePool alloc] init]; @@ -14,6 +16,17 @@ main() [task waitUntilExit]; printf("Exit status - %d\n", [task terminationStatus]); + [pool release]; + pool = [[NSAutoreleasePool alloc] init]; + + task = [NSTask new]; + env = [[[[NSProcessInfo processInfo] environment] mutableCopy] autorelease]; + [task setEnvironment: env]; + [task setLaunchPath: @"/bin/sh"]; + [task setArguments: [NSArray arrayWithObjects: @"-c", @"echo $PATH", nil]]; + [task launch]; + [task waitUntilExit]; + [task release]; [pool release]; exit(0); diff --git a/Tools/gdomap.c b/Tools/gdomap.c index e858697a7..5214e262a 100644 --- a/Tools/gdomap.c +++ b/Tools/gdomap.c @@ -537,16 +537,17 @@ prb_del(struct in_addr *p) } /* - * Remove any server from which we have had no messages in the last - * thirty minutes. + * Remove any server from which we have had no messages in the last + * thirty minutes (as long as we have sent as probe in that time). */ static void prb_tim(long when) { int i; + when -= 1800; for (i = prb_used - 1; i >= 0; i--) { - if (when - prb[i]->when > 1800) { + if (prb[i]->when < when && prb[i]->when < last_probe) { prb_del(&prb[i]->sin); } } @@ -1524,10 +1525,10 @@ handle_request(int desc) if (debug > 2) { fprintf(stderr, "Probe from '%s'\n", inet_ntoa(sin)); } - prb_add(&sin); net = inet_netof(sin); ptr = (struct in_addr*)&r_info[desc].buf.r.name[2*IASIZE]; c = (r_info[desc].buf.r.nsize - 2*IASIZE)/IASIZE; + prb_add(&sin); while (c-- > 0) { if (debug > 2) { fprintf(stderr, "Delete server '%s'\n", inet_ntoa(*ptr)); @@ -1535,6 +1536,12 @@ handle_request(int desc) prb_del(ptr); ptr++; } + /* + * Irrespective of what we are told to do - we also add the + * interface from which this packet arrived so we have a + * route we KNOW we can use. + */ + prb_add(&r_info[desc].addr.sin_addr); } /* * For a UDP request from another name server, we send a reply @@ -1611,10 +1618,10 @@ handle_request(int desc) if (debug > 2) { fprintf(stderr, "Probe reply from '%s'\n", inet_ntoa(sin)); } - prb_add(&sin); net = inet_netof(sin); ptr = (struct in_addr*)&r_info[desc].buf.r.name[2*IASIZE]; c = (r_info[desc].buf.r.nsize - 2*IASIZE)/IASIZE; + prb_add(&sin); while (c-- > 0) { if (debug > 2) { fprintf(stderr, "Delete server '%s'\n", inet_ntoa(*ptr)); @@ -1622,6 +1629,12 @@ handle_request(int desc) prb_del(ptr); ptr++; } + /* + * Irrespective of what we are told to do - we also add the + * interface from which this packet arrived so we have a + * route we KNOW we can use. + */ + prb_add(&r_info[desc].addr.sin_addr); } /* * Because this is really a reply to us, we don't want to reply