Newsgroup: it.comp.os.linux.development
Titolo: pipe & buffer

salve a tutti, sto scrivendo un'interfaccia grafica per tcpdump, e mi
sono imbattuto in un problemino. Per ora ho scritto il parser (usando
flex e bison), e per testarlo ho scritto un main che, una volta ridotto
all'osso, diventa cosi':
#include <stdio.h>
int main(void){
extern FILE *yyin;
	yyin=stdin;
    setlinebuf(yyin);
    while(1){
        yyparse();
        text_interface();
    }
    return 0;
}
il parser legge una riga alla volta (viene forzata l'uscita con
YYACCPET), per questo ho usato setlinebuf(yyin). text_interface()
scrive semplicemente i valori che sono stati memorizzati in una
apposita struttura dati in fase di parsing.
In questo modo il programma funziona benone, se lo eseguo lui si
mette in attesa di input, e una volta scritta una linea valida e
premuto enter, da' subito l'output corrispondente.
Il passo successivo e' stato quello di ricevere i dati in ingresso
direttamente da tcpdump tramite una pipe. Ho semplicemente sostituito
la riga  yyin=stdin;  con  yyin=popen("tcpdump -e -v -l -i eth0", "r");
(ho provato anche senza il -l).
La cosa che mi lascia perplesso e' che adesso il programma continua a
leggere l'input dalla pipe (con strace posso vedere che fa delle read
ogni volta che ha una linea da leggere), pero' l'output e' in qualche
modo bufferizzato: all'inizio non scrive niente, poi mi sputa fuori
una valanga di dati tutti in un colpo (circa 25K di output).
Quello che non capisco e' perche' lo faccia nonostante abbia provato
a mettere un  setbuf(stdout, NULL)  all'inizio del programma,
oppure un  fflush(stdout)  dopo la chiamata a text_interface().
Forse mi sfugge qualcosa di molto profondo, o forse sono cosi'
stupido da non accorgermi di una banalita', fatto sta che non ne
vengo fuori. Qualche idea?
-- 
addio, e grazie per tutto il pesce

 salve a tutti, sto scrivendo un'interfaccia grafica per tcpdump
(Sai gia` che esiste Ethereal, vero?)
Bye
 David
-- 
<d.santinoli presso mi. flashnet. it>

 vengo fuori. Qualche idea?
allora...
leggendo man popen ho trovato: "Note that output popen streams are fully
buffered by default."
ma allora non devi chiamare fflush ogni volta che ti appresti a leggere
dalla pipe?
-- 
Non c'è più forza nella normalità, c'è solo monotonia.

> salve a tutti, sto scrivendo un'interfaccia grafica per tcpdump
DS> (Sai gia` che esiste Ethereal, vero?)
io lo so, il docente che mi ha dato questo progetto non credo, in
effetti avevo pensato di presentargli ethereal e spacciarlo per mio
:))) (ma non sono COSI' fetente).


 :))) (ma non sono COSI' fetente).
Mah, per un esame forse e` un po' overkill, magari per una tesi... ;-)


Pape' Satan, pape' Satan aleppe, comincio' Ottavio con voce chioccia:
OC> leggendo man popen ho trovato: "Note that output popen streams are fully
OC> buffered by default."
OC> ma allora non devi chiamare fflush ogni volta che ti appresti a leggere
OC> dalla pipe?
non credo dipenda da quello, perche' io ho fatto cosi':
da una parte c'e' tcpdump, che viene lanciato con l'opzione -l, in
modo che il suo output sia line-buffered. Poi passa attraverso la
pipe e arriva dall'altra parte dove c'e' il mio programma, che a sua
volta fa un setlinebuf(yyin)  (dove yyin e' una stream associata
all'altra estremita' della pipe).
In effetti credo che i dati passino sulla pipe proprio quando voglio
io, perche' se faccio un strace -p <pid_del_programma> vedo che legge
i dati una linea alla volta non appena sono disponibili. Insomma,
sembra che non sia il buffer della pipe a dare problemi. Tuttavia
l'output finale del programma arriva "a blocchi", proprio lui che con
la pipe non c'entra niente! Eppure senza la pipe, prendendo l'input
direttamente da terminale, funziona egregiamente. Per me rimane un
mistero.


sembra che non sia il buffer della pipe a dare problemi.
Quello che tu vedi e' il buffer che prende i dati da tcpdump. Non vedi
il buffer che viene letto dal programma, pero'.
Prova a mettere nel programma una serie di righe, che stampino, dentro
a un file di log, il timestamp attuale, del tipo:
	printtime("Leggo da buffer");
	printtime("Ora scrivo");
e ottenendo
...
12:17:05.283 Leggo da buffer
12:17:05.297 Ora scrivo
...
Leonardo
-- 
".signature": bad command or file name


Premesso che slrn mi ha appena cancellato un pezzo di thread;
Da quello che ho capito tu setti yyin come line-buffered (anche se non c'era
bisogno, se , come ricordo yyin non era che stdin)
Il punto e' che anche se la read-end e' messa come line-buffered, quando con
popen associ alla sequenza crea_pipe->fork->exec... uno stream questo ti
viene fuori fully-buffered e quindi l'output avverra' solo quando il buffer
si e' riempito (a forza di metterci dentro l'input "a linee") o quando
chiami fflush.
Comunque hai provato a mettere fflush?? Cosi' tagli la testa al
toro...
Vi][oZ 
-- 
          We are the true believers
       It's our turn to show the world
 In the fire of heavy metal we were burned
         It's more than our religion
          It's the only way to live
           But the enemies of metal
              We can't forgive

Pape' Satan, pape' Satan aleppe, comincio' Dr. con voce chioccia:
DF> La cosa che mi lascia perplesso e' che adesso il programma continua a
DF> leggere l'input dalla pipe (con strace posso vedere che fa delle read
DF> ogni volta che ha una linea da leggere), pero' l'output e' in qualche
DF> modo bufferizzato: all'inizio non scrive niente, poi mi sputa fuori
DF> una valanga di dati tutti in un colpo (circa 25K di output).
risolto. E' bastato usare la linea di comando -Cr di flex, che, come
da man page:
              -Cr  causes  the generated scanner to bypass use of
              the  standard  I/O  library  (stdio)   for   input.
              Instead  of  calling fread() or getc(), the scanner
              will use the read() system  call
pero' ora mi piacerebbe capire se c'e' un metodo piu' pulito per
evitare che l'analizzatore lessicale bufferizzi tutto l'input.


>sembra che non sia il buffer della pipe a dare problemi.
LS> Quello che tu vedi e' il buffer che prende i dati da tcpdump. Non vedi
LS> il buffer che viene letto dal programma, pero'.
mi sa che hai proprio ragione. Infatti poi ho scoperto che,
nonostante i read che vedevo con strace, era il parser a bloccarsi in
attesa di input. Come forse avrai letto, per ora non ho trovato niente
di meglio che usare l'opzione -Cr di flex, di modo che legga l'input
tramite read() anziche' fread() o getc(). In questo modo salto a pie'
pari il buffer in ricezione.
Il mio errore era quello di pensare che la cosa si risolvesse con un
setlinebuf sullo stream di input, ma rileggendo bene la man page
mi sono reso conto che questa funzione (cosi' come setbuf o fflush)
ha senso solo quando e' applicata ad uno stream di output.
A questo punto la domanda nasce spontanea (C): c'e' un modo per
togliere il buffer in ingresso, o renderlo line-buffered?
Giusto per curiosita', tanto il problema e' risolto :)
PS: non hai ancora pensato di proclamare il dogma dell'infallibilita'
di Leonardo Serni? :)


Pape' Satan, pape' Satan aleppe, comincio' Vi][oZ con voce chioccia:
Vo> Il punto e' che anche se la read-end e' messa come line-buffered, quando con
Vo> popen associ alla sequenza crea_pipe->fork->exec... uno stream questo ti
Vo> viene fuori fully-buffered e quindi l'output avverra' solo quando il buffer
Vo> si e' riempito (a forza di metterci dentro l'input "a linee") o quando
Vo> chiami fflush.
Vo> Comunque hai provato a mettere fflush?? Cosi' tagli la testa al
Vo> toro...
ho provato e non cambiava niente. A quanto pare fflush si puo' usare
su uno stream di output (almeno cosi' dice la man page), ma non serve
a niente su uno stream di input.
colgo comunque l'occasione per ringraziare te e tutti quelli che mi
hanno risposto.


di Leonardo Serni? :)
Si', ma c'e' in giro troppa gente con buona memoria e un enorme archivio
delle mie cazzate, che mi ricatta.
