How can you flush a write using a file descriptor?
Solution 1
You have two choices:
Use
fileno()
to obtain the file descriptor associated with thestdio
stream pointerDon'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 thewrite()
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);
Related videos on Youtube
Sergey Kotyushkin
Updated on August 04, 2020Comments
-
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 over 15 yearsIn 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 over 15 yearsIf 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 over 15 yearsAvoiding <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 over 15 yearsLet'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 about 10 yearsThe OP stated this is an i2c character device, not a disk.
-
Danke Xie almost 10 yearsOk, 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 almost 9 yearsThough 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 almost 7 yearsThis 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 over 5 yearsThis only works for fopen() and not for open(). The original question asks about disabling buffering for open() call.
-
rustyx over 5 years
open()
has no buffer, it goes straight to the device driver.