-
-
Notifications
You must be signed in to change notification settings - Fork 31.9k
os: support creating FIFOs on Windows #103510
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
The semantics are significantly different for a FIFO on POSIX compared to a named pipe on Windows. On POSIX, a FIFO is half-duplex, and it opens as a single file in the kernel that has a write end and a read end. Either end of the FIFO can be opened by name multiple times, depending on whether On Windows, a named pipe is opened as a pipe instance in the named-pipe filesystem ('\\.\PIPE\"), which connects two kernel file objects -- one for each end of the pipe, the server side and the client side. The number of allowed instances of a pipe can be limited up to 254, or unlimited. The client end can be remote (over SMB) if the pipe mode isn't restricted to local clients. A named pipe can be inbound (server reads; client writes), outbound (server writes; client reads), or duplex. For the latter, the server end reads what the client end writes, and the client end reads what the server end writes. Unlike a POSIX FIFO, a named pipe can be opened by name only once on each end of an instance of the pipe -- once by the server end via |
What about this - On Windows, pipe servers are created by FIFO_PATH = "/tmp/myfifo"
os.mkfifo(FIFO_PATH)
with open(FIFO_PATH, "w") as mypipe:
mypipe.write("Message\n") becomes FIFO_PATH = "/tmp/myfifo"
pipe_fd = os.mkfifo(FIFO_PATH, open_flags=os.WRONLY)
with os.fdopen(pipe_fd, "w") as mypipe:
mypipe.write("Message\n") The deletion semantics will be different between Unix and Windows, although I don't think it matters as Windows pipes cannot be persistent. Moreover, the API will of course only present identical semantics for the case of one single read & write end. Opening a named pipe multiple times will by nature exhibit different semantics between Unix and Windows. Comments? @eryksun |
Make os.mkfifo return an open fd on Windows and the original path object on Unix. The user would then pass the return value into open, which accepts both path and fd as file.
Make os.mkfifo return an open fd on Windows and the original path object on Unix. The user would then pass the return value into open, which accepts both path and fd as file.
@SuibianP From Eryk Sun's comment and my thoughts, it can be seen that Unix FIFO and Windows Named Pipes are very different. Mimicking Unix FIFO is difficult. So I propose creating a new function The code will look like this: # name just string, default mode "x+", raise an OSError if pipe exists, FILE_FLAG_FIRST_PIPE_INSTANCE
mypipe_fd = os.namedpipe(name, mode)
# since 3.12 available as SetNamedPipeHandleState(PIPE_NOWAIT)
os.set_blocking(mypipe_fd, False)
# create a new mypipe instance
mypipe2_fd = os.namedpipe(name, "w+") Duplex Modes:
Server Write, Client Read Modes:
New Instance Exclusive Modes:
|
(Continuing the discussion from #129420)
@vstinner (Sorry for not replying in one batch; still grokking your proposals)
This is exactly what I meant by "simple IPC case", which is the scope of common semantics I intended to support. IMHO this would cover the majority of named pipe use cases, and is self-contained without opening a can of worms as you noted. I considered platform-specific features (message-based FIFOs, MPMC semantics) out of scope for my original proposal. Frankly, I am not sure if anything beyond that would be very useful with a semantic difference this great -- a quick search did not find real-world Python code using |
@SuibianP It is preferable to use existing Python file calls rather than creating new ones.
Creates a new Windows named pipe instance. The function's behavior is something between Args:
Returns:
Raises:
Available create modes:
Local nonblocking write: mypipe_fd = os.namedpipe(r"\\.\pipe\mypipe", wait=False)
os.set_blocking(mypipe_fd, False)
mypipe = os.fdopen(mypipe_fd, "w")
mypipe.write("Hello from mypipe server!") mypipe = open(r"\\.\pipe\mypipe")
print(mypipe.read())
# Hello from mypipe server! Remote: mypipe_fd = os.namedpipe(r"\\.\pipe\mypipe", open=True)
mypipe = os.fdopen(mypipe_fd, "w+") mypipe = open(r"\\ComputerName\pipe\mypipe", "w+")
mypipe.write("Message over SMB") |
os.mkfifo()
creates a named pipe that is accessible on the file system. It is currently only supported on Unix.Windows also supports creating named pipes with
CreateNamedPipeW()
which returns a handle to the server end of the pipe. However, they can only be created on a special filesystem in the\\.\pipe\
directory.The Windows docs say that:
And
os.mkfifo
doesn't return the pipe handles, it just creates the pipe:This would mean that implementing Windows support into
os.mkfifo
would mean that the pipe is deleted as soon as it is created (if we close the handle returned byCreateNamedPipeW()
), or we have a pipe that we can't delete (if we leave the pipe handle open).Unless there is some way to pass that back to the calling code - like
os.pipe()
that's supported on Windows.I'm not sure how I would go about implementing this. Returning the handle only on Windows? Making a new cross-platform function that always returns the handle (perhaps called
os.fifo
)?Linked PRs
os.mkfifo
on Windows #129420The text was updated successfully, but these errors were encountered: