Tre righe su shmat
[gapil.git] / ipc.tex
diff --git a/ipc.tex b/ipc.tex
index 4db9ea2db3dbb3bdf45d6668be6ff306c8156a54..2bd1a9ccdcbbf00ec46c4df004ca434496e63f6d 100644 (file)
--- a/ipc.tex
+++ b/ipc.tex
@@ -830,7 +830,7 @@ descriptor connessi fra di loro (tramite un socket, appunto), senza dover
 ricorrere ad un file speciale sul filesystem, i descrittori sono del tutto
 analoghi a quelli che si avrebbero con una chiamata a \func{pipe}, con la sola
 differenza è che in questo caso il flusso dei dati può essere effettuato in
-emtrambe le direzioni. Il prototipo della funzione è:
+entrambe le direzioni. Il prototipo della funzione è:
 \begin{functions}
   \headdecl{sys/types.h} 
   \headdecl{sys/socket.h} 
@@ -903,7 +903,7 @@ file, un contatore del numero di riferimenti che ne indichi l'essere in uso,
 essi possono essere cancellati anche se ci sono dei processi che li stanno
 utilizzando, con tutte le conseguenze (negative) del caso.
 
-Un'ulteriore caratterestica negativa è che gli oggetti usati nel System V IPC
+Un'ulteriore caratteristica negativa è che gli oggetti usati nel System V IPC
 vengono creati direttamente dal kernel, e sono accessibili solo specificando
 il relativo \textsl{identificatore}. Questo è un numero progressivo (un po'
 come il \acr{pid} dei processi) che il kernel assegna a ciascuno di essi
@@ -1242,7 +1242,7 @@ una 
     di messaggi specificando una chiave che non esiste e \macro{IPC\_CREAT}
     non era specificato.
   \item[\macro{ENOSPC}] Si è cercato di creare una coda di messaggi quando è
-    stato il limite massimo del sistema.
+    stato superato il limite massimo di code (\macro{MSGMNI}).
   \end{errlist}
   ed inoltre \macro{ENOMEM}.
 }
@@ -1716,57 +1716,60 @@ void HandSIGTERM(int signo) {
 \end{figure}
 
 In \figref{fig:ipc_mq_fortune_server} si è riportato un estratto delle parti
-primcipali del codice del nuovo server (il codice completo è nel file
+principali del codice del nuovo server (il codice completo è nel file
 \file{MQFortuneServer.c} nei sorgenti allegati). Il programma è basato su un
-uso accorto dei tipi di messaggi per permettere una comunicazione indipendente
-fra il server ed i vari client, usando il \acr{pid} di questi ultimi come
-identificativo. Questo è possibile in quanto, al contrario di una fifo, la
-lettura di una coda di messaggi può non essere sequanziale, proprio grazie
-alla classificazione dei messaggi sulla base del loro tipo.  
-
-
-Oltre alle solite variabili per il nome del file delle fifo e per il vettore
-di stringhe che contiene le frasi, il programma utilizza due strutture per la
-comunicazione; con \var{msgbuf\_read} (\texttt{\small 8--11}) vengono passate
-le richieste mentre con \var{msgbuf\_write} (\texttt{\small 12--15}) vengono
-restituite le frasi.
-
-La gestione delle opzioni si è al solito omessa, essa si curerà di restituire
-in \var{n} il numero di file da leggere ed in \var{fortunefilename} il file da
-cui leggerle; dopo aver installato (\texttt{\small 19--21}) dei manipolatori
-per gestire l'uscita prima viene controllato (\texttt{\small 22}) che si siano
-richiesti un numero positivo di messaggi, che poi (\texttt{\small 23}) vengono
-letti con la stessa funzione \code{FortuneParse()} usata anche per il server
-basato sulle fifo.
+uso accorto della caratteristica di poter associate un ``tipo'' ai messaggi
+per permettere una comunicazione indipendente fra il server ed i vari client,
+usando il \acr{pid} di questi ultimi come identificativo. Questo è possibile
+in quanto, al contrario di una fifo, la lettura di una coda di messaggi può
+non essere sequenziale, proprio grazie alla classificazione dei messaggi sulla
+base del loro tipo.
+
+Il programma, oltre alle solite variabili per il nome del file da cui leggere
+le \textit{fortunes} e per il vettore di stringhe che contiene le frasi,
+definisce due strutture appositamente per la comunicazione; con
+\var{msgbuf\_read} (\texttt{\small 8--11}) vengono passate le richieste mentre
+con \var{msgbuf\_write} (\texttt{\small 12--15}) vengono restituite le frasi.
+
+La gestione delle opzioni si è al solito omessa, essa si curerà di impostare
+in \var{n} il numero di frasi da leggere specificato a linea di comando ed in
+\var{fortunefilename} il file da cui leggerle; dopo aver installato
+(\texttt{\small 19--21}) dei manipolatori per gestire l'uscita dal server,
+viene prima controllato (\texttt{\small 22}) il numero di frasi richieste
+abbia senso (cioè sia maggiore di zero), le quali poi (\texttt{\small 23})
+vengono lette nel vettore in memoria con la stessa funzione
+\code{FortuneParse()} usata anche per il server basato sulle fifo.
 
 Una volta inizializzato il vettore di stringhe coi messaggi presi dal file
-delle fortunes si procede (\texttt{\small 25}) con la generazione di una
-chiave (si usa il nome del file dei sorgenti del server) con la quale poi si
-esegue (\texttt{\small 26}) la creazione della nostra coda di messaggi (si
-noti come si sia chiamata \func{msgget} con un valore opportuno per il flag),
-avendo cura di abortire il programma (\texttt{\small 27--29}) in caso di
-errore.
+delle \textit{fortune} si procede (\texttt{\small 25}) con la generazione di
+una chiave per identificare la coda di messaggi (si usa il nome del file dei
+sorgenti del server) con la quale poi si esegue (\texttt{\small 26}) la
+creazione della stessa (si noti come si sia chiamata \func{msgget} con un
+valore opportuno per l'argomento \param{flag}), avendo cura di abortire il
+programma (\texttt{\small 27--29}) in caso di errore.
 
 Finita la fase di inizializzazione il server esegue in permanenza il ciclo
 principale (\texttt{\small 32--41}). Questo inizia (\texttt{\small 33}) con il
 porsi in attesa di un messaggio di richiesta da parte di un client; si noti
-infatti come \func{msgrcv} richieda un messaggio con \var{mtype} uguale a 1,
-che è il valore usato per le richieste dato che corriponde al \acr{pid} di
+infatti come \func{msgrcv} richieda un messaggio con \var{mtype} uguale a 1:
+questo è il valore usato per le richieste dato che corrisponde al \acr{pid} di
 \cmd{init}, che non può essere un client. L'uso del flag \macro{MSG\_NOERROR}
 è solo per sicurezza, dato che i messaggi di richiesta sono di dimensione
-fissa.
+fissa (e contengono solo il \acr{pid} del client).
 
-Se non sono presenti messaggi di richiesta \func{msgrcv} si bloccherà;
-all'arrivo sulla coda di un messaggio di richiesta da parte di un client la
-funzione ritorna, ed il ciclo prosegue (\texttt{\small 34}) selezionando una
-frase a caso, copiandola (\texttt{\small 35}) nella struttura
-\var{msgbuf\_write} usata per la risposta e calcolandone (\texttt{\small 36})
-la dimensione.
+Se non sono presenti messaggi di richiesta \func{msgrcv} si bloccherà,
+ritornando soltanto in corrispondenza dell'arrivo sulla coda di un messaggio
+di richiesta da parte di un client, in tal caso il ciclo prosegue
+(\texttt{\small 34}) selezionando una frase a caso, copiandola (\texttt{\small
+  35}) nella struttura \var{msgbuf\_write} usata per la risposta e
+calcolandone (\texttt{\small 36}) la dimensione.
 
 Per poter permettere a ciascun client di ricevere solo la risposta indirizzata
 a lui il tipo del messaggio in uscita viene inizializzato (\texttt{\small 37})
-al valore ricevuto nel messaggio di richiesta.  L'ultimo passo del ciclo
-(\texttt{\small 38}) è inviare sulla coda il messaggio di risposta.
+al valore del \acr{pid} del client ricevuto nel messaggio di richiesta.
+L'ultimo passo del ciclo (\texttt{\small 38}) è inviare sulla coda il
+messaggio di risposta. Si tenga conto che se la coda è piena anche questa
+funzione potrà bloccarsi fintanto che non venga liberato dello spazio.
 
 Si noti che il programma può terminare solo grazie ad una interruzione da
 parte di un segnale; in tal caso verrà eseguito il manipolatore
@@ -1803,27 +1806,44 @@ int main(int argc, char *argv[])
 \end{figure}
 
 In \figref{fig:ipc_mq_fortune_client} si è riportato un estratto il codice del
-programma client, al solito il codice completo è con i sorgenti allegati, nel
+programma client.  Al solito il codice completo è con i sorgenti allegati, nel
 file \file{MQFortuneClient.c}.  Come sempre si sono rimosse le parti relative
 alla gestione delle opzioni, ed in questo caso, anche la dichiarazione delle
-variabili.
+variabili, che, per la parte relative alle strutture usate per la
+comunicazione tramite le code, sono le stesse viste in
+\figref{fig:ipc_mq_fortune_server}.
 
 Il client in questo caso è molto semplice; la prima parte del programma
 (\texttt{\small 4--9}) si occupa di accedere alla coda di messaggi, ed è
 identica a quanto visto per il server, solo che in questo caso \func{msgget}
 non viene chiamata con il flag di creazione in quanto la coda deve essere
-preesistente.
+preesistente. In caso di errore (ad esempio se il server non è stato avviato)
+il programma termina immediatamente. 
 
-Una volta acquistito l'identificatore della coda il client compone il
+Una volta acquisito l'identificatore della coda il client compone il
 messaggio di richiesta (\texttt{\small 12--13}) in \var{msg\_read}, usando 1
 per il tipo ed inserendo il proprio \acr{pid} come dato da passare al server.
 Calcolata (\texttt{\small 14}) la dimensione, provvede (\texttt{\small 15}) ad
-immettere la richiesta sulla coda. A questo punto non resta che
-(\texttt{\small 16}) rileggere dalla coda la risposta del server richiedendo a
-\func{msgrcv} di selezionare i messaggi di tipo corrispondente al valore del
-\acr{pid} inviato nella richiesta. L'ultimo passo (\texttt{\small 17}) prima
-di uscire è quello di stampare a video il messaggio ricevuto.
+immettere la richiesta sulla coda. 
+
+A questo punto non resta che (\texttt{\small 16}) rileggere dalla coda la
+risposta del server richiedendo a \func{msgrcv} di selezionare i messaggi di
+tipo corrispondente al valore del \acr{pid} inviato nella richiesta. L'ultimo
+passo (\texttt{\small 17}) prima di uscire è quello di stampare a video il
+messaggio ricevuto.
  
+Benché funzionante questa architettura risente dello stesso inconveniente
+visto anche nel caso del precedente server basato sulle fifo; se il client
+viene interrotto dopo l'invio del messaggio di richiesta e prima della lettura
+della risposta, quest'ultima resta nella coda (così come per le fifo si aveva
+il problema delle fifo che restavano nel filesystem). In questo caso però il
+problemi sono maggiori, sia perché è molto più facile esaurire la memoria
+dedicata ad una coda di messaggi che gli inode di un filesystem, sia perché,
+con il riutilizzo dei \acr{pid} da parte dei processi, un client eseguito in
+un momento successivo potrebbe ricevere un messaggio non indirizzato a
+lui.
+
+
 
 \subsection{Semafori}
 \label{sec:ipc_sysv_sem}
@@ -1881,8 +1901,21 @@ permette di creare o ottenere l'identificatore di un insieme di semafori 
   Restituisce l'identificatore di un insieme di semafori.
   
   \bodydesc{La funzione restituisce l'identificatore (un intero positivo) o -1
-    in caso di errore, nel qual caso \var{errno} assumerà gli stessi valori
-    visti per \func{msgget}.}
+    in caso di errore, nel qual caso \var{errno} assumerà i valori:
+    \begin{errlist}
+    \item[\macro{ENOSPC}] Si è cercato di creare una insieme di semafori
+      quando è stato superato o il limite per il numero totale di semafori
+      (\macro{SEMMNS}) o quello per il numero totale degli insiemi
+      (\macro{SEMMNI}) nel sistema.
+    \item[\macro{EINVAL}] L'argomento \param{nsems} è minore di zero o
+      maggiore del limite sul numero di semafori per ciascun insieme
+      (\macro{SEMMSL}), o se l'insieme già esiste, maggiore del numero di
+      semafori che contiene.
+    \item[\macro{ENOMEM}] Il sistema non ha abbastanza memoria per poter
+      contenere le strutture per un nuovo insieme di semafori.
+    \end{errlist}
+    ed inoltre \macro{EACCES}, \macro{ENOENT}, \macro{EEXIST}, \macro{EIDRM},
+    con lo stesso significato che hanno per \func{msgget}.}
 \end{functions}
 
 La funzione è del tutto analoga a \func{msgget}, solo che in questo caso
@@ -1913,6 +1946,7 @@ del sistema. Come vedremo esistono delle modalit
 diventa necessario indicare esplicitamente che si vuole il ripristino del
 semaforo all'uscita del processo.
 
+
 \begin{figure}[!htb]
   \footnotesize \centering
   \begin{minipage}[c]{15cm}
@@ -1933,21 +1967,24 @@ struct semid_ds
 \end{figure}
 
 A ciascun insieme di semafori è associata una struttura \var{semid\_ds},
-riportata in \figref{fig:ipc_semid_ds}. Come nel caso delle code di messaggi
-quando si crea un nuovo insieme di semafori con \func{semget} questa struttura
-viene inizializzata, in particolare il campo \var{sem\_perm} viene
-inizializzato come illustrato in \secref{sec:ipc_sysv_access_control} (si
-ricordi che in questo caso il permesso di scrittura è in realtà permesso di
-alterare il semaforo), per quanto riguarda gli altri campi invece:
+riportata in \figref{fig:ipc_semid_ds}.\footnote{non si sono riportati i campi
+  ad uso interno del kernel, che vedremo in \figref{fig:ipc_sem_schema}, che
+  dipendono dall'implementazione.} Come nel caso delle code di messaggi quando
+si crea un nuovo insieme di semafori con \func{semget} questa struttura viene
+inizializzata, in particolare il campo \var{sem\_perm} viene inizializzato
+come illustrato in \secref{sec:ipc_sysv_access_control} (si ricordi che in
+questo caso il permesso di scrittura è in realtà permesso di alterare il
+semaforo), per quanto riguarda gli altri campi invece:
 \begin{itemize*}
 \item il campo \var{sem\_nsems}, che esprime il numero di semafori
   nell'insieme, viene inizializzato al valore di \param{nsems}.
 \item il campo \var{sem\_ctime}, che esprime il tempo di creazione
-  dell'insieme, viene inizializzato al tempo corrente
+  dell'insieme, viene inizializzato al tempo corrente.
 \item il campo \var{sem\_otime}, che esprime il tempo dell'ultima operazione
   effettuata, viene inizializzato a zero.
 \end{itemize*}
 
+
 Ciascun semaforo dell'insieme è realizzato come una struttura di tipo
 \var{sem} che ne contiene i dati essenziali, la sua definizione\footnote{si è
   riportata la definizione originaria del kernel 1.0, che contiene la prima
@@ -1955,13 +1992,10 @@ Ciascun semaforo dell'insieme 
   ridotta ai soli due primi membri, e gli altri vengono calcolati
   dinamicamente. La si è utilizzata a scopo di esempio, perché indica tutti i
   valori associati ad un semaforo, restituiti dalle funzioni di controllo, e
-  citati dalla pagine di manuale.} è riportata in \figref{fig:ipc_sem}. Di
-norma questa struttura non è accessibile in user space, ma lo sono, in maniera
-indiretta, tramite l'uso delle funzioni di controllo, i valori in essa
-specificati, che indicano rispettivamente: il valore del semaforo, il
-\acr{pid} dell'ultimo processo che ha eseguito una operazione, il numero di
-processi in attesa che esso venga incrementato ed il numero di processi in
-attesa che esso si annulli.
+  citati dalle pagine di manuale.} è riportata in \figref{fig:ipc_sem}. Questa
+struttura, non è accessibile in user space, ma i valori in essa specificati
+possono essere letti in maniera indiretta, attraverso l'uso delle funzioni di
+controllo.
 
 \begin{figure}[!htb]
   \footnotesize \centering
@@ -1980,11 +2014,16 @@ struct sem {
   \label{fig:ipc_sem}
 \end{figure}
 
-Come per le code di messaggi anche per gli insiemi di semafori esistono una
-serie di limiti, i cui valori sono associati ad altrettante costanti, che si
-sono riportate in \tabref{tab:ipc_sem_limits}. Alcuni di questi limiti sono
-al solito accessibili e modificabili attraverso \func{sysctl} o scrivendo
-direttamente nel file \file{/proc/sys/kernel/sem}.
+I dati mantenuti nella struttura, ed elencati in \figref{fig:ipc_sem},
+indicano rispettivamente: 
+\begin{description*}
+\item[\var{semval}] il valore numerico del semaforo.
+\item[\var{sempid}] il \acr{pid} dell'ultimo processo che ha eseguito una
+  operazione sul semaforo.
+\item[\var{semncnt}] il numero di processi in attesa che esso venga
+  incrementato.
+\item[\var{semzcnt}] il numero di processi in attesa che esso si annulli.
+\end{description*}
 
 \begin{table}[htb]
   \footnotesize
@@ -2012,6 +2051,12 @@ direttamente nel file \file{/proc/sys/kernel/sem}.
   \label{tab:ipc_sem_limits}
 \end{table}
 
+Come per le code di messaggi anche per gli insiemi di semafori esistono una
+serie di limiti, i cui valori sono associati ad altrettante costanti, che si
+sono riportate in \tabref{tab:ipc_sem_limits}. Alcuni di questi limiti sono al
+solito accessibili e modificabili attraverso \func{sysctl} o scrivendo
+direttamente nel file \file{/proc/sys/kernel/sem}.
+
 La funzione che permette di effettuare le varie operazioni di controllo sui
 semafori (fra le quali, come accennato, è impropriamente compresa anche la
 loro inizializzazione) è \func{semctl}; il suo prototipo è:
@@ -2224,7 +2269,6 @@ opportuna struttura \var{sembuf} (la cui definizione 
 \figref{fig:ipc_sembuf}) che il programma chiamante deve avere cura di
 allocare in un opportuno vettore. La struttura permette di indicare il
 semaforo su cui operare, il tipo di operazione, ed un flag di controllo.
-
 Il campo \var{sem\_num} serve per indicare a quale semaforo dell'insieme fa
 riferimento l'operazione; si ricordi che i semafori sono numerati come in un
 vettore, per cui il primo semaforo corrisponde ad un valore nullo di
@@ -2311,24 +2355,79 @@ strutture non vengono ereditate attraverso una \func{fork} (altrimenti si
 avrebbe un doppio ripristino), mentre passano inalterate nell'esecuzione di
 una \func{exec} (altrimenti non si avrebbe ripristino).
 
-Resta comunque insoluto il problema di fondo di questo meccanismo, che non si
-adatta al concetto di operazioni atomiche su un semaforo. Infatti siccome le
-richieste di ripristino si accumulano attraverso diverse chiamate a
-\func{semop}, si pone il problema di cosa fare all'uscita del processo quando
-viene eseguito il ripristino.  Il punto è se si deve porre il processo in
-stato di \textit{sleep} se non si può accedere al semaforo o andare avanti
-come se fosse stato impostato \macro{IPC\_NOWAIT}. La scelta del kernel è
-quella di effettuare le operazioni che non prevedono un blocco del processo ed
-ignorare silenziosamente le altre.  Questo comporta che un comportamento senza
-problemi può essere garantito solo per i semafori privati.
+Tutto questo però ha un problema di fondo. Per capire di cosa si tratta
+occorre fare riferimento all'implementazione usata in Linux, che è riportata
+in maniera semplificata nello schema di \figref{fig:ipc_sem_schema}.  Si è
+presa come riferimento l'architettura usata fino al kernel 2.2.x che è più
+semplice (ed illustrata in dettaglio in \cite{tlk}); nel kernel 2.4.x la
+struttura del System V IPC è stata modificata, ma le definizioni relative a
+queste strutture restano per compatibilità.\footnote{in particolare con le
+  vecchie versioni delle librerie del C, come le libc5.}
+
+\begin{figure}[htb]
+  \centering \includegraphics[width=15cm]{img/semtruct}
+  \caption{Schema della struttura di un insieme di semafori.}
+  \label{fig:ipc_sem_schema}
+\end{figure}
+
+Alla creazione di un nuovo insieme viene allocata una nuova strutture
+\var{semid\_ds} ed il relativo vettore di strutture \var{sem}. Quando si
+richiede una operazione viene anzitutto verificato che tutte le operazioni
+possono avere successo; se una di esse comporta il blocco del processo il
+kernel crea una struttura \var{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 \var{semid\_ds}.}. Nella struttura viene memorizzato il riferimento alle
+operazioni richieste (nel campo \var{sops}, che è un puntatore ad una
+struttura \var{sembuf}) e al processo corrente (nel campo \var{sleeper}) poi
+quest'ultimo viene messo stato di attesa e viene invocato lo
+scheduler\index{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
+attesa (a partire da \var{sem\_pending}) per verificare se qualcuna delle
+operazioni sospese in precedenza può essere eseguita, nel qual caso la
+struttura \var{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 \macro{SEM\_UNDO} viene mantenuta per ciascun insieme
+di semafori una apposita struttura \var{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
+all'insieme di cui fa parte il semaforo, che viene usata per invalidare le
+strutture se questo viene cancellato o per azzerarle se si è eseguita una
+operazione con \func{semctl}; l'altra associata al processo che ha eseguito
+l'operazione;\footnote{attraverso il campo \var{semundo} di
+  \var{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.
 
 
 \subsection{Memoria condivisa}
 \label{sec:ipc_sysv_shm}
 
-Il terzo oggetto introdotto dal \textit{System V IPC} è quello della memoria
-condivisa. La funzione che permette di ottenerne uno è \func{shmget} ed il suo
-prototipo è:
+Il terzo oggetto introdotto dal \textit{System V IPC} è quello dei segmenti di
+memoria condivisa. La funzione che permette di ottenerne uno è \func{shmget}
+ed il suo prototipo è:
 \begin{functions}
   \headdecl{sys/types.h} 
   \headdecl{sys/ipc.h} 
@@ -2339,12 +2438,162 @@ prototipo 
   Restituisce l'identificatore di una memoria condivisa.
   
   \bodydesc{La funzione restituisce l'identificatore (un intero positivo) o -1
-    in caso di errore, nel qual caso \var{errno} assumerà gli stessi valori
-    visti per \func{msgget}.}
+    in caso di errore, nel qual caso \var{errno} assumerà i valori:
+    \begin{errlist}
+    \item[\macro{ENOSPC}] Si è superato il limite (\macro{SHMMNI}) sul numero
+      di segmenti di memoria nel sistema, o cercato di allocare un segmento le
+      cui dimensioni fanno superare il limite di sistema (\macro{SHMALL}) per
+      la memoria ad essi riservata.
+    \item[\macro{EINVAL}] Si è richiesta una dimensione per un nuovo segmento
+      maggiore di \macro{SHMMAX} o minore di \macro{SHMMIN}, o se il segmento
+      già esiste \param{size} è maggiore delle sue dimensioni.
+    \item[\macro{ENOMEM}] Il sistema non ha abbastanza memoria per poter
+      contenere le strutture per un nuovo segmento di memoria condivisa.
+    \end{errlist}
+    ed inoltre \macro{EACCES}, \macro{ENOENT}, \macro{EEXIST}, \macro{EIDRM},
+    con lo stesso significato che hanno per \func{msgget}.}
 \end{functions}
 
 La funzione, come \func{semget}, è del tutto analoga a \func{msgget}, ed
-identico è l'uso degli argomenti \param{key} e \param{flag}. L'argomento
+identico è l'uso degli argomenti \param{key} e \param{flag} per cui non
+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}.
+
+\begin{figure}[!htb]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \begin{lstlisting}[labelstep=0]{}
+struct shmid_ds {
+     struct    ipc_perm shm_perm;  /* operation perms */
+     int  shm_segsz;               /* size of segment (bytes) */
+     time_t    shm_atime;          /* last attach time */
+     time_t    shm_dtime;          /* last detach time */
+     time_t    shm_ctime;          /* last change time */
+     unsigned short shm_cpid;      /* pid of creator */
+     unsigned short shm_lpid;      /* pid of last operator */
+     short     shm_nattch;         /* no. of current attaches */
+};
+    \end{lstlisting}
+  \end{minipage} 
+  \normalsize 
+  \caption{La struttura \var{shmid\_ds}, associata a ciascun segmento di
+    memoria condivisa.}
+  \label{fig:ipc_shmid_ds}
+\end{figure}
+
+A ciascun segmento di memoria condivisa è associata una struttura
+\var{shmid\_ds}, riportata in \figref{fig:ipc_shmid_ds}.  Come nel caso delle
+code di messaggi quando si crea un nuovo segmento di memoria condivisa con
+\func{shmget} questa struttura viene inizializzata, in particolare il campo
+\var{shm\_perm} viene inizializzato come illustrato in
+\secref{sec:ipc_sysv_access_control}, e valgono le considerazioni ivi fatte
+relativamente ai permessi di accesso; per quanto riguarda gli altri campi
+invece:
+\begin{itemize*}
+\item il campo \var{shm\_segsz}, che esprime la dimensione del segmento, viene
+  inizializzato al valore di \param{size}.
+\item il campo \var{shm\_ctime}, che esprime il tempo di creazione del
+  segmento, viene inizializzato al tempo corrente.
+\item i campi \var{shm\_atime} e \var{shm\_atime}, che esprimno
+  rispettivamente il tempo dell'ultima volta che il segmento è stato
+  agganciato o sganciato da un processo, vengono inizializzati a zero.
+\item il campo \var{shm\_lpid}, che esprime il \acr{pid} del processo che ha
+  eseguito l'ultima operazione, viene inizializzato a zero.
+\item il campo \var{shm\_cpid}, che esprime il \acr{pid} del processo che ha
+  creato il segmento, viene inizializzato al \acr{pid} del processo chiamante.
+\item il campo \var{shm\_nattac}, che esprime il numero di processi agganciati
+  al segmento viene inizializzato a zero.
+\end{itemize*}
+
+Come per le code di messaggi e gli insiemi di semafori, anche per i segmenti
+di memoria condivisa esistono una serie di limiti, i cui valori, riportati in
+\tabref{tab:ipc_shm_limits} sono associati ad altrettante costanti.  Alcuni di
+questi limiti sono al solito accessibili e modificabili attraverso
+\func{sysctl} o scrivendo direttamente nei rispettivi file di
+\file{/proc/sys/kernel/}.
+
+\begin{table}[htb]
+  \footnotesize
+  \centering
+  \begin{tabular}[c]{|c|r|c|p{7cm}|}
+    \hline
+    \textbf{Costante} & \textbf{Valore} & \textbf{File in \texttt{proc}}
+    & \textbf{Significato} \\
+    \hline
+    \hline
+    \macro{SHMALL}&0x200000&\file{shmall}& Numero massimo di pagine che 
+                                       possono essere usate per i segmenti di
+                                       memoria condivisa. \\
+    \macro{SHMMAX}&0x2000000&\file{shmmax}& Dimensione massima di un segmento 
+                                       di memoria condivisa.\\
+    \macro{SHMMNI}&4096&\file{msgmni}& Numero massimo di segmenti di memoria
+                                       condivisa presenti nel kernel.\\
+    \macro{SHMMIN}&   1& ---         & Dimensione minima di un segmento di
+                                       memoria condivisa. \\
+    \hline
+  \end{tabular}
+  \caption{Valori delle costanti associate ai limiti dei segmenti di memoria
+    condivisa, insieme al relativo file in \file{/proc/sys/kernel/} ed al
+    valore preimpostato presente nel sistema.} 
+  \label{tab:ipc_shm_limits}
+\end{table}
+
+Al solito la funzione che permette di effettuare le operazioni di controllo su
+un segmento di memoria condivisa è \func{shmctl}; il suo prototipo è:
+\begin{functions}
+  \headdecl{sys/ipc.h} 
+  \headdecl{sys/shm.h}
+  
+  \funcdecl{int shmctl(int shmid, int cmd, struct shmid\_ds *buf)}
+  
+  Esegue le operazioni di controllo su un segmento di memoria condivisa.
+  
+  \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
+    errore, nel qual caso \var{errno} assumerà i valori:
+    \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}.}
+\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:
+\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.
+
+  \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}] Si è specificato un identificatore invalido per
+      \param{shmid}, o un indirizzo non valido per \param{shmaddr}.
+    \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}.}
+\end{functions}
+
+La prima funzione, \func{shmat}, aggancia un segmento di memoria condivisa
+allo spazio di indirizzi del processo, così che questo possa accedervi.
+L'argomento \param{shmaddr} specifica a quale indirizzo deve essere associato
+il segmento.