mirror of
https://github.com/python/cpython.git
synced 2025-07-07 19:35:27 +00:00
gh-101881: Support (non-)blocking read/write functions on Windows pipes (GH-101882)
* fileutils: handle non-blocking pipe IO on Windows Handle erroring operations on non-blocking pipes by reading the _doserrno code. Limit writes on non-blocking pipes that are too large. * Support blocking functions on Windows Use the GetNamedPipeHandleState and SetNamedPipeHandleState Win32 API functions to add support for os.get_blocking and os.set_blocking.
This commit is contained in:
parent
36b139af63
commit
739c026f44
8 changed files with 107 additions and 25 deletions
|
@ -1750,7 +1750,15 @@ _Py_read(int fd, void *buf, size_t count)
|
|||
Py_BEGIN_ALLOW_THREADS
|
||||
errno = 0;
|
||||
#ifdef MS_WINDOWS
|
||||
_doserrno = 0;
|
||||
n = read(fd, buf, (int)count);
|
||||
// read() on a non-blocking empty pipe fails with EINVAL, which is
|
||||
// mapped from the Windows error code ERROR_NO_DATA.
|
||||
if (n < 0 && errno == EINVAL) {
|
||||
if (_doserrno == ERROR_NO_DATA) {
|
||||
errno = EAGAIN;
|
||||
}
|
||||
}
|
||||
#else
|
||||
n = read(fd, buf, count);
|
||||
#endif
|
||||
|
@ -1804,6 +1812,7 @@ _Py_write_impl(int fd, const void *buf, size_t count, int gil_held)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
if (count > _PY_WRITE_MAX) {
|
||||
count = _PY_WRITE_MAX;
|
||||
|
@ -1814,7 +1823,18 @@ _Py_write_impl(int fd, const void *buf, size_t count, int gil_held)
|
|||
Py_BEGIN_ALLOW_THREADS
|
||||
errno = 0;
|
||||
#ifdef MS_WINDOWS
|
||||
n = write(fd, buf, (int)count);
|
||||
// write() on a non-blocking pipe fails with ENOSPC on Windows if
|
||||
// the pipe lacks available space for the entire buffer.
|
||||
int c = (int)count;
|
||||
do {
|
||||
_doserrno = 0;
|
||||
n = write(fd, buf, c);
|
||||
if (n >= 0 || errno != ENOSPC || _doserrno != 0) {
|
||||
break;
|
||||
}
|
||||
errno = EAGAIN;
|
||||
c /= 2;
|
||||
} while (c > 0);
|
||||
#else
|
||||
n = write(fd, buf, count);
|
||||
#endif
|
||||
|
@ -1829,7 +1849,18 @@ _Py_write_impl(int fd, const void *buf, size_t count, int gil_held)
|
|||
do {
|
||||
errno = 0;
|
||||
#ifdef MS_WINDOWS
|
||||
n = write(fd, buf, (int)count);
|
||||
// write() on a non-blocking pipe fails with ENOSPC on Windows if
|
||||
// the pipe lacks available space for the entire buffer.
|
||||
int c = (int)count;
|
||||
do {
|
||||
_doserrno = 0;
|
||||
n = write(fd, buf, c);
|
||||
if (n >= 0 || errno != ENOSPC || _doserrno != 0) {
|
||||
break;
|
||||
}
|
||||
errno = EAGAIN;
|
||||
c /= 2;
|
||||
} while (c > 0);
|
||||
#else
|
||||
n = write(fd, buf, count);
|
||||
#endif
|
||||
|
@ -2450,6 +2481,64 @@ error:
|
|||
return -1;
|
||||
}
|
||||
#else /* MS_WINDOWS */
|
||||
int
|
||||
_Py_get_blocking(int fd)
|
||||
{
|
||||
HANDLE handle;
|
||||
DWORD mode;
|
||||
BOOL success;
|
||||
|
||||
handle = _Py_get_osfhandle(fd);
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
success = GetNamedPipeHandleStateW(handle, &mode,
|
||||
NULL, NULL, NULL, NULL, 0);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
if (!success) {
|
||||
PyErr_SetFromWindowsErr(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return !(mode & PIPE_NOWAIT);
|
||||
}
|
||||
|
||||
int
|
||||
_Py_set_blocking(int fd, int blocking)
|
||||
{
|
||||
HANDLE handle;
|
||||
DWORD mode;
|
||||
BOOL success;
|
||||
|
||||
handle = _Py_get_osfhandle(fd);
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
success = GetNamedPipeHandleStateW(handle, &mode,
|
||||
NULL, NULL, NULL, NULL, 0);
|
||||
if (success) {
|
||||
if (blocking) {
|
||||
mode &= ~PIPE_NOWAIT;
|
||||
}
|
||||
else {
|
||||
mode |= PIPE_NOWAIT;
|
||||
}
|
||||
success = SetNamedPipeHandleState(handle, &mode, NULL, NULL);
|
||||
}
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
if (!success) {
|
||||
PyErr_SetFromWindowsErr(0);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void*
|
||||
_Py_get_osfhandle_noraise(int fd)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue