Pipes et fin des commandes

Le
Antoine
Salut,

Quand je fais un:
% find / | head

qu'est-ce qui fait exactement que le find s'arrête ?


-- antoine
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Stephane CHAZELAS
Le #18153781
2008-12-16, 11:07(+00), Antoine:
Salut,

Quand je fais un:
% find / | head

qu'est-ce qui fait exactement que le find s'arrête ?


[...]

head va faire un ou plusieurs read(0, buf, sizeof(buf)). Des
qu'il a trouvé 10 caracteres "NL" dans son input il va se
terminer, ce qui va fermer la sortie du pipe. A partir de ce
moment la, des que find va faire un write(1, ...), il va se
prendre un signal SIGPIPE qui va le tuer.

Donc:

1- pour qu'il meurt, il faut qu'il ecrive quelque chose apres
que head se termine, donc il peut ne pas se terminer tout de
suite s'il ne trouve pas de fichier.

2- find peut ecrire bien plus de 10 lignes avant d'etre tué,
parce que:
- dans un pipe, on peut ecrire pas mal avant que l'autre ne
lise (ya un buffer qui peut contenir plusieurs dixaines de kB
suivant les implementations), donc apres, c'est une histoire
de quel process est schedulé.
- "head" va lire morceau par morceau, les morceaux faisant
typiquement 4, 5 or 8 kB selon les implementation de stdio.
mais note que le read(0, ...) retournera mois que sizeof(buf)
si find n'en a pas ecrit autant au moment ou head fait appel a
read().
- surtout, find lui-meme va ecrire morceau par morceau puisque
son stdout n'est pas un terminal, donc ne va probablement rien
ecrire avant d'avoir trouver suffisamment de fichier pour
remplir un "morceau" de 4, 5 ou 8kB (stdio encore, il doit
faire des puts() ou printf()).


--
Stéphane
Nicolas George
Le #18153941
Stephane CHAZELAS wrote in message
- surtout, find lui-meme va ecrire morceau par morceau puisque
son stdout n'est pas un terminal, donc ne va probablement rien
ecrire avant d'avoir trouver suffisamment de fichier pour
remplir un "morceau" de 4, 5 ou 8kB (stdio encore, il doit
faire des puts() ou printf()).



Ça, ce n'est pas clair du tout. Si je devais écrire un find, je mettrais un
fflush après chaque nom de fichier, pour ne pas retarder la suite du
traitement. Et de fait, au moins GNU find se comporte ainsi.
Stephane CHAZELAS
Le #18153931
2008-12-16, 11:34(+00), Nicolas George:
Stephane CHAZELAS wrote in message
- surtout, find lui-meme va ecrire morceau par morceau puisque
son stdout n'est pas un terminal, donc ne va probablement rien
ecrire avant d'avoir trouver suffisamment de fichier pour
remplir un "morceau" de 4, 5 ou 8kB (stdio encore, il doit
faire des puts() ou printf()).



Ça, ce n'est pas clair du tout. Si je devais écrire un find, je mettrais un
fflush après chaque nom de fichier, pour ne pas retarder la suite du
traitement. Et de fait, au moins GNU find se comporte ainsi.



??? Au contraire, faire des fflush sur un pipe est suboptimal,
ca causerait plein de context-switch.

$ strace -e write find / | head
write(1, "/n/.journaln/mpl2n/binn/bin/chgrp"..., 4096/
/.journal
/mpl2
/bin
/bin/chgrp
/bin/busybox
/bin/gzip
/bin/bzexe
/bin/hostname
/bin/tartest
) = 4096
write(1, "0n/dev/.udev/names/snd\x2fcontrol"..., 4096) = -1 EPIPE (Broken pipe)
--- SIGPIPE (Broken pipe) @ 0 (0) ---
+++ killed by SIGPIPE +++

~$ find --version
find (GNU findutils) 4.4.0
[...]

ltrace -Se fprintf,fflush
montre dans les 200 fprintf et pas un fflush et deux SYS_write
de 4096 octets le deuxieme causant un SIGPIPE.

--
Stéphane
Antoine
Le #18154061
> 2008-12-16, 11:07(+00), Antoine:
Salut,

Quand je fais un:
% find / | head

qu'est-ce qui fait exactement que le find s'arrête ?


[...]

head va faire un ou plusieurs read(0, buf, sizeof(buf)). Des qu'il a
trouvé 10 caracteres "NL" dans son input il va se terminer, ce qui va
fermer la sortie du pipe. A partir de ce moment la, des que find va
faire un write(1, ...), il va se prendre un signal SIGPIPE qui va le
tuer.



D'accord. Et admettons que je veuille regarder comment ceci est
implémenté par exemple sur mon système ( OpenBSD 4.4 GENERIC#1021 i386),
comment je peux trouver, à part un % grep SIGPIPE dans les sources ? Et
sys.tar.gz ou src.tar.gz ?

-- antoine
Stephane Chazelas
Le #18154161
2008-12-16, 11:50(+00), Antoine:
[...]
head va faire un ou plusieurs read(0, buf, sizeof(buf)). Des qu'il a
trouvé 10 caracteres "NL" dans son input il va se terminer, ce qui va
fermer la sortie du pipe. A partir de ce moment la, des que find va
faire un write(1, ...), il va se prendre un signal SIGPIPE qui va le
tuer.



D'accord. Et admettons que je veuille regarder comment ceci est
implémenté par exemple sur mon système ( OpenBSD 4.4 GENERIC#1021 i386),
comment je peux trouver, à part un % grep SIGPIPE dans les sources ? Et
sys.tar.gz ou src.tar.gz ?


[...]

C'est l'appel systeme pipe() appliqué a un fd ouvert sur un
pipe. Je ne connais pas les details d'implementation sur
OpenBSD, mais l'entry point dans le kernel de l'appel system
write(2) sera probablement dans sys.tar.gz. Ensuite, il est
probable que ca dispatche vers une fonction/methode "write"
specifique aux pipes, donc peut-etre dans un pipe.c. Il y aura
probablement un if (pipe.number_of_open_readers == 0) { ...;
send_SIGPIPE_to(current_thread); ...; }. Faire un
grep SIGPIPE est probablement un bon raccourci.

--
Stéphane
Nicolas George
Le #18157661
Stephane CHAZELAS wrote in message
??? Au contraire, faire des fflush sur un pipe est suboptimal,
ca causerait plein de context-switch.



find a de bonnes chances d'être intensif en I/O. Si la sortie de find est
rare et que la suite du pipeline est intensive en CPU, c'est un net gain de
temps de bufferiser par ligne.

~$ find --version
find (GNU findutils) 4.4.0
[...]



Oui, j'ai mal testé, au temps pour moi.

Ceci dit, je maintiens ma position de principe : j'ai horreur de ces
programmes orientés traitement de fichiers textes par ligne qui bufferisent
par bloc.
Vincent Lefevre
Le #18163911
Dans l'article Nicolas George
Stephane CHAZELAS wrote in message
> ??? Au contraire, faire des fflush sur un pipe est suboptimal,
> ca causerait plein de context-switch.



find a de bonnes chances d'être intensif en I/O. Si la sortie de find est
rare et que la suite du pipeline est intensive en CPU, c'est un net gain de
temps de bufferiser par ligne.



Je suis d'accord. Donc en gros, ça dépend du contexte. Dans l'idéal,
il serait bien que les fflush soient contrôlés par le temps (voire
au niveau du scheduler, mais ce n'est probablement pas possible).

Ceci dit, je maintiens ma position de principe : j'ai horreur de ces
programmes orientés traitement de fichiers textes par ligne qui
bufferisent par bloc.



Oui, surtout quand on a juste un filtre (e.g. de colorisation) et que
la sortie se fera tout de même sur le terminal.

Le problème s'est justement posé avec Subversion (e.g. svn log) et
a été corrigé.

De même que la commande après le pipe n'est pas censée bloquer les
écritures en ne lisant rien (si bien que le buffer devient plein).
C'est le problème de "less"...

--
Vincent Lefèvre 100% accessible validated (X)HTML - Blog: Work: CR INRIA - computer arithmetic / Arenaire project (LIP, ENS-Lyon)
Publicité
Poster une réponse
Anonyme