Add newere method

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@39924 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 2016-06-26 05:56:10 +00:00
parent 35962654cb
commit 04406427e3
5 changed files with 122 additions and 53 deletions

View file

@ -1,3 +1,11 @@
2016-06-26 Richard Frith-Macdonald <rfm@gnu.org>
* Headers/Foundation/NSTask.h:
* Source/NSTask.m:
* Tests/base/NSTask/general.m:
* Tests/base/NSTask/notify.m:
Add -terminationReason method from OSX10.5
2016-06-25 Richard Frith-Macdonald <rfm@gnu.org> 2016-06-25 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSMessagePort.m: * Source/NSMessagePort.m:

View file

@ -36,6 +36,14 @@
extern "C" { extern "C" {
#endif #endif
#if OS_API_VERSION(MAC_OS_X_VERSION_10_5,GS_API_LATEST)
enum {
NSTaskTerminationReasonExit = 1,
NSTaskTerminationReasonUncaughtSignal = 2
};
typedef NSInteger NSTaskTerminationReason;
#endif
@interface NSTask : NSObject @interface NSTask : NSObject
{ {
#if GS_EXPOSE(NSTask) #if GS_EXPOSE(NSTask)
@ -53,6 +61,7 @@ extern "C" {
BOOL _hasTerminated; BOOL _hasTerminated;
BOOL _hasCollected; BOOL _hasCollected;
BOOL _hasNotified; BOOL _hasNotified;
NSTaskTerminationReason _terminationReason;
#endif #endif
#if GS_NONFRAGILE #if GS_NONFRAGILE
#else #else
@ -97,6 +106,9 @@ extern "C" {
#if OS_API_VERSION(GS_API_MACOSX, GS_API_LATEST) #if OS_API_VERSION(GS_API_MACOSX, GS_API_LATEST)
- (int) processIdentifier; - (int) processIdentifier;
#endif #endif
#if OS_API_VERSION(MAC_OS_X_VERSION_10_5,GS_API_LATEST)
- (NSTaskTerminationReason) terminationReason;
#endif
- (int) terminationStatus; - (int) terminationStatus;
/* /*

View file

@ -118,6 +118,10 @@ static void handleSignal(int sig)
} }
#ifdef _WIN32 #ifdef _WIN32
/* We use exit code 10 to denote a process termination.
* Windows does nt have an exit code to denote termination this way.
*/
#define WIN_SIGNALLED 10
@interface NSConcreteWindowsTask : NSTask @interface NSConcreteWindowsTask : NSTask
{ {
@public @public
@ -222,7 +226,7 @@ pty_slave(const char* name)
@interface NSTask (Private) @interface NSTask (Private)
- (NSString *) _fullLaunchPath; - (NSString *) _fullLaunchPath;
- (void) _collectChild; - (void) _collectChild;
- (void) _terminatedChild: (int)status; - (void) _terminatedChild: (int)status reason: (NSTaskTerminationReason)reason;
@end @end
@ -673,6 +677,30 @@ pty_slave(const char* name)
#endif #endif
} }
/**
* Returns the termination reason of the task.<br />
* If the task has not completed running, raises an
* NSInvalidArgumentException.
*/
- (NSTaskTerminationReason) terminationReason
{
if (_hasLaunched == NO)
{
[NSException raise: NSInvalidArgumentException
format: @"NSTask - task has not yet launched"];
}
if (_hasCollected == NO)
{
[self _collectChild];
}
if (_hasTerminated == NO)
{
[NSException raise: NSInvalidArgumentException
format: @"NSTask - task has not yet terminated"];
}
return _terminationReason;
}
/** /**
* Returns the termination status of the task.<br /> * Returns the termination status of the task.<br />
* If the task has not completed running, raises an * If the task has not completed running, raises an
@ -876,13 +904,14 @@ pty_slave(const char* name)
[self subclassResponsibility: _cmd]; [self subclassResponsibility: _cmd];
} }
- (void) _terminatedChild: (int)status - (void) _terminatedChild: (int)status reason: (NSTaskTerminationReason)reason
{ {
[tasksLock lock]; [tasksLock lock];
IF_NO_GC([[self retain] autorelease];) IF_NO_GC([[self retain] autorelease];)
NSMapRemove(activeTasks, (void*)(intptr_t)_taskId); NSMapRemove(activeTasks, (void*)(intptr_t)_taskId);
[tasksLock unlock]; [tasksLock unlock];
_terminationStatus = status; _terminationStatus = status;
_terminationReason = reason;
_hasCollected = YES; _hasCollected = YES;
_hasTerminated = YES; _hasTerminated = YES;
if (_hasNotified == NO) if (_hasNotified == NO)
@ -930,7 +959,9 @@ GSPrivateCheckTasks()
{ {
if (eCode != STILL_ACTIVE) if (eCode != STILL_ACTIVE)
{ {
[t _terminatedChild: eCode]; [t _terminatedChild: eCode reason: (WIN_SIGNALLED == eCode)
? NSTaskTerminationReasonUncaughtSignal
: NSTaskTerminationReasonExit];
found = YES; found = YES;
} }
} }
@ -972,8 +1003,11 @@ GSPrivateCheckTasks()
return; return;
} }
/* We use exit code 10 to denote a process termination.
* Windows does nt have an exit code to denote termination this way.
*/
_hasTerminated = YES; _hasTerminated = YES;
TerminateProcess(procInfo.hProcess, 10); TerminateProcess(procInfo.hProcess, WIN_SIGNALLED);
} }
@ -1307,7 +1341,9 @@ quotedFromString(NSString *aString)
} }
else if (eCode != STILL_ACTIVE) else if (eCode != STILL_ACTIVE)
{ {
[self _terminatedChild: eCode]; [self _terminatedChild: eCode reason: (WIN_SIGNALLED == eCode)
? NSTaskTerminationReasonUncaughtSignal
: NSTaskTerminationReasonExit];
} }
} }
} }
@ -1364,7 +1400,8 @@ GSPrivateCheckTasks()
NSLog(@"waitpid %d, exit status = %d", NSLog(@"waitpid %d, exit status = %d",
result, status); result, status);
#endif #endif
[t _terminatedChild: WEXITSTATUS(status)]; [t _terminatedChild: WEXITSTATUS(status)
reason: NSTaskTerminationReasonExit];
found = YES; found = YES;
} }
else if (WIFSIGNALED(status)) else if (WIFSIGNALED(status))
@ -1373,7 +1410,8 @@ GSPrivateCheckTasks()
NSLog(@"waitpid %d, termination status = %d", NSLog(@"waitpid %d, termination status = %d",
result, status); result, status);
#endif #endif
[t _terminatedChild: WTERMSIG(status)]; [t _terminatedChild: WTERMSIG(status)
reason: NSTaskTerminationReasonUncaughtSignal];
found = YES; found = YES;
} }
else else
@ -1669,7 +1707,8 @@ GSPrivateCheckTasks()
NSLog(@"waitpid %d, exit status = %d", NSLog(@"waitpid %d, exit status = %d",
result, status); result, status);
#endif #endif
[self _terminatedChild: WEXITSTATUS(status)]; [self _terminatedChild: WEXITSTATUS(status)
reason: NSTaskTerminationReasonExit];
} }
else if (WIFSIGNALED(status)) else if (WIFSIGNALED(status))
{ {
@ -1677,7 +1716,8 @@ GSPrivateCheckTasks()
NSLog(@"waitpid %d, termination status = %d", NSLog(@"waitpid %d, termination status = %d",
result, status); result, status);
#endif #endif
[self _terminatedChild: WTERMSIG(status)]; [self _terminatedChild: WTERMSIG(status)
reason: NSTaskTerminationReasonUncaughtSignal];
} }
else else
{ {

View file

@ -49,6 +49,8 @@ int main()
[task setArguments: args]; [task setArguments: args];
[task launch]; [task launch];
[task waitUntilExit]; [task waitUntilExit];
PASS([task terminationReason] == NSTaskTerminationReasonExit,
"termination reason for normal exit works");
[arp release]; arp = nil; [arp release]; arp = nil;
return 0; return 0;

View file

@ -6,7 +6,7 @@
#import <Foundation/NSRunLoop.h> #import <Foundation/NSRunLoop.h>
#import <Foundation/NSAutoreleasePool.h> #import <Foundation/NSAutoreleasePool.h>
#import "ObjectTesting.h" #import "ObjectTesting.h"
@interface TaskHandler : NSObject @interface TaskHandler : NSObject
{ {
@ -16,74 +16,81 @@
@implementation TaskHandler @implementation TaskHandler
static BOOL taskTerminationNotificationReceived; static BOOL taskTerminationNotificationReceived;
- (void) setLaunchPath: (NSString*)s - (void) setLaunchPath: (NSString*)s
{ {
ASSIGNCOPY(path, s); ASSIGNCOPY(path, s);
} }
- (void) taskDidTerminate: (NSNotification *)notification - (void) taskDidTerminate: (NSNotification *)notification
{ {
NSLog(@"Received NSTaskDidTerminateNotification %@", notification); NSLog(@"Received NSTaskDidTerminateNotification %@", notification);
taskTerminationNotificationReceived = YES; taskTerminationNotificationReceived = YES;
} }
- (void) testNSTaskNotifications - (void) testNSTaskNotifications
{ {
NSDate *deadline; NSDate *deadline;
BOOL earlyTermination = NO; BOOL earlyTermination = NO;
for (;;) for (;;)
{ {
NSTask *task = [NSTask new]; NSTask *task = [NSTask new];
[task setLaunchPath: path]; [task setLaunchPath: path];
[task setArguments: [NSArray arrayWithObjects: [task setArguments: [NSArray arrayWithObjects:
@"-c", @"echo Child starting; sleep 10; echo Child exiting", nil]]; @"-c", @"echo Child starting; sleep 10; echo Child exiting", nil]];
taskTerminationNotificationReceived = NO; taskTerminationNotificationReceived = NO;
[[NSNotificationCenter defaultCenter] [[NSNotificationCenter defaultCenter]
addObserver: self addObserver: self
selector: @selector(taskDidTerminate:) selector: @selector(taskDidTerminate:)
name: NSTaskDidTerminateNotification name: NSTaskDidTerminateNotification
object: task]; object: task];
[task launch]; [task launch];
NSLog(@"Launched pid %d", [task processIdentifier]); NSLog(@"Launched pid %d", [task processIdentifier]);
if (earlyTermination) if (earlyTermination)
{ {
NSLog(@"Running run loop for 5 seconds"); NSLog(@"Running run loop for 5 seconds");
deadline = [NSDate dateWithTimeIntervalSinceNow:5.0]; deadline = [NSDate dateWithTimeIntervalSinceNow:5.0];
while ([deadline timeIntervalSinceNow] > 0.0) while ([deadline timeIntervalSinceNow] > 0.0
&& !taskTerminationNotificationReceived)
{ {
[[NSRunLoop currentRunLoop] [[NSRunLoop currentRunLoop]
runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 1.0]]; runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 1.0]];
NSLog(@"Run loop finished, will now call -[NSTask terminate]"); NSLog(@"Run loop finished, will now call -[NSTask terminate]");
[task terminate]; [task terminate];
NSLog(@"Terminate returned, waiting for termination"); NSLog(@"Terminate returned, waiting for termination");
[task waitUntilExit]; [task waitUntilExit];
PASS([task terminationReason]
== NSTaskTerminationReasonUncaughtSignal,
"termination reason for signal exit works");
} }
} }
else else
{ {
NSLog(@"Running run loop for 15 seconds"); NSLog(@"Running run loop for 15 seconds");
deadline = [NSDate dateWithTimeIntervalSinceNow: 15.0]; deadline = [NSDate dateWithTimeIntervalSinceNow: 15.0];
while ([deadline timeIntervalSinceNow] > 0.0 while ([deadline timeIntervalSinceNow] > 0.0
&& !taskTerminationNotificationReceived) && !taskTerminationNotificationReceived)
{ {
[[NSRunLoop currentRunLoop] [[NSRunLoop currentRunLoop]
runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 1.0]]; runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 1.0]];
} }
} PASS([task terminationReason]
[task release]; == NSTaskTerminationReasonExit,
"termination reason for normal exit works");
}
[task release];
NSAssert(taskTerminationNotificationReceived, NSAssert(taskTerminationNotificationReceived,
@"termination notification not received"); @"termination notification not received");
[[NSNotificationCenter defaultCenter] [[NSNotificationCenter defaultCenter]
removeObserver: self name: NSTaskDidTerminateNotification object: nil]; removeObserver: self name: NSTaskDidTerminateNotification object: nil];
if (earlyTermination) if (earlyTermination)
break; break;
earlyTermination = YES; earlyTermination = YES;
} }
} }
@end @end