X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=ipc.tex;h=a7cb5768702723fc39aeafb1b03b17e5da4ae6ca;hp=0637d4722a7bf91b71c319ea466b1d2be98f2259;hb=6725bff66b54efcaa3c054d0424721f0adb6396f;hpb=0e9d5d9643607c94e7faced765248ac4d223548f diff --git a/ipc.tex b/ipc.tex index 0637d47..a7cb576 100644 --- a/ipc.tex +++ b/ipc.tex @@ -124,7 +124,7 @@ consiste nell'inviare l'output di un processo (lo standard output) sull'input di un'altro. Realizzeremo il programma di esempio nella forma di un \textit{CGI}\footnote{Un CGI (\textit{Common Gateway Interface}) è un programma che permette la creazione dinamica di un oggetto da inserire - all'interno di una pagina HTML.} per apache, che genera una immagine JPEG + all'interno di una pagina HTML.} per Apache, che genera una immagine JPEG di un codice a barre, specificato come parametro di input. Un programma che deve essere eseguito come \textit{CGI} deve rispondere a @@ -558,7 +558,7 @@ leggerli, quando i dati inviati sono destinati a loro. Per risolvere questo problema, si può usare un'architettura come quella illustrata in \figref{fig:ipc_fifo_server_arch} in cui i client inviano le richieste al server su una fifo nota mentre le risposte vengono reinviate dal -server a ciascuno di essi su una fifo temporanea creata per l'occazione. +server a ciascuno di essi su una fifo temporanea creata per l'occasione. \begin{figure}[htb] \centering @@ -1229,11 +1229,11 @@ coda. messaggi. \\ \macro{MSGMAX}& 8192& \file{msgmax} & Dimensione massima di un singolo messaggio.\\ - \macro{MSGMNB}&16384& \file{msgmnb} & Dimensione massima di una coda di - messaggi.\\ + \macro{MSGMNB}&16384& \file{msgmnb} & Dimensione massima del contenuto di + una coda.\\ \hline \end{tabular} - \caption{Valori delle costanti associati ai limiti delle code di messaggi.} + \caption{Valori delle costanti associate ai limiti delle code di messaggi.} \label{tab:ipc_msg_limits} \end{table} @@ -1297,7 +1297,7 @@ riportato nella figura. In questa struttura il kernel\footnote{come accennato questo vale fino ai kernel della serie 2.2.x, essa viene usata nei kernel della serie 2.4.x solo per compatibilità in quanto è quella restituita dalle funzioni dell'interfaccia. In \figref{fig:ipc_msgid_sd} sono elencati i - campi significativi definiti in \file{sys/msg.h}, a cui si sono agguinti gli + campi significativi definiti in \file{sys/msg.h}, a cui si sono aggiunti gli ultimi tre campi che sono previsti dalla implementazione originale di System V, ma non dallo standard Unix98.} mantiene le principali informazioni riguardo lo stato corrente della coda. Quando si crea una nuova coda con @@ -1314,10 +1314,13 @@ 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 inizializzati al limite di sistema. +\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 messagio sono inizializzati a \macro{NULL} e + primo e ultimo messaggio sono inizializzati a \macro{NULL} e \var{msg\_cbytes}, che esprime la dimensione in byte dei messaggi presenti è inizializzato a zero. Questi campi sono ad uso interno dell'implementazione e non devono essere utilizzati da programmi in user space). @@ -1341,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 @@ -1356,7 +1359,7 @@ mantenuta all'indirizzo \param{buf}, per la coda specificata dall'identificatore \param{msqid}. Il comportamento della funzione dipende dal valore dell'argomento \param{cmd}, che specifica il tipo di azione da eseguire; i valori possibili sono: -\begin{basedescript}{\desclabelwidth{3cm}\desclabelstyle{\nextlinelabel}} +\begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}} \item[\macro{IPC\_STAT}] Legge le informazioni riguardo la coda nella struttura indicata da \param{buf}. Occorre avere il permesso di lettura sulla coda. @@ -1373,9 +1376,8 @@ eseguire; i valori possibili sono: struttura \var{msqid\_ds} puntata da \param{buf}. Per modificare i valori di \var{msg\_perm.mode}, \var{msg\_perm.uid} e \var{msg\_perm.gid} occorre essere il proprietario o il creatore della coda, oppure l'amministratore; lo - stesso vale per \var{msg\_qbytes}, con la restrizione che solo - l'amministratore può incrementarne il valore a limiti superiori a - \macro{MSGMNB}. + stesso vale per \var{msg\_qbytes}, ma l'amministratore ha la facoltà di + incrementarne il valore a limiti superiori a \macro{MSGMNB}. \end{basedescript} @@ -1413,22 +1415,31 @@ 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 struttura è solo un modello, la sola cosa che -conta è abbia come primo membro un campo \var{mtype}, come nell'esempio; esso -infatti serve ad identificare il tipo di messaggio e deve essere sempre -specificato come intero positivo. Il campo \var{mtext} invece può essere di -qualsiasi tipo e dimensione, e deve contenere il testo del messaggio. - -In generale pertanto occorrerà ridefinire una struttura analoga a quella di -\figref{fig:ipc_msbug}, adattando alle proprie esigenze il campo \var{mtype}, -e avendo cura di mantenere come primo campo un valore di tipo \ctyp{long}. Il -resto della struttura andrà a costituire il corpo del messaggio, la cui -dimensione deve essere specificata sempre attraverso \param{msgsz}. Si tenga -presente che la lunghezza che deve essere indicata in questo argomento è solo -quella del messaggio, non di tutta la struttura, se cioè \var{message} è la -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} dovrà essere pari a \macro{LENGHT}). +\figref{fig:ipc_msbug}. 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 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}, +come nell'esempio; esso infatti serve ad identificare il tipo di messaggio e +deve essere sempre specificato come intero positivo. Il campo \var{mtext} +invece può essere di qualsiasi tipo e dimensione, e deve contenere il testo +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 +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 +indica il tipo. + +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} +dovrà essere pari a \macro{LENGHT}). \begin{figure}[!htb] \footnotesize \centering @@ -1512,46 +1523,51 @@ rimosso dalla stessa) } \end{functions} -La funzione permette di estrarre un messaggio dalla coda e di scriverlo nel -buffer indicato da \param{msgp}, che deve puntare ad una struttura della forma -mostrata in \figref{fig:ipc_msbug}. 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}). +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 +del testo del messaggio (equivalente al valore del parametro \macro{LENGHT} +nell'esempio di \figref{fig:ipc_msbug}). Se il testo del messaggio ha lunghezza inferiore a \param{msgsz} esso viene -rimosso dalla coda, in caso contrario se \param{msgflg} è impostato a -\macro{MSG\_NOERROR} il messaggio viene troncato e la parte in eccesso viene +rimosso dalla coda; in caso contrario, se \param{msgflg} è impostato a +\macro{MSG\_NOERROR}, il messaggio viene troncato e la parte in eccesso viene perduta, altrimenti il messaggio non viene estratto e la funzione ritorna con un errore di \macro{E2BIG}. L'argomento \param{msgtyp} permette di restringere la ricerca ad un -sottoinsieme dei messaggi presenti sulla coda; in particolare: +sottoinsieme dei messaggi presenti sulla coda; la ricerca infatti è fatta con +una scansione della struttura mostrata in \figref{fig:ipc_mq_schema}, +restituendo il primo messaggio incontrato che corrisponde ai criteri +specificati (che quindi, visto che i messaggi vengono sempre inseriti dalla +coda, è quello meno recente); in particolare: \begin{itemize} \item se \param{msgtyp} è 0 viene estratto il messaggio in cima alla coda, cioè quello fra i presenti che è stato inserito inserito per primo. \item se \param{msgtyp} è positivo viene estratto il primo messaggio il cui - tipo (il valore del campo \var{mtype}) corrisponde a quanto specificato. -\item se \param{msgtyp} è negativo viene estratto il primo messaggio nella coda - con il tipo più basso, fra quelli di tipo inferiore al valore assoluto di - quanto specificato. + tipo (il valore del campo \var{mtype}) corrisponde al valore di + \param{msgtyp}. +\item se \param{msgtyp} è negativo viene estratto il primo fra i messaggi con + il tipo di valore più basso, fra tutti quelli con un tipo inferiore al + valore assoluto di \param{msgtyp}. \end{itemize} Il valore di \param{msgflg} permette di controllare il comportamento della -funzione, esso può assumere valore nullo o essere specificato come maschera -binaria di uno o più dei valori. Oltre al precedente \macro{MSG\_NOERROR}, si -può impostare il valore \macro{MSG\_EXCEPT}, che quando \param{msgtyp} è -positivo permette di leggere il primo messaggio nella coda con tipo diverso da -\param{msgtyp}, ed il valore \macro{IPC\_NOWAIT} che causa il ritorno -immediato della funzione quando non ci sono messaggi sulla coda. - -Il comportamento usuale della funzione infatti, quando non ci sono messaggi +funzione, esso può essere nullo o una maschera binaria composta da uno o più +valori. Oltre al precedente \macro{MSG\_NOERROR}, sono possibili altri due +valori: \macro{MSG\_EXCEPT}, che permette, quando \param{msgtyp} è positivo, +di leggere il primo messaggio nella coda con tipo diverso da \param{msgtyp}, e +\macro{IPC\_NOWAIT} che causa il ritorno immediato della funzione quando non +ci sono messaggi sulla coda. + +Il comportamento usuale della funzione infatti, se non ci sono messaggi disponibili per la lettura, è di bloccare il processo in stato di -\textit{sleep}; nel caso però si sia specificato \macro{IPC\_NOWAIT} la +\textit{sleep}. Nel caso però si sia specificato \macro{IPC\_NOWAIT} la funzione ritorna immediatamente con un errore \macro{ENOMSG}. Altrimenti la funzione ritorna normalmente non appena viene inserito un messaggio del tipo -desiderato, oppure ritorna con errore qualora la cosa sia rimossa (con un -\macro{EIDRM}) o se il processo viene interrotto da un segnale (con un -\macro{EINTR}). +desiderato, oppure ritorna con errore qualora la coda sia rimossa (con +\var{errno} settata a \macro{EIDRM}) o se il processo viene interrotto da un +segnale (con \var{errno} settata a \macro{EINTR}). Una volta completata con successo l'estrazione del messaggio dalla coda, la funzione aggiorna i dati mantenuti in \var{msqid\_ds}, in particolare vengono @@ -1563,8 +1579,10 @@ modificati: \item Il valore \var{msg\_rtime}, che viene impostato al tempo corrente. \end{itemize} - - +Come esempio dell'uso delle code di messaggi possiamo riscrivere il nostro +server di \textit{fortunes} usando queste al posto delle fifo. In questo caso +useremo una coda di messaggi, usando il \acr{pid} del client come valore per +il tipo di messaggio, per restituire indietro le frasi ai client. \subsection{Semafori} \label{sec:ipc_sysv_sem} @@ -1599,8 +1617,9 @@ A ciascun insieme di semafori 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}. @@ -1621,7 +1640,6 @@ struct semid_ds time_t sem_ctime; /* last time changed by semctl() */ unsigned long int sem_nsems; /* number of semaphores in set */ }; - \end{lstlisting} \end{minipage} \normalsize @@ -1630,6 +1648,148 @@ struct semid_ds \label{fig:ipc_semid_sd} \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 sono +accessibili e modificabili al solito 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} + +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 binaria}, 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. + +Purtroppo l'implementazione effettuata nel sistema di intercomunicazione di +System V complica inutilmente questo schema elementare: anzittutto non è +possibile definire un singolo semaforo, ma se ne deve creare per forza un +insieme, specificando il numero di semafori che esso deve contenere con +l'argomento \param{nsem} di \func{semget}. + +Ma i difetti maggiori dei semafori nel System V IPC sono due: il primo è che +non esiste una funzione che permetta di creare ed inizializzare un semaforo in +un'unica operazione atomica; occorre prima creare l'insieme con \func{semget} +e poi inizializzarlo con \func{semctl}. + +Il secondo è che essendo i semafori delle risorse globali di sistema, che non +vengono cancellate quando nessuno le usa più, ci si trova a dover affrontare +esplicitamente il caso in cui un processo termina per un qualche errore, +lasciando un semaforo occupato, che resterà tale per sempre, a meno di non +rimediare la situazione con opportune operazioni di ripristino. + +Come accennato una volta creato l'insieme di semafori per l'inizializzazione +dei valori occorre ricorrere ad una funzione separata, \func{semctl}, che è +quella che effettua le operazioni di controllo; 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, ...)} + + Esegue le operazioni di controllo su un semaforo o un insieme di semafori. + + \bodydesc{La funzione restituisce 0 in caso di successo o -1 in caso di + errore, nel qual caso \var{errno} viene settato 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} + + + + + +\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} + + + \subsection{Memoria condivisa} \label{sec:ipc_sysv_shm}