GNU/Linux >> Linux Esercitazione >  >> Linux

O_RDWR su named pipe con poll()

Secondo la pagina man di open(2), puoi passare O_RDONLY|O_NONBLOCK o O_WRONLY|O_NONBLOCK per evitare il open syscall da bloccare (otterrai errno == ENXIO in tal caso)

Come ho commentato, leggi anche le pagine man di fifo(7) e mkfifo(3).


Innanzitutto, alcuni preliminari:

Usando O_NONBLOCK e poll() è una pratica comune, non il contrario. Per funzionare correttamente, devi essere sicuro di gestire tutti i poll() e read() return indica correttamente:

  • read() valore di ritorno di 0 significa EOF -- l'altro lato ha chiuso la sua connessione. Questo corrisponde (di solito, ma non su tutti i sistemi operativi) a poll() restituendo un POLLHUP revent. Potresti voler controllare POLLHUP prima di tentare read() , ma non è assolutamente necessario poiché read() è garantito che restituisca 0 dopo che il lato di scrittura si è chiuso.
  • Se chiami il read() prima che uno scrittore si sia connesso e tu hai O_RDONLY | O_NONBLOCK , otterrai EOF (read() restituendo 0 ) ripetutamente, come avrai notato. Tuttavia, se usi poll() per attendere un POLLIN evento prima di chiamare read() , attenderà che il writer si connetta e non produrrà gli EOF.
  • read() valore di ritorno -1 di solito significa errore. Tuttavia, se errno == EAGAIN , questo significa semplicemente che al momento non ci sono più dati disponibili e che non stai bloccando, quindi puoi tornare a poll() nel caso in cui sia necessario maneggiare altri dispositivi. Se errno == EINTR , quindi read() è stato interrotto prima di leggere qualsiasi dato e puoi tornare a poll() o chiama semplicemente read() di nuovo immediatamente.

Ora, per Linux:

  • Se apri dal lato lettura con O_RDONLY , quindi:
    • Il open() si bloccherà fino a quando non sarà aperto un writer corrispondente.
    • poll() darà un POLLIN revent quando i dati sono pronti per essere letti o si verifica EOF.
    • read() si bloccherà fino a quando non viene letto il numero di byte richiesto, la connessione viene chiusa (restituisce 0), viene interrotta da un segnale o si verifica un errore I/O irreversibile. Questo tipo di blocco vanifica lo scopo dell'utilizzo di poll() , motivo per cui poll() è quasi sempre usato con O_NONBLOCK . Potresti usare un alarm() per svegliarsi da read() dopo un timeout, ma è eccessivamente complicato.
    • Se lo scrittore chiude, il lettore riceverà un poll() POLLHUP revent e read() restituirà 0 indefinitamente dopo. A questo punto, il lettore deve chiudere il suo filehandle e riaprirlo.
  • Se apri sul lato lettura con O_RDONLY | O_NONBLOCK , quindi:
    • Il open() non verrà bloccato.
    • poll() darà un POLLIN revent quando i dati sono pronti per essere letti o si verifica EOF. poll() si bloccherà anche fino a quando non sarà disponibile un writer, se nessuno è presente.
    • Dopo che tutti i dati attualmente disponibili sono stati letti, read() restituirà -1 e imposterà errno == EAGAIN se la connessione è ancora aperta, o restituirà 0 se la connessione è chiusa (EOF) o non ancora aperta da un writer . Quando errno == EAGAIN , questo significa che è ora di tornare a poll() , poiché la connessione è aperta ma non ci sono più dati. Quando errno == EINTR , read() non ha ancora letto byte ed è stato interrotto da un segnale, quindi può essere riavviato.
    • Se lo scrittore chiude, il lettore riceverà un poll() POLLHUP revent e read() restituirà 0 indefinitamente dopo. A questo punto il lettore deve chiudere il suo filehandle e riaprirlo.
  • (Specifico per Linux:) Se apri sul lato lettura con O_RDWR , quindi:
    • Il open() non verrà bloccato.
    • poll() darà un POLLIN revent quando i dati sono pronti per essere letti. Tuttavia, per le named pipe, EOF non causerà POLLIN o POLLHUP revents.
    • read() si bloccherà fino a quando non viene letto il numero di byte richiesto, viene interrotto da un segnale o si verifica qualche altro errore IO fatale. Per le named pipe, non restituirà errno == EAGAIN , né restituirà nemmeno 0 uno di. Resterà lì finché non viene letto il numero esatto di byte richiesti, o finché non riceve un segnale (nel qual caso restituirà il numero di byte letti fino a quel momento, oppure restituirà -1 e imposterà errno == EINTR se finora non sono stati letti byte).
    • Se il writer si chiude, il reader non perderà la possibilità di leggere la named pipe in un secondo momento se un altro writer apre la named pipe, ma neanche il reader riceverà alcuna notifica.
  • (Specifico per Linux:) Se apri sul lato lettura con O_RDWR | O_NONBLOCK , quindi:
    • Il open() non verrà bloccato.
    • poll() darà un POLLIN revent quando i dati sono pronti per essere letti. Tuttavia, EOF non causerà POLLIN o POLLHUP revent su named pipe.
    • Dopo che tutti i dati attualmente disponibili sono stati letti, read() restituirà -1 e imposta errno == EAGAIN . Questo è il momento di tornare a poll() per attendere altri dati, possibilmente da altri flussi.
    • Se il writer si chiude, il lettore non perderà la capacità di leggere la named pipe in un secondo momento se un altro writer apre la named pipe. La connessione è permanente.

Come sei giustamente preoccupato, usando O_RDWR con pipe non è standard, POSIX o altrove.

Tuttavia, poiché questa domanda sembra sorgere spesso, il modo migliore su Linux per creare "pipe con nome resilienti" che rimangono attive anche quando un lato si chiude e che non causano POLLHUP revents o restituisce 0 per read() , consiste nell'usare O_RDWR | O_NONBLOCK .

Vedo tre modi principali per gestire le named pipe su Linux:

  1. (Portatile.) Senza poll() , e con una singola pipe:

    • open(pipe, O_RDONLY);
    • Ciclo principale:
      • read() tutti i dati necessari, possibilmente in loop su read() chiama.
        • Se read() == -1 e errno == EINTR , read() tutto da capo.
        • Se read() == 0 , la connessione viene chiusa e tutti i dati sono stati ricevuti.

  2. (Portatile.) Con poll() , e con l'aspettativa che le pipe, anche quelle nominate, vengano aperte solo una volta e che, una volta chiuse, debbano essere riaperte sia dal lettore che dallo scrittore, creando una nuova pipeline:

    • open(pipe, O_RDONLY | O_NONBLOCK);
    • Ciclo principale:
      • poll() per POLLIN eventi, possibilmente su più pipe contemporaneamente. (Nota:questo impedisce a read() dall'ottenere più EOF prima che uno scrittore si sia connesso.)
      • read() tutti i dati necessari, possibilmente in loop su read() chiama.
        • Se read() == -1 e errno == EAGAIN , torna a poll() passo.
        • Se read() == -1 e errno == EINTR , read() tutto da capo.
        • Se read() == 0 , la connessione viene chiusa ed è necessario terminare o chiudere e riaprire la pipe.

  3. (Non portatile, specifico per Linux.) Con poll() , e con l'aspettativa che le named pipe non terminino mai e possano essere connesse e disconnesse più volte:

    • open(pipe, O_RDWR | O_NONBLOCK);
    • Ciclo principale:
      • poll() per POLLIN eventi, possibilmente su più pipe contemporaneamente.
      • read() tutti i dati necessari, possibilmente in loop su read() chiama.
        • Se read() == -1 e errno == EAGAIN , torna a poll() passo.
        • Se read() == -1 e errno == EINTR , read() tutto da capo.
        • Se read() == 0 , qualcosa non va -- non dovrebbe succedere con O_RDWR su named pipe, ma solo con O_RDONLY o tubi senza nome; indica un tubo chiuso che deve essere chiuso e riaperto. Se mescoli pipe con nome e senza nome nello stesso poll() ciclo di gestione degli eventi, potrebbe essere necessario gestire ancora questo caso.

Linux
  1. Lavorare con le pipe sulla riga di comando di Linux

  2. Lettura di righe da un file con Bash:per vs. Mentre?

  3. Cosa fa poll() con un timeout pari a 0?

  4. Esempio di utilizzo di named pipe in Linux Bash

  5. Python legge denominato PIPE

Un'introduzione alle pipe e alle named pipe in Linux

Linux mkfifo Command Tutorial per principianti (con esempi)

Come utilizzare pipe e pipe con nome in Linux (con esempi)

Leggi gli ebook dalla riga di comando con Epy Ebook Reader

Suggerimenti Vim:leggi e scrivi file remoti con Vim su Linux

Perché poll non viene sostituito con epoll?