From 1eb95e2a35acc78407e7d988604719bb92da7253 Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Wed, 1 May 2013 12:47:23 +0000 Subject: [PATCH] Ancora pipe e correzioni per l'uso della macro Console. --- gapil.tex | 4 ++ ipc.tex | 121 +++++++++++++++++++++++++++------------------------ process.tex | 20 ++++----- prochand.tex | 68 +++++++++++++---------------- 4 files changed, 105 insertions(+), 108 deletions(-) diff --git a/gapil.tex b/gapil.tex index 16626ef..6f6bff9 100644 --- a/gapil.tex +++ b/gapil.tex @@ -60,6 +60,10 @@ inner=2.5cm,outer=1.8cm,bottom=3.3cm,top=2.3cm]{geometry} {xleftmargin=\parindent,xrightmargin=\parindent,fontseries=b, fontfamily=courier,fontsize=\footnotesize} +\DefineVerbatimEnvironment{Console}{Verbatim} +{commandchars=\\\{\},xleftmargin=\parindent,xrightmargin=\parindent,fontfamily=courier,fontsize=\footnotesize} + + \usepackage[bookmarks=true,plainpages=false,pdfpagelabels, hyperfootnotes=false]{hyperref} diff --git a/ipc.tex b/ipc.tex index 550b323..45917eb 100644 --- a/ipc.tex +++ b/ipc.tex @@ -401,7 +401,7 @@ precedente: il programma mostrato in fig.~\ref{fig:ipc_barcodepage_code} per quanto funzionante, è volutamente codificato in maniera piuttosto complessa, inoltre doveva scontare un problema di \cmd{gs} che non era in grado di riconoscere correttamente l'Encapsulated PostScript,\footnote{si fa - riferimento alla versione di GNU Ghostscript 6.53 del 2002-02-13, quando + riferimento alla versione di GNU Ghostscript 6.53 (2002-02-13), usata quando l'esempio venne scritto per la prima volta.} per cui si era utilizzato il PostScript semplice, generando una pagina intera invece che una immagine delle dimensioni corrispondenti al codice a barre. @@ -495,32 +495,34 @@ create in precedenza. Come accennato in sez.~\ref{sec:ipc_pipes} il problema delle \textit{pipe} è che esse possono essere utilizzate solo da processi con un progenitore comune o nella relazione padre/figlio. Per superare questo problema lo standard -POSIX.1 ha definito dei nuovi oggetti, le \textit{fifo}, che hanno le stesse -caratteristiche delle \textit{pipe}, ma che invece di essere strutture interne -del kernel, visibili solo attraverso un file descriptor, sono accessibili -attraverso un \itindex{inode} \textit{inode} che risiede sul filesystem, così -che i processi le possono usare senza dovere per forza essere in una relazione -di \textsl{parentela}. +POSIX.1 ha introdotto le \textit{fifo}, che hanno le stesse caratteristiche +delle \textit{pipe}, ma che invece di essere visibili solo attraverso un file +descriptor creato all'interno di un processo da una \textit{system call} +apposita, costituiscono un oggetto che risiede sul filesystem (si rammenti +quanto detto in sez.~\ref{sec:file_file_types}) che può essere aperto come un +qualunque file, così che i processi le possono usare senza dovere per forza +essere in una relazione di \textsl{parentela}. Utilizzando una \textit{fifo} tutti i dati passeranno, come per le -\textit{pipe}, attraverso un apposito buffer nel kernel, senza transitare dal -filesystem; \itindex{inode} l'\textit{inode} allocato sul filesystem serve -infatti solo a fornire un punto di riferimento per i processi, che permetta -loro di accedere alla stessa fifo; il comportamento delle funzioni di lettura -e scrittura è identico a quello illustrato per le \textit{pipe} in -sez.~\ref{sec:ipc_pipes}. - -Abbiamo già visto in sez.~\ref{sec:file_mknod} le funzioni \func{mknod} e -\func{mkfifo} che permettono di creare una \textit{fifo}; per utilizzarne una +\textit{pipe}, attraverso un buffer nel kernel, senza transitare dal +filesystem. Il fatto che siano associate ad un \itindex{inode} +\textit{inode} presente sul filesystem serve infatti solo a fornire un punto +di accesso per i processi, che permetta a questi ultimi di accedere alla +stessa \textit{fifo} senza avere nessuna relazione, con una semplice +\func{open}. Il comportamento delle funzioni di lettura e scrittura è identico +a quello illustrato per le \textit{pipe} in sez.~\ref{sec:ipc_pipes}. + +Abbiamo già trattato in sez.~\ref{sec:file_mknod} le funzioni \func{mknod} e +\func{mkfifo} che permettono di creare una \textit{fifo}. Per utilizzarne una un processo non avrà che da aprire il relativo \index{file!speciali} file -speciale o in lettura o scrittura; nel primo caso sarà collegato al capo di -uscita della \textit{fifo}, e dovrà leggere, nel secondo al capo di ingresso, -e dovrà scrivere. +speciale o in lettura o scrittura; nel primo caso il processo sarà collegato +al capo di uscita della \textit{fifo}, e dovrà leggere, nel secondo al capo di +ingresso, e dovrà scrivere. -Il kernel crea una singola \textit{pipe} per ciascuna \textit{fifo} che sia -stata aperta, che può essere acceduta contemporaneamente da più processi, sia +Il kernel alloca un singolo buffer per ciascuna \textit{fifo} che sia stata +aperta, e questa potrà essere acceduta contemporaneamente da più processi, sia in lettura che in scrittura. Dato che per funzionare deve essere aperta in -entrambe le direzioni, per una \textit{fifo} di norma la funzione \func{open} +entrambe le direzioni, per una \textit{fifo} la funzione \func{open} di norma si blocca se viene eseguita quando l'altro capo non è aperto. Le \textit{fifo} però possono essere anche aperte in modalità @@ -529,56 +531,59 @@ successo solo quando anche l'altro capo è aperto, mentre l'apertura del capo in scrittura restituirà l'errore di \errcode{ENXIO} fintanto che non verrà aperto il capo in lettura. -In Linux è possibile aprire le \textit{fifo} anche in -lettura/scrittura,\footnote{lo standard POSIX lascia indefinito il - comportamento in questo caso.} operazione che avrà sempre successo -immediato qualunque sia la modalità di apertura (bloccante e non bloccante); -questo può essere utilizzato per aprire comunque una fifo in scrittura anche -se non ci sono ancora processi il lettura; è possibile anche usare la fifo -all'interno di un solo processo, nel qual caso però occorre stare molto -attenti alla possibili situazioni di stallo.\footnote{se si cerca di leggere - da una fifo che non contiene dati si avrà un \itindex{deadlock} - \textit{deadlock} immediato, dato che il processo si blocca e non potrà - quindi mai eseguire le funzioni di scrittura.} +In Linux è possibile aprire le \textit{fifo} anche in lettura/scrittura (lo +standard POSIX lascia indefinito il comportamento in questo caso) operazione +che avrà sempre successo immediato qualunque sia la modalità di apertura, +bloccante e non bloccante. Questo può essere utilizzato per aprire comunque +una \textit{fifo} in scrittura anche se non ci sono ancora processi il +lettura. Infine è possibile anche usare la \textit{fifo} all'interno di un +solo processo, nel qual caso però occorre stare molto attenti alla possibili +situazioni di stallo: se si cerca di leggere da una \textit{fifo} che non +contiene dati si avrà infatti un \itindex{deadlock} \textit{deadlock} +immediato, dato che il processo si blocca e quindi non potrà mai eseguire le +funzioni di scrittura. Per la loro caratteristica di essere accessibili attraverso il filesystem, è -piuttosto frequente l'utilizzo di una fifo come canale di comunicazione nelle -situazioni un processo deve ricevere informazioni da altri. In questo caso è -fondamentale che le operazioni di scrittura siano atomiche; per questo si deve -sempre tenere presente che questo è vero soltanto fintanto che non si supera -il limite delle dimensioni di \const{PIPE\_BUF} (si ricordi quanto detto in -sez.~\ref{sec:ipc_pipes}). +piuttosto frequente l'utilizzo di una \textit{fifo} come canale di +comunicazione nelle situazioni un processo deve ricevere informazioni da +altri. In questo caso è fondamentale che le operazioni di scrittura siano +atomiche; per questo si deve sempre tenere presente che questo è vero soltanto +fintanto che non si supera il limite delle dimensioni di \const{PIPE\_BUF} (si +ricordi quanto detto in sez.~\ref{sec:ipc_pipes}). A parte il caso precedente, che resta probabilmente il più comune, Stevens riporta in \cite{APUE} altre due casistiche principali per l'uso delle fifo: \begin{itemize*} \item Da parte dei comandi di shell, per evitare la creazione di file temporanei quando si devono inviare i dati di uscita di un processo - sull'input di parecchi altri (attraverso l'uso del comando \cmd{tee}). - -\item Come canale di comunicazione fra client ed server (il modello - \textit{client-server} è illustrato in sez.~\ref{sec:net_cliserv}). + sull'input di parecchi altri (attraverso l'uso del comando \cmd{tee}). +\item Come canale di comunicazione fra un \textit{client} ed un + \textit{server} (il modello \textit{client-server} è illustrato in + sez.~\ref{sec:net_cliserv}). \end{itemize*} -Nel primo caso quello che si fa è creare tante fifo, da usare come standard -input, quanti sono i processi a cui i vogliono inviare i dati, questi ultimi -saranno stati posti in esecuzione ridirigendo lo standard input dalle fifo, si -potrà poi eseguire il processo che fornisce l'output replicando quest'ultimo, -con il comando \cmd{tee}, sulle varie fifo. +Nel primo caso quello che si fa è creare tante \textit{fifo} da usare come +\textit{standard input} quanti sono i processi a cui i vogliono inviare i +dati; questi ultimi saranno stati posti in esecuzione ridirigendo lo +\textit{standard input} dalle \textit{fifo}, si potrà poi eseguire il processo +che fornisce l'output replicando quest'ultimo, con il comando \cmd{tee}, sulle +varie \textit{fifo}. Il secondo caso è relativamente semplice qualora si debba comunicare con un -processo alla volta (nel qual caso basta usare due fifo, una per leggere ed -una per scrivere), le cose diventano invece molto più complesse quando si -vuole effettuare una comunicazione fra il server ed un numero imprecisato di -client; se il primo infatti può ricevere le richieste attraverso una fifo -``\textsl{nota}'', per le risposte non si può fare altrettanto, dato che, per -la struttura sequenziale delle fifo, i client dovrebbero sapere, prima di -leggerli, quando i dati inviati sono destinati a loro. +processo alla volta, nel qual caso basta usare due \textit{fifo}, una per +leggere ed una per scrivere. Le cose diventano invece molto più complesse +quando si vuole effettuare una comunicazione fra un \textit{server} ed un +numero imprecisato di \textit{client}. Se il primo infatti può ricevere le +richieste attraverso una fifo ``\textsl{nota}'', per le risposte non si può +fare altrettanto, dato che, per la struttura sequenziale delle \textit{fifo}, +i \textit{client} dovrebbero sapere prima di leggerli quando i dati inviati +sono destinati a loro. Per risolvere questo problema, si può usare un'architettura come quella -illustrata in fig.~\ref{fig:ipc_fifo_server_arch} in cui i client inviano le -richieste al server su una fifo nota mentre le risposte vengono reinviate dal -server a ciascuno di essi su una fifo temporanea creata per l'occasione. +illustrata in fig.~\ref{fig:ipc_fifo_server_arch} in cui i \textit{client} +inviano le richieste al \textit{server} su una \textit{fifo} nota mentre le +risposte vengono reinviate dal \textit{server} a ciascuno di essi su una +\textit{fifo} temporanea creata per l'occasione. \begin{figure}[!htb] \centering diff --git a/process.tex b/process.tex index 0ad45f7..2376ec7 100644 --- a/process.tex +++ b/process.tex @@ -2698,30 +2698,26 @@ una variabile per poi ristamparne il contenuto leggendolo un byte alla volta. Il codice di detto programma, \file{endtest.c}, è nei sorgenti allegati, allora se lo eseguiamo su un normale PC compatibile, che è \textit{little endian} otterremo qualcosa del tipo: -\begin{Command} -[piccardi@gont sources]$ ./endtest -\end{Command} -%$ -\begin{Terminal} +\begin{Console} +[piccardi@gont sources]$ \textbf{./endtest} Using value ABCDEF01 val[0]= 1 val[1]=EF val[2]=CD val[3]=AB -\end{Terminal} +\end{Console} +%$ mentre su un vecchio Macintosh con PowerPC, che è \textit{big endian} avremo qualcosa del tipo: -\begin{Command} -piccardi@anarres:~/gapil/sources$ ./endtest -\end{Command} -%$ -\begin{Terminal} +\begin{Console} +piccardi@anarres:~/gapil/sources$ \textbf{./endtest} Using value ABCDEF01 val[0]=AB val[1]=CD val[2]=EF val[3]= 1 -\end{Terminal} +\end{Console} +%$ L'attenzione alla \textit{endianness} nella programmazione è importante, perché se si fanno assunzioni relative alla propria architettura non è detto che diff --git a/prochand.tex b/prochand.tex index 5b063ee..c7186d5 100644 --- a/prochand.tex +++ b/prochand.tex @@ -80,10 +80,8 @@ posto.\footnote{la cosa si fa passando la riga \cmd{init=/bin/sh} come \begin{figure}[!htb] \footnotesize -\begin{Command} -[piccardi@gont piccardi]$ pstree -n -\end{Command} -\begin{Terminal} +\begin{Console} +[piccardi@gont piccardi]$ \textbf{pstree -n} init-+-keventd |-kapm-idled |-kreiserfsd @@ -115,7 +113,7 @@ init-+-keventd |-5*[getty] |-snort `-wwwoffled -\end{Terminal} +\end{Console} %$ \caption{L'albero dei processi, così come riportato dal comando \cmd{pstree}.} @@ -400,11 +398,8 @@ Se eseguiamo il comando, che è preceduto dall'istruzione \code{export specificare attese (come si può notare in (\texttt{\small 17--19}) i valori predefiniti specificano di non attendere), otterremo come risultato sul terminale: -\begin{Command} -[piccardi@selidor sources]$ export LD_LIBRARY_PATH=./; ./forktest 3 -\end{Command} -%$ -\begin{Terminal} +\begin{Console} +[piccardi@selidor sources]$ \textbf{export LD_LIBRARY_PATH=./; ./forktest 3} Process 1963: forking 3 child Spawned 1 child, pid 1964 Child 1 successfully executing @@ -418,7 +413,8 @@ Child 3 successfully executing Child 3, parent 1963, exiting Spawned 3 child, pid 1966 Go to next child -\end{Terminal} +\end{Console} +%$ Esaminiamo questo risultato: una prima conclusione che si può trarre è che non si può dire quale processo fra il padre ed il figlio venga eseguito per primo @@ -488,11 +484,9 @@ se buona parte dei concetti relativi ai file verranno trattati più avanti (principalmente in sez.~\ref{sec:file_unix_interface}). Per illustrare meglio quello che avviene si può redirigere su un file l'output del programma di test, quello che otterremo è: -\begin{Command} -[piccardi@selidor sources]$ ./forktest 3 > output -[piccardi@selidor sources]$ cat output -\end{Command} -\begin{Terminal} +\begin{Console} +[piccardi@selidor sources]$ \textbf{./forktest 3 > output} +[piccardi@selidor sources]$ \textbf{cat output} Process 1967: forking 3 child Child 1 successfully executing Child 1, parent 1967, exiting @@ -515,7 +509,7 @@ Spawned 2 child, pid 1969 Go to next child Spawned 3 child, pid 1970 Go to next child -\end{Terminal} +\end{Console} che come si vede è completamente diverso da quanto ottenevamo sul terminale. Il comportamento delle varie funzioni di interfaccia con i file è analizzato @@ -782,10 +776,8 @@ stato di terminazione. Come verifica di questo comportamento possiamo eseguire il nostro programma \cmd{forktest} imponendo a ciascun processo figlio due secondi di attesa prima di uscire, il risultato è: -\begin{Command} -[piccardi@selidor sources]$ ./forktest -c2 3 -\end{Command} -\begin{Terminal}[commandchars=\\\{\}] +\begin{Console} +[piccardi@selidor sources]$ \textbf{./forktest -c2 3} Process 1972: forking 3 child Spawned 1 child, pid 1973 Child 1 successfully executing @@ -797,10 +789,10 @@ Child 3 successfully executing Spawned 3 child, pid 1975 Go to next child -\textbf{[piccardi@selidor sources]$} Child 3, parent 1, exiting +[piccardi@selidor sources]$ Child 3, parent 1, exiting Child 2, parent 1, exiting Child 1, parent 1, exiting -\end{Terminal} +\end{Console} come si può notare in questo caso il processo padre si conclude prima dei figli, tornando alla shell, che stampa il prompt sul terminale: circa due secondi dopo viene stampato a video anche l'output dei tre figli che @@ -831,11 +823,8 @@ condizione: lanciamo il comando \cmd{forktest} in \textit{background} (vedi sez.~\ref{sec:sess_job_control}), indicando al processo padre di aspettare 10 secondi prima di uscire. In questo caso, usando \cmd{ps} sullo stesso terminale (prima dello scadere dei 10 secondi) otterremo: -\begin{Command} -[piccardi@selidor sources]$ ps T -\end{Command} -%$ -\begin{Terminal} +\begin{Console} +[piccardi@selidor sources]$ \textbf{ps T} PID TTY STAT TIME COMMAND 419 pts/0 S 0:00 bash 568 pts/0 S 0:00 ./forktest -e10 3 @@ -843,7 +832,8 @@ terminale (prima dello scadere dei 10 secondi) otterremo: 570 pts/0 Z 0:00 [forktest ] 571 pts/0 Z 0:00 [forktest ] 572 pts/0 R 0:00 ps T -\end{Terminal} +\end{Console} +%$ e come si vede, dato che non si è fatto nulla per riceverne lo stato di terminazione, i tre processi figli sono ancora presenti pur essendosi conclusi, con lo stato di \itindex{zombie} \textit{zombie} e l'indicazione che @@ -1376,7 +1366,7 @@ Ci sono sei diverse versioni di \func{exec} (per questo la si è chiamata famiglia di funzioni) che possono essere usate per questo compito, in realtà (come mostrato in fig.~\ref{fig:proc_exec_relat}), tutte queste funzioni sono tutte varianti che consentono di invocare in modi diversi, semplificando il -passaggio degli argomenti, la \textit{system call} \funcd{execve}, il cui +passaggio degli argomenti, la funzione di sistema \funcd{execve}, il cui prototipo è: \begin{funcproto}{ @@ -1665,14 +1655,16 @@ nella forma: \end{Example} dove l'interprete indicato deve essere un eseguibile binario e non un altro script, che verrà chiamato come se si fosse eseguito il comando -\cmd{interpreter [argomenti] filename}.\footnote{si tenga presente che con - Linux quanto viene scritto come \texttt{argomenti} viene passato - all'interprete come un unico argomento con una unica stringa di lunghezza - massima di 127 caratteri e se questa dimensione viene ecceduta la stringa - viene troncata; altri Unix hanno dimensioni massime diverse, e diversi - comportamenti, ad esempio FreeBSD esegue la scansione della riga e la divide - nei vari argomenti e se è troppo lunga restituisce un errore di - \const{ENAMETOOLONG}, una comparazione dei vari comportamenti si trova su +\cmd{interpreter [argomenti] filename}. + +Si tenga presente che con Linux quanto viene scritto come \texttt{argomenti} +viene passato all'interprete come un unico argomento con una unica stringa di +lunghezza massima di 127 caratteri e se questa dimensione viene ecceduta la +stringa viene troncata; altri Unix hanno dimensioni massime diverse, e diversi +comportamenti, ad esempio FreeBSD esegue la scansione della riga e la divide +nei vari argomenti e se è troppo lunga restituisce un errore di +\const{ENAMETOOLONG}.\footnote{una comparazione dei vari comportamenti sui + diversi sistemi unix-like si trova su \url{http://www.in-ulm.de/~mascheck/various/shebang/}.} Con la famiglia delle \func{exec} si chiude il novero delle funzioni su cui è -- 2.30.2