X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=ipc.tex;h=f3fb316f85dafe8f6f2091a9401989ace8d34f89;hp=e56386f04109b2b17f287e121acbc3cafca9fb72;hb=789a38451310ab1b56885887e36f97124e8f86e6;hpb=d7d656d5cd4969c58126d2c35950a607c282e330 diff --git a/ipc.tex b/ipc.tex index e56386f..f3fb316 100644 --- 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} @@ -2554,43 +2572,195 @@ un segmento di memoria condivisa \begin{errlist} \item[\macro{EACCES}] Si è richiesto \macro{IPC\_STAT} ma i permessi non consentono l'accesso in lettura al segmento. - \item[\macro{EINVAL}] . - \item[\macro{ENOMEM}] . - \end{errlist}.} + \item[\macro{EINVAL}] O \param{shmid} o \param{cmd} hanno valori non + validi. + \item[\macro{EIDRM}] L'argomento \param{shmid} fa riferimento ad un + segmento che è stato cancellato. + \item[\macro{EPERM}] Si è specificato un comando con \macro{IPC\_SET} o + \macro{IPC\_RMID} senza i permessi necessari. + \item[\macro{EOVERFLOW}] L'argomento \param{shmid} fa riferimento ad un + segmento che è stato cancellato. + \end{errlist} + ed inoltre \macro{EFAULT}.} \end{functions} -Per utilizzare i segmenti di memoria condivisa si usano due funzioni, -\func{shmat} e \func{shmdt}, che consentono di agganciarli e sganciarli da un -processo, così che questo possa vederli nel suo spazio di indirizzi; i loro -prototipi sono: +Il comportamento della funzione dipende dal valore del comando passato +attraverso l'argomento \param{cmd}, i valori possibili sono i seguenti: +\begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}} +\item[\macro{IPC\_STAT}] Legge le informazioni riguardo il segmento di memoria + condivisa nella struttura \var{shmid\_ds} puntata da \param{buf}. Occorre + avere il permesso di lettura sulla coda. +\item[\macro{IPC\_RMID}] Marca il segmento di memoria condivisa per la + rimozione, questo verrà cancellato effettivamente solo quando l'ultimo + processo ad esso agganciato si sarà staccato. Questo comando può essere + eseguito solo da un processo con userid effettivo, corrispondente al + creatore o al proprietario della coda, o all'amministratore. +\item[\macro{IPC\_SET}] Permette di modificare i permessi ed il proprietario + del segmento. Per modificare i valori di \var{shm\_perm.mode}, + \var{shm\_perm.uid} e \var{shm\_perm.gid} occorre essere il proprietario o + il creatore della coda, oppure l'amministratore. Compiuta l'operazione + aggiorna anche il valore del campo \var{shm\_ctime}. +\item[\macro{SHM\_LOCK}] Abilita il \textit{memory locking}\index{memory + locking} (vedi \secref{sec:proc_mem_lock}) sul segmento di memoria + condivisa. Solo l'amministratore può utilizzare questo comando. +\item[\macro{SHM\_UNLOCK}] Disabilita il \textit{memory locking}. Solo + 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 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 +chiamante, in modo che quest'ultimo possa vederlo nel suo spazio di indirizzi; +il suo prototipo è: \begin{functions} \headdecl{sys/types.h} \headdecl{sys/shm.h} \funcdecl{void *shmat(int shmid, const void *shmaddr, int shmflg)} Aggancia al processo un segmento di memoria condivisa. + + \bodydesc{La funzione restituisce l'indirizzo del segmento in caso di + successo, e -1 in caso di errore, nel qual caso \var{errno} assumerà i + valori: + \begin{errlist} + \item[\macro{EACCES}] Il processo non ha i privilegi per accedere al + segmento nella modalità richiesta. + \item[\macro{EINVAL}] Si è specificato un identificatore invalido per + \param{shmid}, o un indirizzo non allineato sul confine di una pagina + per \param{shmaddr}. + \end{errlist} + ed inoltre \macro{ENOMEM}.} +\end{functions} + +La funzione inserisce un segmento di memoria condivisa all'interno dello +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 è: +\begin{functions} + \headdecl{sys/types.h} + \headdecl{sys/shm.h} \funcdecl{int shmdt(const void *shmaddr)} Sgancia dal processo un segmento di memoria condivisa. - \bodydesc{Le funzioni restituiscono rispettivamente l'indirizzo del segmento - e 0 in caso di successo, mentre entrambe restituiscono -1 in caso di - errore, nel qual caso \var{errno} assumerà i valori: - \begin{errlist} - \item[\macro{EACCES}] Il processo non ha i provilegi di accesso. - \item[\macro{EINVAL}] . - \item[\macro{EPERM}] Si è è richiesto \macro{IPC\_SET} o \macro{IPC\_RMID} - senza avere i permessi del creatore o del proprietario del segmento (o - quelli dell'amministratore). - \item[\macro{EOVERFLOW}] Si è richiesto \macro{IPC\_STAT} ma alcuni valori - sono troppo grandi per essere memorizzati nella struttura puntata da - \param{buf}. - \end{errlist} - ed inoltre \macro{EFAULT} e \macro{EIDRM}.} + \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 + \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}