varie su read/pread/dup/dup2 ecc.
authorSimone Piccardi <piccardi@gnulinux.it>
Fri, 21 Jun 2002 22:24:10 +0000 (22:24 +0000)
committerSimone Piccardi <piccardi@gnulinux.it>
Fri, 21 Jun 2002 22:24:10 +0000 (22:24 +0000)
fileunix.tex
ipc.tex
signal.tex
sources/BarCode.c

index 8428e10..7eddb14 100644 (file)
@@ -538,44 +538,43 @@ come valore di ritorno.
 Con i \textsl{file regolari} questa è l'unica situazione in cui si può avere
 un numero di byte letti inferiore a quello richiesto, ma questo non è vero
 quando si legge da un terminale, da una fifo o da una pipe. In tal caso
-infatti, se non ci sono dati in ingresso, la \func{read} si blocca e ritorna
-solo quando ne arrivano; se il numero di byte richiesti eccede quelli
-disponibili la funzione ritorna comunque, ma con un numero di byte inferiore a
-quelli richiesti.
+infatti, se non ci sono dati in ingresso, la \func{read} si blocca (a meno di
+non aver selezionato la modalità non bloccante, vedi
+\secref{sec:file_noblocking}) e ritorna solo quando ne arrivano; se il numero
+di byte richiesti eccede quelli disponibili la funzione ritorna comunque, ma
+con un numero di byte inferiore a quelli richiesti.
 
 Lo stesso comportamento avviene caso di lettura dalla rete (cioè su un socket,
-come vedremo in \secref{sec:sock_io_behav}), o per certi dispositivi, come le
-unità a nastro, che restituiscono un singolo blocco di dati alla volta.
+come vedremo in \secref{sec:sock_io_behav}), o per la lettura da certi file di
+dispositivo, come le unità a nastro, che restituiscono sempre i dati ad un
+singolo blocco alla volta.
 
 In realtà anche le due condizioni segnalate dagli errori \macro{EINTR} e
 \macro{EAGAIN} non sono errori. La prima si verifica quando la \func{read} è
 bloccata in attesa di dati in ingresso e viene interrotta da un segnale; in
-tal caso l'azione da prendere è quella di rieseguire la funzione. Torneremo
-sull'argomento in \secref{sec:sig_gen_beha}. 
-
-La seconda si verifica quando il file è in modalità non bloccante e non ci
-sono dati in ingresso: la funzione allora ritorna immediatamente con un errore
-\macro{EAGAIN}\footnote{sotto BSD questo per questo errore viene usata la
-  costante \macro{EWOULDBLOCK}, in GNU/Linux questa è sinonima di
-  \macro{EAGAIN}.} che nel caso indica soltanto che occorrerà provare a
-ripetere la lettura.
-
-
-Nella seconda versione delle \textit{Single Unix
+tal caso l'azione da prendere è quella di rieseguire la funzione. Torneremo in
+dettaglio sull'argomento in \secref{sec:sig_gen_beha}.
+
+La seconda si verifica quando il file è in modalità non bloccante (vedi
+\secref{sec:file_noblocking}) e non ci sono dati in ingresso: la funzione
+allora ritorna immediatamente con un errore \macro{EAGAIN}\footnote{sotto BSD
+  questo per questo errore viene usata la costante \macro{EWOULDBLOCK}, in
+  Linux, con le glibc, questa è sinonima di \macro{EAGAIN}.} che nel caso
+indica soltanto che occorrerà provare a ripetere la lettura.
+
+La funzione \func{read} è una delle system call esistenti fin dagli abori di
+Unix, ma nella seconda versione delle \textit{Single Unix
   Specification}\footnote{questa funzione, e l'analoga \func{pwrite} sono
   state aggiunte nel kernel 2.1.60, il supporto nelle \acr{glibc}, compresa
   l'emulazione per i vecchi kernel che non hanno la system call, è stato
-  aggiunto con la versione 2.1.} (quello che viene chiamato normalmente Unix98,
-vedi \secref{sec:intro_opengroup}) è stata introdotta la definizione di
-un'altra funzione di lettura, \func{pread}, che diventa accessibile con la
-definizione:
-\begin{verbatim}
-       #define _XOPEN_SOURCE 500
-\end{verbatim}
-il prototipo di questa funzione è:
+  aggiunto con la versione 2.1, in versioni precedenti sia del kernel che
+  delle librerie la funzione non è disponibile.} (quello che viene chiamato
+normalmente Unix98, vedi \secref{sec:intro_opengroup}) è stata introdotta la
+definizione di un'altra funzione di lettura, \func{pread}, il cui prototipo di
+questa funzione è:
 \begin{prototype}{unistd.h}
 {ssize\_t pread(int fd, void * buf, size\_t count, off\_t offset)}
-  
+
 Cerca di leggere \var{count} byte dal file \var{fd}, a partire dalla posizione
 \var{offset}, nel buffer \var{buf}.
   
@@ -583,10 +582,15 @@ Cerca di leggere \var{count} byte dal file \var{fd}, a partire dalla posizione
   in caso di errore, nel qual caso \var{errno} viene settata secondo i valori
   già visti per \func{read} e \func{lseek}.}
 \end{prototype}
+\noindent che però diventa accessibile solo con la definizione della macro:
+\begin{verbatim}
+       #define _XOPEN_SOURCE 500
+\end{verbatim}
 
 Questa funzione serve quando si vogliono leggere dati dal file senza
 modificarne la posizione corrente. È equivalente alla esecuzione di una
-\func{read} e una \func{lseek}, ma permette di eseguire l'operazione
+\func{read} seguita da una \func{lseek} che riporti al valore precedente la
+posizione corrente sul file, ma permette di eseguire l'operazione
 atomicamente. Questo può essere importante quando la posizione sul file viene
 condivisa da processi diversi (vedi \secref{sec:file_sharing}).  Il valore di
 \var{offset} fa sempre riferimento all'inizio del file.
@@ -881,7 +885,8 @@ interscambiati nell'uso. Per capire meglio il funzionamento della funzione si
 può fare riferimento a \figref{fig:file_dup}: l'effetto della funzione è
 semplicemente quello di copiare il valore nella struttura \var{file\_struct},
 cosicché anche il nuovo file descriptor fa riferimento alla stessa voce
-nella \textit{file table}.
+nella \textit{file table}; per questo si dice che il nuovo file descriptor è
+\textsl{duplicato}, da cui il nome della funzione.
 
 \begin{figure}[htb]
   \centering \includegraphics[width=13cm]{img/filedup}
@@ -889,18 +894,30 @@ nella \textit{file table}.
   \label{fig:file_dup}
 \end{figure}
 
-In questo modo entrambi i file condivideranno eventuali lock, \textit{file
-  status flag}, e posizione corrente: se ad esempio \func{lseek} modifica la
-posizione su uno dei due file descriptor essa sarà modificata anche sull'altro
-(al solito viene modificato lo stesso campo nella voce della \textit{file
-  table} a cui entrambi fanno riferimento).
-
-L'unica differenza fra i due file descriptor è che ciascuno avrà il suo
-\textit{file descriptor flag}: nel caso di \func{dup} il flag di \textit{close
-  on exec} viene sempre cancellato nella copia.  
-
-Una diversa versione della funzione, \func{dup2} viene utilizzata per
-specificare esplicitamente il nuovo file descriptor; il suo prototipo è:
+Si noti che per quanto illustrato in\figref{fig:file_dup} i file descriptor
+duplicati condivideranno eventuali lock, \textit{file status flag}, e
+posizione corrente. Se ad esempio si esegue una \func{lseek} per modificare la
+posizione su uno dei due file descriptor, essa risulterà modificata anche
+sull'altro (dato che quello che viene modificato è lo stesso campo nella voce
+della \textit{file table} a cui entrambi fanno riferimento). L'unica
+differenza fra due file descriptor duplicati è che ciascuno avrà il suo
+\textit{file descriptor flag}; a questo proposito va specificato che nel caso
+di \func{dup} il flag di \textit{close on exec} viene sempre cancellato nella
+copia.
+
+L'uso principale di questa funzione è per la redirezione dell'input e
+dell'output fra l'esecuzione di una \func{fork} e la successiva \func{exec};
+diventa così possibile associare un file (o una pipe) allo standard input o
+allo standard output (torneremo sull'argomento in \secref{sec:ipc_pipe_use},
+quando tratteremo le pipe). Per fare questo in genere occorre prima chiudere
+il file che si vuole sostituire, cossicché il suo file descriptor possa esser
+restituito alla chiamata di \func{dup}, come primo file descriptor
+disponibile.
+
+Dato che questa è l'operazione più comune, è prevista una diversa versione
+della funzione, \func{dup2}, che permette di specificare esplicitamente qual'è
+il valore di file descriptor che si vuole avere come duplicato; il suo
+prototipo è:
 \begin{prototype}{unistd.h}{int dup2(int oldfd, int newfd)}
   
   Rende \param{newfd} una copia del file descriptor \param{oldfd}.
@@ -915,11 +932,12 @@ specificare esplicitamente il nuovo file descriptor; il suo prototipo 
     descriptor aperti.
   \end{errlist}}
 \end{prototype}
-\noindent la funzione chiude il file descriptor \param{newfd} se è aperto.
+\noindent e qualora il  file descriptor \param{newfd} sia già aperto esso
+sarà chiuso e poi duplicato.
 
 La duplicazione dei file descriptor può essere effettuata anche usando la
 funzione di controllo dei file \func{fnctl} (che esamineremo in
-\secref{sec:file_fcntl}) con il parametro \macro{F\_DUPFD}. 
+\secref{sec:file_fcntl}) con il parametro \macro{F\_DUPFD}.
 
 L'operazione ha la sintassi \code{fnctl(oldfd, F\_DUPFD, newfd)} e se si usa 0
 come valore per \param{newfd} diventa equivalente a \func{dup}. La sola
@@ -928,12 +946,6 @@ se 
 superiore, per cui per poterla usare come \func{dup2} occorrerebbe prima
 effettuare una \func{close}, perdendo l'atomicità dell'operazione.
 
-L'uso principale di queste funzioni è per la redirezione dell'input e
-dell'output fra l'esecuzione di una \func{fork} e la successiva \func{exec};
-diventa così possibile associare un file (o una pipe) allo standard input o
-allo standard output, torneremo su questo uso in \secref{sec:ipc_pipe_use}
-quando tratteremo le pipe.
-
 
 \subsection{La funzione \func{fcntl}}
 \label{sec:file_fcntl}
diff --git a/ipc.tex b/ipc.tex
index 21fae71..0b7818c 100644 (file)
--- a/ipc.tex
+++ b/ipc.tex
@@ -1,4 +1,4 @@
-f\chapter{La comunicazione fra processi}
+\chapter{La comunicazione fra processi}
 \label{cha:IPC}
 
 
@@ -110,9 +110,9 @@ Per capire meglio il funzionamento di una pipe faremo un esempio di quello che
 è il loro uso più comune, analogo a quello effettuato della shell, e che
 consiste nell'inviare l'output di un processo (lo standard output) sull'input
 di un'altro. Realizzaremo il programma nella forma di un
-\textit{cgi-bin}\footnote{breve descrizione, da fare, di cosa è un cgi-bin.}
-per apache, che genera una immagine JPEG di un codice a barre, specificato
-come parametro di input.
+\textit{cgi-bin}\footnote{NdA, inserire una breve descrizione di cosa è un
+  cgi-bin.}  per apache, che genera una immagine JPEG di un codice a barre,
+specificato come parametro di input.
 
 Un programma che deve essere eseguito come \textit{cgi-bin} per apache deve
 rispondere a delle caratteristiche specifiche, esso infatti non viene lanciato
@@ -136,10 +136,10 @@ intermedio su un file temporaneo. Questo per
 \textit{cgi-bin} deve poter gestire più richieste in concorrenza, e si avrebbe
 una evidente race condition in caso di accesso simultaneo a detto
 file.\footnote{la questione potrebbe essere evitata creando prima dei file
-  temporanei, da comunicare poi ai vari processi, e da cancellare alla fine
-  dell'esecuzione; ma a questo punto avremmo perso tutta la semplicità.} L'uso
-di una pipe invece permette di risolvere il problema in maniera semplice ed
-elegante.
+  temporanei, da comunicare poi ai vari sotto-processi, da cancellare alla
+  fine dell'esecuzione; ma a questo punto avremmo perso tutta la semplicità.}
+L'uso di una pipe invece permette di risolvere il problema in maniera semplice
+ed elegante.
 
 Il programma ci servirà anche come esempio dell'uso di alcune delle funzioni
 di manipolazione dei file descriptor, come \func{dup} e \func{dup2}, viste in
@@ -167,41 +167,39 @@ int main(int argc, char *argv[], char *envp[])
         WriteMess("output pipe creation error");
         exit(0);        
     }    
-    /* fork child to run barcode program */
-    pid = fork();
-    if (pid == -1) {
+    /* First fork: use child to run barcode program */
+    if ( (pid = fork()) == -1) {          /* on error exit */
         WriteMess("child creation error");
         exit(0);        
     }
     /* if child */
     if (pid == 0) {
-        close(pipein[1]);        /* close output side of input pipe */
-        dup2(0, pipein[0]);      /* remap stdin in pipe input */
-        close(pipeout[0]);       /* close input side of output pipe */
-        dup2(1, pipeout[1]);     /* remap stdout in pipe output */
-        execlp("barcode", "barcode", "-E", NULL);
-    } else { 
-        /* first set the pipe */
-        close(pipein[0]);        /* close input side of input pipe */
-        close(pipeout[1]);       /* close output side of output pipe */
-        write(pipein[1], argv[1], strlen(argv[1]));
-        close(pipein[1]);
-        waitpid(pid, NULL, 0);
-        pid = fork();
-        if (pid == -1) {
-            WriteMess("child creation error")
-            exit(0);
-        }
-        if (pid == 0) {
-            /* send mime type */
-            write(0,content, strlen(content));
-            dup2(0, pipeout[0]);
-            execlp("gs", "gs", "-sDEVICE=jpeg", "-sOutputFile=-", "-", NULL);
-        } else {
-            close(pipeout[0]);
-            waitpid(pid, NULL, 0);
-        }
+        close(pipein[1]);                /* close pipe write end  */
+        dup2(pipein[0], STDIN_FILENO);   /* remap stdin to pipe read end */
+        close(pipeout[0]);
+        dup2(pipeout[1], STDOUT_FILENO); /* remap stdout in pipe output */
+        execlp("barcode", "barcode", size, NULL); //"-o", "-",  NULL);
+    } 
+    close(pipein[0]);                    /* close input side of input pipe */
+    write(pipein[1], argv[1], strlen(argv[1]));  /* write parameter to pipe */
+    close(pipein[1]);                    /* closing write end */
+    waitpid(pid, NULL, 0);               /* wait child completion */
+    /* Second fork: use child to run ghostscript */
+    if ( (pid = fork()) == -1) {          /* on error exit */
+        WriteMess("child creation error");
+        exit(0);
+    }
+    /* second child, convert PS to JPEG  */
+    if (pid == 0) {                     
+        close(pipeout[1]);              /* close write end */
+        dup2(pipeout[0], STDIN_FILENO); /* remap read end to stdin */
+        /* send mime type */
+        write(STDOUT_FILENO, content, strlen(content));
+        execlp("gs", "gs", "-q", "-sDEVICE=jpeg", "-sOutputFile=-", "-", NULL);
     }
+    /* still parent */
+    close(pipeout[1]);
+    waitpid(pid, NULL, 0);
     exit(0);
 }
     \end{lstlisting}
@@ -212,28 +210,34 @@ int main(int argc, char *argv[], char *envp[])
 \end{figure}
 
 
-Il primo passo (\texttt{\small 4-12}) è quello di creare le due pipe, una per
-l'input e l'altra per l'output, che servono per la comunicazione con i due
-programmi che verranno utilizzati, inviando in caso di errore (attraverso una
-apposita funzione \func{WriteMess}, non riportata in
-\ref{fig:ipc_barcode_code}, che si incarica di formattare l'output in HTML
-perché sia interpretabile da un browser) un messaggio invece dell'immagine
-richiesta.
+Il primo passo (\texttt{\small 4-12}) è quello di creare le due pipe che
+servono per la comunicazione fra i due programmi che verranno utilizzati per
+produrre il codice a barre; si ha cura di controllare la riuscita della
+chiamata, inviando in caso di errore un messaggio invece dell'immagine
+richiesta.\footnote{la funzione \func{WriteMess}, non è riportata in
+  \ref{fig:ipc_barcode_code}, ma si incarica semplicemente di formattare
+  l'uscita, aggiungendo un \textit{mime type}, in modo che possa essere
+  interpretata direttamente da un browser.}
 
-Una volta create le pipe il programma può creare (\texttt{\small 13-18}) il
+Una volta create le pipe il programma può creare (\texttt{\small 13-17}) il
 primo processo figlio, che si incaricherà (\texttt{\small 19-25}) di eseguire
-\cmd{barcode}: quest'ultimo funziona ricevendo dallo standard input la stringa
-da convertire nell'immagine postscript del codice a barre che sarà scritta
-sullo standard output.  
-
-Per questo il processo figlio prima chiude (\texttt{\small 21}) il capo aperto
-in scrittura della prima pipe (che sarà usato dal padre per trasmettergli la
-stringa da codificare), e poi collega (\texttt{\small 22}) il capo il lettura
-allo standard input usando \func{dup2}.  Analogamente il capo in lettura della
-seconda pipe sarà chiuso mentre il capo in scrittura viene collegato allo
-standard output (\texttt{\small 23-24}.  In questo modo all'esecuzione
-(\texttt{\small 25}) di \cmd{barcode} quest'ultimo leggerà la stringa da
-codificare dalla prima pipe e scriverà l'immagine postscript nella seconda.
+il programma \cmd{barcode}: quest'ultimo funziona ricevendo dallo standard
+input la stringa da convertire nell'immagine postscript del codice a barre,
+che sarà scritta sullo standard output.
+
+Per utilizzare queste caratteristiche il primo figlio chiude (\texttt{\small
+  21}) il capo aperto in scrittura della prima pipe, dato che userà il capo
+aperto in lettura per ricevere dal padre la stringa da codificare; per far
+questo collega (\texttt{\small 22}) il capo in lettura allo standard input
+usando \func{dup2}; 
+
+
+
+Analogamente il capo in lettura della seconda pipe sarà chiuso mentre il capo
+in scrittura viene collegato allo standard output (\texttt{\small 23-24}.  In
+questo modo all'esecuzione (\texttt{\small 25}) di \cmd{barcode} quest'ultimo
+leggerà la stringa da codificare dalla prima pipe e scriverà l'immagine
+postscript nella seconda.
 
 Dall'altra parte il processo padre prima chiude (\texttt{\small 28-29}) i due
 capi inutilizzati delle pipe (input della prima ed output della seconda), poi
index 519cf44..4a81828 100644 (file)
@@ -750,7 +750,7 @@ processo alla loro occorrenza.
 
 
 \subsection{Il comportamento generale del sistema.}
-  \label{sec:sig_gen_beha}
+\label{sec:sig_gen_beha}
 
 Abbiamo già trattato in \secref{sec:sig_intro} le modalità con cui il sistema
 gestisce l'interazione fra segnali e processi, ci resta da esaminare però il
index 138e23a..7852dae 100644 (file)
@@ -29,7 +29,7 @@
  * http://localhost/cgi-bin/barcode?string
  * where string is the code to be converted
  *
- * $Id: BarCode.c,v 1.1 2002/06/18 22:11:06 piccardi Exp $ 
+ * $Id: BarCode.c,v 1.2 2002/06/21 22:24:10 piccardi Exp $ 
  *
  ****************************************************************/
 /* 
@@ -57,15 +57,12 @@ int main(int argc, char *argv[], char *envp[])
 /*
  * Variables definition         
  */
-    char buffer[8192];
     pid_t pid;
-    size_t n;
     int retval;
     int pipein[2];
     int pipeout[2];
-    char size[]="-pA9";
-    char psize[]="-sPAPERSIZE=a9";
     char content[]="Content-type: image/jpeg\n\n";
+    char size[]="-pA9";
     /* 
      * Begin
      */
@@ -88,7 +85,7 @@ int main(int argc, char *argv[], char *envp[])
     if (pid == 0) {
        /*
         * Child exec barcode program, that take input (string to encode)
-        * from pipein, remapped to stdin, and write the output (a ppm 
+        * from pipein, remapped to stdin, and write the output (a PS
         * image) to stdout, remapped to pipeout 
         */
        close(pipein[1]);                /* close output side of input pipe */
@@ -100,14 +97,14 @@ int main(int argc, char *argv[], char *envp[])
     /*
      * Parent write string to pipe input and close it, 
      * then wait child execution and results form pipeout, 
-     * then fork to convert ppm to gif using ppmtogif
+     * then fork to convert PS to JPEG using gs
      */
     close(pipein[0]);        /* close input side of input pipe */
-    n=write(pipein[1], argv[1], strlen(argv[1]));
+    write(pipein[1], argv[1], strlen(argv[1]));
     close(pipein[1]);
     waitpid(pid, NULL, 0);
     /* 
-     * refork to use ppmtogif
+     * refork to use gs
      */
     pid = fork();
     if (pid == -1) {
@@ -115,16 +112,13 @@ int main(int argc, char *argv[], char *envp[])
        exit(0);
     }
     /*
-     * second child, convert ppm to gif
+     * second child, convert PS to JPEG
      */
     if (pid == 0) {
        /* send mime type */
        close(pipeout[1]);
        dup2(pipeout[0], STDIN_FILENO);
        write(STDOUT_FILENO, content, strlen(content));
-       n=read(pipeout[0], buffer, sizeof(buffer));
-       printf("Letti %n di %n, %s\n", n, sizeof(buffer), buffer);
-       exit(0);
        execlp("gs", "gs", "-q", "-sDEVICE=jpeg", "-sOutputFile=-", "-", NULL);
     }
     /*