In \figref{fig:ipc_mq_fortune_server} si è riportato un estratto delle parti
primcipali 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 sequanziale, 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 corriponde 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
\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
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 archietettura 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}
diventa necessario indicare esplicitamente che si vuole il ripristino del
semaforo all'uscita del processo.
+
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
\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}.
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
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, come le altre, 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
\label{fig:ipc_sem}
\end{figure}
-L'architettura dell'implementazione dei semafori è riportata in
-\figref{fig:ipc_sem_schema}. Si è presa come riferimento l'architettura
-usata fino al kernel 2.2.x (ed illustrata anche in \cite{tlk}) in quanto), che
-viene mantenuta per compatibilità anche nel 2.4.x.
-
-\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}
-
-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 mentenuti 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
\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 è:
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 creaa 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 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 le richieste di ripristino si accumulano attraverso diverse chiamate a
+\func{semop} per semafori diversi, si pone il problema di come viene eseguito
+il ripristino all'uscita del processo, 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}