X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=ipc.tex;h=e6b45de65be21c0d310fca5609d8e467311a5626;hp=fa3f73c61f49e3fb744c3d2cee463182801387b1;hb=9a6d19e384fe9b1afbe4d9124ac34eaf7aa57562;hpb=66e83c068629844f84fe4a0d44b382f756c9ef32 diff --git a/ipc.tex b/ipc.tex index fa3f73c..e6b45de 100644 --- a/ipc.tex +++ b/ipc.tex @@ -98,7 +98,7 @@ capo della pipe, l'altro pu Tutto ciò ci mostra come sia immediato realizzare un meccanismo di comunicazione fra processi attraverso una pipe, utilizzando le proprietà -ordinarie dei file, ma ci mostra anche qual'è il principale\footnote{Stevens +ordinarie dei file, ma ci mostra anche qual è il principale\footnote{Stevens in \cite{APUE} riporta come limite anche il fatto che la comunicazione è unidirezionale, ma in realtà questo è un limite facilmente superabile usando una coppia di pipe.} limite nell'uso delle pipe. È necessario infatti che i @@ -135,14 +135,14 @@ di un'altro. Realizzeremo il programma di esempio nella forma di un \textit{CGI}\footnote{Un CGI (\textit{Common Gateway Interface}) è un programma che permette la creazione dinamica di un oggetto da inserire all'interno di una pagina HTML.} per Apache, che genera una immagine JPEG -di un codice a barre, specificato come parametro di input. +di un codice a barre, specificato come argomento in ingresso. Un programma che deve essere eseguito come \textit{CGI} deve rispondere a delle caratteristiche specifiche, esso infatti non viene lanciato da una shell, ma dallo stesso web server, alla richiesta di una specifica URL, che di solito ha la forma: \begin{verbatim} - http://www.sito.it/cgi-bin/programma?parametro + http://www.sito.it/cgi-bin/programma?argomento \end{verbatim} ed il risultato dell'elaborazione deve essere presentato (con una intestazione che ne descrive il mime-type) sullo standard output, in modo che il web-server @@ -371,7 +371,7 @@ dei programmi effettivamente eseguiti. Questo non comporta nessun problema dato che la lettura su una pipe è bloccante, per cui ciascun processo, per quanto lanciato per primo, si bloccherà in attesa di ricevere sullo standard input il -risultato dell'elaborazione del precedente, benchè quest'ultimo venga invocato +risultato dell'elaborazione del precedente, benché quest'ultimo venga invocato dopo. \begin{figure}[!htb] @@ -761,11 +761,12 @@ effettuato in entrambe le direzioni. Il prototipo della funzione La funzione restituisce in \param{sv} la coppia di descrittori connessi fra di loro: quello che si scrive su uno di essi sarà ripresentato in input -sull'altro e viceversa. I parametri \param{domain}, \param{type} e -\param{protocol} derivano dall'interfaccia dei socket\index{socket} (che è -quella che fornisce il substrato per connettere i due descrittori), ma in -questo caso i soli valori validi che possono essere specificati sono -rispettivamente \const{AF\_UNIX}, \const{SOCK\_STREAM} e \val{0}. +sull'altro e viceversa. Gli argomenti \param{domain}, \param{type} e +\param{protocol} derivano dall'interfaccia dei socket\index{socket} (vedi +sez.~\ref{sec:sock_creation}) che è quella che fornisce il substrato per +connettere i due descrittori, ma in questo caso i soli valori validi che +possono essere specificati sono rispettivamente \const{AF\_UNIX}, +\const{SOCK\_STREAM} e \val{0}. L'utilità di chiamare questa funzione per evitare due chiamate a \func{pipe} può sembrare limitata; in realtà l'utilizzo di questa funzione (e dei @@ -848,14 +849,14 @@ mantiene varie propriet Usando la stessa chiave due processi diversi possono ricavare l'identificatore associato ad un oggetto ed accedervi. Il problema che sorge a questo punto è come devono fare per accordarsi sull'uso di una stessa chiave. Se i processi -sono \textsl{parenti} la soluzione è relativamente semplice, in tal caso +sono \textsl{imparentati} la soluzione è relativamente semplice, in tal caso infatti si può usare il valore speciale \texttt{IPC\_PRIVATE} per creare un nuovo oggetto nel processo padre, l'identificatore così ottenuto sarà -disponibile in tutti i figli, e potrà essere passato come parametro attraverso +disponibile in tutti i figli, e potrà essere passato come argomento attraverso una \func{exec}. -Però quando i processi non sono \textsl{parenti} (come capita tutte le volte -che si ha a che fare con un sistema client-server) tutto questo non è +Però quando i processi non sono \textsl{imparentati} (come capita tutte le +volte che si ha a che fare con un sistema client-server) tutto questo non è possibile; si potrebbe comunque salvare l'identificatore su un file noto, ma questo ovviamente comporta lo svantaggio di doverselo andare a rileggere. Una alternativa più efficace è quella che i programmi usino un valore comune per @@ -1185,22 +1186,23 @@ file \file{msgmax}, \file{msgmnb} e \file{msgmni} di \file{/proc/sys/kernel/}. \end{figure} -Una coda di messaggi è costituita da una \textit{linked list};\footnote{una - \textit{linked list} è una tipica struttura di dati, organizzati in una - lista in cui ciascun elemento contiene un puntatore al successivo. In questo - modo la struttura è veloce nell'estrazione ed immissione dei dati dalle - estremità dalla lista (basta aggiungere un elemento in testa o in coda ed - aggiornare un puntatore), e relativamente veloce da attraversare in ordine - sequenziale (seguendo i puntatori), è invece relativamente lenta - nell'accesso casuale e nella ricerca.} i nuovi messaggi vengono inseriti in -coda alla lista e vengono letti dalla cima, in fig.~\ref{fig:ipc_mq_schema} si -è riportato lo schema con cui queste strutture vengono mantenute dal -kernel.\footnote{lo schema illustrato in fig.~\ref{fig:ipc_mq_schema} è in - realtà una semplificazione di quello usato effettivamente fino ai kernel - della serie 2.2.x, nei kernel della serie 2.4.x la gestione delle code di - messaggi è stata modificata ed è effettuata in maniera diversa; abbiamo - mantenuto lo schema precedente in quanto illustra comunque in maniera più - che adeguata i principi di funzionamento delle code di messaggi.} +Una coda di messaggi è costituita da una +\index{\textit{linked~list}}\textit{linked list};\footnote{una \textit{linked + list} è una tipica struttura di dati, organizzati in una lista in cui + ciascun elemento contiene un puntatore al successivo. In questo modo la + struttura è veloce nell'estrazione ed immissione dei dati dalle estremità + dalla lista (basta aggiungere un elemento in testa o in coda ed aggiornare + un puntatore), e relativamente veloce da attraversare in ordine sequenziale + (seguendo i puntatori), è invece relativamente lenta nell'accesso casuale e + nella ricerca.} i nuovi messaggi vengono inseriti in coda alla lista e +vengono letti dalla cima, in fig.~\ref{fig:ipc_mq_schema} si è riportato lo +schema con cui queste strutture vengono mantenute dal kernel.\footnote{lo + schema illustrato in fig.~\ref{fig:ipc_mq_schema} è in realtà una + semplificazione di quello usato effettivamente fino ai kernel della serie + 2.2.x, nei kernel della serie 2.4.x la gestione delle code di messaggi è + stata modificata ed è effettuata in maniera diversa; abbiamo mantenuto lo + schema precedente in quanto illustra comunque in maniera più che adeguata i + principi di funzionamento delle code di messaggi.} \begin{figure}[!htb] \footnotesize \centering @@ -1916,7 +1918,7 @@ loro inizializzazione) } \end{functions} -La funzione può avere tre o quattro parametri, a seconda dell'operazione +La funzione può avere tre o quattro argomenti, a seconda dell'operazione specificata con \param{cmd}, ed opera o sull'intero insieme specificato da \param{semid} o sul singolo semaforo di un insieme, specificato da \param{semnum}. @@ -1940,7 +1942,7 @@ definizione, con i possibili valori che pu fig.~\ref{fig:ipc_semun}. Come già accennato sia il comportamento della funzione che il numero di -parametri con cui deve essere invocata, dipendono dal valore dell'argomento +argomenti con cui deve essere invocata dipendono dal valore dell'argomento \param{cmd}, che specifica l'azione da intraprendere; i valori validi (che cioè non causano un errore di \errcode{EINVAL}) per questo argomento sono i seguenti: @@ -2179,7 +2181,7 @@ a queste strutture restano per compatibilit vecchie versioni delle librerie del C, come le libc5.} \begin{figure}[htb] - \centering \includegraphics[width=15cm]{img/semtruct} + \centering \includegraphics[width=13cm]{img/semtruct} \caption{Schema della struttura di un insieme di semafori.} \label{fig:ipc_sem_schema} \end{figure} @@ -2191,12 +2193,13 @@ possono avere successo; se una di esse comporta il blocco del processo il kernel crea una struttura \struct{sem\_queue} che viene aggiunta in fondo alla coda di attesa associata a ciascun insieme di semafori\footnote{che viene referenziata tramite i campi \var{sem\_pending} e \var{sem\_pending\_last} - di \struct{semid\_ds}.}. Nella struttura viene memorizzato il riferimento -alle operazioni richieste (nel campo \var{sops}, che è un puntatore ad una -struttura \struct{sembuf}) e al processo corrente (nel campo \var{sleeper}) -poi quest'ultimo viene messo stato di attesa e viene invocato lo -scheduler\index{\textit{scheduler}} per passare all'esecuzione di un altro -processo. + di \struct{semid\_ds}.}. + +Nella struttura viene memorizzato il riferimento alle operazioni richieste +(nel campo \var{sops}, che è un puntatore ad una struttura \struct{sembuf}) e +al processo corrente (nel campo \var{sleeper}) poi quest'ultimo viene messo +stato di attesa e viene invocato lo scheduler\index{\textit{scheduler}} per +passare all'esecuzione di un altro processo. Se invece tutte le operazioni possono avere successo queste vengono eseguite immediatamente, dopo di che il kernel esegue una scansione della coda di @@ -2205,13 +2208,12 @@ operazioni sospese in precedenza pu struttura \struct{sem\_queue} viene rimossa e lo stato del processo associato all'operazione (\var{sleeper}) viene riportato a \textit{running}; il tutto viene ripetuto fin quando non ci sono più operazioni eseguibili o si è -svuotata la coda. - -Per gestire il meccanismo del ripristino tutte le volte che per un'operazione -si è specificato il flag \const{SEM\_UNDO} viene mantenuta per ciascun insieme -di semafori una apposita struttura \struct{sem\_undo} che contiene (nel vettore -puntato dal campo \var{semadj}) un valore di aggiustamento per ogni semaforo -cui viene sommato l'opposto del valore usato per l'operazione. +svuotata la coda. Per gestire il meccanismo del ripristino tutte le volte che +per un'operazione si è specificato il flag \const{SEM\_UNDO} viene mantenuta +per ciascun insieme di semafori una apposita struttura \struct{sem\_undo} che +contiene (nel vettore puntato dal campo \var{semadj}) un valore di +aggiustamento per ogni semaforo cui viene sommato l'opposto del valore usato +per l'operazione. Queste strutture sono mantenute in due liste,\footnote{rispettivamente attraverso i due campi \var{id\_next} e \var{proc\_next}.} una associata @@ -2221,20 +2223,21 @@ operazione con \func{semctl}; l'altra associata al processo che ha eseguito l'operazione;\footnote{attraverso il campo \var{semundo} di \struct{task\_struct}, come mostrato in \ref{fig:ipc_sem_schema}.} quando un processo termina, la lista ad esso associata viene scandita e le operazioni -applicate al semaforo. - -Siccome un processo può accumulare delle richieste di ripristino per semafori -differenti chiamate attraverso diverse chiamate a \func{semop}, si pone il -problema di come eseguire il ripristino dei semafori all'uscita del processo, -ed in particolare se questo può essere fatto atomicamente. Il punto è cosa -succede quando una delle operazioni previste per il ripristino non può essere -eseguita immediatamente perché ad esempio il semaforo è occupato; in tal caso -infatti, se si pone il processo in stato di \textit{sleep} aspettando la -disponibilità del semaforo (come faceva l'implementazione originaria) si perde -l'atomicità dell'operazione. La scelta fatta dal kernel è pertanto quella di -effettuare subito le operazioni che non prevedono un blocco del processo e di -ignorare silenziosamente le altre; questo però comporta il fatto che il -ripristino non è comunque garantito in tutte le occasioni. +applicate al semaforo. Siccome un processo può accumulare delle richieste di +ripristino per semafori differenti chiamate attraverso diverse chiamate a +\func{semop}, si pone il problema di come eseguire il ripristino dei semafori +all'uscita del processo, ed in particolare se questo può essere fatto +atomicamente. + +Il punto è cosa succede quando una delle operazioni previste per il ripristino +non può essere eseguita immediatamente perché ad esempio il semaforo è +occupato; in tal caso infatti, se si pone il processo in stato di +\textit{sleep} aspettando la disponibilità del semaforo (come faceva +l'implementazione originaria) si perde l'atomicità dell'operazione. La scelta +fatta dal kernel è pertanto quella di effettuare subito le operazioni che non +prevedono un blocco del processo e di ignorare silenziosamente le altre; +questo però comporta il fatto che il ripristino non è comunque garantito in +tutte le occasioni. Come esempio di uso dell'interfaccia dei semafori vediamo come implementare con essa dei semplici \textit{mutex} (cioè semafori binari), tutto il codice @@ -2555,9 +2558,9 @@ direttamente, la situazione dopo l'esecuzione di \func{shmat} fig.~\ref{fig:ipc_shmem_layout} (per la comprensione del resto dello schema si ricordi quanto illustrato al proposito in sez.~\ref{sec:proc_mem_layout}). In particolare l'indirizzo finale del segmento dati (quello impostato da -\func{brk}, vedi sez.~\ref{sec:proc_mem_sbrk}) non viene influenzato. Si tenga -presente infine che la funzione ha successo anche se il segmento è stato -marcato per la cancellazione. +\func{brk}, vedi sez.~\ref{sec:proc_mem_sbrk_alloca}) non viene influenzato. +Si tenga presente infine che la funzione ha successo anche se il segmento è +stato marcato per la cancellazione. \begin{figure}[htb] \centering @@ -2638,7 +2641,7 @@ dell'interfaccia, \funcd{shmdt}, il cui prototipo \bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di errore, la funzione fallisce solo quando non c'è un segmento agganciato - all'indirizzo \func{shmaddr}, con \var{errno} che assume il valore + all'indirizzo \param{shmaddr}, con \var{errno} che assume il valore \errval{EINVAL}.} \end{functions} @@ -2767,11 +2770,11 @@ Il programma, dopo la sezione, omessa, relativa alla gestione delle opzioni da riga di comando (che si limitano alla eventuale stampa di un messaggio di aiuto a video ed all'impostazione della durata dell'intervallo con cui viene ripetuto il calcolo delle proprietà della directory) controlla (\texttt{\small - 20--23}) che sia stato specificato il parametro necessario contenente il -nome della directory da tenere sotto controllo, senza il quale esce -immediatamente con un messaggio di errore. + 20--23}) che sia stato specificato l'argoemnto necessario contenente il nome +della directory da tenere sotto controllo, senza il quale esce immediatamente +con un messaggio di errore. -Poi, per verificare che il parametro specifichi effettivamente una directory, +Poi, per verificare che l'argomento specifichi effettivamente una directory, si esegue (\texttt{\small 24--26}) su di esso una \func{chdir}, uscendo immediatamente in caso di errore. Questa funzione serve anche per impostare la directory di lavoro del programma nella directory da tenere sotto @@ -3311,9 +3314,9 @@ processo che esegue la creazione). Le code di messaggi non sono ancora supportate nel kernel ufficiale, esiste però una implementazione sperimentale di Michal Wronski e Krzysztof Benedyczak,\footnote{i patch al kernel e la relativa libreria possono essere - trovati su \href{http://www.mat.uni.torun.pl/~wrona/posix_ipc} - {http://www.mat.uni.torun.pl/\tild{}wrona/posix\_ipc}, questi sono stati - inseriti nel kernel ufficiale a partire dalla versione 2.6.6-rc1.}. In +trovati su \href{http://www.mat.uni.torun.pl/~wrona/posix_ipc} +{\textsf{http://www.mat.uni.torun.pl/\tild{}wrona/posix\_ipc}}, questi sono +stati inseriti nel kernel ufficiale a partire dalla versione 2.6.6-rc1.}. In generale, come le corrispettive del SysV IPC, le code di messaggi sono poco usate, dato che i socket\index{socket}, nei casi in cui sono sufficienti, sono più comodi, e che in casi più complessi la comunicazione può essere gestita