diff --git a/Source/NSTask.m b/Source/NSTask.m index 99bb07d05..5774513b2 100644 --- a/Source/NSTask.m +++ b/Source/NSTask.m @@ -42,11 +42,11 @@ #import "Foundation/NSNotification.h" #import "Foundation/NSNotificationQueue.h" #import "Foundation/NSTask.h" +#import "Foundation/NSThread.h" #import "Foundation/NSTimer.h" #import "Foundation/NSLock.h" #import "GNUstepBase/NSString+GNUstepBase.h" #import "GNUstepBase/NSObject+GNUstepBase.h" -#import "GNUstepBase/NSThread+GNUstepBase.h" #import "GSPrivate.h" #include @@ -1005,50 +1005,6 @@ GSPrivateCheckTasks() TerminateProcess(procInfo.hProcess, 10); } -/* - * Wait for child process completion. - */ -static DWORD WINAPI _threadFunction(LPVOID t) -{ - DWORD milliseconds = 60000; - int taskId; - NSConcreteWindowsTask *task; - - GSRegisterCurrentThread(); - taskId = [(NSTask*)t processIdentifier]; - [tasksLock lock]; - task = (NSConcreteWindowsTask*)NSMapGet(activeTasks, - (void*)(intptr_t) taskId); - [task retain]; - [tasksLock unlock]; - if (task != nil) - { - for (;;) - { - NSConcreteWindowsTask *present; - - [tasksLock lock]; - present = (NSConcreteWindowsTask*)NSMapGet(activeTasks, - (void*)(intptr_t) taskId); - [tasksLock unlock]; - if (present == nil) - { - [task release]; - break; // Task gone away. - } - if (WaitForSingleObject(task->procInfo.hProcess, milliseconds) - != WAIT_TIMEOUT) - { - [task release]; - handleSignal(0); // Signal child process state change. - break; - } - } - } - GSUnregisterCurrentThread(); - return 0; -} - static NSString* endSlashesDoubledFromString(NSString *aString) @@ -1101,9 +1057,53 @@ quotedFromString(NSString *aString) return resultString; } + +/* Wait for child process completion. The task object is retained by the + * current thread until it exits, but may be removed from the table of + * active tasks by another thread, so we must check that it's still + * active at intervals. + */ +- (void) _windowsTaskWatcher +{ + void *taskId = (void*)(intptr_t)[self processIdentifier]; + + for (;;) + { + NSConcreteWindowsTask *task; + + /* Check that this task is still active. + */ + [tasksLock lock]; + task = (NSConcreteWindowsTask*)NSMapGet(activeTasks, taskId); + [tasksLock unlock]; + if (task != self) + { + /* Task has been reaped by another thread ... so we can exit. + */ + [NSThread exit]; + } + + /* Wait for up to 1 minute (60,000 milliseconds) to get a notification + * of an event from the subprocess. + */ + if (WaitForSingleObject(procInfo.hProcess, (DWORD)60000) + != WAIT_TIMEOUT) + { + /* The subprocess has terminated or failed in some way ... + * Set flag so child task can be reaped, then exit since this + * thread no longer needs to watch for events. + */ + handleSignal(0); + [NSThread exit]; + } + + /* Timed out ... repeat wait attempt. + */ + } +} + - (void) launch { - DWORD tid; STARTUPINFOW start_info; NSString *lpath; NSString *arg; @@ -1305,10 +1305,13 @@ quotedFromString(NSString *aString) [tasksLock lock]; NSMapInsert(activeTasks, (void*)(intptr_t) _taskId, (void*)self); [tasksLock unlock]; + /* * Create thread to watch for termination of process. */ - wThread = CreateThread(NULL, 0, _threadFunction, (LPVOID)self, 0, &tid); + [NSThread detachNewThreadSelector: @selector(_windowsTaskWatcher) + totarget: self + withObject: nil]; /* * Close the ends of any pipes used by the child.