X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=ipc.tex;h=c2d3c213cfbacf57bc8213e734f5039fb100ff16;hp=9d8ebe6d88822dd1788a9782dd6fcaaec37e8792;hb=08e339a5f489c9401e931a214b37de26be6669a6;hpb=06604d9d9800ff3f095bda01f9c93bc2e82d50eb diff --git a/ipc.tex b/ipc.tex index 9d8ebe6..c2d3c21 100644 --- a/ipc.tex +++ b/ipc.tex @@ -1967,7 +1967,7 @@ Let's call it an accidental feature. \end{verbatim} con un risultato del tutto equivalente al precedente. Infine potremo chiudere il server inviando il segnale di terminazione con il comando \code{killall - mqfortuned} verficando che effettivamente la coda di messaggi viene rimossa. + mqfortuned} verificando che effettivamente la coda di messaggi viene rimossa. Benché funzionante questa architettura risente dello stesso inconveniente visto anche nel caso del precedente server basato sulle fifo; se il client @@ -2670,7 +2670,7 @@ caso di terminazione imprevista del processo. L'ultima funzione (\texttt{\small 46--49}) della serie, è \func{MutexRemove}, che rimuove il mutex. Anche in questo caso si ha un wrapper per una chiamata a \func{semctl} con il comando \const{IPC\_RMID}, che permette di cancellare il -smemaforo; il valore di ritorno di quest'ultima viene passato all'indietro. +semaforo; il valore di ritorno di quest'ultima viene passato all'indietro. Chiamare \func{MutexLock} decrementa il valore del semaforo: se questo è libero (ha già valore 1) sarà bloccato (valore nullo), se è bloccato la @@ -2872,7 +2872,7 @@ un segmento di memoria condivisa Il comando specificato attraverso l'argomento \param{cmd} determina i diversi effetti della funzione; i possibili valori che esso può assumere, ed il -corripondente comportamento della funzione, sono i seguenti: +corrispondente comportamento della funzione, sono i seguenti: \begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}} \item[\const{IPC\_STAT}] Legge le informazioni riguardo il segmento di memoria @@ -3197,8 +3197,8 @@ l'accesso alla memoria condivisa. Una volta completata l'inizializzazione e la creazione degli oggetti di intercomunicazione il programma entra nel ciclo principale (\texttt{\small - 45--54}) dove vengono eseguitw indefinitamente le attività di monitoraggio. -Il primo passo (\texttt{\small 46}) è esguire \func{daemon} per proseguire con + 45--54}) dove vengono eseguite indefinitamente le attività di monitoraggio. +Il primo passo (\texttt{\small 46}) è eseguire \func{daemon} per proseguire con l'esecuzione in background come si conviene ad un programma demone; si noti che si è mantenuta, usando un valore non nullo del primo argomento, la directory di lavoro corrente. @@ -3328,8 +3328,8 @@ int main(int argc, char *argv[]) \end{lstlisting} \end{minipage} \normalsize - \caption{Codice del programma client del monitori di directory, - \file{ReadMonitor.c}.} + \caption{Codice del programma client del monitor delle proprietà di una + directory, \file{ReadMonitor.c}.} \label{fig:ipc_dirmonitor_client} \end{figure} @@ -3361,7 +3361,7 @@ stampano i vari valori mantenuti nella memoria condivisa attraverso l'uso di il mutex, prima di uscire. Verifichiamo allora il funzionamento dei nostri programmi; al solito, usando -le funzioni di libreira occorre definire opportunamente +le funzioni di libreria occorre definire opportunamente \code{LD\_LIBRARY\_PATH}; poi si potrà lanciare il server con: \begin{verbatim} [piccardi@gont sources]$ ./dirmonitor ./ @@ -3419,7 +3419,7 @@ nel qual caso, ripetendo la lettura otterremo che: [piccardi@gont sources]$ ./readmon Cannot find shared memory: No such file or directory \end{verbatim}%$ -e potremo verificare che anche gli oggetti di intercomunicazion e sono stati +e potremo verificare che anche gli oggetti di intercomunicazione sono stati cancellati: \begin{verbatim} [piccardi@gont sources]$ ipcs @@ -3615,7 +3615,6 @@ int FindMutex(const char *path_name) int LockMutex(int fd) { struct flock lock; /* file lock structure */ - /* first open the file (creating it if not existent) */ /* set flock structure */ lock.l_type = F_WRLCK; /* set type: read or write */ lock.l_whence = SEEK_SET; /* start from the beginning of the file */ @@ -3686,53 +3685,54 @@ aprire il file da usare per il file locking, solo che in questo caso le opzioni di \func{open} sono tali che il file in questione deve esistere di già. -La terza funzione (\texttt{\small 11--23}) è \func{LockMutex} e serve per +La terza funzione (\texttt{\small 11--22}) è \func{LockMutex} e serve per acquisire il mutex. La funzione definisce (\texttt{\small 14}) e inizializza -(\texttt{\small 17--20}) la struttura \var{lock} da usare per acquisire un +(\texttt{\small 16--19}) la struttura \var{lock} da usare per acquisire un write lock sul file, che poi (\texttt{\small 21}) viene richiesto con \func{fcntl}, restituendo il valore di ritorno di quest'ultima. Se il file è libero il lock viene acquisito e la funzione ritorna immediatamente; altrimenti \func{fcntl} si bloccherà (si noti che la si è chiamata con \func{F\_SETLKW}) fino al rilascio del lock. -La quarta funzione (\texttt{\small 24--35}) è \func{UnlockMutex} e serve a +La quarta funzione (\texttt{\small 24--34}) è \func{UnlockMutex} e serve a rilasciare il mutex. La funzione è analoga alla precedente, solo che in questo -caso si inizializza (\texttt{\small 29--32}) la struttura \var{lock} per il -rilascio del lock, che viene effettuato (\texttt{\small 34}) con la opportuna +caso si inizializza (\texttt{\small 28--31}) la struttura \var{lock} per il +rilascio del lock, che viene effettuato (\texttt{\small 33}) con la opportuna chiamata a \func{fcntl}. Avendo usato il file locking in semantica POSIX (si riveda quanto detto \secref{sec:file_posix_lock}) solo il processo che ha precedentemente eseguito il lock può sbloccare il mutex. -La quinta funzione (\texttt{\small 36--40}) è \func{RemoveMutex} e serve a +La quinta funzione (\texttt{\small 36--39}) è \func{RemoveMutex} e serve a cancellare il mutex. Anche questa funzione è stata definita per mantenere una analogia con le funzioni basate sui semafori, e si limita a cancellare -(\texttt{\small 39}) il file con una chiamata ad \func{unlink}. Si noti che in +(\texttt{\small 38}) il file con una chiamata ad \func{unlink}. Si noti che in questo caso la funzione non ha effetto sui mutex già ottenuti con precedenti chiamate a \func{FindMutex} o \func{CreateMutex}, che continueranno ad essere disponibili fintanto che i relativi file descriptor restano aperti. Pertanto per rilasciare un mutex occorrerà prima chiamare \func{UnlockMutex} oppure chiudere il file usato per il lock. -La sesta funzione (\texttt{\small 41--56}) è \func{ReadMutex} e serve a -leggere lo stato del mutex. In questo caso si prepara (\texttt{\small 47--50}) +La sesta funzione (\texttt{\small 41--55}) è \func{ReadMutex} e serve a +leggere lo stato del mutex. In questo caso si prepara (\texttt{\small 46--49}) la solita struttura \var{lock} come l'acquisizione del lock, ma si effettua -(\texttt{\small 52}) la chiamata a \func{fcntl} usando il comando +(\texttt{\small 51}) la chiamata a \func{fcntl} usando il comando \const{F\_GETLK} per ottenere lo stato del lock, e si restituisce -(\texttt{\small 53}) il valore di ritorno in caso di errore, ed il valore del -campo \var{l\_type} (che descrive lo stato del lock) altrimenti. Per questo -motivo la funzione restituirà -1 in caso di errore e uno dei due valori -\const{F\_UNLCK} o \const{F\_WRLCK}\footnote{non si dovrebbe mai avere il - terzo valore possibile, \const{F\_RDLCK}, dato che la nostra interfaccia usa - solo i write lock. Però è sempre possibile che siano richiesti altri lock - sul file al di fuori dell'interfaccia, nel qual caso si potranno avere, - ovviamente, interferenze indesiderate.} in caso di successo, ad indicare che -il mutex è, rispettivamente, libero o occupato. +(\texttt{\small 52}) il valore di ritorno in caso di errore, ed il valore del +campo \var{l\_type} (che descrive lo stato del lock) altrimenti +(\texttt{\small 54}). Per questo motivo la funzione restituirà -1 in caso di +errore e uno dei due valori \const{F\_UNLCK} o \const{F\_WRLCK}\footnote{non + si dovrebbe mai avere il terzo valore possibile, \const{F\_RDLCK}, dato che + la nostra interfaccia usa solo i write lock. Però è sempre possibile che + siano richiesti altri lock sul file al di fuori dell'interfaccia, nel qual + caso si potranno avere, ovviamente, interferenze indesiderate.} in caso di +successo, ad indicare che il mutex è, rispettivamente, libero o occupato. Basandosi sulla semantica dei file lock POSIX valgono tutte le considerazioni relative al comportamento di questi ultimi fatte in \secref{sec:file_posix_lock}; questo significa ad esempio che, al contrario di quanto avveniva con l'interfaccia basata sui semafori, chiamate multiple a -\func{UnlockMutex} o \func{LockMutex} non hanno nessun inconveniente. +\func{UnlockMutex} o \func{LockMutex} non si cumulano e non danno perciò +nessun inconveniente. \subsection{Il \textit{memory mapping} anonimo} @@ -3744,7 +3744,7 @@ una valida alternativa alle code di messaggi; nella stessa situazione si pu evitare l'uso di una memoria condivisa facendo ricorso al cosiddetto \textit{memory mapping} anonimo. -Abbiamo visto in \secref{sec:file_memory_map} che è possibile mappare il +In \secref{sec:file_memory_map} abbiamo visto come sia possibile mappare il contenuto di un file nella memoria di un processo, e che, quando viene usato il flag \const{MAP\_SHARED}, le modifiche effettuate al contenuto del file vengono viste da tutti i processi che lo hanno mappato. Utilizzare questa @@ -3763,8 +3763,9 @@ il \textit{memory mapping} anonimo.\footnote{nei sistemi derivati da SysV una \file{/dev/zero}. In tal caso i valori scritti nella regione mappata non vengono ignorati (come accade qualora si scriva direttamente sul file), ma restano in memoria e possono essere riletti secondo le stesse modalità usate - nel \textit{memory mapping} anonimo.} Un esempio di utilizzo di questa -tecnica è mostrato in + nel \textit{memory mapping} anonimo.} Vedremo come utilizzare questa tecnica +più avanti, quando realizzeremo una nuova versione del monitor visto in +\secref{sec:ipc_sysv_shm} che possa restituisca i risultati via rete. @@ -3778,29 +3779,59 @@ meccanismi di comunicazione, che vanno sotto il nome di POSIX IPC, definendo una interfaccia completamente nuova, che tratteremo in questa sezione. - \subsection{Considerazioni generali} \label{sec:ipc_posix_generic} -Il Linux non tutti gli oggetti del POSIX IPC sono supportati nel kernel -ufficiale; solo la memoria condivisa è presente, ma solo a partire dal kernel -2.4.x, per gli altri oggetti esistono patch e librerie non ufficiali. -Nonostante questo è importante esaminare questa interfaccia per la sua netta -superiorità nei confronti di quella del \textit{SysV IPC}. +In Linux non tutti gli oggetti del POSIX IPC sono pienamente supportati nel +kernel ufficiale; solo la memoria condivisa è presente con l'interfaccia +completa, ma solo a partire dal kernel 2.4.x, i semafori sono forniti dalle +\acr{glibc} nella sezione che implementa i thread POSIX, le code di messaggi +non hanno alcun tipo di supporto ufficiale. Per queste ultime esistono +tuttavia dei patch e una libreria aggiuntiva. + +La caratteristica fondamentale dell'interfaccia POSIX è l'abbandono dell'uso +degli identificatori e delle chiavi visti nel SysV IPC, per passare ai +\textit{Posix IPC names}\index{Posix IPC names}, che sono sostanzialmente +equivalenti ai nomi dei file. Tutte le funzioni che creano un oggetto di IPC +Posix prendono come primo argomento una stringa che indica uno di questi nomi; +lo standard è molto generico riguardo l'implementazione, ed i nomi stessi +possono avere o meno una corrispondenza sul filesystem; tutto quello che è +richiesto è che: +\begin{itemize} +\item i nomi devono essere conformi alle regole che caratterizzano i + \textit{pathname}, in particolare non essere più lunghi di \const{PATH\_MAX} + byte e terminati da un carattere nullo. +\item se il nome inizia per una \texttt{/} chiamate differenti allo stesso + nome fanno riferimento allo stesso oggetto, altrimenti l'interpretazione del + nome dipende dall'implementazione. +\item l'interpretazione di ulteriori \texttt{/} presenti nel nome dipende + dall'implementazione. +\end{itemize} + +Il comportamento delle funzioni è pertanto subordinato in maniera quasi +completa alla relativa implementazione.\footnote{tanto che Stevens in + \cite{UNP2} cita questo caso come un esempio della maniera standard per + consentire soluzioni non standard.} Nel caso di Linux per quanto riguarda la +memoria condivisa, tutto viene creato nella directory \file{/dev/shm}, ed i +nomi sono presi come pathname assoluto (comprendente eventuali sottodirectory) +rispetto a questa radice (per maggiori dettagli si veda quanto illustrato in +\secref{sec:ipc_posix_shm}). Lo stesso accade per l'implementazione +sperimentale delle code di messaggi, che però fa riferimento alla directory +\file{/dev/mqueue}. \subsection{Code di messaggi} \label{sec:ipc_posix_mq} -Le code di messaggi non sono ancora supportate nel kernel -ufficiale;\footnote{esiste però una proposta di implementazione di Krzysztof - Benedyczak, a partire dal kernel 2.5.50.} inoltre esse possono essere -implementate, usando la memoria condivisa ed i mutex, con funzioni di -libreria. In generale, come le corrispettive del SysV IPC, sono poco usate, -dato che i socket\index{socket}, nei casi in cui sono sufficienti, sono più -comodi, e negli altri casi la comunicazione può essere gestita direttamente -con mutex e memoria condivisa. Per questo ci limiteremo ad una descrizione -essenziale. +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 \href{http://www.mat.uni.torun.pl/~wrona/posix_ipc} + {http://www.mat.uni.torun.pl/\~{}wrona/posix\_ipc}.}. In generale, come le +corrispettive del SysV IPC, sono poco usate, dato che i socket\index{socket}, +nei casi in cui sono sufficienti, sono più comodi, e negli altri casi la +comunicazione può essere gestita direttamente con mutex e memoria condivisa. + @@ -3809,16 +3840,50 @@ essenziale. Dei semafori POSIX esistono sostanzialmente due implementazioni; una è fatta a livello di libreria ed è fornita dalla libreria dei thread; questa però li -implementa solo a livello di thread e non di processi. Esiste un'altra -versione, realizzata da Konstantin Knizhnik, che reimplementa l'interfaccia -POSIX usando i semafori di SysV IPC. +implementa solo a livello di thread e non di processi.\footnote{questo + significa che i semafori sono visibili solo all'interno dei thread creati da + un singolo processo, e non possono essere usati come meccanismo di + sincronizzazione fra processi diversi.} Esiste però anche una libreria +realizzata da Konstantin Knizhnik, che reimplementa l'interfaccia POSIX usando +i semafori di SysV IPC, e che non vale comunque la pena di usare visto che i +problemi sottolineati in \secref{sec:ipc_sysv_sem} rimangono, anche se +mascherati. + + \subsection{Memoria condivisa} \label{sec:ipc_posix_shm} La memoria condivisa è l'unico degli oggetti di IPC POSIX già presente nel -kernel ufficiale. +kernel ufficiale. Per poterla utilizzare occorre abilitare il filesystem +\texttt{tmpfs}, uno speciale filesystem che mantiene tutti i suoi contenuti in +memoria,\footnote{il filesystem \texttt{tmpfs} è diverso da un normale RAM + disk, anch'esso disponibile attraverso il filesystem \texttt{ramfs}, proprio + perché realizza una interfaccia utilizzabile anche per la memoria condivisa; + esso infatti non ha dimensione fissa, ed usa direttamente la cache interna + del kernel (viene usato anche per la SysV shared memory). In più i suoi + contenuti, essendo trattati direttamente dalla memoria + virtuale\index{memoria virtuale} e possono essere salvati sullo swap + automaticamente.} abilitando l'opzione \texttt{CONFIG\_TMPFS} in fase di +compilazione del kernel, e montando il filesystem aggiungendo una riga tipo: +\begin{verbatim} +tmpfs /dev/shm tmpfs defaults 0 0 +\end{verbatim} +ad \file{/etc/fstab}, oppure dove si preferisce con un comando del +tipo:\footnote{il filesystem riconosce, oltre quelle mostrate, le opzioni + \texttt{uid} e \texttt{gid} che identificano rispettivamente utente e gruppo + cui assegnarne la titolarità, e \texttt{nr\_blocks} che permette di + specificarne la dimensione in blocchi, cioè in multipli di + \const{PAGECACHE\_SIZE}.} +\begin{verbatim} +mount -t tmpfs -o size=10G,nr_inodes=10k,mode=700 tmpfs /mytmpfs +\end{verbatim} + + + la memoria +condivisa è trattata come un filesystem separato, con tutte le caratteristiche +di un qualunque filesystem, %%% Local Variables: