X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=ipc.tex;h=6bb3836063151a4225ae1c543b38fbd041b621ba;hp=6ecd5b161ddb4e9888c93d8b49a4885e941dd77e;hb=34f320bccbbb744f178061b94e3a7197c35edd28;hpb=e7c1eaebbc012ee182a8d82fc75968969549821d diff --git a/ipc.tex b/ipc.tex index 6ecd5b1..6bb3836 100644 --- a/ipc.tex +++ b/ipc.tex @@ -1314,8 +1314,10 @@ invece: \item i campi \var{msg\_stime} e \var{msg\_rtime}, che esprimono rispettivamente il tempo in cui è stato inviato o ricevuto l'ultimo messaggio sulla coda, sono inizializzati a 0. -\item il campo \var{msg\_ctime} viene inizializzato al tempo corrente. -\item il campo \var{msg\_qbytes} viene inizializzato al valore preimpostato +\item il campo \var{msg\_ctime}, che esprime il tempo di creazione della coda, + viene inizializzato al tempo corrente. +\item il campo \var{msg\_qbytes} che esprime la dimensione massima del + contenuto della coda (in byte) viene inizializzato al valore preimpostato del sistema (\macro{MSGMNB}). \item i campi \var{msg\_first} e \var{msg\_last} che esprimono l'indirizzo del primo e ultimo messaggio sono inizializzati a \macro{NULL} e @@ -1342,7 +1344,7 @@ prototipo \begin{errlist} \item[\macro{EACCES}] Si è richiesto \macro{IPC\_STAT} ma processo chiamante non ha i privilegi di lettura sulla coda. - \item[\macro{EIDRM}] La coda richiesta è marcata per essere cancellata. + \item[\macro{EIDRM}] La coda richiesta è stata cancellata. \item[\macro{EPERM}] Si è richiesto \macro{IPC\_SET} o \macro{IPC\_RMID} ma il processo non ha i privilegi, o si è richiesto di aumentare il valore di \var{msg\_qbytes} oltre il limite \macro{MSGMNB} senza essere @@ -1366,7 +1368,7 @@ eseguire; i valori possibili sono: riceveranno un errore di \macro{EIDRM}, e tutti processi in attesa su funzioni di di lettura o di scrittura sulla coda saranno svegliati ricevendo il medesimo errore. Questo comando può essere eseguito solo da un processo - con userid effettivo corrispondente al creatore a o al proprietario della + con userid effettivo corrispondente al creatore o al proprietario della coda, o all'amministratore. \item[\macro{IPC\_SET}] Permette di modificare i permessi ed il proprietario della coda, ed il limite massimo sulle dimensioni del totale dei messaggi in @@ -1413,10 +1415,10 @@ La funzione inserisce il messaggio sulla coda specificata da \param{msqid}; il messaggio ha lunghezza specificata da \param{msgsz} ed è passato attraverso l'argomento \param{msgp}. Quest'ultimo deve venire passato sempre in una forma che corrisponda alla struttura \var{msgbuf} riportata in -\figref{fig:ipc_msbug}. La dimensione massima per il testo di un messaggio +\figref{fig:ipc_msbuf}. La dimensione massima per il testo di un messaggio non può comunque superare il limite \macro{MSGMAX}. -La struttura di \figref{fig:ipc_msbug} comunque è solo un modello, tanto che +La struttura di \figref{fig:ipc_msbuf} comunque è solo un modello, tanto che la definizione contenuta in \file{sys/msg.h} usa esplicitamente per il secondo campo il valore \code{mtext[1]}, che non è di nessuna utilità ai fini pratici. La sola cosa che conta è che abbia come primo membro un campo \var{mtype}, @@ -1426,7 +1428,7 @@ invece pu del messaggio. In generale pertanto per inviare un messaggio con \func{msgsnd} si usa -ridefinire una struttura simile a quella di \figref{fig:ipc_msbug}, adattando +ridefinire una struttura simile a quella di \figref{fig:ipc_msbuf}, adattando alle proprie esigenze il campo \var{mtype}, (o ridefinendo come si vuole il corpo del messaggio, anche con più campi o con strutture più complesse) avendo però la cura di mantenere nel primo campo un valore di tipo \ctyp{long} che ne @@ -1436,7 +1438,7 @@ Si tenga presente che la lunghezza che deve essere indicata in questo argomento è solo quella del messaggio, non quella di tutta la struttura, se 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_msbug}, \param{msgsz} +consideriamo il caso dell'esempio in \figref{fig:ipc_msbuf}, \param{msgsz} dovrà essere pari a \macro{LENGHT}). \begin{figure}[!htb] @@ -1450,14 +1452,14 @@ dovr \end{lstlisting} \end{minipage} \normalsize - \caption{Schema della struttura \var{msgbug}, da utilizzare come argomento + \caption{Schema della struttura \var{msgbuf}, da utilizzare come argomento per inviare/ricevere messaggi.} - \label{fig:ipc_msbug} + \label{fig:ipc_msbuf} \end{figure} Per capire meglio il funzionamento della funzione riprendiamo in considerazione la struttura della coda illustrata in -\secref{fig:ipc_mq_schema}. Alla chiamata di \func{msgsnd} il nuovo messaggio +\figref{fig:ipc_mq_schema}. Alla chiamata di \func{msgsnd} il nuovo messaggio sarà aggiunto in fondo alla lista inserendo una nuova struttura \var{msg}, il puntatore \var{msg\_last} di \var{msqid\_ds} verrà aggiornato, come pure il puntatore al messaggio successivo per quello che era il precedente ultimo @@ -1523,9 +1525,9 @@ rimosso dalla stessa) 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_msbug}. L'argomento \param{msgsz} indica la lunghezza massima +\figref{fig:ipc_msbuf}. L'argomento \param{msgsz} indica la lunghezza massima del testo del messaggio (equivalente al valore del parametro \macro{LENGHT} -nell'esempio di \figref{fig:ipc_msbug}). +nell'esempio di \figref{fig:ipc_msbuf}). Se il testo del messaggio ha lunghezza inferiore a \param{msgsz} esso viene rimosso dalla coda; in caso contrario, se \param{msgflg} è impostato a @@ -1585,11 +1587,49 @@ il tipo di messaggio, per restituire indietro le frasi ai client. \subsection{Semafori} \label{sec:ipc_sysv_sem} -Il secondo oggetto introdotto dal \textit{System V IPC} è quello dei semafori. -Un semaforo è uno speciale contatore che permette di controllare l'accesso a -risorse condivise. La funzione che permette di creare o ottenere -l'identificatore di un insieme di semafori è \func{semget}, ed il suo prototipo -è: +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 +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. + +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} @@ -1604,19 +1644,60 @@ l'identificatore di un insieme di semafori valori visti per \func{msgget}.} \end{functions} -La funzione è del tutto analoga a \func{msgget} ed 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 qualora se ne richieda la -creazione, e deve essere nullo quando si effettua una richiesta -dell'identificatore di un insieme già esistente. +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 grave 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 esegure 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 +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}, per -quanto riguarda gli altri campi invece: +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}. @@ -1626,43 +1707,203 @@ quanto riguarda gli altri campi invece: effettuata, viene inizializzato a zero. \end{itemize*} +Ciascun semaforo dell'isnsieme è 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 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 */ +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{semid\_ds}, associata a ciascun insieme di - semafori.} - \label{fig:ipc_semid_sd} + \caption{La struttura \var{sem}, che contiene i dati di un signolo 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|l|l|} + \begin{tabular}[c]{|c|r|p{8cm}|} \hline \textbf{Costante} & \textbf{Valore} & \textbf{Significato} \\ \hline \hline - \macro{SEMMNI}& 16& Numero massimo di insiemi di semafori. \\ - \macro{SEMMAX}& 8192& .\\ - \macro{SEMMNB}&16384& .\\ + \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.} + 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} viene settata a: + \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 sigolo 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}. + +\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} + +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: +\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 (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. +\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. +\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 + 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. +\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 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. + + + +\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} +