web-dev-qa-db-fra.com

Comment vider une écriture à l'aide d'un descripteur de fichier?

Il s'avère que tout ce malentendu entre open () et fopen () provient d'un pilote buggy I2C dans le noyau Linux 2.6.14 sur un ARM. Le rétroportage d'un pilote en panne fonctionnant sur des bits a résolu la cause première du problème que j'essayais de résoudre ici.

J'essaie de résoudre un problème avec un pilote de périphérique série sous Linux (I2C). Il semble qu'en ajoutant des pauses (mises en veille) du système d'exploitation chronométrées entre les écritures et les lectures sur l'appareil, les choses fonctionnent ... (beaucoup) mieux.

À part: La nature de I2C est que chaque octet lu ou écrit par le maître est reconnu par l'appareil à l'autre extrémité du fil (esclave) - les pauses améliorant les choses m'encouragent à penser à le conducteur fonctionne de manière asynchrone - quelque chose que je ne peux pas concilier avec le fonctionnement du bus. Anyhoo ...

Je voudrais soit flush l'écriture pour être sûr (plutôt que d'utiliser une pause à durée fixe), ou teste en quelque sorte que la transaction d'écriture/lecture a terminée d'une manière conviviale multi-thread.

Le problème avec l'utilisation de fflush(fd); est qu'il nécessite que 'fd' soit un pointeur de flux (pas un descripteur de fichier), c'est-à-dire.

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

Mon problème est que j'ai besoin de l'utilisation de la ioctl(), qui n'utilise pas de pointeur de flux. c'est à dire.

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

Suggestions?

35
Jamie

Vous avez deux choix:

  1. Utilisez fileno() pour obtenir le descripteur de fichier associé au pointeur de flux stdio

  2. N'utilisez pas du tout <stdio.h>, De cette façon vous n'avez pas non plus à vous soucier du vidage - toutes les écritures iront immédiatement sur le périphérique, et pour les périphériques de caractères, l'appel write() ne sera pas même retourner jusqu'à ce que le niveau inférieur IO soit terminé (en théorie).

Pour le niveau de l'appareil IO je dirais qu'il est assez inhabituel d'utiliser stdio. Je recommande fortement d'utiliser le niveau inférieur open(), read() et write() à la place (sur la base de votre réponse ultérieure):

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

Je pense que ce que vous cherchez peut être

int fsync(int fd);

ou

int fdatasync(int fd);

fsync videra le fichier du tampon du noyau sur le disque. fdatasync fera aussi l'affaire sauf pour les métadonnées.

33
Danke Xie

fflush() vide uniquement la mémoire tampon ajoutée par la couche stdio fopen(), telle que gérée par l'objet FILE *. Le fichier sous-jacent lui-même, vu par le noyau, n'est pas mis en mémoire tampon à ce niveau. Cela signifie que les écritures qui contournent la couche FILE *, En utilisant fileno() et un brut write(), ne sont pas non plus mises en mémoire tampon d'une manière que fflush() viderait.

Comme d'autres l'ont souligné, essayez pas mélanger les deux. Si vous devez utiliser des fonctions d'E/S "brutes" telles que ioctl(), alors open() le fichier vous-même directement, sans en utilisant fopen<() et amis de stdio.

8
unwind

Avez-vous essayé de désactiver la mise en mémoire tampon?

setvbuf(fd, NULL, _IONBF, 0);
2
rustyx

Il semble que ce que vous recherchez soit la fonction fsync () (ou fdatasync ()?), Ou vous pouvez utiliser l'indicateur O_SYNC dans votre appel open ().

2
jstedfast

Si vous souhaitez inverser la procédure (associer FILE * au descripteur de fichier existant), utilisez fdopen ():

                                                          FDOPEN(P)

NAME

       fdopen - associate a stream with a file descriptor

SYNOPSIS

       #include <stdio.h>

       FILE *fdopen(int fildes, const char *mode);
1
Arkadiy