+\label{sec:ipc_sysv_sem}
+
+I semafori non sono meccanismi di intercomunicazione diretta come quelli
+(pipe, fifo e code di messaggi) visti finora, e non consentono di scambiare
+dati fra processi, ma servono piuttosto come meccanismi di sincronizzazione o
+di protezione per le \textsl{sezioni critiche}\index{sezioni critiche} del
+codice (si ricordi quanto detto in \secref{sec:proc_race_cond}).
+
+Un semaforo è uno speciale contatore, mantenuto nel kernel, che permette, a
+seconda del suo valore, di consentire o meno la prosecuzione dell'esecuzione
+di un programma. In questo modo l'accesso ad una risorsa condivisa da più
+processi può essere controllato, associando ad essa un semaforo che consente
+di assicurare che non più di un processo alla volta possa usarla.
+
+Il concetto di semaforo è uno dei concetti base nella programmazione ed è
+assolutamente generico, così come del tutto generali sono modalità con cui lo
+si utilizza. Un processo che deve accedere ad una risorsa eseguirà un
+controllo del semaforo: se questo è positivo il suo valore sarà decrementato,
+indicando che si è consumato una unità della risorsa, ed il processo potrà
+proseguire nell'utilizzo di quest'ultima, provvedendo a rilasciarla, una volta
+completate le operazioni volute, reincrementando il semaforo.
+
+Se al momento del controllo il valore del semaforo è nullo, siamo invece in
+una situazione in cui la risorsa non è disponibile, ed il processo si
+bloccherà in stato di \textit{sleep} fin quando chi la sta utilizzando non la
+rilascerà, incrementando il valore del semaforo. Non appena il semaforo torna
+positivo, indicando che la risorsa è disponibile, il processo sarà svegliato,
+e si potrà operare come nel caso precedente (decremento del semaforo, accesso
+alla risorsa, incremento del semaforo).
+
+Per poter implementare questo tipo di logica le operazioni di controllo e
+decremento del contatore associato al semaforo devono essere atomiche,
+pertanto una realizzazione di un oggetto di questo tipo è necessariamente
+demandata al kernel. La forma più semplice di semaforo è quella del
+\textsl{semaforo binario}, o \textit{mutex}, in cui un valore diverso da zero
+(normalmente 1) indica la libertà di accesso, e un valore nullo l'occupazione
+della risorsa; in generale però si possono usare semafori con valori interi,
+utilizzando il valore del contatore come indicatore del ``numero di risorse''
+ancora disponibili.
+
+Il sistema di comunicazione interprocesso di System V IPC prevede anche i
+semafori, ma gli oggetti utilizzati non sono semafori singoli, ma gruppi di
+semafori detti \textsl{insiemi} (o \textit{semaphore set}); la funzione che
+permette di creare o ottenere l'identificatore di un insieme di semafori è
+\func{semget}, ed il suo prototipo è:
+\begin{functions}
+ \headdecl{sys/types.h}
+ \headdecl{sys/ipc.h}
+ \headdecl{sys/sem.h}
+
+ \funcdecl{int semget(key\_t key, int nsems, int flag)}
+
+ 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}.}
+\end{functions}
+
+La funzione è del tutto analoga a \func{msgget}, solo che in questo caso
+restituisce l'identificatore di un insieme di semafori, in particolare è
+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{nsems} permette di specificare quanti semafori deve contenere l'insieme
+quando se ne richieda la creazione, e deve essere nullo quando si effettua una
+richiesta dell'identificatore di un insieme già esistente.
+
+Purtroppo questa implementazione complica inutilmente lo schema elementare che
+abbiamo descritto, dato che non è possibile definire un singolo semaforo, ma
+se ne deve creare per forza un insieme. Ma questa in definitiva è solo una
+complicazione inutile, il problema è che i semafori del System V IPC soffrono
+di altri due, ben più gravi, difetti.
+
+Il primo difetto è che non esiste una funzione che permetta di creare ed
+inizializzare un semaforo in un'unica chiamata; occorre prima creare l'insieme
+dei semafori con \func{semget} e poi inizializzarlo con \func{semctl}, si
+perde così ogni possibilità di eseguire atomicamente questa operazione.
+
+Il secondo difetto deriva dalla caratteristica generale degli oggetti del
+System V IPC di essere risorse globali di sistema, che non vengono cancellate
+quando nessuno le usa più; ci si così a trova a dover affrontare
+esplicitamente il caso in cui un processo termina per un qualche errore,
+lasciando un semaforo occupato, che resterà tale fino al successivo riavvio
+del sistema. Come vedremo esistono delle modalità per evitare tutto ciò, ma
+diventa necessario indicare esplicitamente che si vuole il ripristino del
+semaforo all'uscita del processo.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}[labelstep=0]{}
+struct semid_ds
+{
+ struct ipc_perm sem_perm; /* operation permission struct */
+ time_t sem_otime; /* last semop() time */
+ time_t sem_ctime; /* last time changed by semctl() */
+ unsigned long int sem_nsems; /* number of semaphores in set */
+};
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{La struttura \var{semid\_ds}, associata a ciascun insieme di
+ semafori.}
+ \label{fig:ipc_semid_sd}
+\end{figure}
+
+A ciascun insieme di semafori è associata una struttura \var{semid\_ds},
+riportata in \figref{fig:ipc_semid_sd}. 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
+\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
+ realizzazione del System V IPC in Linux. In realtà questa struttura ormai è
+ 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.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}[labelstep=0]{}
+struct sem {
+ short sempid; /* pid of last operation */
+ ushort semval; /* current value */
+ ushort semncnt; /* num procs awaiting increase in semval */
+ ushort semzcnt; /* num procs awaiting semval = 0 */
+};
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{La struttura \var{sem}, che contiene i dati di un singolo semaforo.}
+ \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}.
+
+\begin{table}[htb]
+ \footnotesize
+ \centering
+ \begin{tabular}[c]{|c|r|p{8cm}|}
+ \hline
+ \textbf{Costante} & \textbf{Valore} & \textbf{Significato} \\
+ \hline
+ \hline
+ \macro{SEMMNI}& 128 & Numero massimo di insiemi di semafori. \\
+ \macro{SEMMSL}& 250 & Numero massimo di semafori per insieme.\\
+ \macro{SEMMNS}&\macro{SEMMNI}*\macro{SEMMSL}& Numero massimo di semafori
+ nel sistema .\\
+ \macro{SEMVMX}& 32767 & Massimo valore per un semaforo.\\
+ \macro{SEMOPM}& 32 & Massimo numero di operazioni per chiamata a
+ \func{semop}. \\
+ \macro{SEMMNU}&\macro{SEMMNS}& Massimo numero di strutture di ripristino.\\
+ \macro{SEMUME}&\macro{SEMOPM}& Massimo numero di voci di ripristino.\\
+ \macro{SEMAEM}&\macro{SEMVMX}& valore massimo per l'aggiustamento
+ all'uscita. \\
+ \hline
+ \end{tabular}
+ \caption{Valori delle costanti associate ai limiti degli insiemi di
+ semafori, definite in \file{linux/sem.h}.}
+ \label{tab:ipc_sem_limits}
+\end{table}
+
+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 è:
+\begin{functions}
+ \headdecl{sys/types.h}
+ \headdecl{sys/ipc.h}
+ \headdecl{sys/sem.h}
+
+ \funcdecl{int semctl(int semid, int semnum, int cmd)}
+ \funcdecl{int semctl(int semid, int semnum, int cmd, union semun arg)}
+
+ Esegue le operazioni di controllo su un semaforo o un insieme di semafori.
+
+ \bodydesc{La funzione restituisce in caso di successo un valore positivo
+ quanto usata con tre argomenti ed un valore nullo quando usata con
+ quattro. In caso di errore restituisce -1, ed \var{errno} assumerà uno dei
+ valori:
+ \begin{errlist}
+ \item[\macro{EACCES}] Il processo non ha i privilegi per eseguire
+ l'operazione richiesta.
+ \item[\macro{EIDRM}] L'insieme di semafori è stato cancellato.
+ \item[\macro{EPERM}] Si è richiesto \macro{IPC\_SET} o \macro{IPC\_RMID} ma
+ il processo non ha privilegi sufficienti ad eseguire l'operazione.
+ \item[\macro{ERANGE}] Si è richiesto \macro{SETALL} \macro{SETVAL} ma il
+ valore a cui si vuole impostare il semaforo è minore di zero o maggiore
+ di \macro{SEMVMX}.
+ \end{errlist}
+ ed inoltre \macro{EFAULT} ed \macro{EINVAL}.
+}
+\end{functions}
+
+La funzione può avere tre o quattro parametri, a seconda dell'operazione
+specificata con \param{cmd}, ed opera o sull'intero insieme specificato da
+\param{semid} o sul singolo semaforo di un insieme, specificato da
+\param{semnum}.
+
+Qualora la funzione operi con quattro argomenti \param{arg} è
+un argomento generico, che conterrà un dato diverso a seconda dell'azione
+richiesta; per unificare l'argomento esso deve essere passato come una
+\var{union semun}, la cui definizione, con i possibili valori che può
+assumere, è riportata in \figref{fig:ipc_semun}.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}[labelstep=0]{}
+union semun {
+ int val; /* value for SETVAL */
+ struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */
+ unsigned short *array; /* array for GETALL, SETALL */
+ /* Linux specific part: */
+ struct seminfo *__buf; /* buffer for IPC_INFO */
+};
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{La definizione dei possibili valori di una \var{union semun}, usata
+ come quarto argomento della funzione \func{semctl}.}
+ \label{fig:ipc_semun}
+\end{figure}
+
+Come già accennato sia il comportamento della funzione che il numero di
+parametri con cui deve essere invocata, dipendono dal valore dell'argomento
+\param{cmd}, che specifica l'azione da intraprendere; i valori validi (che
+cioè non causano un errore di \macro{EINVAL}) per questo argomento sono i
+seguenti:
+\begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}}
+\item[\macro{IPC\_STAT}] Legge i dati dell'insieme di semafori, copiando il
+ contenuto della relativa struttura \var{semid\_ds} all'indirizzo specificato
+ con \var{arg.buf}. Occorre avere il permesso di lettura. L'argomento
+ \param{semnum} viene ignorato.
+\item[\macro{IPC\_RMID}] Rimuove l'insieme di semafori e le relative strutture
+ dati, con effetto immediato. Tutti i processi che erano stato di
+ \textit{sleep} vengono svegliati, ritornando con un errore di \macro{EIDRM}.
+ L'userid effettivo del processo deve corrispondere o al creatore o al
+ proprietario dell'insieme, o all'amministratore. L'argomento \param{semnum}
+ viene ignorato.
+\item[\macro{IPC\_SET}] Permette di modificare i permessi ed il proprietario
+ dell'insieme. I valori devono essere passati in una struttura
+ \var{semid\_ds} puntata da \param{arg.buf} di cui saranno usati soltanto i
+ campi \var{sem\_perm.uid}, \var{sem\_perm.gid} e i nove bit meno
+ significativi di \var{sem\_perm.mode}. L'userid effettivo del processo deve
+ corrispondere o al creatore o al proprietario dell'insieme, o
+ all'amministratore. L'argomento \param{semnum} viene ignorato.
+\item[\macro{GETALL}] Restituisce il valore corrente di ciascun semaforo
+ dell'insieme (corrispondente al campo \var{semval} di \var{sem}) nel vettore
+ indicato da \param{arg.array}. Occorre avere il permesso di lettura.
+ L'argomento \param{semnum} viene ignorato.
+\item[\macro{GETNCNT}] Restituisce come valore di ritorno della funzione il
+ numero di processi in attesa che il semaforo \param{semnum} dell'insieme
+ \param{semid} venga incrementato (corrispondente al campo \var{semncnt} di
+ \var{sem}); va invocata con tre argomenti. Occorre avere il permesso di
+ lettura.
+\item[\macro{GETPID}] Restituisce come valore di ritorno della funzione il
+ \acr{pid} dell'ultimo processo che ha compiuto una operazione sul semaforo
+ \param{semnum} dell'insieme \param{semid} (corrispondente al campo
+ \var{sempid} di \var{sem}); va invocata con tre argomenti. Occorre avere il
+ permesso di lettura.
+\item[\macro{GETVAL}] Restituisce come valore di ritorno della funzione il il
+ valore corrente del semaforo \param{semnum} dell'insieme \param{semid}
+ (corrispondente al campo \var{semval} di \var{sem}); va invocata con tre
+ argomenti. Occorre avere il permesso di lettura.
+\item[\macro{GETZCNT}] Restituisce come valore di ritorno della funzione il
+ numero di processi in attesa che il valore del semaforo \param{semnum}
+ dell'insieme \param{semid} diventi nullo (corrispondente al campo
+ \var{semncnt} di \var{sem}); va invocata con tre argomenti. Occorre avere
+ il permesso di lettura.
+\item[\macro{SETALL}] Inizializza il valore di tutti i semafori dell'insieme,
+ aggiornando il campo \var{sem\_ctime} di \var{semid\_ds}. I valori devono
+ essere passati nel vettore indicato da \param{arg.array}. Si devono avere i
+ privilegi di scrittura sul semaforo. L'argomento \param{semnum} viene
+ ignorato.
+\item[\macro{SETVAL}] Inizializza il semaforo \param{semnum} al valore passato
+ dall'argomento \param{arg.val}, aggiornando il campo \var{sem\_ctime} di
+ \var{semid\_ds}. Si devono avere i privilegi di scrittura sul semaforo.
+\end{basedescript}
+
+Quando si imposta il valore di un semaforo (sia che lo si faccia per tutto
+l'insieme con \macro{SETALL}, che per un solo semaforo con \macro{SETVAL}), i
+processi in attesa su di esso reagiscono di conseguenza al cambiamento di
+valore. Inoltre la coda delle operazioni di ripristino viene cancellata per
+tutti i semafori il cui valore viene modificato.
+
+\begin{table}[htb]
+ \footnotesize
+ \centering
+ \begin{tabular}[c]{|c|l|}
+ \hline
+ \textbf{Operazione} & \textbf{Valore restituito} \\
+ \hline
+ \hline
+ \macro{GETNCNT}& valore di \var{semncnt}.\\
+ \macro{GETPID} & valore di \var{sempid}.\\
+ \macro{GETVAL} & valore di \var{semval}.\\
+ \macro{GETZCNT}& valore di \var{semzcnt}.\\
+ \hline
+ \end{tabular}
+ \caption{Valori di ritorno della funzione \func{semctl}.}
+ \label{tab:ipc_semctl_returns}
+\end{table}
+
+Il valore di ritorno della funzione in caso di successo dipende
+dall'operazione richiesta; per tutte le operazioni che richiedono quattro
+argomenti esso è sempre nullo, per le altre operazioni, elencate in
+\tabref{tab:ipc_semctl_returns} viene invece restituito il valore richiesto,
+corrispondente al campo della struttura \var{sem} indicato nella seconda
+colonna della tabella.
+
+Le operazioni ordinarie sui semafori, come l'acquisizione o il rilascio degli
+stessi (in sostanza tutte quelle non comprese nell'uso di \func{semctl})
+vengono effettuate con la funzione \func{semop}, il cui prototipo è:
+\begin{functions}
+ \headdecl{sys/types.h}
+ \headdecl{sys/ipc.h}
+ \headdecl{sys/sem.h}
+
+ \funcdecl{int semop(int semid, struct sembuf *sops, unsigned nsops)}
+
+ Esegue le operazioni ordinarie su un semaforo o un insieme di semafori.
+
+ \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
+ errore, nel qual caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\macro{EACCES}] Il processo non ha i privilegi per eseguire
+ l'operazione richiesta.
+ \item[\macro{EIDRM}] L'insieme di semafori è stato cancellato.
+ \item[\macro{ENOMEM}] Si è richiesto un \macro{SEM\_UNDO} ma il sistema
+ non ha le risorse per allocare la struttura di ripristino.
+ \item[\macro{EAGAIN}] Un'operazione comporterebbe il blocco del processo,
+ ma si è specificato \macro{IPC\_NOWAIT} in \var{sem\_flg}.
+ \item[\macro{EINTR}] La funzione, bloccata in attesa dell'esecuzione
+ dell'operazione, viene interrotta da un segnale.
+ \item[\macro{E2BIG}] L'argomento \param{nsops} è maggiore del numero
+ massimo di operazioni \macro{SEMOPM}.
+ \item[\macro{ERANGE}] Per alcune operazioni il valore risultante del
+ semaforo viene a superare il limite massimo \macro{SEMVMX}.
+ \end{errlist}
+ ed inoltre \macro{EFAULT} ed \macro{EINVAL}.
+}
+\end{functions}