win32: Support overlapped (asynchronous) I/O on standard streams in GSFileHandle

* win32: Support overlapped I/O on standard streams in GSFileHandle

* Add isStandardInput instance variable

* Restrict PeekConsoleInput on stdin

* Update ChangeLog
This commit is contained in:
Hugo Melder 2022-08-23 18:43:14 +02:00 committed by GitHub
parent 6b537b4a45
commit 32eb5d2acd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 100 additions and 25 deletions

View file

@ -1,3 +1,12 @@
2022-08-16 Hugo Melder <contact@hugomelder.com>
* Source/win32/GSFileHandle.m:
Support overlapped I/O on standard streams in GSFileHandle.
* Source/GSFileHandle.h:
Add the isStandardStream instance variable.
* Tests/base/NSRunLoop/performers.m:
Remove extraneous unistd header from unit test.
2022-08-16 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSOperation.m: Remove restriction (of 8) on the maximum

View file

@ -52,6 +52,9 @@ struct sockaddr_in;
int descriptor;
BOOL closeOnDealloc;
BOOL isStandardFile;
// stdin, stdout, and stderr
BOOL isStandardStream;
BOOL isStandardInput;
BOOL isNullDevice;
BOOL isSocket;
BOOL isNonBlocking;

View file

@ -1065,6 +1065,7 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
if (self)
{
readOK = NO;
isStandardStream = YES;
}
}
return self;
@ -1083,6 +1084,8 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
if (self)
{
writeOK = NO;
isStandardStream = YES;
isStandardInput = YES;
}
}
return self;
@ -1101,6 +1104,7 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
if (self)
{
readOK = NO;
isStandardStream = YES;
}
}
return self;
@ -1158,8 +1162,7 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
{
if (GetFileType(h) == FILE_TYPE_PIPE)
{
/* If we can't get named pipe info, we assume this is a socket.
*/
// If we can't get named pipe info, we assume this is a socket.
if (GetNamedPipeInfo(h, 0, 0, 0, 0) == 0)
{
isSocket = YES;
@ -2089,12 +2092,60 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
}
else
{
HANDLE h;
h = (HANDLE)_get_osfhandle(descriptor);
/* Overlapped (asynchronous) I/O on a standard stream requires
* a different interface to that of a pipe.
*
* Opening a standard stream ("CONIN$", "CONOUT$", "CONERR$") via
* CreateFile() with the FILE_FLAG_OVERLAPPED flag has no effect
* on the handle; the parameter dwFlagsAndAttributes is ignored when
* creating a standard stream handle.
*
* A Windows standard stream is not an anonymous or named pipe and
* PeekNamedPipe is therefore not supported. Instead, PeekConsoleInput
* is used to "peek" into the standard stream.
*/
if (YES == isStandardInput && YES == isStandardStream)
{
/* Stores the number of input records read
*/
DWORD bytes = 0;
/* PeekConsoleInput fails, if it returns a non-zero value.
*/
if (PeekConsoleInput(h, 0, 0, &bytes) == 0)
{
DWORD e = GetLastError();
NSString *s;
s = [NSString stringWithFormat: @"Standard input peek problem: %lu - %@", e,
[NSError _last]];
[readInfo setObject: s forKey: GSFileHandleNotificationError];
NSLog(@"%@", s);
return;
}
else if (bytes == 0)
{
return; // No data available yet.
}
}
else if (NO == isStandardInput && YES == isStandardStream) {
NSString *s;
s = @"Reading from stdout and stderr is not available.";
[readInfo setObject: s forKey: GSFileHandleNotificationError];
NSLog(@"%@", s);
return;
}
/* 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)
else if (NO == isSocket && NO == isStandardFile)
{
HANDLE h = (HANDLE)_get_osfhandle(descriptor);
DWORD bytes = 0;
if (PeekNamedPipe(h, 0, 0, 0, &bytes, 0) == 0)
@ -2103,7 +2154,13 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
if (e != ERROR_BROKEN_PIPE && e != ERROR_HANDLE_EOF)
{
NSLog(@"pipe peek problem %lu: %@", e, [NSError _last]);
NSString *s;
s = [NSString stringWithFormat: @"pipe peek problem: %lu - %@", e,
[NSError _last]];
[readInfo setObject: s forKey: GSFileHandleNotificationError];
NSLog(@"%@", s);
return;
}
/* In the case of a broken pipe, we fall through so that a read
@ -2417,6 +2474,14 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
{
return;
}
/* Invoking SetNamedPipeHandleState on a standard stream results in an
* ERROR_INVALID_FUNCTION (1) error message. Proceed only if the
* file descriptor is not a standard stream.
*/
else if (isStandardStream == YES)
{
return;
}
else if (isNonBlocking == flag)
{
return;

View file

@ -7,8 +7,6 @@
#import <Foundation/NSFileHandle.h>
#import <Foundation/NSDictionary.h>
#include <unistd.h>
int main()
{
START_SET("NSRunLoop performers")