From: Simone Piccardi Date: Sat, 4 May 2013 18:47:34 +0000 (+0000) Subject: Correzioni varie, aggiornamento delle strutture per semafori e code di X-Git-Url: https://gapil.gnulinux.it/gitweb/?a=commitdiff_plain;h=fb71887fc0911d61330d6a81fd0f854ffe587666;p=gapil.git Correzioni varie, aggiornamento delle strutture per semafori e code di messaggi, revisione code di messaggi finita, iniziata quella dei semafori. --- diff --git a/ipc.tex b/ipc.tex index 87c35f8..cd29ca7 100644 --- a/ipc.tex +++ b/ipc.tex @@ -269,7 +269,7 @@ formattare l'uscita alla maniera dei CGI, aggiungendo l'opportuno quest'ultimo possa essere visualizzato correttamente da un browser. Una volta create le \textit{pipe}, il programma può creare (\texttt{\small - 13-17}) il primo processo figlio, che si incaricherà (\texttt{\small + 13--17}) il primo processo figlio, che si incaricherà (\texttt{\small 19--25}) di eseguire \cmd{barcode}. Quest'ultimo legge dallo standard input una stringa di caratteri, la converte nell'immagine PostScript del codice a barre ad essa corrispondente, e poi scrive il risultato direttamente sullo @@ -641,25 +641,25 @@ ovviamente il caso in cui la funzione \func{mkfifo} fallisce per la precedente esistenza della \textit{fifo}). Una volta che si è certi che la \textit{fifo} di ascolto esiste la procedura -di inizializzazione è completata. A questo punto si può chiamare -(\texttt{\small 23}) la funzione \func{daemon} per far proseguire l'esecuzione -del programma in background come demone. Si può quindi procedere -(\texttt{\small 24--33}) alla apertura della \textit{fifo}: si noti che questo -viene fatto due volte, prima in lettura e poi in scrittura, per evitare di -dover gestire all'interno del ciclo principale il caso in cui il server è in -ascolto ma non ci sono client che effettuano richieste. Si ricordi infatti -che quando una \textit{fifo} è aperta solo dal capo in lettura, l'esecuzione di -\func{read} ritorna con zero byte (si ha cioè una condizione di end-of-file). +di inizializzazione è completata. A questo punto (\texttt{\small 23}) si può +chiamare la funzione \func{daemon} per far proseguire l'esecuzione del +programma in background come demone. Si può quindi procedere (\texttt{\small + 24--33}) alla apertura della \textit{fifo}: si noti che questo viene fatto +due volte, prima in lettura e poi in scrittura, per evitare di dover gestire +all'interno del ciclo principale il caso in cui il server è in ascolto ma non +ci sono client che effettuano richieste. Si ricordi infatti che quando una +\textit{fifo} è aperta solo dal capo in lettura, l'esecuzione di \func{read} +ritorna con zero byte (si ha cioè una condizione di end-of-file). Nel nostro caso la prima apertura si bloccherà fintanto che un qualunque -client non apre a sua volta la \textit{fifo} nota in scrittura per effettuare la sua -richiesta. Pertanto all'inizio non ci sono problemi, il client però, una volta -ricevuta la risposta, uscirà, chiudendo tutti i file aperti, compresa la -\textit{fifo}. A questo punto il server resta (se non ci sono altri client -che stanno effettuando richieste) con la \textit{fifo} chiusa sul lato in -lettura, ed in questo stato la funzione \func{read} non si bloccherà in attesa -di dati in ingresso, ma ritornerà in continuazione, restituendo una condizione -di \textit{end-of-file}. +client non apre a sua volta la \textit{fifo} nota in scrittura per effettuare +la sua richiesta. Pertanto all'inizio non ci sono problemi, il client però, +una volta ricevuta la risposta, uscirà, chiudendo tutti i file aperti, +compresa la \textit{fifo}. A questo punto il server resta (se non ci sono +altri client che stanno effettuando richieste) con la \textit{fifo} chiusa sul +lato in lettura, ed in questo stato la funzione \func{read} non si bloccherà +in attesa di dati in ingresso, ma ritornerà in continuazione, restituendo una +condizione di \textit{end-of-file}. Si è usata questa tecnica per compatibilità, Linux infatti supporta l'apertura delle \textit{fifo} in lettura/scrittura, per cui si sarebbe potuto effettuare @@ -714,7 +714,7 @@ principale del programma e le definizioni delle variabili. Il codice completo La prima istruzione (\texttt{\small 12}) compone il nome della \textit{fifo} che dovrà essere utilizzata per ricevere la risposta dal server. Si usa il \ids{PID} del processo per essere sicuri di avere un nome univoco; dopo di che -(\texttt{\small 13-18}) si procede alla creazione del relativo file, uscendo +(\texttt{\small 13--18}) si procede alla creazione del relativo file, uscendo in caso di errore (a meno che il file non sia già presente sul filesystem). A questo punto il client può effettuare l'interrogazione del server, per @@ -722,7 +722,7 @@ questo prima si apre la \textit{fifo} nota (\texttt{\small 19--23}), e poi ci si scrive (\texttt{\small 24}) la stringa composta in precedenza, che contiene il nome della \textit{fifo} da utilizzare per la risposta. Infine si richiude la \textit{fifo} del server che a questo punto non serve più (\texttt{\small - 25}). + 25}). Inoltrata la richiesta si può passare alla lettura della risposta; anzitutto si apre (\texttt{\small 26--30}) la \textit{fifo} appena creata, da cui si @@ -1171,11 +1171,11 @@ di creazione, stampa, cancellazione. I valori di default sono per l'uso delle code di messaggi e per 5 ripetizioni del ciclo. Per questo motivo se non si utilizzano opzioni verrà eseguito per -cinque volte il ciclo (\texttt{\small 7-11}), in cui si crea una coda di +cinque volte il ciclo (\texttt{\small 7--11}), in cui si crea una coda di messaggi (\texttt{\small 8}), se ne stampa l'identificativo (\texttt{\small 9}) e la si rimuove (\texttt{\small 10}). Non stiamo ad approfondire adesso il significato delle funzioni utilizzate, che verranno esaminate nelle -prossime sezioni. +prossime sezioni. Quello che ci interessa infatti è verificare l'allocazione degli identificativi associati agli oggetti; lanciando il comando si otterrà @@ -1325,12 +1325,12 @@ Una coda di messaggi è costituita da una \itindex{linked~list} \textit{linked puntatori), è invece relativamente lenta nell'accesso casuale e nella ricerca.} I nuovi messaggi vengono inseriti in coda alla lista e vengono letti dalla cima, in fig.~\ref{fig:ipc_mq_schema} si è riportato uno schema -semplificato con cui queste strutture vengono mantenute dal -kernel.\footnote{lo schema illustrato è in realtà una semplificazione di - quello usato fino ai kernel della serie 2.2, a partire della serie 2.4 la - gestione delle code di messaggi è effettuata in maniera diversa, ma abbiamo - mantenuto lo schema precedente dato che illustra in maniera più che adeguata - i principi di funzionamento delle code di messaggi.} +semplificato con cui queste strutture vengono mantenute dal kernel. Lo schema +illustrato in realta è una semplificazione di quello usato fino ai kernel +della serie 2.2. A partire della serie 2.4 la gestione delle code di messaggi +è effettuata in maniera diversa (e non esiste una struttura \struct{msqid\_ds} +nel kernel), ma abbiamo mantenuto lo schema precedente dato che illustra in +maniera più che adeguata i principi di funzionamento delle code di messaggi. \begin{figure}[!htb] \centering \includegraphics[width=13cm]{img/mqstruct} @@ -1340,22 +1340,27 @@ kernel.\footnote{lo schema illustrato è in realtà una semplificazione di A ciascuna coda è associata una struttura \struct{msqid\_ds} la cui -definizione è riportata in fig.~\ref{fig:ipc_msqid_ds}. In questa struttura il -kernel mantiene le principali informazioni riguardo lo stato corrente della -coda.\footnote{come accennato questo vale fino ai kernel della serie 2.2, essa - viene usata nei kernel della serie 2.4 solo per compatibilità in quanto è - quella restituita dalle funzioni dell'interfaccia; si noti come ci sia una - differenza con i campi mostrati nello schema di fig.~\ref{fig:ipc_mq_schema} - che sono presi dalla definizione di \file{include/linux/msg.h}, e fanno - riferimento alla definizione della omonima struttura usata nel kernel.} In -fig.~\ref{fig:ipc_msqid_ds} sono elencati i campi significativi definiti in -\headfile{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. +definizione è riportata in fig.~\ref{fig:ipc_msqid_ds} ed a cui si accede +includendo \headfile{sys/msg.h}; +% +% INFO: sotto materiale obsoleto e non interessante +% In questa struttura il +% kernel mantiene le principali informazioni riguardo lo stato corrente della +% coda. Come accennato questo vale fino ai kernel della serie 2.2, essa viene +% usata nei kernel della serie 2.4 solo per compatibilità in quanto è quella +% restituita dalle funzioni dell'interfaccia; si noti come ci sia una differenza +% con i campi mostrati nello schema di fig.~\ref{fig:ipc_mq_schema} che sono +% presi dalla definizione di \file{include/linux/msg.h}, e fanno riferimento +% alla definizione della omonima struttura usata nel kernel. +%In fig.~\ref{fig:ipc_msqid_ds} sono elencati i campi definiti in +%\headfile{sys/msg.h}; +si tenga presente che il campo \var{\_\_msg\_cbytes} non è previsto dallo +standard POSIX.1-2001 e che alcuni campi fino al kernel 2.2 erano definiti +come \ctyp{short}. \begin{figure}[!htb] \footnotesize \centering - \begin{minipage}[c]{\textwidth} + \begin{minipage}[c]{.90\textwidth} \includestruct{listati/msqid_ds.h} \end{minipage} \normalsize @@ -1365,9 +1370,11 @@ Unix98. \end{figure} Quando si crea una nuova coda con \func{msgget} questa struttura viene -inizializzata, in particolare il campo \var{msg\_perm} viene inizializzato -come illustrato in sez.~\ref{sec:ipc_sysv_access_control}, per quanto riguarda -gli altri campi invece: +inizializzata,\footnote{in realtà viene inizializzata una struttura interna al + kernel, ma i dati citati sono gli stessi.} in particolare il campo +\var{msg\_perm} che esprime i permessi di accesso viene inizializzato nella +modalità illustrata in sez.~\ref{sec:ipc_sysv_access_control}. Per quanto +riguarda gli altri campi invece: \begin{itemize*} \item il campo \var{msg\_qnum}, che esprime il numero di messaggi presenti sulla coda, viene inizializzato a 0. @@ -1377,16 +1384,18 @@ gli altri campi 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}, 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 +\item il campo \var{msg\_ctime}, che esprime il tempo di ultima modifica 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 (\const{MSGMNB}). -\item i campi \var{msg\_first} e \var{msg\_last} che esprimono l'indirizzo del - primo e ultimo messaggio sono inizializzati a \val{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). +\item il campo \var{\_\_msg\_cbytes}, che esprime la dimensione in byte dei + messaggi presenti sulla coda, viene inizializzato a zero. +% i campi \var{msg\_first} e \var{msg\_last} che esprimono l'indirizzo del +% primo e ultimo messaggio sono inizializzati a \val{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). \end{itemize*} Una volta creata una coda di messaggi le operazioni di controllo vengono @@ -1417,16 +1426,16 @@ file; il suo prototipo è: generico.} \end{funcproto} - -La funzione permette di accedere ai valori della struttura \struct{msqid\_ds}, -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{2.2cm}\desclabelstyle{\nextlinelabel}} +La funzione permette di eseguire una operazione di controllo per la coda +specificata dall'identificatore \param{msqid}, utilizzando i valori della +struttura \struct{msqid\_ds}, mantenuta all'indirizzo \param{buf}. Il +comportamento della funzione dipende dal valore dell'argomento \param{cmd}, +che specifica il tipo di azione da eseguire. I valori possibili +per \param{cmd} sono: +\begin{basedescript}{\desclabelwidth{1.6cm}\desclabelstyle{\nextlinelabel}} \item[\const{IPC\_STAT}] Legge le informazioni riguardo la coda nella - struttura indicata da \param{buf}. Occorre avere il permesso di lettura - sulla coda. + struttura \struct{msqid\_ds} indicata da \param{buf}. Occorre avere il + permesso di lettura sulla coda. \item[\const{IPC\_RMID}] Rimuove la coda, cancellando tutti i dati, con effetto immediato. Tutti i processi che cercheranno di accedere alla coda riceveranno un errore di \errcode{EIDRM}, e tutti processi in attesa su @@ -1437,41 +1446,50 @@ eseguire; i valori possibili sono: \item[\const{IPC\_SET}] Permette di modificare i permessi ed il proprietario della coda, ed il limite massimo sulle dimensioni del totale dei messaggi in essa contenuti (\var{msg\_qbytes}). I valori devono essere passati in una - struttura \struct{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}, ma l'amministratore ha la facoltà di - incrementarne il valore a limiti superiori a \const{MSGMNB}. + struttura \struct{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 e lo stesso vale per \var{msg\_qbytes}. Infine solo + l'amministratore (più precisamente un processo con la capacità + \itindex{capability} \const{CAP\_IPC\_RESOURCE}) ha la facoltà di + incrementarne il valore a limiti superiori a \const{MSGMNB}. Se eseguita con + successo la funzione aggiorna anche il campo \var{msg\_ctime}. \end{basedescript} +A questi tre valori, che sono quelli previsti dallo standard, su Linux se ne +affiancano altri tre (\const{IPC\_INFO}, \const{MSG\_STAT} e +\const{MSG\_INFO}) introdotti ad uso del programma \cmd{icps} per ottenere le +informazioni generali relative alle risorse usate dalle code di +messaggi. Questi potranno essere modificati o rimossi in favore dell'uso di +\texttt{/proc}, per cui non devono essere usati e non li tratteremo. Una volta che si abbia a disposizione l'identificatore, per inviare un -messaggio su una coda si utilizza la funzione \funcd{msgsnd}; il suo prototipo -è: -\begin{functions} - \headdecl{sys/types.h} - \headdecl{sys/ipc.h} - \headdecl{sys/msg.h} - - \funcdecl{int msgsnd(int msqid, struct msgbuf *msgp, size\_t msgsz, int - msgflg)} +messaggio su una coda si utilizza la funzione di sistema \funcd{msgsnd}, il +cui prototipo è: - Invia un messaggio sulla coda \param{msqid}. - - \bodydesc{La funzione restituisce 0, e $-1$ in caso di errore, nel qual caso - \var{errno} assumerà uno dei valori: +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{sys/ipc.h} +\fhead{sys/msg.h} +\fdecl{int msgsnd(int msqid, struct msgbuf *msgp, size\_t msgsz, int msgflg)} +\fdesc{Invia un messaggio su una coda.} +} + +{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual + caso \var{errno} assumerà uno dei valori: \begin{errlist} \item[\errcode{EACCES}] non si hanno i privilegi di accesso sulla coda. - \item[\errcode{EIDRM}] la coda è stata cancellata. \item[\errcode{EAGAIN}] il messaggio non può essere inviato perché si è - superato il limite \var{msg\_qbytes} sul numero massimo di byte presenti - sulla coda, e si è richiesto \const{IPC\_NOWAIT} in \param{flag}. + superato il limite \var{msg\_qbytes} sul numero massimo di byte presenti + sulla coda, e si è richiesto \const{IPC\_NOWAIT} in \param{flag}. + \item[\errcode{EIDRM}] la coda è stata cancellata. \item[\errcode{EINVAL}] si è specificato un \param{msgid} invalido, o un valore non positivo per \param{mtype}, o un valore di \param{msgsz} maggiore di \const{MSGMAX}. \end{errlist} - ed inoltre \errval{EFAULT}, \errval{EINTR} ed \errval{ENOMEM}. } -\end{functions} + ed inoltre \errval{EFAULT}, \errval{EINTR} e \errval{ENOMEM} nel loro + significato generico.} +\end{funcproto} La funzione inserisce il messaggio sulla coda specificata da \param{msqid}; il messaggio ha lunghezza specificata da \param{msgsz} ed è passato attraverso il @@ -1481,6 +1499,17 @@ fig.~\ref{fig:ipc_msbuf} che è quella che deve contenere effettivamente il messaggio. La dimensione massima per il testo di un messaggio non può comunque superare il limite \const{MSGMAX}. +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{0.8\textwidth} + \includestruct{listati/msgbuf.h} + \end{minipage} + \normalsize + \caption{Schema della struttura \structd{msgbuf}, da utilizzare come + argomento per inviare/ricevere messaggi.} + \label{fig:ipc_msbuf} +\end{figure} + La struttura di fig.~\ref{fig:ipc_msbuf} è comunque solo un modello, tanto che la definizione contenuta in \headfile{sys/msg.h} usa esplicitamente per il secondo campo il valore \code{mtext[1]}, che non è di nessuna utilità ai fini @@ -1504,17 +1533,6 @@ cioè \var{message} è una propria struttura che si passa alla funzione, consideriamo il caso dell'esempio in fig.~\ref{fig:ipc_msbuf}, \param{msgsz} dovrà essere pari a \const{LENGTH}). -\begin{figure}[!htb] - \footnotesize \centering - \begin{minipage}[c]{\textwidth} - \includestruct{listati/msgbuf.h} - \end{minipage} - \normalsize - \caption{Schema della struttura \structd{msgbuf}, da utilizzare come - argomento per inviare/ricevere messaggi.} - \label{fig:ipc_msbuf} -\end{figure} - Per capire meglio il funzionamento della funzione riprendiamo in considerazione la struttura della coda illustrata in fig.~\ref{fig:ipc_mq_schema}. Alla chiamata di \func{msgsnd} il nuovo messaggio @@ -1529,14 +1547,13 @@ Il valore dell'argomento \param{flag} permette di specificare il comportamento della funzione. Di norma, quando si specifica un valore nullo, la funzione ritorna immediatamente a meno che si sia ecceduto il valore di \var{msg\_qbytes}, o il limite di sistema sul numero di messaggi, nel qual -caso si blocca mandando il processo in stato di \textit{sleep}. Se si -specifica per \param{flag} il valore \const{IPC\_NOWAIT} la funzione opera in -modalità non bloccante, ed in questi casi ritorna immediatamente con un errore -di \errcode{EAGAIN}. +caso si blocca. Se si specifica per \param{flag} il valore +\const{IPC\_NOWAIT} la funzione opera in modalità non-bloccante, ed in questi +casi ritorna immediatamente con un errore di \errcode{EAGAIN}. Se non si specifica \const{IPC\_NOWAIT} la funzione resterà bloccata fintanto che non si liberano risorse sufficienti per poter inserire nella coda il -messaggio, nel qual caso ritornerà normalmente. La funzione può ritornare, con +messaggio, nel qual caso ritornerà normalmente. La funzione può ritornare con una condizione di errore anche in due altri casi: quando la coda viene rimossa (nel qual caso si ha un errore di \errcode{EIDRM}) o quando la funzione viene interrotta da un segnale (nel qual caso si ha un errore di \errcode{EINTR}). @@ -1551,41 +1568,39 @@ vengono modificati: \item Il valore \var{msg\_stime}, che viene impostato al tempo corrente. \end{itemize*} -La funzione che viene utilizzata per estrarre un messaggio da una coda è -\funcd{msgrcv}; il suo prototipo è: -\begin{functions} - \headdecl{sys/types.h} - \headdecl{sys/ipc.h} - \headdecl{sys/msg.h} +La funzione di sistema che viene utilizzata per estrarre un messaggio da una +coda è \funcd{msgrcv}, ed il suo prototipo è: - \funcdecl{ssize\_t msgrcv(int msqid, struct msgbuf *msgp, size\_t msgsz, +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{sys/ipc.h} +\fhead{sys/msg.h} +\fdecl{ssize\_t msgrcv(int msqid, struct msgbuf *msgp, size\_t msgsz, long msgtyp, int msgflg)} - - Legge un messaggio dalla coda \param{msqid}. - - \bodydesc{La funzione restituisce il numero di byte letti in caso di - successo, e -1 in caso di errore, nel qual caso \var{errno} assumerà uno - dei valori: +\fdesc{Legge un messaggio da una coda.} +} + +{La funzione ritorna il numero di byte letti in caso di successo e $-1$ per un + errore, nel qual caso \var{errno} assumerà uno dei valori: \begin{errlist} - \item[\errcode{EACCES}] non si hanno i privilegi di accesso sulla coda. - \item[\errcode{EIDRM}] la coda è stata cancellata. \item[\errcode{E2BIG}] il testo del messaggio è più lungo di \param{msgsz} e non si è specificato \const{MSG\_NOERROR} in \param{msgflg}. + \item[\errcode{EACCES}] non si hanno i privilegi di accesso sulla coda. + \item[\errcode{EIDRM}] la coda è stata cancellata. \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale mentre era in attesa di ricevere un messaggio. \item[\errcode{EINVAL}] si è specificato un \param{msgid} invalido o un valore di \param{msgsz} negativo. \end{errlist} - ed inoltre \errval{EFAULT}. -} -\end{functions} + ed inoltre \errval{EFAULT} nel suo significato generico.} +\end{funcproto} -La funzione legge un messaggio dalla coda specificata, scrivendolo sulla -struttura puntata da \param{msgp}, che dovrà avere un formato analogo a quello -di fig.~\ref{fig:ipc_msbuf}. Una volta estratto, il messaggio sarà rimosso -dalla coda. L'argomento \param{msgsz} indica la lunghezza massima del testo -del messaggio (equivalente al valore del parametro \const{LENGTH} nell'esempio -di fig.~\ref{fig:ipc_msbuf}). +La funzione legge un messaggio dalla coda specificata da \param{msqid}, +scrivendolo sulla struttura puntata da \param{msgp}, che dovrà avere un +formato analogo a quello di fig.~\ref{fig:ipc_msbuf}. Una volta estratto, il +messaggio sarà rimosso dalla coda. L'argomento \param{msgsz} indica la +lunghezza massima del testo del messaggio (equivalente al valore del parametro +\const{LENGTH} nell'esempio di fig.~\ref{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 @@ -1599,7 +1614,7 @@ una scansione della struttura mostrata in fig.~\ref{fig:ipc_mq_schema}, restituendo il primo messaggio incontrato che corrisponde ai criteri specificati (che quindi, visto come i messaggi vengono sempre inseriti dalla coda, è quello meno recente); in particolare: -\begin{itemize} +\begin{itemize*} \item se \param{msgtyp} è 0 viene estratto il messaggio in cima alla coda, cioè quello fra i presenti che è stato inserito per primo. \item se \param{msgtyp} è positivo viene estratto il primo messaggio il cui @@ -1608,7 +1623,7 @@ coda, è quello meno recente); in particolare: \item se \param{msgtyp} è negativo viene estratto il primo fra i messaggi con il valore più basso del tipo, fra tutti quelli il cui tipo ha un valore inferiore al valore assoluto di \param{msgtyp}. -\end{itemize} +\end{itemize*} Il valore di \param{msgflg} permette di controllare il comportamento della funzione, esso può essere nullo o una maschera binaria composta da uno o più @@ -1619,13 +1634,13 @@ di leggere il primo messaggio nella coda con tipo diverso da \param{msgtyp}, e 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 \const{IPC\_NOWAIT} la -funzione ritorna immediatamente con un errore \errcode{ENOMSG}. Altrimenti la -funzione ritorna normalmente non appena viene inserito un messaggio del tipo -desiderato, oppure ritorna con errore qualora la coda sia rimossa (con -\var{errno} impostata a \errcode{EIDRM}) o se il processo viene interrotto da -un segnale (con \var{errno} impostata a \errcode{EINTR}). +disponibili per la lettura, è di bloccare il processo. Nel caso però si sia +specificato \const{IPC\_NOWAIT} la funzione ritorna immediatamente con un +errore \errcode{ENOMSG}. Altrimenti la funzione ritorna normalmente non appena +viene inserito un messaggio del tipo desiderato, oppure ritorna con errore +qualora la coda sia rimossa (con \var{errno} impostata a \errcode{EIDRM}) o se +il processo viene interrotto da un segnale (con \var{errno} impostata a +\errcode{EINTR}). Una volta completata con successo l'estrazione del messaggio dalla coda, la funzione aggiorna i dati mantenuti in \struct{msqid\_ds}, in particolare @@ -1638,15 +1653,15 @@ vengono modificati: \end{itemize*} Le code di messaggi presentano il solito problema di tutti gli oggetti del -SysV-IPC; essendo questi permanenti restano nel sistema occupando risorse -anche quando un processo è terminato, al contrario delle \textit{pipe} per le -quali tutte le risorse occupate vengono rilasciate quanto l'ultimo processo -che le utilizzava termina. Questo comporta che in caso di errori si può -saturare il sistema, e che devono comunque essere esplicitamente previste +\textit{SysV-IPC} che essendo questi permanenti restano nel sistema occupando +risorse anche quando un processo è terminato, al contrario delle \textit{pipe} +per le quali tutte le risorse occupate vengono rilasciate quanto l'ultimo +processo che le utilizzava termina. Questo comporta che in caso di errori si +può saturare il sistema, e che devono comunque essere esplicitamente previste delle funzioni di rimozione in caso di interruzioni o uscite dal programma (come vedremo in fig.~\ref{fig:ipc_mq_fortune_server}). -L'altro problema è non facendo uso di file descriptor le tecniche di +L'altro problema è che non facendo uso di file descriptor le tecniche di \textit{I/O multiplexing} descritte in sez.~\ref{sec:file_multiplexing} non possono essere utilizzate, e non si ha a disposizione niente di analogo alle funzioni \func{select} e \func{poll}. Questo rende molto scomodo usare più di @@ -1684,18 +1699,17 @@ messaggi sulla base del loro tipo. Il programma, oltre alle solite variabili per il nome del file da cui leggere le \textit{fortunes} e per il vettore di stringhe che contiene le frasi, definisce due strutture appositamente per la comunicazione; con -\var{msgbuf\_read} (\texttt{\small 8--11}) vengono passate le richieste mentre -con \var{msgbuf\_write} (\texttt{\small 12--15}) vengono restituite le frasi. +\var{msgbuf\_read} vengono passate (\texttt{\small 8--11}) le richieste mentre +con \var{msgbuf\_write} vengono restituite (\texttt{\small 12--15}) le frasi. La gestione delle opzioni si è al solito omessa, essa si curerà di impostare -in \var{n} il numero di frasi da leggere specificato a linea di comando ed in -\var{fortunefilename} il file da cui leggerle; dopo aver installato -(\texttt{\small 19--21}) i gestori dei segnali per trattare l'uscita dal -server, viene prima controllato (\texttt{\small 22}) il numero di frasi -richieste abbia senso (cioè sia maggiore di zero), le quali poi -(\texttt{\small 23}) vengono lette nel vettore in memoria con la stessa -funzione \code{FortuneParse} usata anche per il server basato sulle -\textit{fifo}. +nella variabile \var{n} il numero di frasi da leggere specificato a linea di +comando ed in \var{fortunefilename} il file da cui leggerle. Dopo aver +installato (\texttt{\small 19--21}) i gestori dei segnali per trattare +l'uscita dal server, viene prima controllato (\texttt{\small 22}) il numero di +frasi richieste abbia senso (cioè sia maggiore di zero), le quali poi vengono +lette (\texttt{\small 23}) nel vettore in memoria con la stessa funzione +\code{FortuneParse} usata anche per il server basato sulle \textit{fifo}. Una volta inizializzato il vettore di stringhe coi messaggi presi dal file delle \textit{fortune} si procede (\texttt{\small 25}) con la generazione di @@ -1709,8 +1723,8 @@ Finita la fase di inizializzazione il server prima (\texttt{\small 32}) chiama la funzione \func{daemon} per andare in background e poi esegue in permanenza il ciclo principale (\texttt{\small 33--40}). Questo inizia (\texttt{\small 34}) con il porsi in attesa di un messaggio di richiesta da parte di un -client; si noti infatti come \func{msgrcv} richieda un messaggio con -\var{mtype} uguale a 1: questo è il valore usato per le richieste dato che +client. Si noti infatti come \func{msgrcv} richieda un messaggio con +\var{mtype} uguale a 1, questo è il valore usato per le richieste dato che corrisponde al \ids{PID} di \cmd{init}, che non può essere un client. L'uso del flag \const{MSG\_NOERROR} è solo per sicurezza, dato che i messaggi di richiesta sono di dimensione fissa (e contengono solo il \ids{PID} del @@ -1761,31 +1775,32 @@ non viene chiamata con il flag di creazione in quanto la coda deve essere preesistente. In caso di errore (ad esempio se il server non è stato avviato) il programma termina immediatamente. -Una volta acquisito l'identificatore della coda il client compone il -messaggio di richiesta (\texttt{\small 12--13}) in \var{msg\_read}, usando 1 -per il tipo ed inserendo il proprio \ids{PID} come dato da passare al server. -Calcolata (\texttt{\small 14}) la dimensione, provvede (\texttt{\small 15}) ad -immettere la richiesta sulla coda. - -A questo punto non resta che (\texttt{\small 16}) rileggere dalla coda la -risposta del server richiedendo a \func{msgrcv} di selezionare i messaggi di -tipo corrispondente al valore del \ids{PID} inviato nella richiesta. L'ultimo -passo (\texttt{\small 17}) prima di uscire è quello di stampare a video il -messaggio ricevuto. +Una volta acquisito l'identificatore della coda il client compone +(\texttt{\small 12--13}) il messaggio di richiesta in \var{msg\_read}, usando +1 per il tipo ed inserendo il proprio \ids{PID} come dato da passare al +server. Calcolata (\texttt{\small 14}) la dimensione, provvede +(\texttt{\small 15}) ad immettere la richiesta sulla coda. + +A questo punto non resta che rileggere la risposta (\texttt{\small 16}) dalla +coda del server richiedendo a \func{msgrcv} di selezionare i messaggi di tipo +corrispondente al valore del \ids{PID} inviato nella richiesta. L'ultimo passo +(\texttt{\small 17}) prima di uscire è quello di stampare a video il messaggio +ricevuto. Proviamo allora il nostro nuovo sistema, al solito occorre definire -\code{LD\_LIBRARY\_PATH} per accedere alla libreria \file{libgapil.so}, dopo di -che, in maniera del tutto analoga a quanto fatto con il programma che usa le -fifo, potremo far partire il server con: -\begin{verbatim} -[piccardi@gont sources]$ ./mqfortuned -n10 -\end{verbatim}%$ +\code{LD\_LIBRARY\_PATH} per accedere alla libreria \file{libgapil.so}, dopo +di che, in maniera del tutto analoga a quanto fatto con il programma che usa +le \textit{fifo}, potremo far partire il server con: +\begin{Console} +[piccardi@gont sources]$ \textbf{./mqfortuned -n10} +\end{Console} +%$ come nel caso precedente, avendo eseguito il server in background, il comando ritornerà immediatamente; potremo però verificare con \cmd{ps} che il programma è effettivamente in esecuzione, e che ha creato una coda di messaggi: -\begin{verbatim} -[piccardi@gont sources]$ ipcs +\begin{Console} +[piccardi@gont sources]$ \textbf{ipcs} ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status @@ -1796,19 +1811,21 @@ key semid owner perms nsems ------ Message Queues -------- key msqid owner perms used-bytes messages 0x0102dc6a 0 piccardi 666 0 0 -\end{verbatim} +\end{Console} +%$ a questo punto potremo usare il client per ottenere le nostre frasi: -\begin{verbatim} -[piccardi@gont sources]$ ./mqfortune +\begin{Console} +[piccardi@gont sources]$ \textbf{./mqfortune} Linux ext2fs has been stable for a long time, now it's time to break it -- Linuxkongreß '95 in Berlin -[piccardi@gont sources]$ ./mqfortune +[piccardi@gont sources]$ \textbf{./mqfortune} Let's call it an accidental feature. --Larry Wall -\end{verbatim} +\end{Console} con un risultato del tutto equivalente al precedente. Infine potremo chiudere il server inviando il segnale di terminazione con il comando \code{killall - mqfortuned} verificando che effettivamente la coda di messaggi viene rimossa. + mqfortuned}, verificando che effettivamente la coda di messaggi venga +rimossa. Benché funzionante questa architettura risente dello stesso inconveniente visto anche nel caso del precedente server basato sulle \textit{fifo}; se il @@ -1817,43 +1834,43 @@ lettura della risposta, quest'ultima resta nella coda (così come per le \textit{fifo} si aveva il problema delle \textit{fifo} che restavano nel filesystem). In questo caso però il problemi sono maggiori, sia perché è molto più facile esaurire la memoria dedicata ad una coda di messaggi che gli -\itindex{inode} inode di un filesystem, sia perché, con il riutilizzo dei -\ids{PID} da parte dei processi, un client eseguito in un momento successivo -potrebbe ricevere un messaggio non indirizzato a lui. +\itindex{inode} \textit{inode} di un filesystem, sia perché, con il riutilizzo +dei \ids{PID} da parte dei processi, un client eseguito in un momento +successivo potrebbe ricevere un messaggio non indirizzato a lui. -\subsection{Semafori} +\subsection{I semafori} \label{sec:ipc_sysv_sem} -I semafori non sono meccanismi di intercomunicazione diretta come quelli -(\textit{pipe}, \textit{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 \index{sezione~critica} +I semafori non sono propriamente meccanismi di intercomunicazione come +\textit{pipe}, \textit{fifo} e code di messaggi, poiché non consentono di +scambiare dati fra processi, ma servono piuttosto come meccanismi di +sincronizzazione o di protezione per le \index{sezione~critica} \textsl{sezioni critiche} del codice (si ricordi quanto detto in -sez.~\ref{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. +sez.~\ref{sec:proc_race_cond}). Un semaforo infatti non è altro che un +contatore mantenuto nel kernel che determina se consentire o meno la +prosecuzione dell'esecuzione di un programma. In questo modo si può +controllare l'accesso ad una risorsa condivisa da più processi, associandovi +un semaforo che assicuri che non possa essere usata da più di un processo alla +volta. 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). +si utilizza. Un processo che deve accedere ad una risorsa condivisa 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 la risorsa viene +considerata non disponibile, ed il processo si bloccherà fin quando chi la sta +utilizzando non la rilascerà, incrementando il valore del semaforo. Non appena +il semaforo diventa positivo, indicando che la risorsa è tornata disponibile, +il processo bloccato in attesa riprenderà l'esecuzione, e 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, @@ -1865,37 +1882,35 @@ 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 inter-processo di \textit{SysV-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 è -\funcd{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à i valori: - \begin{errlist} - \item[\errcode{ENOSPC}] si è cercato di creare una insieme di semafori - quando è stato superato o il limite per il numero totale di semafori - (\const{SEMMNS}) o quello per il numero totale degli insiemi - (\const{SEMMNI}) nel sistema. - \item[\errcode{EINVAL}] l'argomento \param{nsems} è minore di zero o - maggiore del limite sul numero di semafori per ciascun insieme - (\const{SEMMSL}), o se l'insieme già esiste, maggiore del numero di - semafori che contiene. - \item[\errcode{ENOMEM}] il sistema non ha abbastanza memoria per poter - contenere le strutture per un nuovo insieme di semafori. - \end{errlist} - ed inoltre \errval{EACCES}, \errval{ENOENT}, \errval{EEXIST}, - \errval{EIDRM}, con lo stesso significato che hanno per \func{msgget}.} -\end{functions} +Il sistema di intercomunicazione di \textit{SysV-IPC} prevede anche una +implementazione dei semafori, ma gli oggetti utilizzati sono tuttavia non +semafori singoli, ma gruppi (più propriamente \textsl{insiemi}) di semafori +detti ``\textit{semaphore set}''. La funzione di sistema che permette di +creare o ottenere l'identificatore di un insieme di semafori è \funcd{semget}, +ed il suo prototipo è: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{sys/ipc.h} +\fhead{sys/sem.h} +\fdecl{int semget(key\_t key, int nsems, int flag)} +\fdesc{Restituisce l'identificatore di un insieme di semafori.} +} + +{La funzione ritorna l'identificatore (un intero positivo) in caso di successo + e $-1$ per un errore, nel qual caso \var{errno} assumerà uno dei valori: + \begin{errlist} + \item[\errcode{ENOSPC}] si è superato il limite di sistema per il numero + totale di semafori (\const{SEMMNS}) o di insiemi (\const{SEMMNI}). + \item[\errcode{EINVAL}] \param{nsems} è minore di zero o maggiore del limite + sul numero di semafori di un insieme (\const{SEMMSL}), o se l'insieme già + esiste, maggiore del numero di semafori che contiene. + \item[\errcode{ENOMEM}] il sistema non ha abbastanza memoria per poter + contenere le strutture per un nuovo insieme di semafori. + \end{errlist} + ed inoltre \errval{EACCES}, \errval{EEXIST}, \errval{EIDRM} e + \errval{ENOENT} con lo stesso significato che hanno per \func{msgget}.} +\end{funcproto} La funzione è del tutto analoga a \func{msgget}, solo che in questo caso restituisce l'identificatore di un insieme di semafori, in particolare è @@ -1908,26 +1923,30 @@ 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 \textit{SysV-IPC} -soffrono di altri due, ben più gravi, difetti. +complicazione inutile dell'interfaccia, il problema è che i semafori forniti +dal \textit{SysV-IPC} soffrono di altri due difetti progettuali molto più +gravi. 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 l'operazione atomicamente. +perde così ogni possibilità di eseguire l'operazione atomicamente. Eventuali +accessi che possono avvenire fra la creazione e l'inizializzazione potranno +avere effetti imprevisti. Il secondo difetto deriva dalla caratteristica generale degli oggetti del \textit{SysV-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. +cancellate quando nessuno le usa più. In questo caso il problema è più grave +perché ci si 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, e la gestione diventa più complicata. \begin{figure}[!htb] \footnotesize \centering - \begin{minipage}[c]{\textwidth} + \begin{minipage}[c]{.80\textwidth} \includestruct{listati/semid_ds.h} \end{minipage} \normalsize @@ -1937,39 +1956,28 @@ semaforo all'uscita del processo. \end{figure} A ciascun insieme di semafori è associata una struttura \struct{semid\_ds}, -riportata in fig.~\ref{fig:ipc_semid_ds}.\footnote{non si sono riportati i - campi ad uso interno del kernel, che vedremo in - fig.~\ref{fig:ipc_sem_schema}, che dipendono dall'implementazione.} 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 +riportata in fig.~\ref{fig:ipc_semid_ds}.\footnote{anche in questo caso in + realtà il kernel usa una sua specifica struttura interna, ma i dati + significativi sono sempre quelli citati.} 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}, che +esprime i permessi di accesso, viene inizializzato come illustrato in sez.~\ref{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 +\item il campo \var{sem\_ctime}, che esprime il tempo di ultimo cambiamento 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 -\struct{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 \textit{SysV-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 dalle pagine di manuale.} è riportata in fig.~\ref{fig:ipc_sem}. -Questa struttura, non è accessibile in user space, ma i valori in essa -specificati possono essere letti in maniera indiretta, attraverso l'uso delle -funzioni di controllo. \begin{figure}[!htb] \footnotesize \centering - \begin{minipage}[c]{\textwidth} + \begin{minipage}[c]{.80\textwidth} \includestruct{listati/sem.h} \end{minipage} \normalsize @@ -1978,16 +1986,33 @@ funzioni di controllo. \label{fig:ipc_sem} \end{figure} -I dati mantenuti nella struttura, ed elencati in fig.~\ref{fig:ipc_sem}, -indicano rispettivamente: -\begin{description*} +Ciascun semaforo dell'insieme è realizzato come una struttura di tipo +\struct{sem} che ne contiene i dati essenziali, la cui definizione è riportata +in fig.~\ref{fig:ipc_sem}.\footnote{in realtà in fig~\ref{fig:ipc_sem} si è + riportata la definizione originaria del kernel 1.0, che contiene la prima + realizzazione del \textit{SysV-IPC} in Linux; ormai questa struttura è + ridotta ai soli due primi membri, e gli altri vengono calcolati + dinamicamente, la si è usata solo a scopo di esempio, perché indica tutti i + valori associati ad un semaforo, restituiti dalle funzioni di controllo, e + citati dalle pagine di manuale.} Questa struttura non è accessibile +direttamente dallo \textit{user space}, ma i valori in essa specificati +possono essere letti in maniera indiretta, attraverso l'uso delle opportune +funzioni di controllo. I dati mantenuti nella struttura, ed elencati in +fig.~\ref{fig:ipc_sem}, indicano rispettivamente: +\begin{basedescript}{\desclabelwidth{2cm}\desclabelstyle{\nextlinelabel}} \item[\var{semval}] il valore numerico del semaforo. \item[\var{sempid}] il \ids{PID} dell'ultimo processo che ha eseguito una operazione sul semaforo. \item[\var{semncnt}] il numero di processi in attesa che esso venga incrementato. \item[\var{semzcnt}] il numero di processi in attesa che esso si annulli. -\end{description*} +\end{basedescript} + +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 tab.~\ref{tab:ipc_sem_limits}. Alcuni di questi limiti sono +al solito accessibili e modificabili attraverso \func{sysctl} o scrivendo +direttamente nel file \sysctlfile{kernel/sem}. \begin{table}[htb] \footnotesize @@ -2015,51 +2040,48 @@ indicano rispettivamente: \label{tab:ipc_sem_limits} \end{table} -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 tab.~\ref{tab:ipc_sem_limits}. Alcuni di questi limiti sono -al solito accessibili e modificabili attraverso \func{sysctl} o scrivendo -direttamente nel file \sysctlfile{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) è \funcd{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[\errcode{EACCES}] il processo non ha i privilegi per eseguire +La funzione di sistema che permette di effettuare le varie operazioni di +controllo sui semafori fra le quali, come accennato, è impropriamente compresa +anche la loro inizializzazione, è \funcd{semctl}; il suo prototipo è: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{sys/ipc.h} +\fhead{sys/sem.h} +\fdecl{int semctl(int semid, int semnum, int cmd)} +\fdecl{int semctl(int semid, int semnum, int cmd, union semun arg)} +\fdesc{Esegue le operazioni di controllo su un semaforo o un insieme di + semafori.} +} + +{La funzione ritorna in caso di successo un valore positivo quanto usata con + tre argomenti ed un valore nullo quando usata con quattro e $-1$ per un + errore, nel qual caso \var{errno} assumerà uno dei valori: + \begin{errlist} + \item[\errcode{EACCES}] i permessi assegnati al semaforo non consentono l'operazione richiesta. \item[\errcode{EIDRM}] l'insieme di semafori è stato cancellato. \item[\errcode{EPERM}] si è richiesto \const{IPC\_SET} o \const{IPC\_RMID} - ma il processo non ha privilegi sufficienti ad eseguire l'operazione. + ma il processo non è né il creatore né il proprietario del semaforo e + non ha i privilegi di amministratore. \item[\errcode{ERANGE}] si è richiesto \const{SETALL} \const{SETVAL} ma il valore a cui si vuole impostare il semaforo è minore di zero o maggiore di \const{SEMVMX}. - \end{errlist} - ed inoltre \errval{EFAULT} ed \errval{EINVAL}. -} -\end{functions} + \end{errlist} + ed inoltre \errval{EFAULT} ed \errval{EINVAL} nel loro significato + generico.} +\end{funcproto} La funzione può avere tre o quattro argomenti, 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}. + \begin{figure}[!htb] \footnotesize \centering - \begin{minipage}[c]{\textwidth} + \begin{minipage}[c]{.80\textwidth} \includestruct{listati/semun.h} \end{minipage} \normalsize @@ -2071,33 +2093,41 @@ specificata con \param{cmd}, ed opera o sull'intero insieme specificato da 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 \struct{semun}, la cui -definizione, con i possibili valori che può assumere, è riportata in -fig.~\ref{fig:ipc_semun}. +unificare detto argomento esso deve essere passato come una unione +\struct{semun}, la cui definizione, con i possibili valori che può assumere, è +riportata in fig.~\ref{fig:ipc_semun}. + +Nelle versioni più vecchie delle \acr{glibc} questa unione veniva definita in +\file{sys/sem.h}, ma nelle versioni più recenti questo non avviene più in +quanto lo standard POSIX.1-2001 richiede che sia sempre definita a cura del +chiamante. In questa seconda evenienza le \acr{glibc} definiscono però la +macro \macro{\_SEM\_SEMUN\_UNDEFINED} che può essere usata per controllare la +situazione. Come già accennato sia il comportamento della funzione che il numero di argomenti 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 \errcode{EINVAL}) per questo argomento sono i +\param{cmd}, che specifica l'azione da intraprendere. I valori validi, che +cioè non causano un errore di \errcode{EINVAL}, per questo argomento sono i seguenti: -\begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}} -\item[\const{IPC\_STAT}] Legge i dati dell'insieme di semafori, copiando il - contenuto della relativa struttura \struct{semid\_ds} all'indirizzo - specificato con \var{arg.buf}. Occorre avere il permesso di lettura. +\begin{basedescript}{\desclabelwidth{1.6cm}\desclabelstyle{\nextlinelabel}} +\item[\const{IPC\_STAT}] Legge i dati dell'insieme di semafori, copiandone i + valori nella struttura \struct{semid\_ds} posta all'indirizzo specificato + con \var{arg.buf}. Occorre avere il permesso di lettura. L'argomento \param{semnum} viene ignorato. \item[\const{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 - \errcode{EIDRM}. L'\ids{UID} effettivo del processo deve corrispondere o al - creatore o al proprietario dell'insieme, o all'amministratore. L'argomento + dati, con effetto immediato. Tutti i processi che erano bloccati in attesa + vengono svegliati, ritornando con un errore di \errcode{EIDRM}. L'\ids{UID} + effettivo del processo deve corrispondere o al creatore o al proprietario + dell'insieme, o all'amministratore. L'argomento \param{semnum} viene ignorato. \item[\const{IPC\_SET}] Permette di modificare i permessi ed il proprietario dell'insieme. I valori devono essere passati in una struttura - \struct{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'\ids{UID} effettivo del processo deve - corrispondere o al creatore o al proprietario dell'insieme, o - all'amministratore. L'argomento \param{semnum} viene ignorato. + \struct{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}. La funziona aggiorna anche il campo + \var{sem\_ctime}. L'\ids{UID} effettivo del processo deve corrispondere o + al creatore o al proprietario dell'insieme, o all'amministratore. + L'argomento \param{semnum} viene ignorato. \item[\const{GETALL}] Restituisce il valore corrente di ciascun semaforo dell'insieme (corrispondente al campo \var{semval} di \struct{sem}) nel vettore indicato da \param{arg.array}. Occorre avere il permesso di lettura. @@ -2131,6 +2161,12 @@ seguenti: \struct{semid\_ds}. Si devono avere i privilegi di scrittura sul semaforo. \end{basedescript} +Come per \func{msgctl} esistono tre ulteriori valori, \const{IPC\_INFO}, +\const{SEM\_STAT} e \const{SEM\_INFO}, specifici di Linux e fuori da ogni +standard, creati specificamente ad uso del comando \cmd{ipcs}. Dato che anche +questi potranno essere modificati o rimossi, non devono essere utilizzati e +pertanto non li tratteremo. + Quando si imposta il valore di un semaforo (sia che lo si faccia per tutto l'insieme con \const{SETALL}, che per un solo semaforo con \const{SETVAL}), i processi in attesa su di esso reagiscono di conseguenza al cambiamento di diff --git a/listati/msqid_ds.h b/listati/msqid_ds.h index 4efeabe..e173954 100644 --- a/listati/msqid_ds.h +++ b/listati/msqid_ds.h @@ -1,13 +1,11 @@ struct msqid_ds { - struct ipc_perm msg_perm; /* structure for operation permission */ - time_t msg_stime; /* time of last msgsnd command */ - time_t msg_rtime; /* time of last msgrcv command */ - time_t msg_ctime; /* time of last change */ - msgqnum_t msg_qnum; /* number of messages currently on queue */ - msglen_t msg_qbytes; /* max number of bytes allowed on queue */ - pid_t msg_lspid; /* pid of last msgsnd() */ - pid_t msg_lrpid; /* pid of last msgrcv() */ - struct msg *msg_first; /* first message on queue, unused */ - struct msg *msg_last; /* last message in queue, unused */ - unsigned long int msg_cbytes; /* current number of bytes on queue */ + struct ipc_perm msg_perm; /* structure for operation permission */ + time_t msg_stime; /* time of last msgsnd command */ + time_t msg_rtime; /* time of last msgrcv command */ + time_t msg_ctime; /* time of last change */ + unsigned long __msg_cbytes; /* current number of bytes on queue */ + msgqnum_t msg_qnum; /* number of messages currently on queue */ + msglen_t msg_qbytes; /* max number of bytes allowed on queue */ + pid_t msg_lspid; /* pid of last msgsnd() */ + pid_t msg_lrpid; /* pid of last msgrcv() */ }; diff --git a/listati/semid_ds.h b/listati/semid_ds.h index 24d797b..6c3a9c0 100644 --- a/listati/semid_ds.h +++ b/listati/semid_ds.h @@ -1,7 +1,7 @@ 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 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 */ }; diff --git a/listati/semun.h b/listati/semun.h index 3b90c50..b295b8a 100644 --- a/listati/semun.h +++ b/listati/semun.h @@ -2,6 +2,6 @@ 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 */ + struct seminfo *__buf; /* buffer for IPC_INFO */ + /* (Linux specific) */ }; diff --git a/process.tex b/process.tex index 2376ec7..a43b810 100644 --- a/process.tex +++ b/process.tex @@ -1826,13 +1826,14 @@ comando da esso supportate. Si può notare che si è anzitutto (\texttt{\small 1}) disabilitata la stampa di messaggi di errore per opzioni non riconosciute, per poi passare al ciclo per -la verifica delle opzioni (\texttt{\small 2-27}); per ciascuna delle opzioni +la verifica delle opzioni (\texttt{\small 2--27}); per ciascuna delle opzioni possibili si è poi provveduto ad un'azione opportuna, ad esempio per le tre opzioni che prevedono un parametro si è effettuata la decodifica del medesimo, il cui indirizzo è contenuto nella variabile \var{optarg}), avvalorando la -relativa variabile (\texttt{\small 12-14}, \texttt{\small 15-17} e -\texttt{\small 18-20}). Completato il ciclo troveremo in \var{optind} l'indice -in \code{argv[]} del primo degli argomenti rimanenti nella linea di comando. +relativa variabile (\texttt{\small 12--14}, \texttt{\small 15--17} e +\texttt{\small 18--20}). Completato il ciclo troveremo in \var{optind} +l'indice in \code{argv[]} del primo degli argomenti rimanenti nella linea di +comando. Normalmente \func{getopt} compie una permutazione degli elementi di \param{argv} cosicché alla fine della scansione gli elementi che non sono diff --git a/session.tex b/session.tex index d3bcdde..862099b 100644 --- a/session.tex +++ b/session.tex @@ -2134,7 +2134,7 @@ dall'argomento \param{flag}; prima si leggono i valori correnti errore (\texttt{\small 9--10}), poi si provvede a impostare solo i bit richiesti (possono essere più di uno) con un OR binario (\texttt{\small 12}); infine si scrive il nuovo valore modificato con \func{tcsetattr} -(\texttt{\small 13}), notificando un eventuale errore (\texttt{\small 14-15}) +(\texttt{\small 13}), notificando un eventuale errore (\texttt{\small 14--15}) o uscendo normalmente. \begin{figure}[!htbp] diff --git a/signal.tex b/signal.tex index 53664b9..ec5b39d 100644 --- a/signal.tex +++ b/signal.tex @@ -1781,13 +1781,13 @@ fig.~\ref{fig:sig_sleep_wrong}. Dato che è nostra intenzione utilizzare \signal{SIGALRM} il primo passo della nostra implementazione sarà quello di installare il relativo gestore salvando -il precedente (\texttt{\small 14-17}). Si effettuerà poi una chiamata ad +il precedente (\texttt{\small 14--17}). Si effettuerà poi una chiamata ad \func{alarm} per specificare il tempo d'attesa per l'invio del segnale a cui segue la chiamata a \func{pause} per fermare il programma (\texttt{\small - 18-20}) fino alla sua ricezione. Al ritorno di \func{pause}, causato dal -ritorno del gestore (\texttt{\small 1-9}), si ripristina il gestore originario -(\texttt{\small 21-22}) restituendo l'eventuale tempo rimanente -(\texttt{\small 23-24}) che potrà essere diverso da zero qualora + 18--20}) fino alla sua ricezione. Al ritorno di \func{pause}, causato dal +ritorno del gestore (\texttt{\small 1--9}), si ripristina il gestore originario +(\texttt{\small 21--22}) restituendo l'eventuale tempo rimanente +(\texttt{\small 23--24}) che potrà essere diverso da zero qualora l'interruzione di \func{pause} venisse causata da un altro segnale. Questo codice però, a parte il non gestire il caso in cui si è avuta una @@ -1816,11 +1816,11 @@ codice del tipo di quello riportato in fig.~\ref{fig:sig_sleep_incomplete}. \label{fig:sig_sleep_incomplete} \end{figure} -In questo caso il gestore (\texttt{\small 18-27}) non ritorna come in +In questo caso il gestore (\texttt{\small 18--27}) non ritorna come in fig.~\ref{fig:sig_sleep_wrong}, ma usa la funzione \func{longjmp} (\texttt{\small 25}) per rientrare direttamente nel corpo principale del programma. Dato che in questo caso il valore di uscita che verrà restituito da -\func{setjmp} è 1, grazie alla condizione impostata in (\texttt{\small 9-12}) +\func{setjmp} è 1, grazie alla condizione impostata in (\texttt{\small 9--12}) si potrà evitare comunque che \func{pause} sia chiamata a vuoto. Ma anche questa implementazione comporta dei problemi, in questo caso infatti @@ -1838,11 +1838,11 @@ da controllare nel corpo principale del programma, con un codice del tipo di quello riportato in fig.~\ref{fig:sig_event_wrong}. La logica del programma è quella di far impostare al gestore (\texttt{\small - 14-19}) una \index{variabili!globali} variabile globale, preventivamente + 14--19}) una \index{variabili!globali} variabile globale, preventivamente inizializzata nel programma principale, ad un diverso valore. In questo modo dal corpo principale del programma si potrà determinare, osservandone il contenuto di detta variabile, l'occorrenza o meno del segnale, ed eseguire le -azioni conseguenti (\texttt{\small 6-11}) relative. +azioni conseguenti (\texttt{\small 6--11}) relative. \begin{figure}[!htbp] \footnotesize\centering @@ -2508,14 +2508,14 @@ presenta neanche questa necessità. Per evitare i problemi di interferenza con gli altri segnali in questo caso non si è usato l'approccio di fig.~\ref{fig:sig_sleep_incomplete} evitando -l'uso di \func{longjmp}. Come in precedenza il gestore (\texttt{\small 27-30}) -non esegue nessuna operazione, limitandosi a ritornare per interrompere il -programma messo in attesa. +l'uso di \func{longjmp}. Come in precedenza il gestore (\texttt{\small + 27--30}) non esegue nessuna operazione, limitandosi a ritornare per +interrompere il programma messo in attesa. -La prima parte della funzione (\texttt{\small 6-10}) provvede ad installare +La prima parte della funzione (\texttt{\small 6--10}) provvede ad installare l'opportuno gestore per \signal{SIGALRM}, salvando quello originario, che sarà ripristinato alla conclusione della stessa (\texttt{\small 23}); il passo -successivo è quello di bloccare \signal{SIGALRM} (\texttt{\small 11-14}) per +successivo è quello di bloccare \signal{SIGALRM} (\texttt{\small 11--14}) per evitare che esso possa essere ricevuto dal processo fra l'esecuzione di \func{alarm} (\texttt{\small 16}) e la sospensione dello stesso. Nel fare questo si salva la maschera corrente dei segnali, che sarà ripristinata alla diff --git a/sockctrl.tex b/sockctrl.tex index 458b811..879da3a 100644 --- a/sockctrl.tex +++ b/sockctrl.tex @@ -1723,12 +1723,12 @@ Una volta definite le variabili necessarie (\texttt{\small 3--5}) la funzione prima (\texttt{\small 6}) azzera il contenuto della struttura \var{hint} e poi provvede (\texttt{\small 7--9}) ad inizializzarne i valori necessari per la chiamata (\texttt{\small 10}) a \func{getaddrinfo}. Di quest'ultima si -controlla (\texttt{\small 12-16}) il codice di ritorno, in modo da stampare un +controlla (\texttt{\small 12--16}) il codice di ritorno, in modo da stampare un avviso di errore, azzerare \var{errno} ed uscire in caso di errore. Dato che ad una macchina possono corrispondere più indirizzi IP, e di tipo diverso (sia IPv4 che IPv6), mentre il servizio può essere in ascolto soltanto su uno solo di questi, si provvede a tentare la connessione per ciascun indirizzo -restituito all'interno di un ciclo (\texttt{\small 18-40}) di scansione della +restituito all'interno di un ciclo (\texttt{\small 18--40}) di scansione della lista restituita da \func{getaddrinfo}, ma prima (\texttt{\small 17}) si salva il valore del puntatore per poterlo riutilizzare alla fine per disallocare la lista. @@ -1738,7 +1738,7 @@ validi, ed inizia (\texttt{\small 19}) con l'apertura del socket; se questa fallisce si controlla (\texttt{\small 20}) se sono disponibili altri indirizzi, nel qual caso si passa al successivo (\texttt{\small 21}) e si riprende (\texttt{\small 22}) il ciclo da capo; se non ve ne sono si stampa -l'errore ritornando immediatamente (\texttt{\small 24-27}). Quando la +l'errore ritornando immediatamente (\texttt{\small 24--27}). Quando la creazione del socket ha avuto successo si procede (\texttt{\small 29}) direttamente con la connessione, di nuovo in caso di fallimento viene ripetuto (\texttt{\small 30--38}) il controllo se vi sono o no altri indirizzi da @@ -1808,11 +1808,11 @@ del valore \const{AI\_PASSIVE} serve ad ottenere il valore generico nella rispettiva struttura degli indirizzi. Come già detto la funzione è analoga a \texttt{sockconn} ed inizia azzerando -ed inizializzando (\texttt{\small 6-11}) opportunamente la struttura +ed inizializzando (\texttt{\small 6--11}) opportunamente la struttura \var{hint} con i valori ricevuti come argomenti, soltanto che in questo caso si è usata (\texttt{\small 8}) una impostazione specifica dei flag di \var{hint} usando \const{AI\_PASSIVE} per indicare che il socket sarà usato -per una apertura passiva. Per il resto la chiamata (\texttt{\small 12-18}) a +per una apertura passiva. Per il resto la chiamata (\texttt{\small 12--18}) a \func{getaddrinfo} e ed il ciclo principale (\texttt{\small 20--42}) sono identici, solo che si è sostituita (\texttt{\small 31}) la chiamata a \func{connect} con una chiamata a \func{bind}. Anche la conclusione @@ -2532,7 +2532,7 @@ guida. In realtà tutto quello che si è fatto è stato introdurre nella nuova funzione (\texttt{\small 1}) un nuovo argomento intero, \param{reuse}, che conterrà il valore logico da usare nella successiva chiamata (\texttt{\small 14}) a -\func{setsockopt}. Si è poi aggiunta una sezione (\texttt{\small 13-17}) che +\func{setsockopt}. Si è poi aggiunta una sezione (\texttt{\small 13--17}) che esegue l'impostazione dell'opzione fra la chiamata a \func{socket} e quella a \func{bind}. @@ -2549,7 +2549,7 @@ usata (\texttt{\small 14}) come ultimo argomento di \func{setsockopt}. Il valore di default di questa variabile è nullo, ma usando l'opzione \texttt{-r} nell'invocazione del server (al solito la gestione delle opzioni non è riportata in fig.~\ref{fig:TCP_echod_fifth}) se ne potrà impostare ad 1 il -valore, per cui in tal caso la successiva chiamata (\texttt{\small 13-17}) a +valore, per cui in tal caso la successiva chiamata (\texttt{\small 13--17}) a \func{setsockopt} attiverà l'opzione \const{SO\_REUSEADDR}. \begin{figure}[!htbp] diff --git a/tcpsock.tex b/tcpsock.tex index 8756e05..30e90a1 100644 --- a/tcpsock.tex +++ b/tcpsock.tex @@ -1385,7 +1385,7 @@ il numero della porta del servizio. Il primo passo (\texttt{\small 20}) è inizializzare tutto a zero, per poi inserire il tipo di indirizzo (\texttt{\small 21}) e la porta (\texttt{\small 22}), usando per quest'ultima la funzione \func{htons} per convertire il formato dell'intero usato dal -computer a quello usato nella rete, infine \texttt{\small 23--27} si può +computer a quello usato nella rete, infine (\texttt{\small 23--27}) si può utilizzare la funzione \func{inet\_pton} per convertire l'indirizzo numerico passato dalla linea di comando.