+Come indicato il contenuto di ciascuna operazione deve essere specificato
+attraverso una struttura \struct{sembuf} (la cui definizione è riportata in
+fig.~\ref{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 gli
+elementi di un vettore, per cui il primo semaforo di un insieme corrisponde ad
+un valore nullo di \var{sem\_num}.
+
+Il campo \var{sem\_flg} è un flag, mantenuto come maschera binaria, per il
+quale possono essere impostati i due valori \const{IPC\_NOWAIT} e
+\const{SEM\_UNDO}. Impostando \const{IPC\_NOWAIT} si fa si che in tutti quei
+casi in cui l'esecuzione di una operazione richiederebbe di porre il processo
+vada nello stato di \textit{sleep}, invece di bloccarsi \func{semop} ritorni
+immediatamente (abortendo così le eventuali operazioni restanti) con un errore
+di \errcode{EAGAIN}. Impostando \const{SEM\_UNDO} si richiede invece che
+l'operazione in questione venga registrata, in modo che il valore del semaforo
+possa essere ripristinato all'uscita del processo.
+
+Infine \var{sem\_op} è il campo che controlla qual'è l'operazione che viene
+eseguita e determina in generale il comportamento della chiamata a
+\func{semop}. I casi possibili per il valore di questo campo sono tre:
+\begin{basedescript}{\desclabelwidth{1.8cm}}
+\item[\var{sem\_op} $>0$] In questo caso il valore viene aggiunto al valore
+ corrente di \var{semval} per il semaforo indicato. Questa operazione non
+ causa mai un blocco del processo, ed eventualmente \func{semop} ritorna
+ immediatamente con un errore di \errcode{ERANGE} qualora si sia superato il
+ limite \const{SEMVMX}. Se l'operazione ha successo si passa immediatamente
+ alla successiva. Specificando \const{SEM\_UNDO} si aggiorna il contatore
+ per il ripristino del valore del semaforo. Al processo chiamante è richiesto
+ il privilegio di alterazione (scrittura) sull'insieme di semafori.
+
+\item[\var{sem\_op} $=0$] Nel caso \var{semval} sia zero l'operazione ha
+ successo immediato, e o si passa alla successiva o \func{semop} ritorna con
+ successo se questa era l'ultima. Se \var{semval} è diverso da zero il
+ comportamento è controllato da \var{sem\_flg}, se è stato impostato
+ \const{IPC\_NOWAIT} \func{semop} ritorna immediatamente abortendo tutte le
+ operazioni con un errore di \errcode{EAGAIN}, altrimenti viene incrementato
+ \var{semzcnt} di uno ed il processo viene bloccato fintanto che non si
+ verifica una delle condizioni seguenti:
+ \begin{itemize*}
+ \item \var{semval} diventa zero, nel qual caso \var{semzcnt} viene
+ decrementato di uno, l'operazione ha successo e si passa alla successiva,
+ oppure \func{semop} ritorna con successo se questa era l'ultima.
+ \item l'insieme di semafori viene rimosso, nel qual caso \func{semop}
+ ritorna abortendo tutte le operazioni con un errore di \errcode{EIDRM}.
+ \item il processo chiamante riceve un segnale, nel qual caso \var{semzcnt}
+ viene decrementato di uno e \func{semop} ritorna abortendo tutte le
+ operazioni con un errore di \errcode{EINTR}.
+ \end{itemize*}
+ Al processo chiamante è richiesto soltanto il privilegio di lettura
+ dell'insieme dei semafori.
+
+\item[\var{sem\_op} $<0$] Nel caso in cui \var{semval} è maggiore o uguale del
+ valore assoluto di \var{sem\_op} (se cioè la somma dei due valori resta
+ positiva o nulla) i valori vengono sommati e l'operazione ha successo e si
+ passa alla successiva, oppure \func{semop} ritorna con successo se questa
+ era l'ultima. Qualora si sia impostato \const{SEM\_UNDO} viene anche
+ aggiornato il contatore per il ripristino del valore del semaforo. In caso
+ contrario (quando cioè la somma darebbe luogo ad un valore di \var{semval}
+ negativo) se si è impostato \const{IPC\_NOWAIT} \func{semop} ritorna
+ immediatamente abortendo tutte le operazioni con un errore di
+ \errcode{EAGAIN}, altrimenti viene incrementato di uno \var{semncnt} ed il
+ processo resta in stato di \textit{sleep} fintanto che non si ha una delle
+ condizioni seguenti:
+ \begin{itemize*}
+ \item \var{semval} diventa maggiore o uguale del valore assoluto di
+ \var{sem\_op}, nel qual caso \var{semncnt} viene decrementato di uno, il
+ valore di \var{sem\_op} viene sommato a \var{semval}, e se era stato
+ impostato \const{SEM\_UNDO} viene aggiornato il contatore per il
+ ripristino del valore del semaforo.
+ \item l'insieme di semafori viene rimosso, nel qual caso \func{semop}
+ ritorna abortendo tutte le operazioni con un errore di \errcode{EIDRM}.
+ \item il processo chiamante riceve un segnale, nel qual caso \var{semncnt}
+ viene decrementato di uno e \func{semop} ritorna abortendo tutte le
+ operazioni con un errore di \errcode{EINTR}.
+ \end{itemize*}
+ Al processo chiamante è richiesto il privilegio di alterazione (scrittura)
+ sull'insieme di semafori.
+\end{basedescript}
+
+Qualora si sia usato \func{semtimedop} alle condizioni di errore precedenti si
+aggiunge anche quella di scadenza del tempo di attesa indicato
+con \param{timeout} che farà abortire la funzione, qualora resti bloccata
+troppo a lungo nell'esecuzione delle operazioni richieste, con un errore di
+\errcode{EAGAIN}.
+
+In caso di successo (sia per \func{semop} che per \func{semtimedop}) per ogni
+semaforo modificato verrà aggiornato il campo \var{sempid} al valore del
+\ids{PID} del processo chiamante; inoltre verranno pure aggiornati al tempo
+corrente i campi \var{sem\_otime} e \var{sem\_ctime}.
+
+Dato che, come già accennato in precedenza, in caso di uscita inaspettata i
+semafori possono restare occupati, abbiamo visto come \func{semop} (e
+\func{semtimedop}) permetta di attivare un meccanismo di ripristino attraverso
+l'uso del flag \const{SEM\_UNDO}. Il meccanismo è implementato tramite una
+apposita struttura \kstruct{sem\_undo}, associata ad ogni processo per ciascun
+semaforo che esso ha modificato; all'uscita i semafori modificati vengono
+ripristinati, e le strutture disallocate. Per mantenere coerente il
+comportamento queste 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).
+
+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 fig.~\ref{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 \textit{SysV-IPC} è stata modificata, ma le definizioni relative
+a queste strutture restano per compatibilità (in particolare con le vecchie
+versioni delle librerie del C, come le \acr{libc5}).
+
+\begin{figure}[!htb]
+ \centering \includegraphics[width=12cm]{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
+\struct{semid\_ds} ed il relativo vettore di strutture \struct{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 \kstruct{sem\_queue} che viene aggiunta in fondo
+alla coda di attesa associata a ciascun insieme di semafori, 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
+\itindex{scheduler} \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
+attesa (a partire da \var{sem\_pending}) per verificare se qualcuna delle
+operazioni sospese in precedenza può essere eseguita, nel qual caso la
+struttura \kstruct{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 \kstruct{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 (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, attraverso il
+campo \var{semundo} di \kstruct{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
+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
+in questione, contenuto nel file \file{Mutex.c} allegato ai sorgenti, è
+riportato in fig.~\ref{fig:ipc_mutex_create}. Utilizzeremo l'interfaccia per
+creare un insieme contenente un singolo semaforo, per il quale poi useremo un
+valore unitario per segnalare la disponibilità della risorsa, ed un valore
+nullo per segnalarne l'indisponibilità.
+
+\begin{figure}[!htbp]
+ \footnotesize \centering
+ \begin{minipage}[c]{\codesamplewidth}
+ \includecodesample{listati/Mutex.c}
+ \end{minipage}
+ \normalsize
+ \caption{Il codice delle funzioni che permettono di creare o recuperare
+ l'identificatore di un semaforo da utilizzare come \textit{mutex}.}
+ \label{fig:ipc_mutex_create}
+\end{figure}
+
+La prima funzione (\texttt{\small 2--15}) è \func{MutexCreate} che data una
+chiave crea il semaforo usato per il mutex e lo inizializza, restituendone
+l'identificatore. Il primo passo (\texttt{\small 6}) è chiamare \func{semget}
+con \const{IPC\_CREATE} per creare il semaforo qualora non esista,
+assegnandogli i privilegi di lettura e scrittura per tutti. In caso di errore
+(\texttt{\small 7--9}) si ritorna subito il risultato di \func{semget},
+altrimenti (\texttt{\small 10}) si inizializza il semaforo chiamando
+\func{semctl} con il comando \const{SETVAL}, utilizzando l'unione
+\struct{semunion} dichiarata ed avvalorata in precedenza (\texttt{\small 4})
+ad 1 per significare che risorsa è libera. In caso di errore (\texttt{\small
+ 11--13}) si restituisce il valore di ritorno di \func{semctl}, altrimenti
+(\texttt{\small 14}) si ritorna l'identificatore del semaforo.
+
+La seconda funzione (\texttt{\small 17--20}) è \func{MutexFind}, che, data una
+chiave, restituisce l'identificatore del semaforo ad essa associato. La
+comprensione del suo funzionamento è immediata in quanto essa è soltanto un
+\textit{wrapper}\footnote{si chiama così una funzione usata per fare da
+ \textsl{involucro} alla chiamata di un altra, usata in genere per
+ semplificare un'interfaccia (come in questo caso) o per utilizzare con la
+ stessa funzione diversi substrati (librerie, ecc.) che possono fornire le
+ stesse funzionalità.} di una chiamata a \func{semget} per cercare
+l'identificatore associato alla chiave, il valore di ritorno di quest'ultima
+viene passato all'indietro al chiamante.
+
+La terza funzione (\texttt{\small 22--25}) è \func{MutexRead} che, dato un
+identificatore, restituisce il valore del semaforo associato al mutex. Anche
+in questo caso la funzione è un \textit{wrapper} per una chiamata a
+\func{semctl} con il comando \const{GETVAL}, che permette di restituire il
+valore del semaforo.
+
+La quarta e la quinta funzione (\texttt{\small 36--44}) sono \func{MutexLock},
+e \func{MutexUnlock}, che permettono rispettivamente di bloccare e sbloccare
+il mutex. Entrambe fanno da wrapper per \func{semop}, utilizzando le due
+strutture \var{sem\_lock} e \var{sem\_unlock} definite in precedenza
+(\texttt{\small 27--34}). Si noti come per queste ultime si sia fatto uso
+dell'opzione \const{SEM\_UNDO} per evitare che il semaforo resti bloccato in
+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
+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
+chiamata a \func{semop} si bloccherà fintanto che la risorsa non venga
+rilasciata. Chiamando \func{MutexUnlock} il valore del semaforo sarà
+incrementato di uno, sbloccandolo qualora fosse bloccato.
+
+Si noti che occorre eseguire sempre prima \func{MutexLock} e poi
+\func{MutexUnlock}, perché se per un qualche errore si esegue più volte
+quest'ultima il valore del semaforo crescerebbe oltre 1, e \func{MutexLock}
+non avrebbe più l'effetto aspettato (bloccare la risorsa quando questa è
+considerata libera). Infine si tenga presente che usare \func{MutexRead} per
+controllare il valore dei mutex prima di proseguire in una operazione di
+sblocco non servirebbe comunque, dato che l'operazione non sarebbe atomica.
+Vedremo in sez.~\ref{sec:ipc_lock_file} come sia possibile ottenere
+un'interfaccia analoga a quella appena illustrata, senza incorrere in questi
+problemi, usando il \itindex{file~locking} \textit{file locking}.
+
+
+\subsection{Memoria condivisa}
+\label{sec:ipc_sysv_shm}
+
+Il terzo oggetto introdotto dal \textit{SysV-IPC} è quello dei segmenti di
+memoria condivisa. La funzione di sistema che permette di ottenerne uno è
+\funcd{shmget}, ed il suo prototipo è:
+
+\begin{funcproto}{
+\fhead{sys/types.h}
+\fhead{sys/ipc.h}
+\fhead{sys/shm.h}
+\fdecl{int shmget(key\_t key, int size, int flag)}
+\fdesc{Ottiene o crea una memoria condivisa.}
+}
+
+{La funzione ritorna l'identificatore (un intero positivo) in caso di successo
+ e $-1$ per un errore, nel qual caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{ENOSPC}] si è superato il limite (\const{SHMMNI}) sul numero
+ di segmenti di memoria nel sistema, o cercato di allocare un segmento le
+ cui dimensioni fanno superare il limite di sistema (\const{SHMALL}) per
+ la memoria ad essi riservata.
+ \item[\errcode{EINVAL}] si è richiesta una dimensione per un nuovo segmento
+ maggiore di \const{SHMMAX} o minore di \const{SHMMIN}, o se il segmento
+ già esiste \param{size} è maggiore delle sue dimensioni.
+ \item[\errcode{ENOMEM}] il sistema non ha abbastanza memoria per poter
+ contenere le strutture per un nuovo segmento di memoria condivisa.
+ \item[\errcode{ENOMEM}] si è specificato \const{IPC\_HUGETLB} ma non si
+ hanno i privilegi di amministratore.
+ \end{errlist}
+ ed inoltre \errval{EACCES}, \errval{ENOENT}, \errval{EEXIST},
+ \errval{EIDRM}, con lo stesso significato che hanno per \func{msgget}.}
+\end{funcproto}
+
+
+La funzione, come \func{semget}, è analoga a \func{msgget}, ed identico è
+l'uso degli argomenti \param{key} e \param{flag} per cui non ripeteremo quanto
+detto al proposito in sez.~\ref{sec:ipc_sysv_mq}. A partire dal kernel 2.6
+però sono stati introdotti degli ulteriori bit di controllo per
+l'argomento \param{flag}, specifici di \func{shmget}, attinenti alle modalità
+di gestione del segmento di memoria condivisa in relazione al sistema della
+memoria virtuale.
+
+Il primo dei due flag è \const{SHM\_HUGETLB} che consente di richiedere la
+creazione del segmento usando una \itindex{huge~page} \textit{huge page}, le
+pagine di memoria di grandi dimensioni introdotte con il kernel 2.6 per
+ottimizzare le prestazioni nei sistemi più recenti che hanno grandi quantità
+di memoria. L'operazione è privilegiata e richiede che il processo abbia la
+\itindex{capability} \textit{capability} \const{CAP\_IPC\_LOCK}. Questa
+funzionalità è specifica di Linux e non è portabile.
+
+Il secondo flag aggiuntivo, introdotto a partire dal kernel 2.6.15, è
+\const{SHM\_NORESERVE}, ed ha lo stesso scopo del flag \const{MAP\_NORESERVE}
+di \func{mmap} (vedi sez.~\ref{sec:file_memory_map}): non vengono riservate
+delle pagine di swap ad uso del meccanismo del \textit{copy on write}
+\itindex{copy~on~write} per mantenere le modifiche fatte sul segmento. Questo
+significa che caso di scrittura sul segmento quando non c'è più memoria
+disponibile, si avrà l'emissione di un \signal{SIGSEGV}.
+
+Infine l'argomento \param{size} specifica la dimensione del segmento di
+memoria condivisa; il valore deve essere specificato in byte, ma verrà
+comunque arrotondato al multiplo superiore di \const{PAGE\_SIZE}. Il valore
+deve essere specificato quando si crea un nuovo segmento di memoria con
+\const{IPC\_CREAT} o \const{IPC\_PRIVATE}, se invece si accede ad un segmento
+di memoria condivisa esistente non può essere maggiore del valore con cui esso
+è stato creato.
+
+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 insieme a dei semafori.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{0.80\textwidth}
+ \includestruct{listati/shmid_ds.h}
+ \end{minipage}
+ \normalsize
+ \caption{La struttura \structd{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
+\struct{shmid\_ds}, riportata in fig.~\ref{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
+sez.~\ref{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\_dtime}, che esprimono
+ 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 \ids{PID} del processo che ha
+ eseguito l'ultima operazione, viene inizializzato a zero.
+\item il campo \var{shm\_cpid}, che esprime il \ids{PID} del processo che ha
+ creato il segmento, viene inizializzato al \ids{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 imposti dal sistema. Alcuni
+di questi limiti sono al solito accessibili e modificabili attraverso
+\func{sysctl} o scrivendo direttamente nei rispettivi file di
+\file{/proc/sys/kernel/}.
+
+In tab.~\ref{tab:ipc_shm_limits} si sono riportate le
+costanti simboliche associate a ciascuno di essi, il loro significato, i
+valori preimpostati, e, quando presente, il file in \file{/proc/sys/kernel/}
+che permettono di cambiarne il valore.
+
+
+\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
+ \const{SHMALL}& 0x200000&\sysctlrelfile{kernel}{shmall}
+ & Numero massimo di pagine che
+ possono essere usate per i segmenti di
+ memoria condivisa.\\
+ \const{SHMMAX}&0x2000000&\sysctlrelfile{kernel}{shmmax}
+ & Dimensione massima di un segmento di memoria
+ condivisa.\\
+ \const{SHMMNI}& 4096&\sysctlrelfile{kernel}{msgmni}
+ & Numero massimo di segmenti di memoria condivisa
+ presenti nel kernel.\\
+ \const{SHMMIN}& 1& --- & Dimensione minima di un segmento di
+ memoria condivisa.\\
+ \const{SHMLBA}&\const{PAGE\_SIZE}&--- & Limite inferiore per le dimensioni
+ minime di un segmento (deve essere
+ allineato alle dimensioni di una
+ pagina di memoria).\\
+ \const{SHMSEG}& --- & --- & Numero massimo di segmenti di
+ memoria condivisa per ciascun
+ processo (l'implementazione non
+ prevede l'esistenza di questo
+ limite).\\
+
+
+ \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 di sistema che permette di effettuare le operazioni di
+controllo su un segmento di memoria condivisa è \funcd{shmctl}; il suo
+prototipo è:
+
+\begin{funcproto}{
+\fhead{sys/ipc.h}
+\fhead{sys/shm.h}
+\fdecl{int shmctl(int shmid, int cmd, struct shmid\_ds *buf)}
+
+\fdesc{Esegue le operazioni di controllo su un segmento di memoria condivisa.}
+}
+
+{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual
+ caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EACCES}] si è richiesto \const{IPC\_STAT} ma i permessi non
+ consentono l'accesso in lettura al segmento.
+ \item[\errcode{EFAULT}] l'indirizzo specificato con \param{buf} non è
+ valido.
+ \item[\errcode{EIDRM}] l'argomento \param{shmid} fa riferimento ad un
+ segmento che è stato cancellato.
+ \item[\errcode{EINVAL}] o \param{shmid} non è un identificatore valido o
+ \param{cmd} non è un comando valido.
+ \item[\errcode{ENOMEM}] si è richiesto un \textit{memory lock} di
+ dimensioni superiori al massimo consentito.
+ \item[\errcode{EOVERFLOW}] si è tentato il comando \const{IPC\_STAT} ma il
+ valore del \ids{GID} o dell'\ids{UID} è troppo grande per essere
+ memorizzato nella struttura puntata da \param{buf}.
+ \item[\errcode{EPERM}] si è specificato un comando con \const{IPC\_SET} o
+ \const{IPC\_RMID} senza i permessi necessari.
+ \end{errlist}
+}
+\end{funcproto}
+
+Il comando specificato attraverso l'argomento \param{cmd} determina i diversi
+effetti della funzione. Nello standard POSIX.1-2001 i valori che esso può
+assumere, ed il 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
+ condivisa nella struttura \struct{shmid\_ds} puntata da \param{buf}. Occorre
+ che il processo chiamante abbia il permesso di lettura sulla segmento.
+\item[\const{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 \ids{UID} effettivo corrispondente o al
+ creatore del segmento, o al proprietario del segmento, o all'amministratore.
+\item[\const{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 del segmento, oppure l'amministratore. Compiuta l'operazione
+ aggiorna anche il valore del campo \var{shm\_ctime}.
+\end{basedescript}
+
+Oltre ai precedenti su Linux sono definiti anche degli ulteriori comandi, che
+consentono di estendere le funzionalità, ovviamente non devono essere usati se
+si ha a cuore la portabilità. Questi comandi aggiuntivi sono:
+
+\begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}}
+\item[\const{SHM\_LOCK}] Abilita il \itindex{memory~locking} \textit{memory
+ locking} sul segmento di memoria condivisa, impedendo che la memoria usata
+ per il segmento venga salvata su disco dal meccanismo della
+ \index{memoria~virtuale} memoria virtuale. Come illustrato in
+ sez.~\ref{sec:proc_mem_lock} fino al kernel 2.6.9 solo l'amministratore
+ poteva utilizzare questa capacità,\footnote{che richiedeva la
+ \textit{capability} \const{CAP\_IPC\_LOCK}.} a partire dal dal kernel
+ 2.6.10 anche gli utenti normali possono farlo fino al limite massimo
+ determinato da \const{RLIMIT\_MEMLOCK} (vedi
+ sez.~\ref{sec:sys_resource_limit}).
+\item[\const{SHM\_UNLOCK}] Disabilita il \itindex{memory~locking}
+ \textit{memory locking} sul segmento di memoria condivisa. Fino al kernel
+ 2.6.9 solo l'amministratore poteva utilizzare questo comando in
+ corrispondenza di un segmento da lui bloccato.
+\end{basedescript}
+
+A questi due, come per \func{msgctl} e \func{semctl}, si aggiungono tre
+ulteriori valori, \const{IPC\_INFO}, \const{MSG\_STAT} e \const{MSG\_INFO},
+introdotti ad uso del programma \cmd{ipcs} per ottenere le informazioni
+generali relative alle risorse usate dai segmenti di memoria condivisa. Dato
+che potranno essere modificati o rimossi in favore dell'uso di \texttt{/proc},
+non devono essere usati e non li tratteremo.
+
+L'argomento \param{buf} viene utilizzato solo con i comandi \const{IPC\_STAT}
+e \const{IPC\_SET} nel qual caso esso dovrà puntare ad una struttura
+\struct{shmid\_ds} precedentemente allocata, in cui nel primo caso saranno
+scritti i dati del segmento di memoria restituiti dalla funzione e da cui, nel
+secondo caso, verranno letti i dati da impostare sul segmento.
+
+Una volta che lo si è creato, per utilizzare un segmento di memoria condivisa
+l'interfaccia prevede due funzioni, \funcd{shmat} e \func{shmdt}. La prima di
+queste serve ad agganciare un segmento al processo chiamante, in modo che
+quest'ultimo possa inserirlo nel suo spazio di indirizzi per potervi accedere;
+il suo prototipo è:
+
+\begin{funcproto}{
+\fhead{sys/types.h}
+\fhead{sys/shm.h}
+\fdecl{void *shmat(int shmid, const void *shmaddr, int shmflg)}
+
+\fdesc{Aggancia un segmento di memoria condivisa al processo chiamante.}
+}
+
+{La funzione ritorna l'indirizzo del segmento in caso di successo e $-1$ (in
+ un cast a \type{void *}) per un errore, nel qual caso \var{errno} assumerà
+ uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EACCES}] il processo non ha i privilegi per accedere al
+ segmento nella modalità richiesta.
+ \item[\errcode{EINVAL}] si è specificato un identificatore invalido per
+ \param{shmid}, o un indirizzo non allineato sul confine di una pagina
+ per \param{shmaddr} o il valore \val{NULL} indicando \const{SHM\_REMAP}.
+ \end{errlist}
+ ed inoltre \errval{ENOMEM} nel suo significato generico.
+}
+\end{funcproto}
+
+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
+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_alloc}) 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 \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 alla \acr{glibc} il tipo di
+ \param{shmaddr} è divenuto un \ctyp{const void *} e quello del valore di
+ ritorno un \ctyp{void *} seguendo POSIX.1-2001.} deve essere associato il
+segmento, se il valore specificato è \val{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 \const{SHMLBA}, che in Linux è sempre uguale
+\const{PAGE\_SIZE}.
+
+Si tenga presente però che quando si usa \val{NULL} come valore di
+\param{shmaddr}, l'indirizzo restituito da \func{shmat} può cambiare da
+processo a processo; pertanto se nell'area di memoria condivisa si salvano
+anche degli indirizzi, si deve avere cura di usare valori relativi (in genere
+riferiti all'indirizzo di partenza del segmento).
+
+L'argomento \param{shmflg} permette di cambiare il comportamento della
+funzione; esso va specificato come maschera binaria, i bit utilizzati al
+momento sono sono tre e sono identificati dalle costanti \const{SHM\_RND},
+\const{SHM\_RDONLY} e \const{SHM\_REMAP} che vanno combinate con un OR
+aritmetico.
+
+Specificando \const{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 \const{SHMLBA}; il nome della
+costante sta infatti per \textit{rounded}, e serve per specificare un
+indirizzo come arrotondamento.
+
+L'uso di \const{SHM\_RDONLY} 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
+\itindex{segment~violation} violazione di accesso con l'emissione di un
+segnale di \signal{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.
+
+Infine \const{SHM\_REMAP} è una estensione specifica di Linux (quindi non
+portabile) che indica che la mappatura del segmento deve rimpiazzare ogni
+precedente mappatura esistente nell'intervallo iniziante
+all'indirizzo \param{shmaddr} e di dimensione pari alla lunghezza del
+segmento. In condizioni normali questo tipo di richiesta fallirebbe con un
+errore di \errval{EINVAL}. Ovviamente usando \const{SHM\_REMAP}
+l'argomento \param{shmaddr} non può essere nullo.
+
+In caso di successo la funzione \func{shmat} aggiorna anche i seguenti campi
+della struttura \struct{shmid\_ds}:
+\begin{itemize*}
+\item il tempo \var{shm\_atime} dell'ultima operazione di aggancio viene
+ impostato al tempo corrente.
+\item il \ids{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 sez.~\ref{sec:proc_fork} un segmento di memoria condivisa
+agganciato ad un processo 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 con uno spazio di indirizzi completamente
+diverso, tutti i segmenti agganciati al processo originario vengono
+automaticamente sganciati. Lo stesso avviene all'uscita del processo
+attraverso una \func{exit}.
+
+Una volta che un segmento di memoria condivisa non serve più, si può
+sganciarlo esplicitamente dal processo usando l'altra funzione
+dell'interfaccia, \funcd{shmdt}, il cui prototipo è:
+
+\begin{funcproto}{
+\fhead{sys/types.h}
+\fhead{sys/shm.h}
+\fdecl{int shmdt(const void *shmaddr)}
+
+\fdesc{Sgancia dal processo un segmento di memoria condivisa.}
+}
+
+{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, la funzione
+ fallisce solo quando non c'è un segmento agganciato
+ all'indirizzo \param{shmaddr}, con \var{errno} che assume il valore
+ \errval{EINVAL}.
+}
+\end{funcproto}
+
+La funzione sgancia dallo spazio degli indirizzi del processo un segmento di
+memoria condivisa; questo viene identificato con l'indirizzo \param{shmaddr}
+restituito dalla precedente chiamata a \func{shmat} con il quale era stato
+agganciato al processo.
+
+In caso di successo la funzione aggiorna anche i seguenti campi di
+\struct{shmid\_ds}: