Detect When Reader Closes Named Pipe (Fifo)

Detect when reader closes named pipe (FIFO)

Oddly enough, it appears that when the last reader closes the pipe, select indicates that the pipe is readable:

writer.py

#!/usr/bin/env python
import os
import select
import time

NAME = 'fifo2'

os.mkfifo(NAME)

def select_test(fd, r=True, w=True, x=True):
rset = [fd] if r else []
wset = [fd] if w else []
xset = [fd] if x else []

t0 = time.time()
r,w,x = select.select(rset, wset, xset)

print 'After {0} sec:'.format(time.time() - t0)
if fd in r: print ' {0} is readable'.format(fd)
if fd in w: print ' {0} is writable'.format(fd)
if fd in x: print ' {0} is exceptional'.format(fd)

try:
fd = os.open(NAME, os.O_WRONLY)
print '{0} opened for writing'.format(NAME)

print 'select 1'
select_test(fd)

os.write(fd, 'test')
print 'wrote data'

print 'select 2'
select_test(fd)

print 'select 3 (no write)'
select_test(fd, w=False)

finally:
os.unlink(NAME)

Demo:

Terminal 1:

$ ./pipe_example_simple.py
fifo2 opened for writing
select 1
After 1.59740447998e-05 sec:
3 is writable
wrote data
select 2
After 2.86102294922e-06 sec:
3 is writable
select 3 (no write)
After 2.15910816193 sec:
3 is readable

Terminal 2:

$ cat fifo2
test
# (wait a sec, then Ctrl+C)

Pipe/FIFO read attempt after writer closed

The data still in the pipe is read first before an EOF is signaled.

Windows named pipe: detect in Python on writer side when reader has closed its end without having to write data

As @eryksun pointed out above, it is actually possible to write a probing zero-length byte string using the Win32 API WriteFile directly: if the pipe is closed, then this will return "no success" (false/0), if the pipe is alive, then "success" (true/!=0). Exactly what I was asking for. As I find this to be simpler than using NtQueryInformationFile I'm now using the empty write method; here's a simplified example:

import ctypes
from ctypes import byref, c_ulong, c_char_p
import msvcrt
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)

fifo = open('//./pipe/somepipe', 'wb')
data = b''
written = c_ulong(0)
if not kernel32.WriteFile(
msvcrt.get_osfhandle(fifo.fileno()),
c_char_p(data), 0,
byref(written),
None):
last_error = ctypes.get_last_error()
if last_error in (
0x000000E8, # ERROR_NO_DATA
# enable as required: 0x000000E9, # ERROR_PIPE_NOT_CONNECTED
):
# pipe broken
pass
else:
# something else is wrong...
pass
else:
# pipe still okay
pass

Helpful resources:

  • Answer to: How to get a win32 handle of an open file in python?
  • Answer to: How to use win32 API's with python? which then links to this straight hit on my question:

    • Example Code - Named Pipes (Python 2.4 + ctypes on Windows)
  • comments section ;)

Detect disconnect from named pipe in linux

This is same as in TCP/IP. You need to attempt to read data, if that fails with 0, pipe is closed.

read and recv:

These calls return the number of bytes received, or -1 if an error
occurred. The return value will be 0 when the peer has performed an
orderly shutdown
.

There is also SIGPIPE signal. It'll be sent when you try write to a broken pipe - pipe with no readers.

Read on closed named pipe blocks

I don't know much about fortran, but I do know you could reproduce the hanging behavior in C by using a read/write mode in your open (for example fopen("test", "r+")

The pipe doesn't get an EOF until the number of writable file descriptors on it drops to 0. When your read file descriptor is also writable, you never get EOF.

So my guess is that fortran opens in read/write mode by default, and you need to tell it not to do that. This question about a fortran readonly flag may help.

FIFO read() function gets stuck in c

The problem is that you closed the pipe in the first process. A pipe doesn't have any permanent storage, it can only hold data while it's open by at least one process. When you close the pipe, the data that you've written to it is discarded.

As a result, when the second process tries to read from the pipe, there's nothing available.

You need to keep the pipe FD open when you execute the second process. Get rid of close(fd); in the reader program.

FIFO pipe only reads after write end has closed

Your problem comes from the buffer. FIFO use block buffer by default. So the c program won't read anything until the write buffer of the fifo in python was full. And there's two way to change this behaviour:

  • specify the buffer mode:

there's three buffer mode:

  1. block buffer(default)
  2. line buffer
  3. no buffer at all

What meet your needs here is the line buffer, so use fifo = open("emg", "w", 1); instead of fifo = open("emg", "w"); will fix.
number 1 here instead line buffer. python doc

  • another method is force flush the buffer, use fifo.flush after the write operation.


Related Topics



Leave a reply



Submit