fixups for win32 pipe management

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@28747 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
rfm 2009-09-27 16:07:50 +00:00
parent 739422c5aa
commit 30f0a67889
8 changed files with 190 additions and 84 deletions

View file

@ -1,3 +1,22 @@
2009-09-27 Richard Frith-Macdonald <rfm@gnu.org>
* Source\win32\GSFileHandle.m:
* Source\win32\NSMessagePort.m:
* Source\win32\GSRunLoopCtxt.m:
* Source\win32\NSStream.m:
* Source\win32\NSMessagePortNameServer.m:
* Source\NSPipe.m:
* Source\NSTask.m:
Fixes to try and improve subtask handling on windows.
1. change scheme to create all handles as not inheritable, and
just make the handles we want the child to have inheritable while
we are launching the child.
2. peek the data on pipes and refrain from notifying about data
availability if the pipe doesn't really have data. This is horrid and
means we poll pipes ... but I can see no other way of implementing the
api on windows as I can find no way to get windows to tell use when
data is available.
2009-09-23 Richard Frith-Macdonald <rfm@gnu.org> 2009-09-23 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSURL.m: OSX compatibility tweaks ... allows initialisation * Source/NSURL.m: OSX compatibility tweaks ... allows initialisation

View file

@ -87,7 +87,7 @@
HANDLE readh, writeh; HANDLE readh, writeh;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE; saAttr.bInheritHandle = FALSE;
saAttr.lpSecurityDescriptor = NULL; saAttr.lpSecurityDescriptor = NULL;
if (CreatePipe(&readh, &writeh, &saAttr, 0) != 0) if (CreatePipe(&readh, &writeh, &saAttr, 0) != 0)

View file

@ -1092,6 +1092,10 @@ quotedFromString(NSString *aString)
NSDictionary *env; NSDictionary *env;
NSMutableArray *toClose; NSMutableArray *toClose;
NSFileHandle *hdl; NSFileHandle *hdl;
HANDLE hIn;
HANDLE hOut;
HANDLE hErr;
id last = nil;
if (_hasLaunched) if (_hasLaunched)
{ {
@ -1163,6 +1167,13 @@ quotedFromString(NSString *aString)
start_info.dwFlags |= STARTF_USESTDHANDLES; start_info.dwFlags |= STARTF_USESTDHANDLES;
toClose = [NSMutableArray arrayWithCapacity: 3]; toClose = [NSMutableArray arrayWithCapacity: 3];
if (_standardInput == nil)
{
start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
}
else
{
hdl = [self standardInput]; hdl = [self standardInput];
if ([hdl isKindOfClass: [NSPipe class]]) if ([hdl isKindOfClass: [NSPipe class]])
{ {
@ -1170,7 +1181,15 @@ quotedFromString(NSString *aString)
[toClose addObject: hdl]; [toClose addObject: hdl];
} }
start_info.hStdInput = [hdl nativeHandle]; start_info.hStdInput = [hdl nativeHandle];
}
hIn = start_info.hStdInput;
if (_standardOutput == nil)
{
start_info.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
}
else
{
hdl = [self standardOutput]; hdl = [self standardOutput];
if ([hdl isKindOfClass: [NSPipe class]]) if ([hdl isKindOfClass: [NSPipe class]])
{ {
@ -1178,7 +1197,15 @@ quotedFromString(NSString *aString)
[toClose addObject: hdl]; [toClose addObject: hdl];
} }
start_info.hStdOutput = [hdl nativeHandle]; start_info.hStdOutput = [hdl nativeHandle];
}
hOut = start_info.hStdOutput;
if (_standardError == nil)
{
start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
}
else
{
hdl = [self standardError]; hdl = [self standardError];
if ([hdl isKindOfClass: [NSPipe class]]) if ([hdl isKindOfClass: [NSPipe class]])
{ {
@ -1192,22 +1219,48 @@ quotedFromString(NSString *aString)
} }
} }
start_info.hStdError = [hdl nativeHandle]; start_info.hStdError = [hdl nativeHandle];
}
hErr = start_info.hStdError;
/* Make the handles inheritable only temporarily while launching the
* child task. This section must be lock protected so we don't have
* another thread trying to launch at the same time and get handles
* inherited by the wrong threads.
*/
[tasksLock lock];
SetHandleInformation(hIn, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
SetHandleInformation(hOut, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
SetHandleInformation(hErr, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
result = CreateProcessW(wexecutable, result = CreateProcessW(wexecutable,
w_args, w_args,
NULL, /* proc attrs */ NULL, /* proc attrs */
NULL, /* thread attrs */ NULL, /* thread attrs */
1, /* inherit handles */ 1, /* inherit handles */
// CREATE_NO_WINDOW|DETACHED_PROCESS|CREATE_UNICODE_ENVIRONMENT, 0
CREATE_NO_WINDOW|CREATE_UNICODE_ENVIRONMENT, // |CREATE_NO_WINDOW
/* One would have thought the the CREATE_NO_WINDOW flag should be used,
* but apparently this breaks for old 16bit applications/tools on XP.
*/
|DETACHED_PROCESS
|CREATE_UNICODE_ENVIRONMENT,
envp, /* env block */ envp, /* env block */
(const unichar*)[[self currentDirectoryPath] fileSystemRepresentation], (const unichar*)[[self currentDirectoryPath] fileSystemRepresentation],
&start_info, &start_info,
&procInfo); &procInfo);
NSZoneFree(NSDefaultMallocZone(), w_args);
if (result == 0) if (result == 0)
{ {
NSLog(@"Error launching task: %@", lpath); last = [NSError _last];
}
NSZoneFree(NSDefaultMallocZone(), w_args);
SetHandleInformation(hIn, HANDLE_FLAG_INHERIT, 0);
SetHandleInformation(hOut, HANDLE_FLAG_INHERIT, 0);
SetHandleInformation(hErr, HANDLE_FLAG_INHERIT, 0);
[tasksLock unlock];
if (result == 0)
{
NSLog(@"Error launching task: %@ ... %@", lpath, last);
return; return;
} }

View file

@ -2003,7 +2003,37 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
} }
[self postReadNotification]; [self postReadNotification];
} }
else if (operation == NSFileHandleDataAvailableNotification) else
{
/* If this is not a socket or a standard file, we assume it's a pipe
* and therefore we need to check to see if data really is available.
*/
if (NO == isSocket && NO == isStandardFile)
{
HANDLE h = (HANDLE)_get_osfhandle(descriptor);
DWORD bytes = 0;
if (PeekNamedPipe(h, 0, 0, 0, &bytes, 0) == 0)
{
DWORD e = GetLastError();
if (e != ERROR_BROKEN_PIPE && e != ERROR_HANDLE_EOF)
{
NSLog(@"pipe peek problem %d, %@", e, [NSError _last]);
return;
}
/* In the case of a broken pipe, we fall through so that a read
* attempt is performed allowing higer level code to notice the
* problem and deal with it.
*/
}
else if (bytes == 0)
{
return; // No data available yet.
}
}
if (operation == NSFileHandleDataAvailableNotification)
{ {
[self postReadNotification]; [self postReadNotification];
} }
@ -2068,6 +2098,7 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
} }
} }
} }
}
} }
- (void) receivedEventWrite - (void) receivedEventWrite

View file

@ -486,6 +486,7 @@ static const NSMapTableValueCallBacks WatcherMapValueCallBacks =
watcher = (GSRunLoopWatcher*)GSIArrayItemAtIndex(_trigger, count).obj; watcher = (GSRunLoopWatcher*)GSIArrayItemAtIndex(_trigger, count).obj;
if (watcher->_invalidated == NO) if (watcher->_invalidated == NO)
{ {
NSDebugMLLog(@"NSRunLoop", @"trigger watcher %@", watcher);
i = [contexts count]; i = [contexts count];
while (i-- > 0) while (i-- > 0)
{ {
@ -511,6 +512,7 @@ static const NSMapTableValueCallBacks WatcherMapValueCallBacks =
// if there are windows message // if there are windows message
if (wait_return == WAIT_OBJECT_0 + num_handles) if (wait_return == WAIT_OBJECT_0 + num_handles)
{ {
NSDebugMLLog(@"NSRunLoop", @"processing windows messages");
[self processAllWindowsMessages: num_winMsgs within: contexts]; [self processAllWindowsMessages: num_winMsgs within: contexts];
return NO; return NO;
} }
@ -518,6 +520,7 @@ static const NSMapTableValueCallBacks WatcherMapValueCallBacks =
// if there aren't events // if there aren't events
if (wait_return == WAIT_TIMEOUT) if (wait_return == WAIT_TIMEOUT)
{ {
NSDebugMLLog(@"NSRunLoop", @"timeout without events");
completed = YES; completed = YES;
return NO; return NO;
} }

View file

@ -194,7 +194,7 @@ static Class messagePortClass = 0;
security.nLength = sizeof(SECURITY_ATTRIBUTES); security.nLength = sizeof(SECURITY_ATTRIBUTES);
security.lpSecurityDescriptor = 0; // Default security.lpSecurityDescriptor = 0; // Default
security.bInheritHandle = TRUE; security.bInheritHandle = FALSE;
} }
} }

View file

@ -105,7 +105,7 @@ static void clean_up_names(void)
security.nLength = sizeof(SECURITY_ATTRIBUTES); security.nLength = sizeof(SECURITY_ATTRIBUTES);
security.lpSecurityDescriptor = 0; // Default security.lpSecurityDescriptor = 0; // Default
security.bInheritHandle = TRUE; security.bInheritHandle = FALSE;
registry = @"Software\\GNUstepNSMessagePort"; registry = @"Software\\GNUstepNSMessagePort";
rc = RegCreateKeyExW( rc = RegCreateKeyExW(

View file

@ -1016,7 +1016,7 @@
fileSystemRepresentation]; fileSystemRepresentation];
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE; saAttr.bInheritHandle = FALSE;
saAttr.lpSecurityDescriptor = NULL; saAttr.lpSecurityDescriptor = NULL;
handle = CreateFileW(name, handle = CreateFileW(name,
@ -1067,7 +1067,7 @@ done:
int rc; int rc;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE; saAttr.bInheritHandle = FALSE;
saAttr.lpSecurityDescriptor = NULL; saAttr.lpSecurityDescriptor = NULL;
/* /*
@ -1346,7 +1346,7 @@ done:
NSAssert(handle == INVALID_HANDLE_VALUE, NSInternalInconsistencyException); NSAssert(handle == INVALID_HANDLE_VALUE, NSInternalInconsistencyException);
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE; saAttr.bInheritHandle = FALSE;
saAttr.lpSecurityDescriptor = NULL; saAttr.lpSecurityDescriptor = NULL;
handle = CreateNamedPipeW([path fileSystemRepresentation], handle = CreateNamedPipeW([path fileSystemRepresentation],