Skip to content

Commit 7d3b7d0

Browse files
committed
fileutils: handle Windows errors in non-blocking mode
Handle erroring operations on non-blocking pipes by reading the _doserrno code.
1 parent 3aef515 commit 7d3b7d0

File tree

1 file changed

+20
-0
lines changed

1 file changed

+20
-0
lines changed

Python/fileutils.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1750,7 +1750,15 @@ _Py_read(int fd, void *buf, size_t count)
17501750
Py_BEGIN_ALLOW_THREADS
17511751
errno = 0;
17521752
#ifdef MS_WINDOWS
1753+
_doserrno = 0;
17531754
n = read(fd, buf, (int)count);
1755+
// read() on a non-blocking empty pipe fails with EINVAL, which is
1756+
// mapped from the Windows error code ERROR_NO_DATA.
1757+
if (n < 0 && errno == EINVAL) {
1758+
if (_doserrno == ERROR_NO_DATA) {
1759+
errno = EAGAIN;
1760+
}
1761+
}
17541762
#else
17551763
n = read(fd, buf, count);
17561764
#endif
@@ -1814,7 +1822,13 @@ _Py_write_impl(int fd, const void *buf, size_t count, int gil_held)
18141822
Py_BEGIN_ALLOW_THREADS
18151823
errno = 0;
18161824
#ifdef MS_WINDOWS
1825+
_doserrno = 0;
18171826
n = write(fd, buf, (int)count);
1827+
// write() on a non-blocking pipe fails with ENOSPC on Windows if
1828+
// the pipe lacks available space for the entire buffer.
1829+
if (n < 0 && errno == ENOSPC && _doserrno == 0) {
1830+
errno = EAGAIN;
1831+
}
18181832
#else
18191833
n = write(fd, buf, count);
18201834
#endif
@@ -1829,7 +1843,13 @@ _Py_write_impl(int fd, const void *buf, size_t count, int gil_held)
18291843
do {
18301844
errno = 0;
18311845
#ifdef MS_WINDOWS
1846+
_doserrno = 0;
18321847
n = write(fd, buf, (int)count);
1848+
// write() on a non-blocking pipe fails with ENOSPC on Windows if
1849+
// the pipe lacks available space for the entire buffer.
1850+
if (n < 0 && errno == ENOSPC && _doserrno == 0) {
1851+
errno = EAGAIN;
1852+
}
18331853
#else
18341854
n = write(fd, buf, count);
18351855
#endif

0 commit comments

Comments
 (0)