GNU/Linux >> Tutoriales Linux >  >> Linux

O_RDWR en canalizaciones con nombre con poll()

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 de 0 significa EOF -- el otro lado ha cerrado su conexión. Esto corresponde (generalmente, pero no en todos los sistemas operativos) a poll() devolviendo un POLLHUP reventar Es posible que desee verificar POLLHUP antes de intentar read() , pero no es absolutamente necesario ya que read() está garantizado para devolver 0 después de que el lado de escritura se haya cerrado.
  • Si llama al read() antes de que un escritor se haya conectado, y usted tiene O_RDONLY | O_NONBLOCK , obtendrá EOF (read() devolviendo 0 ) repetidamente, como habrás notado. Sin embargo, si usa poll() esperar un POLLIN evento antes de llamar read() , esperará a que el escritor se conecte y no generará los EOF.
  • read() valor de retorno -1 generalmente significa error. Sin embargo, si errno == EAGAIN , esto simplemente significa que no hay más datos disponibles en este momento y no está bloqueando, por lo que puede volver a poll() en caso de que otros dispositivos necesiten manipulación. Si errno == EINTR , luego read() fue interrumpido antes de leer cualquier dato, y puede volver a poll() o simplemente llama al read() 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á un POLLIN prevenga 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 usar poll() , por lo que poll() casi siempre se usa con O_NONBLOCK . Podrías usar un alarm() despertar de read() después de un tiempo de espera, pero eso es demasiado complicado.
    • Si el escritor cierra, el lector recibirá un poll() POLLHUP prevención y read() devolverá 0 indefinidamente después. En este punto, el lector debe cerrar su identificador de archivo y volver a abrirlo.
  • Si abre en el lado de lectura con O_RDONLY | O_NONBLOCK , entonces:
    • El open() no bloqueará.
    • poll() dará un POLLIN prevenga 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 == EAGAIN si la conexión aún está abierta, o devolverá 0 si la conexión está cerrada (EOF) o aún no ha sido abierta por un escritor . Cuando errno == EAGAIN , esto significa que es hora de volver a poll() , ya que la conexión está abierta pero no hay más datos. Cuando errno == 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() POLLHUP evento, y read() devolverá 0 indefinidamente después. En este punto, el lector debe cerrar su identificador de archivo y volver a abrirlo.
  • (Específico de Linux:) Si abre en el lado de lectura con O_RDWR , entonces:
    • El open() no bloqueará.
    • poll() dará un POLLIN revent cuando los datos están listos para ser leídos. Sin embargo, para canalizaciones con nombre, EOF no causará POLLIN o POLLHUP eventos.
    • 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á 0 uno 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 == EINTR si 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.
  • (Específico de Linux:) Si abre en el lado de lectura con O_RDWR | O_NONBLOCK , entonces:
    • El open() no bloqueará.
    • poll() dará un POLLIN revent cuando los datos están listos para ser leídos. Sin embargo, EOF no causará POLLIN o POLLHUP eventos en canalizaciones con nombre.
    • Después de leer todos los datos disponibles actualmente, read() devolverá -1 y establecer errno == EAGAIN . Este es el momento de volver a poll() 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.

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:

  1. (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 en read() llamadas.
        • Si read() == -1 y errno == EINTR , read() todo de nuevo.
        • Si read() == 0 , la conexión se cierra y se han recibido todos los datos.

  2. (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() para POLLIN eventos, posiblemente en múltiples conductos a la vez. (Nota:esto evita que read() obtener múltiples EOF antes de que un escritor se haya conectado).
      • read() tantos datos como sea necesario, posiblemente en bucle en read() llamadas.
        • Si read() == -1 y errno == EAGAIN , vuelve a poll() paso.
        • Si read() == -1 y errno == 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.

  3. (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() para POLLIN eventos, posiblemente en múltiples conductos a la vez.
      • read() tantos datos como sea necesario, posiblemente en bucle en read() llamadas.
        • Si read() == -1 y errno == EAGAIN , vuelve a poll() paso.
        • Si read() == -1 y errno == EINTR , read() todo de nuevo.
        • Si read() == 0 , algo anda mal, no debería pasar con O_RDWR en canalizaciones con nombre, pero solo con O_RDONLY o 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 mismo poll() ciclo de manejo de eventos, es posible que este caso aún deba manejarse.

Linux
  1. Trabajando con tuberías en la línea de comando de Linux

  2. Linux:¿hay una lectura o recepción desde el socket con tiempo de espera?

  3. Ejemplo de uso de canalizaciones con nombre en Linux Bash

  4. letsencrypt falló con ImportError:No hay módulo llamado interfaz

  5. ¿Por qué poll no se reemplaza con epoll?

Una introducción a las canalizaciones y canalizaciones con nombre en Linux

Tutorial de comando Linux mkfifo para principiantes (con ejemplos)

Lea libros electrónicos desde la línea de comandos con Epy Ebook Reader

Consejos de Vim:lea y escriba archivos remotos con Vim en Linux

¿Cómo copio el archivo cuyo nombre comienza con un punto?

¿Comando Linux/Unix para unir N líneas de entrada con delimitadores?