Wie können Sie einen Schreibvorgang mit einem Dateideskriptor leeren?
Lesezeit: 4 Minuten
Jamie
Es stellt sich heraus, dass dieses ganze Missverständnis von open() gegenüber fopen() auf einen fehlerhaften I2C-Treiber im Linux 2.6.14-Kernel auf einem ARM zurückzuführen ist. Das Zurückportieren eines funktionierenden Bit-Bashed-Treibers löste die Grundursache des Problems, das ich hier ansprechen wollte.
Ich versuche, ein Problem mit einem seriellen Gerätetreiber in Linux (I2C) herauszufinden. Es scheint, dass durch das Hinzufügen von zeitgesteuerten Betriebssystempausen (Schlafzeiten) zwischen Schreib- und Lesevorgängen auf dem Gerät die Dinge funktionieren … (viel) besser.
Beiseite: Die Natur von I2C ist, dass jedes vom Master gelesene oder geschriebene Byte vom Gerät am anderen Ende des Kabels (Slave) bestätigt wird – die Pausen, die die Dinge verbessern, ermutigen mich, an den Treiber zu denken, der asynchron arbeitet – etwas, das ich kann. t vereinbaren, wie der Bus funktioniert. Wie auch immer …
Ich möchte entweder spülen das Schreiben, um sicherzugehen (anstatt eine Pause mit fester Dauer zu verwenden), oder irgendwie testen, dass die Schreib/Lese-Transaktion hat abgeschlossen auf eine multithreadingfreundliche Weise.
Das Problem mit der Verwendung fflush(fd); ist, dass ‘fd’ ein Stream-Zeiger sein muss (kein Dateideskriptor), dh
FILE * fd = fopen("filename","r+");
... // do read and writes
fflush(fd);
Mein Problem ist, dass ich die Verwendung von benötige ioctl(), die keinen Stream-Zeiger verwendet. dh
int fd = open("filename",O_RDWR);
ioctl(fd,...);
Anregungen?
Im User-Land-Code ist die Funktion write() automatisch nicht gepuffert. Sie müssen es nicht spülen – es spült sich selbst. In der Tat ist es auch mit dem Gerätetreiber synchron, es sei denn, Sie verwenden spezielle Systemaufrufe.
– Jonathan Leffler
3. November 2008 um 23:09 Uhr
Wenn Sie ein Kernel-Level-Modul schreiben, können die Regeln etwas anders sein, aber dann sollten Sie wahrscheinlich den Dateideskriptor i/o und nicht den Standard (Dateizeiger) i/o verwenden.
– Jonathan Leffler
3. November 2008 um 23:10 Uhr
Danke Xie
Ich denke, was Sie suchen, könnte sein
int fsync(int fd);
oder
int fdatasync(int fd);
fsync löscht die Datei aus dem Kernel-Puffer auf die Festplatte. fdatasync wird auch tun, außer für die Metadaten.
Das OP gab an, dass dies ein i2c-Zeichengerät ist, keine Festplatte.
– Alnitak
20. April 2014 um 22:45 Uhr
Ok, i2c-Entwicklungsknoten sind nicht seitengepuffert, sodass sie nicht geleert/synchronisiert werden müssen. Die fops im Gerätetreiber bestimmen, was tatsächlich getan wird.
– Danke Xie
22. Mai 2014 um 1:37 Uhr
Obwohl dies nicht die Lösung für die Frage des OP ist, ist es für andere nützlich, die die Haupttitelfrage stellen. ich bin Schreiben auf eine Festplatte über ein fd, daher war es sehr hilfreich zu sehen, wie die Kernel-Puffer geleert werden.
– Namensgebend
12. August 2015 um 14:27 Uhr
Alnitak
Sie haben zwei Möglichkeiten:
Verwenden fileno() um den mit dem verknüpften Dateideskriptor zu erhalten stdio Stream-Zeiger
Nicht verwenden <stdio.h> Auf diese Weise müssen Sie sich auch keine Gedanken über Flush machen – alle Schreibvorgänge werden sofort an das Gerät gesendet, und für Zeichengeräte an die write() Der Aufruf wird nicht einmal zurückkehren, bis die IO auf niedrigerer Ebene abgeschlossen ist (theoretisch).
Für E/A auf Geräteebene würde ich sagen, dass die Verwendung ziemlich ungewöhnlich ist stdio. Ich würde dringend empfehlen, die untere Ebene zu verwenden open(), read() und write() funktioniert stattdessen (basierend auf Ihrer späteren Antwort):
Ich vermeide ; Das “Nebenbei” in meinem ursprünglichen Beitrag ließ mich denken, dass die Dateideskriptoren könnte gepuffert wurden. Vielen Dank für die Bestätigung, dass dies nicht der Fall ist und dass ich nach einem anderen Grund suchen sollte, warum das Verprügeln des I2C-Busses Probleme verursacht.
– Jamie
4. November 2008 um 14:19 Uhr
Lassen Sie uns die Terminologie klarstellen – ein UNIX-Dateideskriptor ist ein ganzzahliger Index und sollte ungepuffert sein, damit ein Aufruf zum Schreiben/Lesen sofort erfolgt. Es soll sehr effizient für “große” Schreibvorgänge und ineffizient für Einzelbyte-Schreibvorgänge sein. fopen gibt Ihnen gepufferte I/O. Verwenden Sie Öffnen/Lesen/Schreiben.
– Sockel
4. November 2008 um 14:31 Uhr
entspannen
fflush() löscht nur die vom stdio hinzugefügte Pufferung fopen() Schicht, wie von der verwaltet FILE * Objekt. Die zugrunde liegende Datei selbst wird, wie der Kernel sieht, auf dieser Ebene nicht gepuffert. Dies bedeutet, dass Schreibvorgänge die umgehen FILE * Schicht, verwenden fileno() und ein roh write()werden auch nicht so gepuffert, dass fflush() würde spülen.
Wie andere bereits betont haben, versuchen Sie es nicht Mischen der beiden. Wenn Sie “rohe” E / A-Funktionen wie z ioctl()dann open() die Datei selbst direkt, ohne verwenden fopen<() und Freunde von stdio.
Haben Sie versucht, die Pufferung zu deaktivieren?
setvbuf(fd, NULL, _IONBF, 0);
Es hört sich so an, als ob Sie nach der fsync()-Funktion (oder fdatasync()?) suchen, oder Sie könnten das O_SYNC-Flag in Ihrem open()-Aufruf verwenden.
bgw
Wenn Sie den umgekehrten Weg gehen möchten (FILE* mit einem vorhandenen Dateideskriptor verknüpfen), verwenden Sie fdopen() :
FDOPEN(P)
NAME
fdopen - associate a stream with a file descriptor
SYNOPSIS
#include <stdio.h>
FILE *fdopen(int fildes, const char *mode);
14073400cookie-checkWie können Sie einen Schreibvorgang mit einem Dateideskriptor leeren?yes
Im User-Land-Code ist die Funktion write() automatisch nicht gepuffert. Sie müssen es nicht spülen – es spült sich selbst. In der Tat ist es auch mit dem Gerätetreiber synchron, es sei denn, Sie verwenden spezielle Systemaufrufe.
– Jonathan Leffler
3. November 2008 um 23:09 Uhr
Wenn Sie ein Kernel-Level-Modul schreiben, können die Regeln etwas anders sein, aber dann sollten Sie wahrscheinlich den Dateideskriptor i/o und nicht den Standard (Dateizeiger) i/o verwenden.
– Jonathan Leffler
3. November 2008 um 23:10 Uhr