2010-05-22 11 views
13

Por lo que he estado leyendo en el sitio web de Open Group en fcntl, open, read y write, me da la impresión de que si O_NONBLOCK se encuentra en un descriptor de archivo, y por lo tanto si no-bloqueo de E/S se utiliza con el descriptor, debe ser una propiedad de ese descriptor de archivo en lugar del archivo subyacente. Ser propiedad del descriptor de archivo significa, por ejemplo, que si duplico un descriptor de archivo o abro otro descriptor en el mismo archivo, entonces puedo usar E/S de bloqueo con una y E/S sin bloqueo con la otra.¿Se está estableciendo O_NONBLOCK como una propiedad del descriptor de archivo o del archivo subyacente?

Experimentando con un FIFO, sin embargo, parece que no es posible tener un descriptor de E/S de bloqueo y un descriptor de E/S sin bloqueo en el FIFO simultáneamente (entonces O_NONBLOCK es una propiedad del subyacente presentar [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; 
} 

Esto me deja pensando: ¿alguna vez es posible tener un no-bloqueo descriptor de e/S y el bloqueo de descriptor de e/S en el mismo archivo y si es así, de qué depende en el tipo de archivo (archivo normal, FIFO, archivo especial de bloque, archivo especial de caracteres, socket, etc.)?

+0

Me pregunto acerca de esto porque si O_NONBLOCK se establece es una propiedad del archivo subyacente, entonces una llamada para abrir un archivo con O_NONBLOCK * no * establecido en oflags * podría * devolver un descriptor de archivo con el indicador O_NONBLOCK. –

Respuesta

22

O_NONBLOCK es una propiedad de la descripción de archivo abierto, no del descriptor de archivo, ni del archivo subyacente.

Sí, podría tener descriptores de archivos separados abiertos para el mismo archivo, uno de los cuales es de bloqueo y el otro no bloquea.

Debe distinguir entre un FIFO (creado con mkfifo()) y un conducto (creado con pipe()).

Tenga en cuenta que el estado de bloqueo es una propiedad de la 'descripción de archivo abierto', pero en los casos más simples, hay una asignación de uno a uno entre descriptores de archivo y descripciones de archivos abiertos. La llamada a la función open() crea una nueva descripción de archivo abierto y un nuevo descriptor de archivo que hace referencia a la descripción de archivo abierto.

Cuando se utiliza dup(), tiene dos descriptores de archivos que comparten una descripción de archivo abierto, y las propiedades pertenecen a la descripción de archivo abierto. La descripción de fcntl() dice que F_SETFL afecta a la descripción de archivo abierto asociado con el descriptor de archivo. Tenga en cuenta que lseek() ajusta la posición del archivo de la descripción de archivo abierto asociada con el descriptor de archivo, por lo que afecta a otros descriptores de archivos duplicados del original.

Extracción de la manipulación de su código de error para reducirlo, usted tiene:

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

Ahora ambos fd0_dup y FDS [0] se refieren a la misma descripción de archivo abierto (debido a la dup()), por lo que el fcntl() la operación afectó ambos descriptores de archivos.

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

Por lo tanto, el comportamiento observado aquí es requerido por POSIX.

+2

Oh, está bien. Entonces hay una diferencia entre un "descriptor de archivo" y "descripción de archivo". Dos descriptores de archivo pueden compartir la misma descripción de archivo, y los indicadores son propiedad de la descripción. Mirando los documentos para abrir nuevamente, dice que la función "creará una descripción de archivo abierta". Creo que ahora entiendo. –

+0

Sí, lo tienes. –

+1

@DanielTrebbien: algunos indicadores pertenecen a los descriptores de archivos, por ejemplo, 'FD_CLOEXEC'. – jfs

Cuestiones relacionadas