Suppose we have a named pipe. We opened it for reading and read reading read. But suddenly the writer deleted this pipe (an error or something else). How to check that the pipe no longer exists.


Is it correct to check the read result and if it is 0, then assume that the channel has fallen off? If there is no data, then read will wait a long time in its hour. But read returns zero if the end of the file is reached (and pipe is essentially the same file, well, almost. Correct if I am mistaken.) And this does not at all mean that the file is deleted (not sure for pipes, therefore I ask) Tell me how to correctly check that the pipe is closed (deleted).

  • came zero - closed the pipe. Then they tried to reconnect. If the pipe is deleted, then connect will not succeed. - KoVadim
  • @KoVadim that is, spinning in a loop and checking if the channel is not deleted? and if the channel is not deleted, how many open will be executed many times. I think this is very bad. how hard is it? - rubeno4ka
  • It all depends on your task. For example, if you were unable to connect for a minute, send a letter to the admin and disconnect. - KoVadim
  • The @KoVadim task is generally educational and quite simple. I wonder how to be in such cases. That is, for some time spent on syscall. I thought there was a more elegant solution. - rubeno4ka
  • one
    You can read man inotify , but in your case, the easiest thing is to do select with timeout and call stat to check if the FIFO is deleted (do you write in linux? There is usually a so-called named channel) - avp

2 answers 2

When using the read() function. If there is no data in the channel, 0 will be returned, and if an error occurred, the value -1 will be returned and the error code is set in the errno variable. Well, here it is still important how the channel is open. In blocking or nonblocking mode. But vseravno reading function will not be able to indicate that the file has been deleted. Therefore, if the program is likely that the channel will be deleted. Then before reading from the channel, you need to use the stat() function. It will indicate whether such a file exists or not. And in this case you need to open the file in nonblocking mode fd = open("test.pipe",O_RDONLY|O_NONBLOCK);

  • work with the channel will go through select. That is non-blocking mode. But now it became interesting how to act if it is blocked. Tried to open the file before reading to fall asleep and during sleep, delete the file. -1 I did not come. - rubeno4ka
  • one
    @ rubeno4ka Because it can be linked from the file system, but nothing happened with the file descriptor in the running process. This is a well-known incident with logs, for example, when a file is already deleted, but it is still being written to it and the space is reduced. - D-side
  • @ rubeno4ka, via select - this does not mean non-blocking mode. Non-blocking, this is when doing fcntl with the O_NONBLOCK flag set. As a result, read returns -1 if there is nothing to read and sets errno to EAGAIN or EWOULDBLOCK . / For “catching” deletions, you can read man inotify - avp

As long as at least one process keeps the pipe open, the object will not be deleted.

That is, even if the FIFO file is deleted (according to stat() ), read() can still return data from an already open pipe.

If there are no processes in which pipe is open for writing, then read() will return 0 (to mark EOF) if there is no more data in the pipe buffer.

If your task is to read data from a FIFO, then open ( open() ) and read ( read() ), remembering to handle errors. No additional calls needed.

Here is an example that shows that data can be written and read even if stat() says that there is no file (executable pseudo-code):

 #!/usr/bin/env python from os import * mkfifo('fifo') # create named pipe r, w = pipe() # "communication tube" between the parent and the child if fork(): # parent process (the reader) close(r) # close the unused end of the pipe fd = open('fifo', O_RDONLY) # open for reading write(1, read(fd, 512)) # read some remove('fifo') # delete fifo write(w, b'\0') # tell the child, the parent removed fifo close(w) # nothing more to say wait() # wait until the writer exits write(2, b'read some more\n') write(1, read(fd, 512)) # read some more if not read(fd, 512): write(1, b'EOF') # read() returns nothing else: # child: writer process close(w) # close the unused end of the pipe fd = open('fifo', O_WRONLY) # open for writing write(fd, b'data\n') read(r, 512) # wait until the parent removes fifo close(r) # won't listen no more try: # make sure fifo is gone stat('fifo') except IOError: pass else: assert 0, "shouldn't happen" write(fd, b'more data\n') # write after fifo is removed _exit(0) 

If you are interested in finding out when the file name (fifo) was removed (and not the ability to read data), then to stat() not to be called continuously, you can use services such as the suggested @avp inotify for Linux to use (on different systems — different interfaces, but opportunity on many common systems is).