How can you flush a write using a file descriptor?

132,766

Solution 1

You have two choices:

  1. Use fileno() to obtain the file descriptor associated with the stdio stream pointer

  2. Don't use <stdio.h> at all, that way you don't need to worry about flush either - all writes will go to the device immediately, and for character devices the write() call won't even return until the lower-level IO has completed (in theory).

For device-level IO I'd say it's pretty unusual to use stdio. I'd strongly recommend using the lower-level open(), read() and write() functions instead (based on your later reply):

int fd = open("/dev/i2c", O_RDWR);
ioctl(fd, IOCTL_COMMAND, args);
write(fd, buf, length);

Solution 2

I think what you are looking for may be

int fsync(int fd);

or

int fdatasync(int fd);

fsync will flush the file from kernel buffer to the disk. fdatasync will also do except for the meta data.

Solution 3

fflush() only flushes the buffering added by the stdio fopen() layer, as managed by the FILE * object. The underlying file itself, as seen by the kernel, is not buffered at this level. This means that writes that bypass the FILE * layer, using fileno() and a raw write(), are also not buffered in a way that fflush() would flush.

As others have pointed out, try not mixing the two. If you need to use "raw" I/O functions such as ioctl(), then open() the file yourself directly, without using fopen<() and friends from stdio.

Solution 4

Have you tried disabling buffering?

setvbuf(fd, NULL, _IONBF, 0);

Solution 5

If you want to go the other way round (associate FILE* with existing file descriptor), use fdopen() :

                                                          FDOPEN(P)

NAME

       fdopen - associate a stream with a file descriptor

SYNOPSIS

       #include <stdio.h>

       FILE *fdopen(int fildes, const char *mode);
Share:
132,766

Related videos on Youtube

Sergey Kotyushkin
Author by

Sergey Kotyushkin

Updated on August 04, 2020

Comments

  • Sergey Kotyushkin
    Sergey Kotyushkin almost 4 years

    It turns out this whole misunderstanding of the open() versus fopen() stems from a buggy I2C driver in the Linux 2.6.14 kernel on an ARM. Backporting a working bit bashed driver solved the root cause of the problem I was trying to address here.

    I'm trying to figure out an issue with a serial device driver in Linux (I2C). It appears that by adding timed OS pauses (sleeps) between writes and reads on the device things work ... (much) better.

    Aside: The nature of I2C is that each byte read or written by the master is acknowledged by the device on the other end of the wire (slave) - the pauses improving things encourage me to think of the driver as working asynchronously - something that I can't reconcile with how the bus works. Anyhoo ...

    I'd either like to flush the write to be sure (rather than using fixed duration pause), or somehow test that the write/read transaction has completed in an multi-threaded friendly way.

    The trouble with using fflush(fd); is that it requires 'fd' to be stream pointer (not a file descriptor) i.e.

    FILE * fd = fopen("filename","r+");
    ... // do read and writes
    fflush(fd);
    

    My problem is that I require the use of the ioctl(), which doesn't use a stream pointer. i.e.

    int fd = open("filename",O_RDWR);
    ioctl(fd,...);
    

    Suggestions?

    • Jonathan Leffler
      Jonathan Leffler over 15 years
      In user-land code, the write() function is automatically non-buffered. You don't need to flush it -- it is self-flushing. Indeed, unless you use special system calls, it is also synchronous with device driver.
    • Jonathan Leffler
      Jonathan Leffler over 15 years
      If you are writing a kernel-level module, the rules may be somewhat different, but then you should probably be using the file descriptor i/o and not standard (file pointer) i/o.
  • Sergey Kotyushkin
    Sergey Kotyushkin over 15 years
    Avoiding <stdio.h> is what I've been doing; the "Aside" in my original post led me to thinking that the file descriptors might have been buffered. Thanks for confirming that they aren't and that I should be looking for another reason pummelling the I2C bus causes trouble.
  • plinth
    plinth over 15 years
    Let's make the terminology clear - a UNIX file descriptor is an integer index and is supposed to be unbuffered so that a call to write/read is immediate. It is supposed to be very efficient for "large" writes and inefficient for single byte writes. fopen gives you buffered I/O. Use open/read/write.
  • Alnitak
    Alnitak about 10 years
    The OP stated this is an i2c character device, not a disk.
  • Danke Xie
    Danke Xie almost 10 years
    Ok, i2c dev nodes are not page-buffered so it does not need to be flushed/sync'ed. The fops in device driver determine what are actually done.
  • Eponymous
    Eponymous almost 9 years
    Though this is not the solution to the OP's question, it is useful to others asking the main title question. I am writing to a disk via an fd, so it was very helpful to see how to flush the kernel buffers.
  • Grifball
    Grifball almost 7 years
    This worked for me. I'm not sure what my setup is, but I used this and "fsync" (using fileno to get the int instead of a FILE*) and I was able to seek and read from the file after closing and reopening it.
  • Anupam
    Anupam over 5 years
    This only works for fopen() and not for open(). The original question asks about disabling buffering for open() call.
  • rustyx
    rustyx over 5 years
    open() has no buffer, it goes straight to the device driver.