Figura sulla struttura dei segmenti di memoria condivisa, e completamenti
[gapil.git] / ipc.tex
diff --git a/ipc.tex b/ipc.tex
index 488e330b50620ec3b0e1386f0960cf118610a09b..f3fb316f85dafe8f6f2091a9401989ace8d34f89 100644 (file)
--- a/ipc.tex
+++ b/ipc.tex
@@ -2426,7 +2426,7 @@ ripristino non 
 \label{sec:ipc_sysv_shm}
 
 Il terzo oggetto introdotto dal \textit{System V IPC} è quello dei segmenti di
-memoria condivisa. La funzione che permette di ottenerne uno è \func{shmget}
+memoria condivisa. La funzione che permette di ottenerne uno è \func{shmget},
 ed il suo prototipo è:
 \begin{functions}
   \headdecl{sys/types.h} 
@@ -2460,6 +2460,24 @@ ripeteremo quanto detto al proposito in \secref{sec:ipc_sysv_mq}. L'argomento
 \param{size} specifica invece la dimensione, in byte, del segmento, che viene
 comunque arrotondata al multiplo superiore di \macro{PAGE\_SIZE}.
 
+La memoria condivisa è la forma più veloce di comunicazione fra due processi,
+in quanto permette agli stessi di vedere nel loro spazio di indirizzi una
+stessa sezione di memoria.  Pertanto non è necessaria nessuna operazione di
+copia per trasmettere i dati da un processo all'altro, in quanto ciascuno può
+accedervi direttamente con le normali operazioni di lettura e scrittura dei
+dati in memoria.
+
+Ovviamente tutto questo ha un prezzo, ed il problema fondamentale della
+memoria condivisa è la sincronizzazione degli accessi. È evidente infatti che
+se un processo deve scambiare dei dati con un altro, si deve essere sicuri che
+quest'ultimo non acceda al segmento di memoria condivisa prima che il primo
+non abbia completato le operazioni di scrittura, inoltre nel corso di una
+lettura si deve essere sicuri che i dati restano coerenti e non vengono
+sovrascritti da un accesso in scrittura sullo stesso segmento da parte di un
+altro processo; per questo in genere la memoria condivisa viene sempre
+utilizzata in abbinamento ad un meccanismo di sincronizzazione, il che, di
+norma, significa insime a dei semafori.
+
 \begin{figure}[!htb]
   \footnotesize \centering
   \begin{minipage}[c]{15cm}
@@ -2589,7 +2607,7 @@ attraverso l'argomento \param{cmd}, i valori possibili sono i seguenti:
   l'amministratore può utilizzare questo comando.
 \end{basedescript}
 i primi tre comandi sono gli stessi già visti anche per le code ed i semafori,
-gli ultimi due sono delle estensioni previste solo in Linux. 
+gli ultimi due sono delle estensioni previste da Linux. 
 
 Per utilizzare i segmenti di memoria condivisa si usano due funzioni, la prima
 di queste è \func{shmat}, che serve ad agganciare un segmento al processo
@@ -2611,26 +2629,81 @@ il suo prototipo 
     \item[\macro{EINVAL}] Si è specificato un identificatore invalido per
       \param{shmid}, o un indirizzo non allineato sul confine di una pagina
       per \param{shmaddr}.
-    \item[\macro{EIDRM}] Si è richiesto un segmento marcato per la
-      cancellazione.
     \end{errlist}
     ed inoltre \macro{ENOMEM}.}
 \end{functions}
 
 La funzione inserisce un segmento di memoria condivisa all'interno dello
-spazio di indirizzi del processo, come mostrato in così che questo possa
-accedervi, L'argomento \param{shmaddr} specifica a quale indirizzo\footnote{Lo
-  standard SVID prevede che l'argomento \param{shmaddr} sia di tipo \ctyp{char
-    *}, così come il valore di ritorno della funzione. In Linux è stato così
-  con le \acr{libc4} e le \acr{libc5}, con il passaggio alle \acr{glibc} il
-  tipo di \param{shmaddr} è divenuto un \ctyp{const void *} e quello del
-  valore di ritorno un \ctyp{void *}.} deve essere associato il segmento, che
-verrà restituito dalla funzione.
+spazio di indirizzi del processo, in modo che questo possa accedervi
+direttamente, la situazione dopo l'esecuzione di \func{shmat} è illustrata in
+\figref{fig:ipc_shmem_layout} (per la comprensione del resto dello schema si
+ricordi quanto illustrato al proposito in \secref{sec:proc_mem_layout}). Si
+tenga presente che la funzione ha successo anche se il segmento è stato
+marcato per la cancellazione.
+
+\begin{figure}[htb]
+  \centering
+  \includegraphics[height=10cm]{img/sh_memory_layout}
+  \caption{Disposizione dei segmenti di memoria di un processo quando si è
+    agganciato un segmento di memoria condivisa.}
+  \label{fig:ipc_shmem_layout}
+\end{figure}
+
+L'argomento \param{shmaddr} specifica a quale indirizzo\footnote{Lo standard
+  SVID prevede che l'argomento \param{shmaddr} sia di tipo \ctyp{char *}, così
+  come il valore di ritorno della funzione. In Linux è stato così con le
+  \acr{libc4} e le \acr{libc5}, con il passaggio alle \acr{glibc} il tipo di
+  \param{shmaddr} è divenuto un \ctyp{const void *} e quello del valore di
+  ritorno un \ctyp{void *}.} deve essere associato il segmento, se il valore
+specificato è \macro{NULL} è il sistema a scegliere opportunamente un'area di
+memoria libera (questo è il modo più portabile e sicuro di usare la funzione).
+Altrimenti il kernel aggancia il segmento all'indirizzo specificato da
+\param{shmaddr}; questo però può avvenire solo se l'indirizzo coincide con il
+limite di una pagina, cioè se è un multiplo esatto del parametro di sistema
+\macro{SHMLBA}, che in Linux è sempre uguale \macro{PAGE\_SIZE}.
+
+L'argomento \param{shmflg} permette di cambiare il comportamento della
+funzione; esso va specificato come maschera binaria, i bit utilizzati sono
+solo due e sono identificati dalle costanti \macro{SHM\_RND} e
+\macro{SHM\_RDONLY}, che vanno combinate con un OR aritmetico.  Specificando
+\macro{SHM\_RND} si evita che \func{shmat} ritorni un errore quando
+\param{shmaddr} non è allineato ai confini di una pagina. Si può quindi usare
+un valore qualunque per \param{shmaddr}, e il segmento verrà comunque
+agganciato, ma al più vicino multiplo di \macro{SHMLBA} (il nome della
+costante sta infatti per \textit{rounded}, e serve per specificare un
+indirizzo come arrotondamento).
+
+Il secondo bit permette di agganciare il segmento in sola lettura (si ricordi
+che anche le pagine di memoria hanno dei permessi), in tal caso un tentativo
+di scrivere sul segmento comporterà una violazione di accesso con l'emissione
+di un segnale di \macro{SIGSEGV}. Il comportamento usuale di \func{shmat} è
+quello di agganciare il segmento con l'accesso in lettura e scrittura (ed il
+processo deve aver questi permessi in \var{shm\_perm}), non è prevista la
+possibilità di agganciare un segmento in sola scrittura.
+
+In caso di successo la funzione aggiorna anche i seguenti campi di
+\var{shmid\_ds}:
+\begin{itemize*}
+\item il tempo \var{shm\_atime} dell'ultima operazione di aggancio viene
+  impostato al tempo corrente.
+\item il \acr{pid} \var{shm\_lpid} dell'ultimo processo che ha operato sul
+  segmento viene impostato a quello del processo corrente.
+\item il numero \var{shm\_nattch} di processi agganciati al segmento viene
+  aumentato di uno.
+\end{itemize*} 
+
+Come accennato in \secref{sec:proc_fork} un segmento di memoria condivisa
+agganciato ad un precesso viene ereditato da un figlio attraverso una
+\func{fork}, dato che quest'ultimo riceve una copia dello spazio degli
+indirizzi del padre. Invece, dato che attraverso una \func{exec} viene
+eseguito un diverso programma, tutti i segmenti eventualmente agganciati al
+processo vengono automaticamente sganciati. Lo stesso avviene all'uscita del
+processo attraverso una \func{exit}.
 
 
 La seconda funzione è \func{shmdt}, che consente di sganciare un segmento di
-memoria condivisa dal processo chiamante, , quando questo non è più
-necessario, il suo prototipo è:
+memoria condivisa dal processo chiamante quando questo non è più necessario,
+il suo prototipo è:
 \begin{functions}
   \headdecl{sys/types.h} 
   \headdecl{sys/shm.h}
@@ -2644,11 +2717,50 @@ necessario, il suo prototipo 
     \macro{EINVAL}.}
 \end{functions}
 
+La funzione esegue lo sganciamento del segmento di memoria condivisa
+agganciato all'indirizzo \param{shmaddr}; quest'ultimo deve essere uguale
+all'indirizzo ottenuto da una precedente chiamata a \func{shmat}. 
+
+
+
+
+
+
+Per capire meglio il funzionamento delle funzioni facciamo ancora una volta
+riferimento alle strutture con cui il kernel implementa i segmenti di memoria
+condivisa; uno schema semplificato della struttura è illustrato in
+\figref{fig:ipc_shm_struct}. 
+
+\begin{figure}[htb]
+  \centering
+  \includegraphics[width=10cm]{img/shmstruct}
+  \caption{Schema dell'implementazione dei segmenti di memoria condivisa in
+    Linux.}
+  \label{fig:ipc_shm_struct}
+\end{figure}
+
+
+\section{Tecniche alternative}
+\label{sec:ipc_alternatives}
+
+Come abbiamo visto in \secref{sec:ipc_sysv_generic} il sistema di IPC di
+System V presenta numerosi problemi; in \cite{APUE}\footnote{nel capitolo 14.}
+Stevens effettua una accurata analisi (i cui concetti sono già stati accennati
+in precedenza) ed elenca alcune possibili alternative, che vogliamo riprendere
+in questa sezione.
+
+
+\subsection{La sincronizzazione con il \textit{file locking}}
+\label{sec:ipc_file_lock}
 
+Abbiamo esaminato il \textit{file locking} in \secref{sec:file_locking}, 
 
 
 
+\subsection{Il \textit{memory mapping} anonimo}
+\label{sec:ipc_mmap_anonymous}
 
+Abbiamo visto in \secref{sec:file_memory_map} come sia possibile 
 
 
 \section{La comunicazione fra processi di POSIX}