Selon la page de manuel open(2), vous pouvez passer O_RDONLY|O_NONBLOCK ou O_WRONLY|O_NONBLOCK pour éviter le open syscall à bloquer (vous obtiendrez errno == ENXIO dans ce cas)
Comme je l'ai commenté, lisez également les pages de manuel fifo(7) et mkfifo(3).
Tout d'abord, quelques préliminaires :
Utilisation de O_NONBLOCK et poll() est une pratique courante - et non l'inverse. Pour travailler avec succès, vous devez être sûr de gérer tous les poll() et read() retourner les états correctement :
read()valeur de retour de0signifie EOF - l'autre côté a fermé sa connexion. Cela correspond (généralement, mais pas sur tous les OS) àpoll()renvoyant unPOLLHUPrevent. Vous voudrez peut-être vérifierPOLLHUPavant de tenterread(), mais ce n'est pas absolument nécessaire depuisread()est garanti de retourner0après la fermeture du côté écriture.- Si vous appelez le
read()avant qu'un rédacteur ne se soit connecté, et vous avezO_RDONLY | O_NONBLOCK, vous obtiendrez EOF (read()retour0) à plusieurs reprises, comme vous l'avez remarqué. Cependant, si vous utilisezpoll()attendre unPOLLINévénement avant d'appelerread(), il attendra que l'enregistreur se connecte et ne produira pas les EOF. read()valeur de retour-1signifie généralement erreur. Cependant, sierrno == EAGAIN, cela signifie simplement qu'il n'y a plus de données disponibles pour le moment et que vous ne bloquez pas, vous pouvez donc revenir àpoll()au cas où d'autres appareils auraient besoin d'être manipulés. Sierrno == EINTR, puisread()a été interrompu avant la lecture des données, et vous pouvez soit revenir àpoll()ou appelez simplement leread()à nouveau immédiatement.
Maintenant, pour Linux :
- Si vous ouvrez côté lecture avec
O_RDONLY, alors :- Le
open()bloquera jusqu'à ce qu'un écrivain correspondant soit ouvert. poll()donnera unPOLLINse déclenche lorsque les données sont prêtes à être lues, ou EOF se produit.read()se bloquera jusqu'à ce que le nombre d'octets demandé soit lu, que la connexion soit fermée (renvoie 0), qu'elle soit interrompue par un signal ou qu'une erreur IO fatale se produise. Ce type de blocage va à l'encontre du but de l'utilisation depoll(), c'est pourquoipoll()est presque toujours utilisé avecO_NONBLOCK. Vous pouvez utiliser unalarm()se réveiller deread()après un délai d'attente, mais c'est trop compliqué.- Si le rédacteur se ferme, le lecteur recevra un
poll()POLLHUPévénement etread()renverra0indéfiniment ensuite. À ce stade, le lecteur doit fermer son descripteur de fichier et le rouvrir.
- Le
- Si vous ouvrez côté lecture avec
O_RDONLY | O_NONBLOCK, alors :- Le
open()ne bloquera pas. poll()donnera unPOLLINévénement lorsque les données sont prêtes à être lues, ou EOF se produit.poll()bloquera également jusqu'à ce qu'un écrivain soit disponible, s'il n'y en a pas.- Une fois toutes les données actuellement disponibles lues,
read()renverra -1 et définiraerrno == EAGAINsi la connexion est toujours ouverte, sinon elle renverra0si la connexion est fermée (EOF) ou pas encore ouverte par un écrivain . Quanderrno == EAGAIN, cela signifie qu'il est temps de revenir àpoll(), puisque la connexion est ouverte mais qu'il n'y a plus de données. Quanderrno == EINTR,read()n'a encore lu aucun octet et a été interrompu par un signal, il peut donc être redémarré. - Si le rédacteur se ferme, le lecteur recevra un
poll()POLLHUPévénement, etread()renverra0indéfiniment ensuite. À ce stade, le lecteur doit fermer son descripteur de fichier et le rouvrir.
- Le
- (Spécifique à Linux :) Si vous ouvrez du côté lecture avec
O_RDWR, alors :- Le
open()ne bloquera pas. poll()donnera unPOLLINlorsque les données sont prêtes à être lues. Cependant, pour les canaux nommés, EOF ne causera pasPOLLINouPOLLHUPévénements.read()se bloquera jusqu'à ce que le nombre d'octets demandé soit lu, qu'il soit interrompu par un signal ou qu'une autre erreur IO fatale se produise. Pour les canaux nommés, il ne renverra paserrno == EAGAIN, il ne renverra même pas0un des. Il restera là jusqu'à ce que le nombre exact d'octets demandés soit lu, ou jusqu'à ce qu'il reçoive un signal (auquel cas il renverra le nombre d'octets lus jusqu'à présent, ou renverra -1 et définiraerrno == EINTRsi aucun octet n'a été lu jusqu'à présent).- Si le rédacteur se ferme, le lecteur ne perdra pas la possibilité de lire le tube nommé plus tard si un autre rédacteur ouvre le tube nommé, mais le lecteur ne recevra aucune notification non plus.
- Le
- (Spécifique à Linux :) Si vous ouvrez du côté lecture avec
O_RDWR | O_NONBLOCK, alors :- Le
open()ne bloquera pas. poll()donnera unPOLLINlorsque les données sont prêtes à être lues. Cependant, EOF ne causera pasPOLLINouPOLLHUPrevents sur les canaux nommés.- Une fois toutes les données actuellement disponibles lues,
read()renverra-1et définissezerrno == EAGAIN. C'est le moment de revenir àpoll()pour attendre plus de données, éventuellement d'autres flux. - Si l'écrivain se ferme, le lecteur ne perdra pas la possibilité de lire le tube nommé plus tard si un autre écrivain ouvre le tube nommé. La connexion est persistante.
- Le
Comme vous êtes à juste titre concerné, en utilisant O_RDWR avec des tuyaux n'est pas standard, POSIX ou ailleurs.
Cependant, comme cette question semble revenir souvent, la meilleure façon sous Linux de créer des "canaux nommés résilients" qui restent actifs même lorsqu'un côté se ferme, et qui ne causent pas POLLHUP renvoie ou retourne 0 pour read() , est d'utiliser O_RDWR | O_NONBLOCK .
Je vois trois manières principales de gérer les canaux nommés sous Linux :
-
(Portable.) Sans
poll(), et avec un seul tube :open(pipe, O_RDONLY);- Boucle principale :
read()autant de données que nécessaire, éventuellement en boucle surread()appels.- Si
read() == -1eterrno == EINTR,read()tout recommencer. - Si
read() == 0, la connexion est fermée et toutes les données ont été reçues.
- Si
-
(Portable.) Avec
poll(), et en s'attendant à ce que les canaux, même nommés, ne soient ouverts qu'une seule fois, et qu'une fois fermés, ils doivent être rouverts à la fois par le lecteur et l'auteur, en créant un nouveau pipeline :open(pipe, O_RDONLY | O_NONBLOCK);- Boucle principale :
poll()pourPOLLINévénements, éventuellement sur plusieurs canaux à la fois. (Remarque :Cela empêcheread()d'obtenir plusieurs EOF avant qu'un écrivain ne se soit connecté.)read()autant de données que nécessaire, éventuellement en boucle surread()appels.- Si
read() == -1eterrno == EAGAIN, revenir àpoll()étape. - Si
read() == -1eterrno == EINTR,read()tout recommencer. - Si
read() == 0, la connexion est fermée et vous devez terminer ou fermer et rouvrir le tuyau.
- Si
-
(Non portable, spécifique à Linux.) Avec
poll(), et en supposant que les canaux nommés ne se terminent jamais et peuvent être connectés et déconnectés plusieurs fois :open(pipe, O_RDWR | O_NONBLOCK);- Boucle principale :
poll()pourPOLLINévénements, éventuellement sur plusieurs canaux à la fois.read()autant de données que nécessaire, éventuellement en boucle surread()appels.- Si
read() == -1eterrno == EAGAIN, revenir àpoll()étape. - Si
read() == -1eterrno == EINTR,read()tout recommencer. - Si
read() == 0, quelque chose ne va pas -- cela ne devrait pas arriver avecO_RDWRsur les canaux nommés, mais uniquement avecO_RDONLYou tuyaux sans nom ; il indique un tuyau fermé qui doit être fermé et rouvert. Si vous mélangez des canaux nommés et sans nom dans le mêmepoll()boucle de gestion des événements, ce cas devra peut-être encore être traité.
- Si