+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 è:
+\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}
+
+La funzione permette di eseguire operazioni multiple sui singoli semafori di
+un insieme. La funzione richiede come primo argomento l'identificatore
+\param{semid} dell'insieme su cui si vuole operare. Il numero di operazioni da
+effettuare viene specificato con l'argomento \param{nsop}, mentre il loro
+contenuto viene passato con un puntatore ad un vettore di strutture
+\var{sembuf} nell'argomento \param{sops}. Le operazioni richieste vengono
+effettivamente eseguite se e soltanto se è possibile effettuarle tutte quante.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}[labelstep=0]{}
+struct sembuf
+{
+ unsigned short int sem_num; /* semaphore number */
+ short int sem_op; /* semaphore operation */
+ short int sem_flg; /* operation flag */
+};
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{La struttura \var{sembuf}, usata per le operazioni sui
+ semafori.}
+ \label{fig:ipc_sembuf}
+\end{figure}
+
+Il contenuto di ciascuna operazione deve essere specificato attraverso una
+opportuna struttura \var{sembuf} (la cui definizione è riportata in
+\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
+\var{sem\_num}.
+
+Il campo \var{sem\_flg} è un flag, mantenuto come maschera binaria, per il
+quale possono essere impostati i due valori \macro{IPC\_NOWAIT} e
+\macro{SEM\_UNDO}. Impostando \macro{IPC\_NOWAIT} si fa si che, invece di
+bloccarsi (in tutti quei casi in cui l'esecuzione di una operazione richiede
+che il processo vada in stato di \textit{sleep}), \func{semop} ritorni
+immediatamente con un errore di \macro{EAGAIN}. Impostando \macro{SEM\_UNDO}
+si richiede invece che l'operazione venga registrata in modo che il valore del
+semaforo possa essere ripristinato all'uscita del processo.
+
+Infine \var{sem\_op} è il campo che controlla l'operazione che viene eseguita
+e determina il comportamento della chiamata a \func{semop}; tre sono i casi
+possibili:
+\begin{basedescript}{\desclabelwidth{2.0cm}}
+\item[\var{sem\_op}$>0$] In questo caso il valore di \var{sem\_op} viene
+ aggiunto al valore corrente di \var{semval}. La funzione ritorna
+ immediatamente (con un errore di \macro{ERANGE} qualora si sia superato il
+ limite \macro{SEMVMX}) ed il processo non viene bloccato in nessun caso.
+ Specificando \macro{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'esecuzione procede
+ immediatamente. Se \var{semval} è diverso da zero il comportamento è
+ controllato da \var{sem\_flg}, se è stato impostato \macro{IPC\_NOWAIT} la
+ funzione ritorna con un errore di \macro{EAGAIN}, altrimenti viene
+ incrementato \var{semzcnt} di uno ed il processo resta in stato di
+ \textit{sleep} fintanto che non si ha una delle condizioni seguenti:
+ \begin{itemize*}
+ \item \var{semval} diventa zero, nel qual caso \var{semzcnt} viene
+ decrementato di uno.
+ \item l'insieme di semafori viene rimosso, nel qual caso \func{semop} ritorna
+ un errore di \macro{EIDRM}.
+ \item il processo chiamante riceve un segnale, nel qual caso \var{semzcnt}
+ viene decrementato di uno e \func{semop} ritorna un errore di
+ \macro{EINTR}.
+ \end{itemize*}
+ Al processo chiamante è richiesto 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 la funzione ritorna
+ immediatamente; qualora si sia impostato \macro{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 \macro{IPC\_NOWAIT} la funzione ritorna con un
+ errore di \macro{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 \macro{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
+ un errore di \macro{EIDRM}.
+ \item il processo chiamante riceve un segnale, nel qual caso \var{semncnt}
+ viene decrementato di uno e \func{semop} ritorna un errore di
+ \macro{EINTR}.
+ \end{itemize*}
+ Al processo chiamante è richiesto il privilegio di alterazione (scrittura)
+ sull'insieme di semafori.
+\end{basedescript}
+
+In caso di successo della funzione viene aggiornato di \var{sempid} per ogni
+semaforo modificato al valore del \acr{pid} del processo chiamante; inoltre
+vengono 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} permetta di
+attivare un meccanismo di ripristino attraverso l'uso del flag
+\macro{SEM\_UNDO}. Il meccanismo è implementato tramite una apposita struttura
+\var{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 \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 \textit{SysV 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.
+