Wie können Sie einen Schreibvorgang mit einem Dateideskriptor leeren?

Lesezeit: 4 Minuten

Jamies Benutzeravatar
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

Benutzeravatar von Danke Xie
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

Benutzeravatar von Alnitak
Alnitak

Sie haben zwei Möglichkeiten:

  1. Verwenden fileno() um den mit dem verknüpften Dateideskriptor zu erhalten stdio Stream-Zeiger

  2. 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):

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

  • 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

Benutzeravatar von unwind
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.

Benutzeravatar von bgw
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);

1407340cookie-checkWie können Sie einen Schreibvorgang mit einem Dateideskriptor leeren?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy