Comment Pouvez-vous vider une écriture en utilisant un descripteur de fichier?

Il s'avère que tout ce malentendu entre open() et fopen () provient d'un pilote I2C bogué dans le noyau Linux 2.6.14 sur un ARM. Le Backporting d'un pilote bit bashed de travail a résolu la cause profonde du problème que j'essayais d'aborder 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 timed OS (sleeps) entre les Écritures et les lectures sur l'appareil, les choses fonctionnent ... (beaucoup) mieux.

Mis à 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 que le pilote fonctionne de manière asynchrone - quelque chose que je ne peux pas concilier avec le fonctionnement du bus. Anyhoo ...

Je voudrais soit vider l'écriture pour être sûr (plutôt que d'utiliser une pause de durée fixe), ou en quelque sorte tester que l'écriture / lecture la transaction a terminé de 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 du ioctl(), qui n'utilise pas de pointeur de flux. c'est à dire

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

Suggestions?

29
demandé sur Iharob Al Asimi 2008-11-03 20:27:41

6 réponses

, Vous avez deux choix:

  1. Utiliser fileno() pour obtenir le descripteur de fichier associé à la stdio flux pointeur

  2. N'utilisez pas <stdio.h> du tout, de cette façon vous n'avez pas besoin de vous soucier de flush non plus - toutes les Écritures iront immédiatement à l'appareil, et pour les périphériques de caractères l'appel write() ne reviendra même pas jusqu'à ce que l'E / S de niveau inférieur soit terminé (en théorie).

Pour les e / s au niveau de l'appareil, je dirais qu'il est assez inhabituel d'utiliser stdio. Je voudrais fortement recommande d'utiliser le niveau inférieur open(), read() et write() fonctionne à la place (en fonction de votre réponse ultérieure):

int fd = open("/dev/i2c", O_RDWR);
ioctl(fd, IOCTL_COMMAND, args);
write(fd, buf, length);
23
répondu Alnitak 2015-12-14 17:43:31

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. {[3] } fera également l'affaire, sauf pour les méta-données.

28
répondu Danke Xie 2011-12-05 15:30:35

fflush() vide uniquement la mise en 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 write() brut, ne sont pas non plus tamponnées d'une manière que fflush() viderait.

Comme d'autres l'ont souligné, essayez Pas de 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
répondu unwind 2015-12-14 18:18:37

On dirait que ce que vous cherchez est la fonction fsync () (ou fdatasync ()?), ou vous pouvez utiliser L'indicateur O_SYNC dans votre appel open ().

2
répondu jstedfast 2009-11-08 14:33:42

Si vous voulez aller dans l'autre sens (associer le fichier * 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
répondu Arkadiy 2012-07-11 23:09:48

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

setvbuf(fd, NULL, _IONBF, 0);
1
répondu rustyx 2016-08-03 20:19:44