De acuerdo con la página de manual de open(2), puede pasar O_RDONLY|O_NONBLOCK o O_WRONLY|O_NONBLOCK para evitar el open syscall para ser bloqueado (obtendrá errno == ENXIO en ese caso)
Como comenté, lea también las páginas man de fifo(7) y mkfifo(3).
Primero, algunos preliminares:
Usando O_NONBLOCK y poll() es una práctica común, no al revés. Para trabajar con éxito, debe asegurarse de manejar todos los poll() y read() estados de retorno correctamente:
read()valor de retorno de0significa EOF -- el otro lado ha cerrado su conexión. Esto corresponde (generalmente, pero no en todos los sistemas operativos) apoll()devolviendo unPOLLHUPreventar Es posible que desee verificarPOLLHUPantes de intentarread(), pero no es absolutamente necesario ya queread()está garantizado para devolver0después de que el lado de escritura se haya cerrado.- Si llama al
read()antes de que un escritor se haya conectado, y usted tieneO_RDONLY | O_NONBLOCK, obtendrá EOF (read()devolviendo0) repetidamente, como habrás notado. Sin embargo, si usapoll()esperar unPOLLINevento antes de llamarread(), esperará a que el escritor se conecte y no generará los EOF. read()valor de retorno-1generalmente significa error. Sin embargo, sierrno == EAGAIN, esto simplemente significa que no hay más datos disponibles en este momento y no está bloqueando, por lo que puede volver apoll()en caso de que otros dispositivos necesiten manipulación. Sierrno == EINTR, luegoread()fue interrumpido antes de leer cualquier dato, y puede volver apoll()o simplemente llama alread()de nuevo inmediatamente.
Ahora, para Linux:
- Si abre en el lado de lectura con
O_RDONLY, entonces:- El
open()bloqueará hasta que haya un escritor correspondiente abierto. poll()dará unPOLLINprevenga cuando los datos estén listos para ser leídos o cuando ocurra EOF.read()se bloqueará hasta que se lea el número solicitado de bytes, se cierre la conexión (devuelve 0), se interrumpa por una señal o se produzca algún error fatal de E/S. Este tipo de bloqueo anula el propósito de usarpoll(), por lo quepoll()casi siempre se usa conO_NONBLOCK. Podrías usar unalarm()despertar deread()después de un tiempo de espera, pero eso es demasiado complicado.- Si el escritor cierra, el lector recibirá un
poll()POLLHUPprevención yread()devolverá0indefinidamente después. En este punto, el lector debe cerrar su identificador de archivo y volver a abrirlo.
- El
- Si abre en el lado de lectura con
O_RDONLY | O_NONBLOCK, entonces:- El
open()no bloqueará. poll()dará unPOLLINprevenga cuando los datos estén listos para ser leídos o cuando ocurra EOF.poll()también bloqueará hasta que haya un escritor disponible, si no hay ninguno presente.- Después de leer todos los datos disponibles actualmente,
read()devolverá -1 y estableceráerrno == EAGAINsi la conexión aún está abierta, o devolverá0si la conexión está cerrada (EOF) o aún no ha sido abierta por un escritor . Cuandoerrno == EAGAIN, esto significa que es hora de volver apoll(), ya que la conexión está abierta pero no hay más datos. Cuandoerrno == EINTR,read()aún no ha leído bytes y fue interrumpido por una señal, por lo que puede reiniciarse. - Si el escritor cierra, el lector recibirá un
poll()POLLHUPevento, yread()devolverá0indefinidamente después. En este punto, el lector debe cerrar su identificador de archivo y volver a abrirlo.
- El
- (Específico de Linux:) Si abre en el lado de lectura con
O_RDWR, entonces:- El
open()no bloqueará. poll()dará unPOLLINrevent cuando los datos están listos para ser leídos. Sin embargo, para canalizaciones con nombre, EOF no causaráPOLLINoPOLLHUPeventos.read()se bloqueará hasta que se lea el número solicitado de bytes, se interrumpa por una señal o se produzca algún otro error fatal de E/S. Para canalizaciones con nombre, no devolveráerrno == EAGAIN, ni siquiera devolverá0uno de. Simplemente permanecerá allí hasta que se lea el número exacto de bytes solicitados, o hasta que reciba una señal (en cuyo caso devolverá el número de bytes leídos hasta el momento, o devolverá -1 y estableceráerrno == EINTRsi no se leyeron bytes hasta el momento).- Si el escritor se cierra, el lector no perderá la capacidad de leer la canalización con nombre más tarde si otro escritor abre la canalización con nombre, pero el lector tampoco recibirá ninguna notificación.
- El
- (Específico de Linux:) Si abre en el lado de lectura con
O_RDWR | O_NONBLOCK, entonces:- El
open()no bloqueará. poll()dará unPOLLINrevent cuando los datos están listos para ser leídos. Sin embargo, EOF no causaráPOLLINoPOLLHUPeventos en canalizaciones con nombre.- Después de leer todos los datos disponibles actualmente,
read()devolverá-1y establecererrno == EAGAIN. Este es el momento de volver apoll()esperar más datos, posiblemente de otros flujos. - Si el escritor se cierra, el lector no perderá la capacidad de leer la canalización con nombre más adelante si otro escritor abre la canalización con nombre. La conexión es persistente.
- El
Como le preocupa, usando O_RDWR con tuberías no es estándar, POSIX o en otro lugar.
Sin embargo, dado que esta pregunta parece surgir con frecuencia, la mejor manera en Linux de hacer "tuberías con nombre resistentes" que permanezcan vivas incluso cuando un lado se cierra, y que no causen POLLHUP revents o return 0 para read() , es usar O_RDWR | O_NONBLOCK .
Veo tres formas principales de manejar canalizaciones con nombre en Linux:
-
(Portátil.) Sin
poll(), y con una sola tubería:open(pipe, O_RDONLY);- Bucle principal:
read()tantos datos como sea necesario, posiblemente en bucle enread()llamadas.- Si
read() == -1yerrno == EINTR,read()todo de nuevo. - Si
read() == 0, la conexión se cierra y se han recibido todos los datos.
- Si
-
(Portátil.) Con
poll(), y con la expectativa de que las canalizaciones, incluso las con nombre, solo se abran una vez y que, una vez que se cierren, tanto el lector como el escritor deban volver a abrirlas, configurando una nueva canalización:open(pipe, O_RDONLY | O_NONBLOCK);- Bucle principal:
poll()paraPOLLINeventos, posiblemente en múltiples conductos a la vez. (Nota:esto evita queread()obtener múltiples EOF antes de que un escritor se haya conectado).read()tantos datos como sea necesario, posiblemente en bucle enread()llamadas.- Si
read() == -1yerrno == EAGAIN, vuelve apoll()paso. - Si
read() == -1yerrno == EINTR,read()todo de nuevo. - Si
read() == 0, la conexión está cerrada y debe terminar o cerrar y volver a abrir la tubería.
- Si
-
(No portátil, específico de Linux). Con
poll(), y con la expectativa de que las canalizaciones con nombre nunca terminen y se puedan conectar y desconectar varias veces:open(pipe, O_RDWR | O_NONBLOCK);- Bucle principal:
poll()paraPOLLINeventos, posiblemente en múltiples conductos a la vez.read()tantos datos como sea necesario, posiblemente en bucle enread()llamadas.- Si
read() == -1yerrno == EAGAIN, vuelve apoll()paso. - Si
read() == -1yerrno == EINTR,read()todo de nuevo. - Si
read() == 0, algo anda mal, no debería pasar conO_RDWRen canalizaciones con nombre, pero solo conO_RDONLYo tuberías sin nombre; indica una tubería cerrada que debe cerrarse y volverse a abrir. Si mezcla tuberías con nombre y sin nombre en el mismopoll()ciclo de manejo de eventos, es posible que este caso aún deba manejarse.
- Si