2010-05-22 14 views
13

Von dem, was ich habe auf fcntl, auf The Open Group Webseite gelesen open, read und write, habe ich den Eindruck, dass, ob O_NONBLOCK auf einem Dateideskriptor gesetzt ist, und somit, ob nicht-blockierende I/O mit der verwendet wird, Deskriptor sollte eher eine Eigenschaft dieses Dateideskriptors als die zugrunde liegende Datei sein. Eine Eigenschaft des Dateideskriptors zu sein bedeutet beispielsweise, dass, wenn ich einen Dateideskriptor dupliziere oder einen anderen Deskriptor für die gleiche Datei öffne, ich blockierende E/A mit einer und nicht blockierenden E/A mit der anderen verwenden kann.Wird O_NONBLOCK als Eigenschaft des Dateideskriptors oder der zugrunde liegenden Datei festgelegt?

Beim Versuch mit einem FIFO scheint es jedoch nicht möglich zu sein, gleichzeitig einen blockierenden E/A-Deskriptor und einen blockierungsfreien E/A-Deskriptor für den FIFO zu haben (ob O_NONBLOCK gesetzt ist, ist eine Eigenschaft des Basiswerts) file [FIFO]):

#include <errno.h> 
#include <fcntl.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 

int main(int argc, char **argv) 
{ 
    int fds[2]; 
    if (pipe(fds) == -1) { 
     fprintf(stderr, "`pipe` failed.\n"); 
     return EXIT_FAILURE; 
    } 

    int fd0_dup = dup(fds[0]); 
    if (fd0_dup <= STDERR_FILENO) { 
     fprintf(stderr, "Failed to duplicate the read end\n"); 
     return EXIT_FAILURE; 
    } 

    if (fds[0] == fd0_dup) { 
     fprintf(stderr, "`fds[0]` should not equal `fd0_dup`.\n"); 
     return EXIT_FAILURE; 
    } 

    if ((fcntl(fds[0], F_GETFL) & O_NONBLOCK)) { 
     fprintf(stderr, "`fds[0]` should not have `O_NONBLOCK` set.\n"); 
     return EXIT_FAILURE; 
    } 

    if (fcntl(fd0_dup, F_SETFL, fcntl(fd0_dup, F_GETFL) | O_NONBLOCK) == -1) { 
     fprintf(stderr, "Failed to set `O_NONBLOCK` on `fd0_dup`\n"); 
     return EXIT_FAILURE; 
    } 

    if ((fcntl(fds[0], F_GETFL) & O_NONBLOCK)) { 
     fprintf(stderr, "`fds[0]` should still have `O_NONBLOCK` unset.\n"); 
     return EXIT_FAILURE; // RETURNS HERE 
    } 

    char buf[1]; 
    if (read(fd0_dup, buf, 1) != -1) { 
     fprintf(stderr, "Expected `read` on `fd0_dup` to fail immediately\n"); 
     return EXIT_FAILURE; 
    } 
    else if (errno != EAGAIN) { 
     fprintf(stderr, "Expected `errno` to be `EAGAIN`\n"); 
     return EXIT_FAILURE; 
    } 

    return EXIT_SUCCESS; 
} 

das läßt ich denken: ist es überhaupt möglich, ein nicht-blockierende E/a-Deskriptor zu haben und blockiert E/a-Deskriptor auf die gleiche Datei und wenn ja, ist es abhängig auf den Typ der Datei (reguläre Datei, FIFO, spezielle Blockdatei, spezielle Zeichendatei, Socket usw.)?

+0

Ich frage mich, denn wenn O_NONBLOCK gesetzt ist eine Eigenschaft der zugrunde liegenden Datei, dann könnte ein Aufruf zum Öffnen einer Datei mit O_NONBLOCK * not * in oflags * gesetzt * konnte dennoch einen Dateideskriptor mit dem O_NONBLOCK Flag zurückgeben. –

Antwort

22

O_NONBLOCK ist eine Eigenschaft der Beschreibung der geöffneten Datei, weder des Dateideskriptors noch der zugrunde liegenden Datei.

Ja, Sie könnten separate Dateideskriptoren für dieselbe Datei öffnen, von denen eine blockiert und die andere nicht blockiert.

Sie müssen zwischen einem FIFO (erstellt mit mkfifo()) und einem Rohr (erstellt mit pipe()) unterscheiden.

Beachten Sie, dass der Blockierungsstatus eine Eigenschaft der 'Open File Description' ist, aber im einfachsten Fall gibt es eine Eins-zu-eins-Zuordnung zwischen Dateideskriptoren und offenen Dateibeschreibungen. Der Funktionsaufruf erstellt eine neue geöffnete Dateibeschreibung und einen neuen Dateideskriptor, der sich auf die geöffnete Dateibeschreibung bezieht.

Wenn Sie verwenden, haben Sie zwei Dateideskriptoren, die sich eine geöffnete Dateibeschreibung teilen, und die Eigenschaften gehören zur Beschreibung der geöffneten Datei. Die Beschreibung von fcntl() besagt, dass F_SETFL die mit dem Dateideskriptor verknüpfte offene Dateibeschreibung beeinflusst. Beachten Sie, dass lseek() die Dateiposition der mit dem Dateideskriptor verknüpften geöffneten Dateibeschreibung anpasst - so dass andere Dateideskriptoren betroffen sind, die vom ursprünglichen dupliziert wurden.

den Fehler Entfernen aus dem Code der Handhabung zu reduzieren, Sie haben:

int fds[2]; 
pipe(fds); 
int fd0_dup = dup(fds[0]); 
fcntl(fd0_dup, F_SETFL, fcntl(fd0_dup, F_GETFL) | O_NONBLOCK); 

Nun sind beide fd0_dup und fds [0] beziehen sich auf die gleiche offene Dateibeschreibung (wegen der dup()), so dass die fcntl() Die Operation hat beide Dateideskriptoren betroffen.

if ((fcntl(fds[0], F_GETFL) & O_NONBLOCK)) { ... } 

Daher wird hier das beobachtete Verhalten von POSIX benötigt.

+2

Oh, okay. Es gibt also einen Unterschied zwischen einem "Dateideskriptor" und einer "Dateibeschreibung". Zwei Dateideskriptoren können dieselbe Dateibeschreibung verwenden, und die Flags sind eine Eigenschaft der Beschreibung. Wenn Sie die Dokumente erneut öffnen, heißt es, dass die Funktion "eine geöffnete Dateibeschreibung erstellen" soll. Ich denke, dass ich jetzt verstehe. –

+0

Ja, du hast es verstanden. –

+1

@DanielTrebbien: einige Flags gehören zu Dateideskriptoren, z.B. 'FD_CLOEXEC'. – jfs