3

I cannot find whether named pipes are buffered, hence the question.

The manpage says https://linux.die.net/man/3/mkfifo:

A FIFO special file is similar to a pipe ... any process can open it for reading or writing, in the same way as an ordinary file.

Pipes are not buffered, no need to flush. But in a ordinary file, I would fflush (or fsync) the file descriptor.

How about named pipe?

rph
  • 901
  • 1
  • 10
  • 26
  • 1
    *Pipes are not buffered* are you really sure of that? In addition C standard library based IO come by default with an additional buffering level. – Serge Ballesta May 03 '18 at 09:05
  • @SergeBallesta as far as I know, there is no secondary storage in PIPEs. As long as you open the pipe stream using `open` (instead of fopen) the read/write operations will happen inside the kernel. Am I missing something? – rph May 03 '18 at 09:11
  • I was not thinking about secondary storage in pipes, but the *write* system call may use a system buffer and only flushes output to the pipe when its internal buffer is full. – Serge Ballesta May 03 '18 at 11:36
  • @SergeBallesta Do you have any source that mention about buffers in the `write` system call? I am genuinely curious. – rph May 03 '18 at 16:31
  • @SergeBallesta, I think you've just flipped between two different things. On one hand, the C standard library's I/O subsystem (stdio) indeed does ordinarily provide buffering. That would be `fwrite()`, `fprintf()`, *etc.*, but *not* the `write()` system call. `write()` is not part of stdio, nor indeed is it specified by the C language standard at all. Instead, it is among the POSIX system interfaces. – John Bollinger May 03 '18 at 17:04
  • you mean `fflush(3)` ??? – Luis Colorado May 05 '18 at 20:13
  • 1
    @rkioji, today fifos and pipes do all stuff in kernel core memory. But that is not what happened long ago. Initially, pipes where implemented on the filesystem, and they consumed an inode (they continue to do, for locking processes and having something to wait on ---the inode is locked for a complete `write/read` syscall) and originally consumed the direct blocks of that inode. – Luis Colorado May 05 '18 at 20:35
  • @rkioji, see my answer and you'll know where is your stopped data. it's `` which is hidding and not sending the buffered data, because the buffer is not full and `` will not send it before the buffer fills up or you force a `fflus(3)` – Luis Colorado May 05 '18 at 20:37
  • @LuisColorado, actually I think this answers my question: `today fifos and pipes do all stuff in kernel core memory`. If they are both implemented in the kernel memory then I suppose I do not have to flush FIFOs. Pretty much like pipes. The reason I ask about flushing is to prevent some data being lost, which is common for example in files or standard output. Do you have reference that mentions that FIFOs are implemented in kernel memory? Also, in that case, what is the purpose of the file created in FIFOs? – rph May 06 '18 at 12:41

2 Answers2

6

Pipes are not buffered, no need to flush.

I'd actually put that the other way around: for most intents and purposes, pipes are nothing but buffer. It is not meaningful to flush them because there is no underlying device to receive the data.

Moreover, although POSIX does not explicitly forbid additional buffering of pipe I/O, it does place sufficient behavioral requirements that I don't think there's any way to determine from observation whether such buffering occurs, except possibly by whether fsync() succeeds. In other words, even if there were extra buffering, it should not be necessary to fsync() a pipe end.

But in a ordinary file, I would fflush (or fsync) the file descriptor.

Well no, you would not fflush() a file descriptor. fflush() operates on streams, represented by FILE objects, not on file descriptors. This is a crucial distinction, because most streams are buffered at the C library level, independent of the nature of the file underneath. It is this library-level buffer that fflush() interacts with. You can control the library-level buffering mode of a stream via the setvbuf() function.

On those systems that provide it, fsync() operates at a different, lower level. It instructs the OS to ensure that all data previously written to the specified file descriptor has been delivered to the underlying storage device. In other words, it flushes OS-level buffers.

Note well that you can wrap a stream around a pipe-end file descriptor via the fdopen() function. That doesn't make the pipe require flushing any more than it did before, but the stream will be buffered by default, so flushing will be relevant to it.

Note, too, that some storage devices perform their own buffering, so that even after the data have been handed off to a storage device, it is not certain that they are immediately persistent.

How about named pipe?

The discussion above about stream I/O vs. POSIX descriptor-based I/O applies here, too. If you access a named pipe via a stream, then its interaction with fflush() will depend on the buffering of that stream.

But I suppose your question is more about os-level buffering and flushing. POSIX does not appear to say much concrete, but since you tag [linux] and refer to a Linux manual page in your question, I offer this in response:

The only difference between pipes and FIFOs is the manner in which they are created and opened. Once these tasks have been accomplished, I/O on pipes and FIFOs has exactly the same semantics.

(Linux pipe(7) manual page.)

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • Yes, my question was more about the os-level buffering. `I/O on pipes and FIFOs has exactly the same semantics`, this is not so clear to me. They might have same semantics but behave differently. – rph May 06 '18 at 12:35
  • 1
    @rkioji, you are focusing on the wrong part of the quotation. The bit about the same semantics is meant to supplement the main point, which is that "The only difference between pipes and FIFOs is the manner in which they are created and opened." However, no, having the same semantics *does not* afford the possibility that the two behave differently. It pretty much means exactly the opposite. – John Bollinger May 06 '18 at 18:35
  • is there any way to flush or clear the data from pipe/fifo without read operation – ixnisarg Feb 23 '21 at 13:33
  • @ixnisarg, rejecting pending input is not "flushing", and thus not what this Q&A is about. With that said, no, there is no special-purpose mechanism for draining a pipe. If you want to do that then you simply read the data from the pipe and ignore it. That is a bit fraught, however, for how does one no how much data to reject? "All the data presently in the pipe" is not a very reliable measure. – John Bollinger Feb 23 '21 at 17:56
  • However, a pipe ceases to exist when it no longer open either for reading or for writing by any process, and any data that was not read is lost. This applies to named pipes just the same as unnamed ones, to the extent that the pipe part of a named pipe is distinguished from the filesystem entry by which one creates and accesses it. – John Bollinger Feb 23 '21 at 18:03
2

I don't understand quite well what you try to ask, but as you have been already told, pipes are not more than buffer.

Historically, fifos (or pipes) consumed the direct blocks of the inode used to maintain them, and they tied to a file (having it a name or not) in some filesystem.

Today, I don't know the exact implementation details for a fifo, but basically, the kernel buffers all data the writers have already written, but the readers haven't read yet. The fifo has an upper limit (system defined) for the amount of buffer they can support, but normally that fails around 10-20kb of data.

The kernel buffers, but there's no delay between writers and readers, because as soon a writer writes on a pipe, the kernel awakens all the readers waiting for it to have data. The reverse is also true, in the case the pipe gets full of data, as soon as a reader consumes it, all the writers are awaken to allow for filling it again.

Anyway, your question about flushing has nothing to do with pipes (well, not like, let me explain myself) but with <stdio.h> package. <stdio.h> does buffer, and it handles buffering on each FILE * individually, so you have calls for flushing buffers when you want them to be write(2)n to disk.

has a dynamic behaviour that allows to optimize buffering and not force programmers to have to flush at each time. That depends on the type of file descriptor associated with a FILE * pointer.

When the FILE * pointer is associated to a serial tty (it does check that calling to isatty(3) call, which internally makes an ioctl(2) call, that allow <stdio.h> to see if you are against a serial device, a char device. If this happens, then <stdio.h> does line buffering that means that always when a '\n' char is output to a device, the buffer is automatically buffered.

This supposes an optimization problem, because when, for example you are using cat(1) to copy a file, the largest the buffer normally supposes the most efficient approach. Well, <stdio.h> comes to solve the problem, because when output is not a tty device, it makes full buffering, and only flushes the internal buffers of the FILE * pointer when it is full of data.

So the question is: How does <stdio.h> behave with a fifo (or pipe) node? The answer is simple.... is is not a char device (or a tty) so <stdio.h> does full buffering on it. If you are communicating data between two processes and you want the reader to receive the data as soon as you have printf(3)ed it, then you have better to fflush(3), because if you don't, you can be waiting for a response that never comes, because what you have written, has not yet been written (not by the kernel, but by the <stdio.h> library)

As I said, I don't know if this is exactly the answer to your question, but for sure it can give you a hint on where the problem could be.

Luis Colorado
  • 10,974
  • 1
  • 16
  • 31