¿Se está configurando O_NONBLOCK una propiedad del descriptor de archivo o el archivo subyacente?

Por lo que he estado leyendo en el sitio web de The Open Group en fcntl , open , read y write , tengo la impresión de que si O_NONBLOCK está configurado en un descriptor de archivo y, por lo tanto, si se usa I / O sin locking con el descriptor, debe ser una propiedad de ese descriptor de archivo en lugar del archivo subyacente. Ser una 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 el locking de E / S con uno y el no locking de E / S con el otro.

Sin embargo, al experimentar con un FIFO, parece que no es posible tener un descriptor de E / S de locking y un descriptor de E / S sin locking al FIFO simultáneamente (por lo tanto, si O_NONBLOCK está configurado es una propiedad del archivo subyacente [el FIFO ]):

 #include  #include  #include  #include  #include  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: ¿es posible tener un descriptor de E / S no bloqueante y un descriptor de E / S bloqueante en el mismo archivo? En caso afirmativo, ¿depende del tipo de archivo (archivo normal, FIFO, archivo especial de bloque)? , archivo especial de caracteres, socket, etc.)?

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 abiertos descriptores de archivo separados para el mismo archivo, uno de los cuales está bloqueando y el otro no está bloqueado.

mkfifo() distinguir entre una FIFO (creada con mkfifo() ) y una tubería (creada con pipe() ).

Tenga en cuenta que el estado de locking es una propiedad de la ‘descripción de archivo abierto’, pero en los casos más simples, existe una asignación uno a uno entre los descriptores de archivo y las descripciones de archivo abiertas. 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 usa dup() , tiene dos descriptores de archivo que comparten una descripción de archivo abierta, y las propiedades pertenecen a la descripción de archivo abierto. La descripción de fcntl() dice que F_SETFL afecta la descripción de archivo abierto asociada 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 archivo duplicados del original.

Al eliminar el manejo de errores de su código 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 tanto fd0_dup como fds [0] se refieren a la misma descripción de archivo abierto (debido a dup() ), por lo que la operación fcntl() afectó a ambos descriptores de archivo.

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

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