Retry connecting to a named pipe if the pipe is busy
Marco Ricci

Marco Ricci commited on 2025-12-28 12:05:37
Zeige 1 geänderte Dateien mit 12 Einfügungen und 1 Löschungen.


In the `WindowsNamedPipeHandle` constructor, if connecting the named
pipe fails with the Windows error 231 (`ERROR_PIPE_BUSY`), retry the
operation.  (For expected future compatibility, we treat
`BlockingIOError` the same way.)  This behavior roughly corresponds to
how system calls on POSIX should usually be retried if they return with
`EINTR`.
... ...
@@ -100,6 +100,8 @@ CRYPTPROTECTMEMORY_CROSS_PROCESS = 0x1
100 100
 
101 101
 PIPE_PREFIX = "//./pipe/".replace("/", "\\")
102 102
 
103
+ERROR_PIPE_BUSY = 231
104
+
103 105
 
104 106
 # The type checker and the standard library use different
105 107
 # (finer-grained?) types and type definitions on The Annoying Operating
... ...
@@ -295,7 +297,10 @@ class WindowsNamedPipeHandle:
295 297
         """
296 298
         if not name.replace("/", "\\").startswith(PIPE_PREFIX):
297 299
             raise ValueError(errno.EINVAL, os.strerror(errno.EINVAL))
298
-        self.handle: HANDLE | None = CreateFile(
300
+        self.handle: HANDLE | None = None
301
+        while self.handle is None:
302
+            try:
303
+                self.handle = CreateFile(
299 304
                     ctypes.c_wchar_p(name),
300 305
                     ctypes.c_ulong(GENERIC_READ | GENERIC_WRITE),
301 306
                     ctypes.c_ulong(FILE_SHARE_READ | FILE_SHARE_WRITE),
... ...
@@ -304,6 +309,12 @@ class WindowsNamedPipeHandle:
304 309
                     ctypes.c_ulong(0),
305 310
                     None,
306 311
                 )
312
+            except BlockingIOError:  # pragma: no cover [external]
313
+                continue  # retry
314
+            except OSError as exc:  # pragma: no cover [external]
315
+                if getattr(exc, "winerror", None) == ERROR_PIPE_BUSY:
316
+                    continue  # retry
317
+                raise
307 318
 
308 319
     def __enter__(self) -> Self:
309 320
         return self
310 321