cioè \var{message} è una propria struttura che si passa alla funzione,
\param{msgsz} dovrà essere uguale a \code{sizeof(message)-sizeof(long)}, (se
consideriamo il caso dell'esempio in \figref{fig:ipc_msbuf}, \param{msgsz}
-dovrà essere pari a \macro{LENGHT}).
+dovrà essere pari a \macro{LENGTH}).
\begin{figure}[!htb]
\footnotesize \centering
La funzione legge un messaggio dalla coda specificata scrivendolo nel buffer
indicato da \param{msgp}, che avrà un formato analogo a quello di
\figref{fig:ipc_msbuf}. L'argomento \param{msgsz} indica la lunghezza massima
-del testo del messaggio (equivalente al valore del parametro \macro{LENGHT}
+del testo del messaggio (equivalente al valore del parametro \macro{LENGTH}
nell'esempio di \figref{fig:ipc_msbuf}).
Se il testo del messaggio ha lunghezza inferiore a \param{msgsz} esso viene
Un semaforo è uno speciale contatore, mantenuto nel kernel, che permette, a
seconda del suo valore, di consentire o meno la prosecuzione dell'esecuzione
-del codice. 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.
+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
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.
+di altri due, ben più gravi, difetti.
-Il primo grave difetto è che non esiste una funzione che permetta di creare ed
+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.
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 deve essere una \var{union semun}, si è riportato la
-relativa definizione in \figref{fig:ipc_semun}.
+\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
\label{fig:ipc_semun}
\end{figure}
-Il comportamento della funzione, come il numero di parametri, dipende dal
-valore dell'argomento \param{cmd}, che specifica l'azione da intraprendere; i
-possibili valori legali per questo argomento sono:
+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
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 (il 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.
+ 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
- venga incrementato (il campo \var{semncnt} di \var{sem}); va invocata con
- tre argomenti. Occorre avere il permesso di lettura.
+ \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 (il 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 (il campo
- \var{semval} di \var{sem}); va invocata con tre argomenti. Occorre avere il
+ \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 diventi nullo (il campo \var{semncnt} di \var{sem}); va
- invocata con tre argomenti. Occorre avere il permesso di lettura.
+ 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
\end{basedescript}
Quando si imposta il valore di un semaforo (sia che lo si faccia per tutto
-l'insieme con \macro{SETALL}, che per uno solo 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.
+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|p{8cm}|}
+ \begin{tabular}[c]{|c|l|}
\hline
\textbf{Operazione} & \textbf{Valore restituito} \\
\hline
\end{table}
Il valore di ritorno della funzione in caso di successo dipende
-dall'operazione richiesta; in generale esso è nullo, a meno che non si sia
-specificata una delle operazioni riportate in
-\tabref{tab:ipc_semctl_returns}, nel qual caso viene restituito il
-corrispondente campo della struttura \var{sem}.
+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
\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 vengono passate 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, dato che le
+richieste di ripristino si accumulano attraverso diverse chiamate a
+\func{semop}, cosa succede se all'uscita del processo? Si deve porre il
+processo in stato di \textit{sleep} 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.
\subsection{Memoria condivisa}