@@ -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
@@ -1804,6 +1812,7 @@ _Py_write_impl(int fd, const void *buf, size_t count, int gil_held)
18041812 }
18051813 }
18061814 }
1815+
18071816#endif
18081817 if (count > _PY_WRITE_MAX ) {
18091818 count = _PY_WRITE_MAX ;
@@ -1814,7 +1823,18 @@ _Py_write_impl(int fd, const void *buf, size_t count, int gil_held)
18141823 Py_BEGIN_ALLOW_THREADS
18151824 errno = 0 ;
18161825#ifdef MS_WINDOWS
1817- n = write (fd , buf , (int )count );
1826+ // write() on a non-blocking pipe fails with ENOSPC on Windows if
1827+ // the pipe lacks available space for the entire buffer.
1828+ int c = (int )count ;
1829+ do {
1830+ _doserrno = 0 ;
1831+ n = write (fd , buf , c );
1832+ if (n >= 0 || errno != ENOSPC || _doserrno != 0 ) {
1833+ break ;
1834+ }
1835+ errno = EAGAIN ;
1836+ c /= 2 ;
1837+ } while (c > 0 );
18181838#else
18191839 n = write (fd , buf , count );
18201840#endif
@@ -1829,7 +1849,18 @@ _Py_write_impl(int fd, const void *buf, size_t count, int gil_held)
18291849 do {
18301850 errno = 0 ;
18311851#ifdef MS_WINDOWS
1832- n = write (fd , buf , (int )count );
1852+ // write() on a non-blocking pipe fails with ENOSPC on Windows if
1853+ // the pipe lacks available space for the entire buffer.
1854+ int c = (int )count ;
1855+ do {
1856+ _doserrno = 0 ;
1857+ n = write (fd , buf , c );
1858+ if (n >= 0 || errno != ENOSPC || _doserrno != 0 ) {
1859+ break ;
1860+ }
1861+ errno = EAGAIN ;
1862+ c /= 2 ;
1863+ } while (c > 0 );
18331864#else
18341865 n = write (fd , buf , count );
18351866#endif
@@ -2450,6 +2481,64 @@ _Py_set_blocking(int fd, int blocking)
24502481 return -1 ;
24512482}
24522483#else /* MS_WINDOWS */
2484+ int
2485+ _Py_get_blocking (int fd )
2486+ {
2487+ HANDLE handle ;
2488+ DWORD mode ;
2489+ BOOL success ;
2490+
2491+ handle = _Py_get_osfhandle (fd );
2492+ if (handle == INVALID_HANDLE_VALUE ) {
2493+ return -1 ;
2494+ }
2495+
2496+ Py_BEGIN_ALLOW_THREADS
2497+ success = GetNamedPipeHandleStateW (handle , & mode ,
2498+ NULL , NULL , NULL , NULL , 0 );
2499+ Py_END_ALLOW_THREADS
2500+
2501+ if (!success ) {
2502+ PyErr_SetFromWindowsErr (0 );
2503+ return -1 ;
2504+ }
2505+
2506+ return !(mode & PIPE_NOWAIT );
2507+ }
2508+
2509+ int
2510+ _Py_set_blocking (int fd , int blocking )
2511+ {
2512+ HANDLE handle ;
2513+ DWORD mode ;
2514+ BOOL success ;
2515+
2516+ handle = _Py_get_osfhandle (fd );
2517+ if (handle == INVALID_HANDLE_VALUE ) {
2518+ return -1 ;
2519+ }
2520+
2521+ Py_BEGIN_ALLOW_THREADS
2522+ success = GetNamedPipeHandleStateW (handle , & mode ,
2523+ NULL , NULL , NULL , NULL , 0 );
2524+ if (success ) {
2525+ if (blocking ) {
2526+ mode &= ~PIPE_NOWAIT ;
2527+ }
2528+ else {
2529+ mode |= PIPE_NOWAIT ;
2530+ }
2531+ success = SetNamedPipeHandleState (handle , & mode , NULL , NULL );
2532+ }
2533+ Py_END_ALLOW_THREADS
2534+
2535+ if (!success ) {
2536+ PyErr_SetFromWindowsErr (0 );
2537+ return -1 ;
2538+ }
2539+ return 0 ;
2540+ }
2541+
24532542void *
24542543_Py_get_osfhandle_noraise (int fd )
24552544{
0 commit comments