This question - How to read from an os.pipe() without getting blocked? - shows a solution how to check if os.pipe
has any data for Linux, and for this you need to put the pipe into non-blocking mode:
import os, fcntl
fcntl.fcntl(thePipe, fcntl.F_SETFL, os.O_NONBLOCK)
On Windows we have this:
ImportError: No module named fcntl
But os.pipe
is there:
>>> os.pipe()
(3, 4)
So, is it possible to do non-blocking read or peek the contents of os.pipe
on Windows?
Answering my own question after digging for some time through StackOverflow.
UPDATE: Things changes thanks to @HarryJohnston.
At first the answer was no, it is not possible to do non-blocking read on os.pipe
on Windows. From this answer I've got that:
The term for non-blocking / asynchronous I/O in Windows is 'overlapped' - that's what you should be looking at.
os.pipe
on Windows is implemented through CreatePipe
API (see here and ... well, I couldn't find os.pipe
code in Python sources). CreatePipe
makes anonymous pipes, and anonymous pipes do not support asynchronous I/O.
But then @HarryJohnston commented that SetNamedPipeHandleState doc allows to put anonymous pipe to non-blocking mode. I wrote the test and it failed with OSError: [Errno 22] Invalid argument
. The error message seemed wrong, so I tried to check what should be return result on non-blocking read operation when data is not available, and after reading MSDN note on named pipe modes I found that it should be ERROR_NO_DATA
that has a int value 232. Adding ctypes.WinError()
call to exception handler revealed the expected [Error 232] The pipe is being closed.
So, the answer is yes, it is possible to do non-blocking read on os.pipe
on Windows, and here is the proof:
import msvcrt
import os
from ctypes import windll, byref, wintypes, GetLastError, WinError
from ctypes.wintypes import HANDLE, DWORD, POINTER, BOOL
LPDWORD = POINTER(DWORD)
PIPE_NOWAIT = wintypes.DWORD(0x00000001)
ERROR_NO_DATA = 232
def pipe_no_wait(pipefd):
""" pipefd is a integer as returned by os.pipe """
SetNamedPipeHandleState = windll.kernel32.SetNamedPipeHandleState
SetNamedPipeHandleState.argtypes = [HANDLE, LPDWORD, LPDWORD, LPDWORD]
SetNamedPipeHandleState.restype = BOOL
h = msvcrt.get_osfhandle(pipefd)
res = windll.kernel32.SetNamedPipeHandleState(h, byref(PIPE_NOWAIT), None, None)
if res == 0:
print(WinError())
return False
return True
if __name__ == '__main__':
# CreatePipe
r, w = os.pipe()
pipe_no_wait(r)
print os.write(w, 'xxx')
print os.read(r, 1024)
try:
print os.write(w, 'yyy')
print os.read(r, 1024)
print os.read(r, 1024)
except OSError as e:
print dir(e), e.errno, GetLastError()
print(WinError())
if GetLastError() != ERROR_NO_DATA:
raise
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With