¿Cómo se puede vaciar una escritura usando un descriptor de archivo?

Resulta todo este malentendido de los tallos de open () versus fopen () de un buggy I2C en el kernel de Linux 2.6.14 en un ARM. Backporting un controlador de bits de trabajo resuelto resolvió la causa raíz del problema que estaba tratando de abordar aquí.

Estoy tratando de resolver un problema con un controlador de dispositivo serie en Linux (I2C). Parece que al agregar pausas del sistema operativo temporizado (duerme) entre escrituras y lecturas en el dispositivo las cosas funcionan … (mucho) mejor.

Aparte: la naturaleza de I2C es que cada byte leído o escrito por el maestro es reconocido por el dispositivo en el otro extremo del cable (esclavo) – las pausas que mejoran las cosas me animan a pensar que el controlador funciona de forma asíncrona – algo que yo no puede reconciliarse con la forma en que funciona el autobús. Anyhoo …

Me gustaría borrar la escritura para estar seguro (en lugar de usar una pausa de duración fija), o de alguna manera probar que la transacción de escritura / lectura se ha completado de una manera amigable con múltiples subprocesos.

El problema con el uso de fflush(fd); es que requiere que ‘fd’ sea un puntero de flujo (no un descriptor de archivo), es decir,

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

Mi problema es que necesito el uso de ioctl() , que no usa un puntero de flujo. es decir

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

Sugerencias?

Tienes dos opciones:

  1. Use fileno() para obtener el descriptor de archivo asociado con el puntero de secuencia stdio

  2. No use en absoluto, así no tendrá que preocuparse por el enjuague tampoco: todas las escrituras irán al dispositivo inmediatamente, y para los dispositivos de caracteres la llamada a write() no regresará hasta que el nivel inferior IO ha completado (en teoría).

Para IO a nivel de dispositivo, diría que es bastante inusual usar stdio . Recomiendo usar las funciones de nivel más bajo open() , read() y write() en su lugar (según su respuesta posterior):

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

Creo que lo que estás buscando puede ser

 int fsync(int fd); 

o

 int fdatasync(int fd); 

fsync vaciará el archivo del buffer del kernel al disco. fdatasync también lo hará a excepción de los metadatos.

fflush() solo fflush() el almacenamiento en búfer agregado por la capa stdio fopen() , tal como lo gestiona el objeto FILE * . El archivo subyacente en sí, como lo ve el kernel, no está almacenado en este nivel. Esto significa que escribe que fileno() capa FILE * , que utiliza fileno() y una write() sin fileno() write() , tampoco se almacenan en el búfer de forma que fflush() se descargue.

Como han señalado otros, intente no mezclar los dos. Si necesita usar funciones de E / S “en bruto” como ioctl() , entonces open() el archivo usted mismo directamente, sin usar fopen< () y amigos de stdio.

Parece que lo que está buscando es la función fsync () (o fdatasync ()?), O podría usar el indicador O_SYNC en su llamada a open ().

Si quiere ir al revés (asociar FILE * con el descriptor de archivo existente), use fdopen ():

  FDOPEN(P) NAME fdopen - associate a stream with a file descriptor SYNOPSIS #include  FILE *fdopen(int fildes, const char *mode); 

¿Has intentado desactivar el almacenamiento en búfer?

 setvbuf(fd, NULL, _IONBF, 0);