X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=ipc.tex;h=ff6e69cb673cfb8729adec98abc31087cc444065;hp=87c35f8c0a8c81a1b0bc159862a5e68290fad41f;hb=9949b501aea36905b12f069e11743b70b3e2df57;hpb=6686b8c78363c1e91e069b0ff9932929b7948136 diff --git a/ipc.tex b/ipc.tex index 87c35f8..ff6e69c 100644 --- a/ipc.tex +++ b/ipc.tex @@ -1,6 +1,6 @@ %% ipc.tex %% -%% Copyright (C) 2000-2013 Simone Piccardi. Permission is granted to +%% Copyright (C) 2000-2014 Simone Piccardi. Permission is granted to %% copy, distribute and/or modify this document under the terms of the GNU Free %% Documentation License, Version 1.1 or any later version published by the %% Free Software Foundation; with the Invariant Sections being "Un preambolo", @@ -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 @@ -355,7 +355,7 @@ chiama \funcd{popen} ed il suo prototipo è: \end{funcproto} La funzione crea una \textit{pipe}, esegue una \func{fork} creando un nuovo -processe nel quale invoca il programma \param{command} attraverso la shell (in +processo nel quale invoca il programma \param{command} attraverso la shell (in sostanza esegue \file{/bin/sh} con il flag \code{-c}). L'argomento \param{type} deve essere una delle due stringhe \verb|"w"| o \verb|"r"|, per richiedere che la \textit{pipe} restituita come valore di @@ -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 @@ -690,9 +690,9 @@ stringa di richiesta dalla \textit{fifo} nota (che a questo punto si bloccherà tutte le volte che non ci sono richieste). Dopo di che, una volta terminata la stringa (\texttt{\small 40}) e selezionato (\texttt{\small 41}) un numero casuale per ricavare la frase da inviare, si procederà (\texttt{\small - 42--46}) all'apertura della \textit{fifo} per la risposta, che poi -\texttt{\small 47--48}) vi sarà scritta. Infine (\texttt{\small 49}) si chiude -la \textit{fifo} di risposta che non serve più. + 42--46}) all'apertura della \textit{fifo} per la risposta, che poi +(\texttt{\small 47--48}) vi sarà scritta. Infine (\texttt{\small 49}) si +chiude la \textit{fifo} di risposta che non serve più. Il codice del client è invece riportato in fig.~\ref{fig:ipc_fifo_client}, anche in questo caso si è omessa la gestione delle opzioni e la funzione che @@ -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 @@ -1020,7 +1020,7 @@ problema del \textit{SysV-IPC}. Non esiste infatti una modalità chiara per identificare un oggetto, come sarebbe stato se lo si fosse associato ad in file, e tutta l'interfaccia è inutilmente complessa. Per questo se ne sconsiglia assolutamente l'uso nei nuovi programmi, considerato che è ormai -disponibile una revisione completa dei meccamismi di IPC fatta secondo quanto +disponibile una revisione completa dei meccanismi di IPC fatta secondo quanto indicato dallo standard POSIX.1b, che presenta una realizzazione più sicura ed una interfaccia più semplice, che tratteremo in sez.~\ref{sec:ipc_posix}. @@ -1161,7 +1161,7 @@ numero di tutti gli oggetti presenti nel \textit{SysV-IPC}, ed il cui default l'identificatore assuma tutti i valori possibili. In fig.~\ref{fig:ipc_sysv_idtest} è riportato il codice di un semplice -programma di test che si limita a creare un oggetto di ICP (specificato con +programma di test che si limita a creare un oggetto di IPC (specificato con una opzione a riga di comando), stamparne il numero di identificatore, e cancellarlo, il tutto un numero di volte specificato tramite una seconda opzione. La figura non riporta il codice di selezione delle opzioni, che @@ -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 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 (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 @@ -1413,20 +1422,20 @@ file; il suo prototipo è: \var{msg\_qbytes} oltre il limite \const{MSGMNB} senza essere amministratore. \end{errlist} - ed inoltre \errval{EFAULT} ed \errval{EINVAL} nel loro significato + ed inoltre \errval{EFAULT} ed \errval{EINVAL} nel loro significato 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{ipcs} 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,42 @@ 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 +1881,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 +1922,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 +1955,27 @@ 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 +1984,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,42 +2038,39 @@ 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 - l'operazione richiesta. +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 di lettura o scrittura richiesta e non si hanno i privilegi + di amministratore. \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 @@ -2059,7 +2079,7 @@ specificata con \param{cmd}, ed opera o sull'intero insieme specificato da \begin{figure}[!htb] \footnotesize \centering - \begin{minipage}[c]{\textwidth} + \begin{minipage}[c]{0.80\textwidth} \includestruct{listati/semun.h} \end{minipage} \normalsize @@ -2071,33 +2091,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 -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. +\param{cmd}, che specifica l'azione da intraprendere. Per questo argomento i +valori validi, quelli cioè che non causano un errore di \errcode{EINVAL}, sono +i seguenti: +\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. @@ -2105,32 +2133,37 @@ seguenti: \item[\const{GETNCNT}] Restituisce come valore di ritorno della funzione il numero di processi in attesa che il semaforo \param{semnum} dell'insieme \param{semid} venga incrementato (corrispondente al campo \var{semncnt} di - \struct{sem}); va invocata con tre argomenti. Occorre avere il permesso di + \struct{sem}). Va invocata con tre argomenti. Occorre avere il permesso di lettura. \item[\const{GETPID}] Restituisce come valore di ritorno della funzione il \ids{PID} dell'ultimo processo che ha compiuto una operazione sul semaforo \param{semnum} dell'insieme \param{semid} (corrispondente al campo - \var{sempid} di \struct{sem}); va invocata con tre argomenti. Occorre avere + \var{sempid} di \struct{sem}). Va invocata con tre argomenti. Occorre avere il permesso di lettura. \item[\const{GETVAL}] Restituisce come valore di ritorno della funzione il il valore corrente del semaforo \param{semnum} dell'insieme \param{semid} - (corrispondente al campo \var{semval} di \struct{sem}); va invocata con tre + (corrispondente al campo \var{semval} di \struct{sem}). Va invocata con tre argomenti. Occorre avere il permesso di lettura. \item[\const{GETZCNT}] Restituisce come valore di ritorno della funzione il numero di processi in attesa che il valore del semaforo \param{semnum} dell'insieme \param{semid} diventi nullo (corrispondente al campo - \var{semncnt} di \struct{sem}); va invocata con tre argomenti. Occorre avere - il permesso di lettura. + \var{semncnt} di \struct{sem}). Va invocata con tre argomenti. Occorre + avere il permesso di lettura. \item[\const{SETALL}] Inizializza il valore di tutti i semafori dell'insieme, aggiornando il campo \var{sem\_ctime} di \struct{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. + privilegi di scrittura. L'argomento \param{semnum} viene ignorato. \item[\const{SETVAL}] Inizializza il semaforo \param{semnum} al valore passato dall'argomento \param{arg.val}, aggiornando il campo \var{sem\_ctime} di - \struct{semid\_ds}. Si devono avere i privilegi di scrittura sul semaforo. + \struct{semid\_ds}. Si devono avere i privilegi di scrittura. \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 @@ -2164,52 +2197,92 @@ colonna della tabella. Le operazioni ordinarie sui semafori, come l'acquisizione o il rilascio degli stessi (in sostanza tutte quelle non comprese nell'uso di \func{semctl}) -vengono effettuate con la funzione \funcd{semop}, il cui prototipo è: -\begin{functions} - \headdecl{sys/types.h} - \headdecl{sys/ipc.h} - \headdecl{sys/sem.h} - - \funcdecl{int semop(int semid, struct sembuf *sops, unsigned nsops)} - - Esegue le operazioni ordinarie su un semaforo o un insieme di semafori. - - \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di - errore, nel qual caso \var{errno} assumerà uno dei valori: - \begin{errlist} - \item[\errcode{EACCES}] il processo non ha i privilegi per eseguire - l'operazione richiesta. - \item[\errcode{EIDRM}] l'insieme di semafori è stato cancellato. - \item[\errcode{ENOMEM}] si è richiesto un \const{SEM\_UNDO} ma il sistema - non ha le risorse per allocare la struttura di ripristino. +vengono effettuate con la funzione di sistema \funcd{semop}, il cui prototipo +è: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{sys/ipc.h} +\fhead{sys/sem.h} +\fdecl{int semop(int semid, struct sembuf *sops, unsigned nsops)} +\fdesc{Esegue operazioni ordinarie su un semaforo o un insieme di semafori.} +} + +{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{E2BIG}] l'argomento \param{nsops} è maggiore del numero + massimo di operazioni \const{SEMOPM}. + \item[\errcode{EACCES}] il processo non ha i permessi per eseguire + l'operazione richiesta e non ha i privilegi di amministratore. \item[\errcode{EAGAIN}] un'operazione comporterebbe il blocco del processo, ma si è specificato \const{IPC\_NOWAIT} in \var{sem\_flg}. + \item[\errcode{EFBIG}] il valore del campo \var{sem\_num} è negativo o + maggiore o uguale al numero di semafori dell'insieme. + \item[\errcode{EIDRM}] l'insieme di semafori è stato cancellato. \item[\errcode{EINTR}] la funzione, bloccata in attesa dell'esecuzione dell'operazione, viene interrotta da un segnale. - \item[\errcode{E2BIG}] l'argomento \param{nsops} è maggiore del numero - massimo di operazioni \const{SEMOPM}. + \item[\errcode{ENOMEM}] si è richiesto un \const{SEM\_UNDO} ma il sistema + non ha le risorse per allocare la struttura di ripristino. \item[\errcode{ERANGE}] per alcune operazioni il valore risultante del semaforo viene a superare il limite massimo \const{SEMVMX}. \end{errlist} - ed inoltre \errval{EFAULT} ed \errval{EINVAL}. -} -\end{functions} - - -%TODO manca semtimedop, trattare qui, referenziata in -%sez.~\ref{sec:sig_gen_beha}. + ed inoltre \errval{EFAULT} ed \errval{EINVAL} nel loro significato + generico.} +\end{funcproto} La funzione permette di eseguire operazioni multiple sui singoli semafori di un insieme. La funzione richiede come primo argomento l'identificatore -\param{semid} dell'insieme su cui si vuole operare. Il numero di operazioni da +\param{semid} dell'insieme su cui si vuole operare, il numero di operazioni da effettuare viene specificato con l'argomento \param{nsop}, mentre il loro contenuto viene passato con un puntatore ad un vettore di strutture \struct{sembuf} nell'argomento \param{sops}. Le operazioni richieste vengono -effettivamente eseguite se e soltanto se è possibile effettuarle tutte quante. +effettivamente eseguite se e soltanto se è possibile effettuarle tutte quante, +ed in tal caso vengono eseguite nella sequenza passata nel +vettore \param{sops}. + +Con lo standard POSIX.1-2001 è stata introdotta una variante di \func{semop} +che consente di specificare anche un tempo massimo di attesa. La nuova +funzione di sistema, disponibile a partire dal kernel 2.4.22 e dalle +\acr{glibc} 2.3.3, ed utilizzabile solo dopo aver definito la macro +\macro{\_GNU\_SOURCE}, è \funcd{semtimedop}, ed il suo prototipo è: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{sys/ipc.h} +\fhead{sys/sem.h} +\fdecl{int semtimedop(int semid, struct sembuf *sops, unsigned nsops, + struct timespec *timeout)} +\fdesc{Esegue operazioni ordinarie su un semaforo o un insieme di semafori.} +} + +{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{EAGAIN}] l'operazione comporterebbe il blocco del processo, + ma si è specificato \const{IPC\_NOWAIT} in \var{sem\_flg} oppure si è + atteso oltre quanto indicato da \param{timeout}. + \end{errlist} + e gli altri valori già visti per \func{semop}, con lo stesso significato.} +\end{funcproto} + +Rispetto a \func{semop} la funzione consente di specificare un tempo massimo +di attesa, indicato con una struttura \struct{timespec} (vedi +fig.~\ref{fig:sys_timespec_struct}), per le operazioni che verrebbero +bloccate. Alla scadenza di detto tempo la funzione ritorna comunque con un +errore di \errval{EAGAIN} senza che nessuna delle operazioni richieste venga +eseguita. + +Si tenga presente che la precisione della temporizzazione è comunque limitata +dalla risoluzione dell'orologio di sistema, per cui il tempo di attesa verrà +arrotondato per eccesso. In caso si passi un valore \val{NULL} +per \param{timeout} il comportamento di \func{semtimedop} è identico a quello +di \func{semop}. + \begin{figure}[!htb] \footnotesize \centering - \begin{minipage}[c]{\textwidth} + \begin{minipage}[c]{.80\textwidth} \includestruct{listati/sembuf.h} \end{minipage} \normalsize @@ -2218,65 +2291,73 @@ effettivamente eseguite se e soltanto se è possibile effettuarle tutte quante. \label{fig:ipc_sembuf} \end{figure} -Il contenuto di ciascuna operazione deve essere specificato attraverso una -opportuna struttura \struct{sembuf} (la cui definizione è riportata in +Come indicato il contenuto di ciascuna operazione deve essere specificato +attraverso una struttura \struct{sembuf} (la cui definizione è riportata in fig.~\ref{fig:ipc_sembuf}) che il programma chiamante deve avere cura di allocare in un opportuno vettore. La struttura permette di indicare il -semaforo su cui operare, il tipo di operazione, ed un flag di controllo. +semaforo su cui operare, il tipo di operazione, ed un flag di controllo. + Il campo \var{sem\_num} serve per indicare a quale semaforo dell'insieme fa -riferimento l'operazione; si ricordi che i semafori sono numerati come in un -vettore, per cui il primo semaforo corrisponde ad un valore nullo di -\var{sem\_num}. +riferimento l'operazione. Si ricordi che i semafori sono numerati come gli +elementi di un vettore, per cui il primo semaforo di un insieme corrisponde ad +un valore nullo di \var{sem\_num}. Il campo \var{sem\_flg} è un flag, mantenuto come maschera binaria, per il quale possono essere impostati i due valori \const{IPC\_NOWAIT} e -\const{SEM\_UNDO}. Impostando \const{IPC\_NOWAIT} si fa si che, invece di -bloccarsi (in tutti quei casi in cui l'esecuzione di una operazione richiede -che il processo vada in stato di \textit{sleep}), \func{semop} ritorni -immediatamente con un errore di \errcode{EAGAIN}. Impostando \const{SEM\_UNDO} -si richiede invece che l'operazione venga registrata in modo che il valore del -semaforo possa essere ripristinato all'uscita del processo. - -Infine \var{sem\_op} è il campo che controlla l'operazione che viene eseguita -e determina il comportamento della chiamata a \func{semop}; tre sono i casi -possibili: -\begin{basedescript}{\desclabelwidth{2.0cm}} -\item[\var{sem\_op}$>0$] In questo caso il valore di \var{sem\_op} viene - aggiunto al valore corrente di \var{semval}. La funzione ritorna - immediatamente (con un errore di \errcode{ERANGE} qualora si sia superato il - limite \const{SEMVMX}) ed il processo non viene bloccato in nessun caso. - Specificando \const{SEM\_UNDO} si aggiorna il contatore per il ripristino - del valore del semaforo. Al processo chiamante è richiesto il privilegio di - alterazione (scrittura) sull'insieme di semafori. +\const{SEM\_UNDO}. Impostando \const{IPC\_NOWAIT} si fa si che in tutti quei +casi in cui l'esecuzione di una operazione richiederebbe di porre il processo +vada nello stato di \textit{sleep}, invece di bloccarsi \func{semop} ritorni +immediatamente (abortendo così le eventuali operazioni restanti) con un errore +di \errcode{EAGAIN}. Impostando \const{SEM\_UNDO} si richiede invece che +l'operazione in questione venga registrata, in modo che il valore del semaforo +possa essere ripristinato all'uscita del processo. + +Infine \var{sem\_op} è il campo che controlla qual'è l'operazione che viene +eseguita e determina in generale il comportamento della chiamata a +\func{semop}. I casi possibili per il valore di questo campo sono tre: +\begin{basedescript}{\desclabelwidth{1.8cm}} +\item[\var{sem\_op} $>0$] In questo caso il valore viene aggiunto al valore + corrente di \var{semval} per il semaforo indicato. Questa operazione non + causa mai un blocco del processo, ed eventualmente \func{semop} ritorna + immediatamente con un errore di \errcode{ERANGE} qualora si sia superato il + limite \const{SEMVMX}. Se l'operazione ha successo si passa immediatamente + alla successiva. Specificando \const{SEM\_UNDO} si aggiorna il contatore + per il ripristino del valore del semaforo. Al processo chiamante è richiesto + il privilegio di alterazione (scrittura) sull'insieme di semafori. -\item[\var{sem\_op}$=0$] Nel caso \var{semval} sia zero l'esecuzione procede - immediatamente. Se \var{semval} è diverso da zero il comportamento è - controllato da \var{sem\_flg}, se è stato impostato \const{IPC\_NOWAIT} la - funzione ritorna con un errore di \errcode{EAGAIN}, altrimenti viene - incrementato \var{semzcnt} di uno ed il processo resta in stato di - \textit{sleep} fintanto che non si ha una delle condizioni seguenti: +\item[\var{sem\_op} $=0$] Nel caso \var{semval} sia zero l'operazione ha + successo immediato, e o si passa alla successiva o \func{semop} ritorna con + successo se questa era l'ultima. Se \var{semval} è diverso da zero il + comportamento è controllato da \var{sem\_flg}, se è stato impostato + \const{IPC\_NOWAIT} \func{semop} ritorna immediatamente abortendo tutte le + operazioni con un errore di \errcode{EAGAIN}, altrimenti viene incrementato + \var{semzcnt} di uno ed il processo viene bloccato fintanto che non si + verifica una delle condizioni seguenti: \begin{itemize*} \item \var{semval} diventa zero, nel qual caso \var{semzcnt} viene - decrementato di uno. - \item l'insieme di semafori viene rimosso, nel qual caso \func{semop} ritorna - un errore di \errcode{EIDRM}. + decrementato di uno, l'operazione ha successo e si passa alla successiva, + oppure \func{semop} ritorna con successo se questa era l'ultima. + \item l'insieme di semafori viene rimosso, nel qual caso \func{semop} + ritorna abortendo tutte le operazioni con un errore di \errcode{EIDRM}. \item il processo chiamante riceve un segnale, nel qual caso \var{semzcnt} - viene decrementato di uno e \func{semop} ritorna un errore di - \errcode{EINTR}. + viene decrementato di uno e \func{semop} ritorna abortendo tutte le + operazioni con un errore di \errcode{EINTR}. \end{itemize*} - Al processo chiamante è richiesto il privilegio di lettura dell'insieme dei - semafori. + Al processo chiamante è richiesto soltanto il privilegio di lettura + dell'insieme dei semafori. -\item[\var{sem\_op}$<0$] Nel caso in cui \var{semval} è maggiore o uguale del +\item[\var{sem\_op} $<0$] Nel caso in cui \var{semval} è maggiore o uguale del valore assoluto di \var{sem\_op} (se cioè la somma dei due valori resta - positiva o nulla) i valori vengono sommati e la funzione ritorna - immediatamente; qualora si sia impostato \const{SEM\_UNDO} viene anche + positiva o nulla) i valori vengono sommati e l'operazione ha successo e si + passa alla successiva, oppure \func{semop} ritorna con successo se questa + era l'ultima. Qualora si sia impostato \const{SEM\_UNDO} viene anche aggiornato il contatore per il ripristino del valore del semaforo. In caso contrario (quando cioè la somma darebbe luogo ad un valore di \var{semval} - negativo) se si è impostato \const{IPC\_NOWAIT} la funzione ritorna con un - errore di \errcode{EAGAIN}, altrimenti viene incrementato di uno - \var{semncnt} ed il processo resta in stato di \textit{sleep} fintanto che - non si ha una delle condizioni seguenti: + negativo) se si è impostato \const{IPC\_NOWAIT} \func{semop} ritorna + immediatamente abortendo tutte le operazioni con un errore di + \errcode{EAGAIN}, altrimenti viene incrementato di uno \var{semncnt} ed il + processo resta in stato di \textit{sleep} fintanto che non si ha una delle + condizioni seguenti: \begin{itemize*} \item \var{semval} diventa maggiore o uguale del valore assoluto di \var{sem\_op}, nel qual caso \var{semncnt} viene decrementato di uno, il @@ -2284,42 +2365,49 @@ possibili: impostato \const{SEM\_UNDO} viene aggiornato il contatore per il ripristino del valore del semaforo. \item l'insieme di semafori viene rimosso, nel qual caso \func{semop} - ritorna un errore di \errcode{EIDRM}. + ritorna abortendo tutte le operazioni con un errore di \errcode{EIDRM}. \item il processo chiamante riceve un segnale, nel qual caso \var{semncnt} - viene decrementato di uno e \func{semop} ritorna un errore di - \errcode{EINTR}. + viene decrementato di uno e \func{semop} ritorna abortendo tutte le + operazioni con un errore di \errcode{EINTR}. \end{itemize*} Al processo chiamante è richiesto il privilegio di alterazione (scrittura) sull'insieme di semafori. \end{basedescript} -In caso di successo della funzione viene aggiornato il campo \var{sempid} per -ogni semaforo modificato al valore del \ids{PID} del processo chiamante; -inoltre vengono pure aggiornati al tempo corrente i campi \var{sem\_otime} e -\var{sem\_ctime}. +Qualora si sia usato \func{semtimedop} alle condizioni di errore precedenti si +aggiunge anche quella di scadenza del tempo di attesa indicato +con \param{timeout} che farà abortire la funzione, qualora resti bloccata +troppo a lungo nell'esecuzione delle operazioni richieste, con un errore di +\errcode{EAGAIN}. + +In caso di successo (sia per \func{semop} che per \func{semtimedop}) per ogni +semaforo modificato verrà aggiornato il campo \var{sempid} al valore del +\ids{PID} del processo chiamante; inoltre verranno pure aggiornati al tempo +corrente i campi \var{sem\_otime} e \var{sem\_ctime}. Dato che, come già accennato in precedenza, in caso di uscita inaspettata i -semafori possono restare occupati, abbiamo visto come \func{semop} permetta di -attivare un meccanismo di ripristino attraverso l'uso del flag -\const{SEM\_UNDO}. Il meccanismo è implementato tramite una apposita struttura -\kstruct{sem\_undo}, associata ad ogni processo per ciascun semaforo che esso -ha modificato; all'uscita i semafori modificati vengono ripristinati, e le -strutture disallocate. Per mantenere coerente il comportamento queste -strutture non vengono ereditate attraverso una \func{fork} (altrimenti si -avrebbe un doppio ripristino), mentre passano inalterate nell'esecuzione di -una \func{exec} (altrimenti non si avrebbe ripristino). +semafori possono restare occupati, abbiamo visto come \func{semop} (e +\func{semtimedop}) permetta di attivare un meccanismo di ripristino attraverso +l'uso del flag \const{SEM\_UNDO}. Il meccanismo è implementato tramite una +apposita struttura \kstruct{sem\_undo}, associata ad ogni processo per ciascun +semaforo che esso ha modificato; all'uscita i semafori modificati vengono +ripristinati, e le strutture disallocate. Per mantenere coerente il +comportamento queste strutture non vengono ereditate attraverso una +\func{fork} (altrimenti si avrebbe un doppio ripristino), mentre passano +inalterate nell'esecuzione di una \func{exec} (altrimenti non si avrebbe +ripristino). Tutto questo però ha un problema di fondo. Per capire di cosa si tratta occorre fare riferimento all'implementazione usata in Linux, che è riportata in maniera semplificata nello schema di fig.~\ref{fig:ipc_sem_schema}. Si è presa come riferimento l'architettura usata fino al kernel 2.2.x che è più -semplice (ed illustrata in dettaglio in \cite{tlk}); nel kernel 2.4.x la +semplice (ed illustrata in dettaglio in \cite{tlk}). Nel kernel 2.4.x la struttura del \textit{SysV-IPC} è stata modificata, ma le definizioni relative -a queste strutture restano per compatibilità.\footnote{in particolare con le - vecchie versioni delle librerie del C, come le libc5.} +a queste strutture restano per compatibilità (in particolare con le vecchie +versioni delle librerie del C, come le \acr{libc5}). \begin{figure}[!htb] - \centering \includegraphics[width=13cm]{img/semtruct} + \centering \includegraphics[width=12cm]{img/semtruct} \caption{Schema della struttura di un insieme di semafori.} \label{fig:ipc_sem_schema} \end{figure} @@ -2328,16 +2416,15 @@ Alla creazione di un nuovo insieme viene allocata una nuova strutture \struct{semid\_ds} ed il relativo vettore di strutture \struct{sem}. Quando si richiede una operazione viene anzitutto verificato che tutte le operazioni possono avere successo; se una di esse comporta il blocco del processo il -kernel crea una struttura \kstruct{sem\_queue} che viene aggiunta in fondo alla -coda di attesa associata a ciascun insieme di semafori\footnote{che viene - referenziata tramite i campi \var{sem\_pending} e \var{sem\_pending\_last} - di \struct{semid\_ds}.}. - -Nella struttura viene memorizzato il riferimento alle operazioni richieste -(nel campo \var{sops}, che è un puntatore ad una struttura \struct{sembuf}) e -al processo corrente (nel campo \var{sleeper}) poi quest'ultimo viene messo -stato di attesa e viene invocato lo \itindex{scheduler} scheduler per passare -all'esecuzione di un altro processo. +kernel crea una struttura \kstruct{sem\_queue} che viene aggiunta in fondo +alla coda di attesa associata a ciascun insieme di semafori, che viene +referenziata tramite i campi \var{sem\_pending} e \var{sem\_pending\_last} di +\struct{semid\_ds}. Nella struttura viene memorizzato il riferimento alle +operazioni richieste (nel campo \var{sops}, che è un puntatore ad una +struttura \struct{sembuf}) e al processo corrente (nel campo \var{sleeper}) +poi quest'ultimo viene messo stato di attesa e viene invocato lo +\itindex{scheduler} \textit{scheduler} per passare all'esecuzione di un altro +processo. Se invece tutte le operazioni possono avere successo queste vengono eseguite immediatamente, dopo di che il kernel esegue una scansione della coda di @@ -2353,21 +2440,18 @@ contiene (nel vettore puntato dal campo \var{semadj}) un valore di aggiustamento per ogni semaforo cui viene sommato l'opposto del valore usato per l'operazione. -%TODO verificare queste strutture \kstruct{sem\_queue} e \kstruct{sem\_undo} - -Queste strutture sono mantenute in due liste,\footnote{rispettivamente - attraverso i due campi \var{id\_next} e \var{proc\_next}.} una associata -all'insieme di cui fa parte il semaforo, che viene usata per invalidare le -strutture se questo viene cancellato o per azzerarle se si è eseguita una -operazione con \func{semctl}; l'altra associata al processo che ha eseguito -l'operazione;\footnote{attraverso il campo \var{semundo} di - \kstruct{task\_struct}, come mostrato in \ref{fig:ipc_sem_schema}.} quando un -processo termina, la lista ad esso associata viene scandita e le operazioni -applicate al semaforo. Siccome un processo può accumulare delle richieste di -ripristino per semafori differenti chiamate attraverso diverse chiamate a -\func{semop}, si pone il problema di come eseguire il ripristino dei semafori -all'uscita del processo, ed in particolare se questo può essere fatto -atomicamente. +Queste strutture sono mantenute in due liste (rispettivamente attraverso i due +campi \var{id\_next} e \var{proc\_next}) una associata all'insieme di cui fa +parte il semaforo, che viene usata per invalidare le strutture se questo viene +cancellato o per azzerarle se si è eseguita una operazione con \func{semctl}, +l'altra associata al processo che ha eseguito l'operazione, attraverso il +campo \var{semundo} di \kstruct{task\_struct}, come mostrato in +\ref{fig:ipc_sem_schema}. Quando un processo termina, la lista ad esso +associata viene scandita e le operazioni applicate al semaforo. Siccome un +processo può accumulare delle richieste di ripristino per semafori differenti +attraverso diverse chiamate a \func{semop}, si pone il problema di come +eseguire il ripristino dei semafori all'uscita del processo, ed in particolare +se questo può essere fatto atomicamente. Il punto è cosa succede quando una delle operazioni previste per il ripristino non può essere eseguita immediatamente perché ad esempio il semaforo è @@ -2463,20 +2547,20 @@ problemi, usando il \itindex{file~locking} \textit{file locking}. \label{sec:ipc_sysv_shm} Il terzo oggetto introdotto dal \textit{SysV-IPC} è quello dei segmenti di -memoria condivisa. La funzione che permette di ottenerne uno è \funcd{shmget}, -ed il suo prototipo è: -\begin{functions} - \headdecl{sys/types.h} - \headdecl{sys/ipc.h} - \headdecl{sys/shm.h} - - \funcdecl{int shmget(key\_t key, int size, int flag)} - - Restituisce l'identificatore di una memoria condivisa. - - \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} +memoria condivisa. La funzione di sistema che permette di ottenerne uno è +\funcd{shmget}, ed il suo prototipo è: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{sys/ipc.h} +\fhead{sys/shm.h} +\fdecl{int shmget(key\_t key, int size, int flag)} +\fdesc{Ottiene o crea una memoria condivisa.} +} + +{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 (\const{SHMMNI}) sul numero di segmenti di memoria nel sistema, o cercato di allocare un segmento le cui dimensioni fanno superare il limite di sistema (\const{SHMALL}) per @@ -2486,18 +2570,45 @@ ed il suo prototipo è: già esiste \param{size} è maggiore delle sue dimensioni. \item[\errcode{ENOMEM}] il sistema non ha abbastanza memoria per poter contenere le strutture per un nuovo segmento di memoria condivisa. - \end{errlist} - ed inoltre \errval{EACCES}, \errval{ENOENT}, \errval{EEXIST}, - \errval{EIDRM}, con lo stesso significato che hanno per \func{msgget}.} -\end{functions} + \item[\errcode{ENOMEM}] si è specificato \const{IPC\_HUGETLB} ma non si + hanno i privilegi di amministratore. + \end{errlist} + ed inoltre \errval{EACCES}, \errval{ENOENT}, \errval{EEXIST}, + \errval{EIDRM}, con lo stesso significato che hanno per \func{msgget}.} +\end{funcproto} -La funzione, come \func{semget}, è 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 sez.~\ref{sec:ipc_sysv_mq}. L'argomento -\param{size} specifica invece la dimensione, in byte, del segmento, che viene -comunque arrotondata al multiplo superiore di \const{PAGE\_SIZE}. -% TODO aggiungere l'uso di SHM_HUGETLB introdotto con il kernel 2.6.0 +La funzione, come \func{semget}, è analoga a \func{msgget}, ed identico è +l'uso degli argomenti \param{key} e \param{flag} per cui non ripeteremo quanto +detto al proposito in sez.~\ref{sec:ipc_sysv_mq}. A partire dal kernel 2.6 +però sono stati introdotti degli ulteriori bit di controllo per +l'argomento \param{flag}, specifici di \func{shmget}, attinenti alle modalità +di gestione del segmento di memoria condivisa in relazione al sistema della +memoria virtuale. + +Il primo dei due flag è \const{SHM\_HUGETLB} che consente di richiedere la +creazione del segmento usando una \itindex{huge~page} \textit{huge page}, le +pagine di memoria di grandi dimensioni introdotte con il kernel 2.6 per +ottimizzare le prestazioni nei sistemi più recenti che hanno grandi quantità +di memoria. L'operazione è privilegiata e richiede che il processo abbia la +\itindex{capability} \textit{capability} \const{CAP\_IPC\_LOCK}. Questa +funzionalità è specifica di Linux e non è portabile. + +Il secondo flag aggiuntivo, introdotto a partire dal kernel 2.6.15, è +\const{SHM\_NORESERVE}, ed ha lo stesso scopo del flag \const{MAP\_NORESERVE} +di \func{mmap} (vedi sez.~\ref{sec:file_memory_map}): non vengono riservate +delle pagine di swap ad uso del meccanismo del \textit{copy on write} +\itindex{copy~on~write} per mantenere le modifiche fatte sul segmento. Questo +significa che caso di scrittura sul segmento quando non c'è più memoria +disponibile, si avrà l'emissione di un \signal{SIGSEGV}. + +Infine l'argomento \param{size} specifica la dimensione del segmento di +memoria condivisa; il valore deve essere specificato in byte, ma verrà +comunque arrotondato al multiplo superiore di \const{PAGE\_SIZE}. Il valore +deve essere specificato quando si crea un nuovo segmento di memoria con +\const{IPC\_CREAT} o \const{IPC\_PRIVATE}, se invece si accede ad un segmento +di memoria condivisa esistente non può essere maggiore del valore con cui esso +è stato creato. La memoria condivisa è la forma più veloce di comunicazione fra due processi, in quanto permette agli stessi di vedere nel loro spazio di indirizzi una @@ -2519,7 +2630,7 @@ norma, significa insieme a dei semafori. \begin{figure}[!htb] \footnotesize \centering - \begin{minipage}[c]{\textwidth} + \begin{minipage}[c]{0.80\textwidth} \includestruct{listati/shmid_ds.h} \end{minipage} \normalsize @@ -2536,7 +2647,7 @@ campo \var{shm\_perm} viene inizializzato come illustrato in sez.~\ref{sec:ipc_sysv_access_control}, e valgono le considerazioni ivi fatte relativamente ai permessi di accesso; per quanto riguarda gli altri campi invece: -\begin{itemize} +\begin{itemize*} \item il campo \var{shm\_segsz}, che esprime la dimensione del segmento, viene inizializzato al valore di \param{size}. \item il campo \var{shm\_ctime}, che esprime il tempo di creazione del @@ -2550,7 +2661,7 @@ invece: creato il segmento, viene inizializzato al \ids{PID} del processo chiamante. \item il campo \var{shm\_nattac}, che esprime il numero di processi agganciati al segmento viene inizializzato a zero. -\end{itemize} +\end{itemize*} Come per le code di messaggi e gli insiemi di semafori, anche per i segmenti di memoria condivisa esistono una serie di limiti imposti dal sistema. Alcuni @@ -2591,7 +2702,9 @@ che permettono di cambiarne il valore. pagina di memoria).\\ \const{SHMSEG}& --- & --- & Numero massimo di segmenti di memoria condivisa per ciascun - processo.\\ + processo (l'implementazione non + prevede l'esistenza di questo + limite).\\ \hline @@ -2602,39 +2715,43 @@ che permettono di cambiarne il valore. \label{tab:ipc_shm_limits} \end{table} -Al solito la funzione che permette di effettuare le operazioni di controllo su -un segmento di memoria condivisa è \funcd{shmctl}; il suo prototipo è: -\begin{functions} - \headdecl{sys/ipc.h} - \headdecl{sys/shm.h} - - \funcdecl{int shmctl(int shmid, int cmd, struct shmid\_ds *buf)} - - Esegue le operazioni di controllo su un segmento di memoria condivisa. - - \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di - errore, nel qual caso \var{errno} assumerà i valori: - \begin{errlist} +Al solito la funzione di sistema che permette di effettuare le operazioni di +controllo su un segmento di memoria condivisa è \funcd{shmctl}; il suo +prototipo è: + +\begin{funcproto}{ +\fhead{sys/ipc.h} +\fhead{sys/shm.h} +\fdecl{int shmctl(int shmid, int cmd, struct shmid\_ds *buf)} + +\fdesc{Esegue le operazioni di controllo su un segmento di memoria condivisa.} +} + +{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}] si è richiesto \const{IPC\_STAT} ma i permessi non consentono l'accesso in lettura al segmento. - \item[\errcode{EINVAL}] o \param{shmid} non è un identificatore valido o - \param{cmd} non è un comando valido. + \item[\errcode{EFAULT}] l'indirizzo specificato con \param{buf} non è + valido. \item[\errcode{EIDRM}] l'argomento \param{shmid} fa riferimento ad un segmento che è stato cancellato. - \item[\errcode{EPERM}] si è specificato un comando con \const{IPC\_SET} o - \const{IPC\_RMID} senza i permessi necessari. + \item[\errcode{EINVAL}] o \param{shmid} non è un identificatore valido o + \param{cmd} non è un comando valido. + \item[\errcode{ENOMEM}] si è richiesto un \textit{memory lock} di + dimensioni superiori al massimo consentito. \item[\errcode{EOVERFLOW}] si è tentato il comando \const{IPC\_STAT} ma il valore del \ids{GID} o dell'\ids{UID} è troppo grande per essere memorizzato nella struttura puntata da \param{buf}. - \item[\errcode{EFAULT}] l'indirizzo specificato con \param{buf} non è - valido. - \end{errlist} -} -\end{functions} + \item[\errcode{EPERM}] si è specificato un comando con \const{IPC\_SET} o + \const{IPC\_RMID} senza i permessi necessari. + \end{errlist} +} +\end{funcproto} Il comando specificato attraverso l'argomento \param{cmd} determina i diversi -effetti della funzione; i possibili valori che esso può assumere, ed il -corrispondente comportamento della funzione, sono i seguenti: +effetti della funzione. Nello standard POSIX.1-2001 i valori che esso può +assumere, ed il corrispondente comportamento della funzione, sono i seguenti: \begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}} \item[\const{IPC\_STAT}] Legge le informazioni riguardo il segmento di memoria @@ -2650,20 +2767,35 @@ corrispondente comportamento della funzione, sono i seguenti: \var{shm\_perm.uid} e \var{shm\_perm.gid} occorre essere il proprietario o il creatore del segmento, oppure l'amministratore. Compiuta l'operazione aggiorna anche il valore del campo \var{shm\_ctime}. +\end{basedescript} + +Oltre ai precedenti su Linux sono definiti anche degli ulteriori comandi, che +consentono di estendere le funzionalità, ovviamente non devono essere usati se +si ha a cuore la portabilità. Questi comandi aggiuntivi sono: + +\begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}} \item[\const{SHM\_LOCK}] Abilita il \itindex{memory~locking} \textit{memory - locking}\footnote{impedisce cioè che la memoria usata per il segmento - venga salvata su disco dal meccanismo della \index{memoria~virtuale} - memoria virtuale; si ricordi quanto trattato in - sez.~\ref{sec:proc_mem_lock}.} sul segmento di memoria condivisa. Solo - l'amministratore può utilizzare questo comando. + locking} sul segmento di memoria condivisa, impedendo che la memoria usata + per il segmento venga salvata su disco dal meccanismo della + \index{memoria~virtuale} memoria virtuale. Come illustrato in + sez.~\ref{sec:proc_mem_lock} fino al kernel 2.6.9 solo l'amministratore + poteva utilizzare questa capacità,\footnote{che richiedeva la + \textit{capability} \const{CAP\_IPC\_LOCK}.} a partire dal dal kernel + 2.6.10 anche gli utenti normali possono farlo fino al limite massimo + determinato da \const{RLIMIT\_MEMLOCK} (vedi + sez.~\ref{sec:sys_resource_limit}). \item[\const{SHM\_UNLOCK}] Disabilita il \itindex{memory~locking} - \textit{memory locking} sul segmento di memoria condivisa. Solo - l'amministratore può utilizzare questo comando. + \textit{memory locking} sul segmento di memoria condivisa. Fino al kernel + 2.6.9 solo l'amministratore poteva utilizzare questo comando in + corrispondenza di un segmento da lui bloccato. \end{basedescript} -i primi tre comandi sono gli stessi già visti anche per le code di messaggi e -gli insiemi di semafori, gli ultimi due sono delle estensioni specifiche -previste da Linux, che permettono di abilitare e disabilitare il meccanismo -della \index{memoria~virtuale} memoria virtuale per il segmento. + +A questi due, come per \func{msgctl} e \func{semctl}, si aggiungono tre +ulteriori valori, \const{IPC\_INFO}, \const{MSG\_STAT} e \const{MSG\_INFO}, +introdotti ad uso del programma \cmd{ipcs} per ottenere le informazioni +generali relative alle risorse usate dai segmenti di memoria condivisa. Dato +che potranno essere modificati o rimossi in favore dell'uso di \texttt{/proc}, +non devono essere usati e non li tratteremo. L'argomento \param{buf} viene utilizzato solo con i comandi \const{IPC\_STAT} e \const{IPC\_SET} nel qual caso esso dovrà puntare ad una struttura @@ -2676,25 +2808,28 @@ l'interfaccia prevede due funzioni, \funcd{shmat} e \func{shmdt}. La prima di queste serve ad agganciare un segmento al processo chiamante, in modo che quest'ultimo possa inserirlo nel suo spazio di indirizzi per potervi accedere; il suo prototipo è: -\begin{functions} - \headdecl{sys/types.h} - \headdecl{sys/shm.h} - - \funcdecl{void *shmat(int shmid, const void *shmaddr, int shmflg)} - Aggancia al processo un segmento di memoria condivisa. - - \bodydesc{La funzione restituisce l'indirizzo del segmento in caso di - successo, e -1 in caso di errore, nel qual caso \var{errno} assumerà i - valori: - \begin{errlist} + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{sys/shm.h} +\fdecl{void *shmat(int shmid, const void *shmaddr, int shmflg)} + +\fdesc{Aggancia un segmento di memoria condivisa al processo chiamante.} +} + +{La funzione ritorna l'indirizzo del segmento in caso di successo e $-1$ (in + un cast a \type{void *}) per un errore, nel qual caso \var{errno} assumerà + uno dei valori: + \begin{errlist} \item[\errcode{EACCES}] il processo non ha i privilegi per accedere al segmento nella modalità richiesta. \item[\errcode{EINVAL}] si è specificato un identificatore invalido per \param{shmid}, o un indirizzo non allineato sul confine di una pagina - per \param{shmaddr}. - \end{errlist} - ed inoltre \errval{ENOMEM}.} -\end{functions} + per \param{shmaddr} o il valore \val{NULL} indicando \const{SHM\_REMAP}. + \end{errlist} + ed inoltre \errval{ENOMEM} nel suo significato generico. +} +\end{funcproto} La funzione inserisce un segmento di memoria condivisa all'interno dello spazio di indirizzi del processo, in modo che questo possa accedervi @@ -2718,13 +2853,14 @@ L'argomento \param{shmaddr} specifica a quale indirizzo\footnote{lo standard come il valore di ritorno della funzione; in Linux è stato così con le \acr{libc4} e le \acr{libc5}, con il passaggio alla \acr{glibc} il tipo di \param{shmaddr} è divenuto un \ctyp{const void *} e quello del valore di - ritorno un \ctyp{void *}.} deve essere associato il segmento, se il valore -specificato è \val{NULL} è il sistema a scegliere opportunamente un'area di -memoria libera (questo è il modo più portabile e sicuro di usare la funzione). -Altrimenti il kernel aggancia il segmento all'indirizzo specificato da -\param{shmaddr}; questo però può avvenire solo se l'indirizzo coincide con il -limite di una pagina, cioè se è un multiplo esatto del parametro di sistema -\const{SHMLBA}, che in Linux è sempre uguale \const{PAGE\_SIZE}. + ritorno un \ctyp{void *} seguendo POSIX.1-2001.} deve essere associato il +segmento, se il valore specificato è \val{NULL} è il sistema a scegliere +opportunamente un'area di memoria libera (questo è il modo più portabile e +sicuro di usare la funzione). Altrimenti il kernel aggancia il segmento +all'indirizzo specificato da \param{shmaddr}; questo però può avvenire solo se +l'indirizzo coincide con il limite di una pagina, cioè se è un multiplo esatto +del parametro di sistema \const{SHMLBA}, che in Linux è sempre uguale +\const{PAGE\_SIZE}. Si tenga presente però che quando si usa \val{NULL} come valore di \param{shmaddr}, l'indirizzo restituito da \func{shmat} può cambiare da @@ -2733,15 +2869,17 @@ anche degli indirizzi, si deve avere cura di usare valori relativi (in genere riferiti all'indirizzo di partenza del segmento). L'argomento \param{shmflg} permette di cambiare il comportamento della -funzione; esso va specificato come maschera binaria, i bit utilizzati sono -solo due e sono identificati dalle costanti \const{SHM\_RND} e -\const{SHM\_RDONLY}, che vanno combinate con un OR aritmetico. Specificando -\const{SHM\_RND} si evita che \func{shmat} ritorni un errore quando -\param{shmaddr} non è allineato ai confini di una pagina. Si può quindi usare -un valore qualunque per \param{shmaddr}, e il segmento verrà comunque -agganciato, ma al più vicino multiplo di \const{SHMLBA} (il nome della +funzione; esso va specificato come maschera binaria, i bit utilizzati al +momento sono sono tre e sono identificati dalle costanti \const{SHM\_RND}, +\const{SHM\_RDONLY} e \const{SHM\_REMAP} che vanno combinate con un OR +aritmetico. + +Specificando \const{SHM\_RND} si evita che \func{shmat} ritorni un errore +quando \param{shmaddr} non è allineato ai confini di una pagina. Si può quindi +usare un valore qualunque per \param{shmaddr}, e il segmento verrà comunque +agganciato, ma al più vicino multiplo di \const{SHMLBA}; il nome della costante sta infatti per \textit{rounded}, e serve per specificare un -indirizzo come arrotondamento, in Linux è equivalente a \const{PAGE\_SIZE}). +indirizzo come arrotondamento. L'uso di \const{SHM\_RDONLY} permette di agganciare il segmento in sola lettura (si ricordi che anche le pagine di memoria hanno dei permessi), in tal @@ -2752,8 +2890,16 @@ di agganciare il segmento con l'accesso in lettura e scrittura (ed il processo deve aver questi permessi in \var{shm\_perm}), non è prevista la possibilità di agganciare un segmento in sola scrittura. -In caso di successo la funzione aggiorna anche i seguenti campi di -\struct{shmid\_ds}: +Infine \const{SHM\_REMAP} è una estensione specifica di Linux (quindi non +portabile) che indica che la mappatura del segmento deve rimpiazzare ogni +precedente mappatura esistente nell'intervallo iniziante +all'indirizzo \param{shmaddr} e di dimensione pari alla lunghezza del +segmento. In condizioni normali questo tipo di richiesta fallirebbe con un +errore di \errval{EINVAL}. Ovviamente usando \const{SHM\_REMAP} +l'argomento \param{shmaddr} non può essere nullo. + +In caso di successo la funzione \func{shmat} aggiorna anche i seguenti campi +della struttura \struct{shmid\_ds}: \begin{itemize*} \item il tempo \var{shm\_atime} dell'ultima operazione di aggancio viene impostato al tempo corrente. @@ -2761,7 +2907,7 @@ In caso di successo la funzione aggiorna anche i seguenti campi di segmento viene impostato a quello del processo corrente. \item il numero \var{shm\_nattch} di processi agganciati al segmento viene aumentato di uno. -\end{itemize*} +\end{itemize*} Come accennato in sez.~\ref{sec:proc_fork} un segmento di memoria condivisa agganciato ad un processo viene ereditato da un figlio attraverso una @@ -2775,18 +2921,21 @@ attraverso una \func{exit}. Una volta che un segmento di memoria condivisa non serve più, si può sganciarlo esplicitamente dal processo usando l'altra funzione dell'interfaccia, \funcd{shmdt}, il cui prototipo è: -\begin{functions} - \headdecl{sys/types.h} - \headdecl{sys/shm.h} - \funcdecl{int shmdt(const void *shmaddr)} - Sgancia dal processo un segmento di memoria condivisa. - - \bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di - errore, la funzione fallisce solo quando non c'è un segmento agganciato - all'indirizzo \param{shmaddr}, con \var{errno} che assume il valore - \errval{EINVAL}.} -\end{functions} +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{sys/shm.h} +\fdecl{int shmdt(const void *shmaddr)} + +\fdesc{Sgancia dal processo un segmento di memoria condivisa.} +} + +{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, la funzione + fallisce solo quando non c'è un segmento agganciato + all'indirizzo \param{shmaddr}, con \var{errno} che assume il valore + \errval{EINVAL}. +} +\end{funcproto} La funzione sgancia dallo spazio degli indirizzi del processo un segmento di memoria condivisa; questo viene identificato con l'indirizzo \param{shmaddr} @@ -2922,13 +3071,14 @@ si esegue (\texttt{\small 24--26}) su di esso una \func{chdir}, uscendo immediatamente in caso di errore. Questa funzione serve anche per impostare la \index{directory~di~lavoro} directory di lavoro del programma nella directory da tenere sotto controllo, in vista del successivo uso della -funzione \func{daemon}.\footnote{si noti come si è potuta fare questa scelta, - nonostante le indicazioni illustrate in sez.~\ref{sec:sess_daemon}, per il - particolare scopo del programma, che necessita comunque di restare - all'interno di una directory.} Infine (\texttt{\small 27--29}) si installano -i gestori per i vari segnali di terminazione che, avendo a che fare con un -programma che deve essere eseguito come server, sono il solo strumento -disponibile per concluderne l'esecuzione. +funzione \func{daemon}. Si noti come si è potuta fare questa scelta, +nonostante le indicazioni illustrate in sez.~\ref{sec:sess_daemon}, per il +particolare scopo del programma, che necessita comunque di restare all'interno +di una directory. + +Infine (\texttt{\small 27--29}) si installano i gestori per i vari segnali di +terminazione che, avendo a che fare con un programma che deve essere eseguito +come server, sono il solo strumento disponibile per concluderne l'esecuzione. Il passo successivo (\texttt{\small 30--39}) è quello di creare gli oggetti di intercomunicazione necessari. Si inizia costruendo (\texttt{\small 30}) la @@ -2964,16 +3114,18 @@ Il primo passo (\texttt{\small 41}) è eseguire \func{daemon} per proseguire con l'esecuzione in background come si conviene ad un programma demone; si noti che si è mantenuta, usando un valore non nullo del primo argomento, la \index{directory~di~lavoro} directory di lavoro corrente. Una volta che il -programma è andato in background l'esecuzione prosegue (\texttt{\small - 42--48}) all'interno di un ciclo infinito: si inizia (\texttt{\small 43}) -bloccando il mutex con \func{MutexLock} per poter accedere alla memoria -condivisa (la funzione si bloccherà automaticamente se qualche client sta -leggendo), poi (\texttt{\small 44}) si cancellano i valori precedentemente -immagazzinati nella memoria condivisa con \func{memset}, e si esegue -(\texttt{\small 45}) un nuovo calcolo degli stessi utilizzando la funzione -\myfunc{dir\_scan}; infine (\texttt{\small 46}) si sblocca il mutex con -\func{MutexUnlock}, e si attende (\texttt{\small 47}) per il periodo di tempo -specificato a riga di comando con l'opzione \code{-p} con una \func{sleep}. +programma è andato in background l'esecuzione prosegue all'interno di un ciclo +infinito (\texttt{\small 42--48}). + +Si inizia (\texttt{\small 43}) bloccando il mutex con \func{MutexLock} per +poter accedere alla memoria condivisa (la funzione si bloccherà +automaticamente se qualche client sta leggendo), poi (\texttt{\small 44}) si +cancellano i valori precedentemente immagazzinati nella memoria condivisa con +\func{memset}, e si esegue (\texttt{\small 45}) un nuovo calcolo degli stessi +utilizzando la funzione \myfunc{dir\_scan}; infine (\texttt{\small 46}) si +sblocca il mutex con \func{MutexUnlock}, e si attende (\texttt{\small 47}) per +il periodo di tempo specificato a riga di comando con l'opzione \code{-p} +usando una \func{sleep}. Si noti come per il calcolo dei valori da mantenere nella memoria condivisa si sia usata ancora una volta la funzione \myfunc{dir\_scan}, già utilizzata (e @@ -3042,15 +3194,15 @@ il mutex, prima di uscire. Verifichiamo allora il funzionamento dei nostri programmi; al solito, usando le funzioni di libreria occorre definire opportunamente \code{LD\_LIBRARY\_PATH}; poi si potrà lanciare il server con: -\begin{Verbatim} -[piccardi@gont sources]$ ./dirmonitor ./ -\end{Verbatim} +\begin{Console} +[piccardi@gont sources]$ \textbf{./dirmonitor ./} +\end{Console} %$ ed avendo usato \func{daemon} il comando ritornerà immediatamente. Una volta che il server è in esecuzione, possiamo passare ad invocare il client per verificarne i risultati, in tal caso otterremo: -\begin{Verbatim} -[piccardi@gont sources]$ ./readmon +\begin{Console} +[piccardi@gont sources]$ \textbf{./readmon} Ci sono 68 file dati Ci sono 3 directory Ci sono 0 link @@ -3059,14 +3211,14 @@ Ci sono 0 socket Ci sono 0 device a caratteri Ci sono 0 device a blocchi Totale 71 file, per 489831 byte -\end{Verbatim} +\end{Console} %$ ed un rapido calcolo (ad esempio con \code{ls -a | wc} per contare i file) ci permette di verificare che il totale dei file è giusto. Un controllo con \cmd{ipcs} ci permette inoltre di verificare la presenza di un segmento di memoria condivisa e di un semaforo: -\begin{Verbatim} -[piccardi@gont sources]$ ipcs +\begin{Console} +[piccardi@gont sources]$ \textbf{ipcs} ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0xffffffff 54067205 piccardi 666 4096 1 @@ -3077,14 +3229,14 @@ key semid owner perms nsems ------ Message Queues -------- key msqid owner perms used-bytes messages -\end{Verbatim} +\end{Console} %$ Se a questo punto aggiungiamo un file, ad esempio con \code{touch prova}, potremo verificare che, passati nel peggiore dei casi almeno 10 secondi (o l'eventuale altro intervallo impostato per la rilettura dei dati) avremo: -\begin{Verbatim} -[piccardi@gont sources]$ ./readmon +\begin{Console} +[piccardi@gont sources]$ \textbf{./readmon} Ci sono 69 file dati Ci sono 3 directory Ci sono 0 link @@ -3093,21 +3245,21 @@ Ci sono 0 socket Ci sono 0 device a caratteri Ci sono 0 device a blocchi Totale 72 file, per 489887 byte -\end{Verbatim} +\end{Console} %$ A questo punto possiamo far uscire il server inviandogli un segnale di \signal{SIGTERM} con il comando \code{killall dirmonitor}, a questo punto ripetendo la lettura, otterremo un errore: -\begin{Verbatim} -[piccardi@gont sources]$ ./readmon +\begin{Console} +[piccardi@gont sources]$ \textbf{./readmon} Cannot find shared memory: No such file or directory -\end{Verbatim} +\end{Console} %$ e inoltre potremo anche verificare che anche gli oggetti di intercomunicazione visti in precedenza sono stati regolarmente cancellati: -\begin{Verbatim} -[piccardi@gont sources]$ ipcs +\begin{Console} +[piccardi@gont sources]$ \textbf{ipcs} ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status @@ -3116,7 +3268,7 @@ key semid owner perms nsems ------ Message Queues -------- key msqid owner perms used-bytes messages -\end{Verbatim} +\end{Console} %$ @@ -3167,7 +3319,7 @@ diversa con un uso combinato della memoria condivisa e dei meccanismi di sincronizzazione, per cui alla fine l'uso delle code di messaggi classiche è relativamente poco diffuso. -% TODO: trattare qui, se non ssis trova posto migliore, copy_from_process e +% TODO: trattare qui, se non si trova posto migliore, copy_from_process e % copy_to_process, introdotte con il kernel 3.2. Vedi % http://lwn.net/Articles/405346/ e % http://ozlabs.org/~cyeoh/cma/process_vm_readv.txt @@ -3187,19 +3339,19 @@ necessità di un contatore come i semafori, si possono utilizzare metodi alternativi. La prima possibilità, utilizzata fin dalle origini di Unix, è quella di usare -dei \textsl{file di lock} (per i quali esiste anche una opportuna directory, -\file{/var/lock}, nel filesystem standard). Per questo si usa la -caratteristica della funzione \func{open} (illustrata in -sez.~\ref{sec:file_open_close}) che prevede\footnote{questo è quanto dettato dallo - standard POSIX.1, ciò non toglie che in alcune implementazioni questa - tecnica possa non funzionare; in particolare per Linux, nel caso di NFS, si - è comunque soggetti alla possibilità di una \itindex{race~condition} - \textit{race condition}.} che essa ritorni un errore quando usata con i -flag di \const{O\_CREAT} e \const{O\_EXCL}. In tal modo la creazione di un -\textsl{file di lock} può essere eseguita atomicamente, il processo che crea -il file con successo si può considerare come titolare del lock (e della -risorsa ad esso associata) mentre il rilascio si può eseguire con una chiamata -ad \func{unlink}. +dei \textsl{file di lock} (per i quali è stata anche riservata una opportuna +directory, \file{/var/lock}, nella standardizzazione del \textit{Filesystem + Hierarchy Standard}). Per questo si usa la caratteristica della funzione +\func{open} (illustrata in sez.~\ref{sec:file_open_close}) che +prevede\footnote{questo è quanto dettato dallo standard POSIX.1, ciò non + toglie che in alcune implementazioni questa tecnica possa non funzionare; in + particolare per Linux, nel caso di NFS, si è comunque soggetti alla + possibilità di una \itindex{race~condition} \textit{race condition}.} che +essa ritorni un errore quando usata con i flag di \const{O\_CREAT} e +\const{O\_EXCL}. In tal modo la creazione di un \textsl{file di lock} può +essere eseguita atomicamente, il processo che crea il file con successo si può +considerare come titolare del lock (e della risorsa ad esso associata) mentre +il rilascio si può eseguire con una chiamata ad \func{unlink}. Un esempio dell'uso di questa funzione è mostrato dalle funzioni \func{LockFile} ed \func{UnlockFile} riportate in fig.~\ref{fig:ipc_file_lock} @@ -3362,22 +3514,24 @@ nessun inconveniente. \label{sec:ipc_mmap_anonymous} \itindbeg{memory~mapping} Abbiamo già visto che quando i processi sono -\textsl{correlati}\footnote{se cioè hanno almeno un progenitore comune.} l'uso -delle \textit{pipe} può costituire una valida alternativa alle code di -messaggi; nella stessa situazione si può evitare l'uso di una memoria -condivisa facendo ricorso al cosiddetto \textit{memory mapping} anonimo. +\textsl{correlati}, se cioè hanno almeno un progenitore comune, l'uso delle +\textit{pipe} può costituire una valida alternativa alle code di messaggi; +nella stessa situazione si può evitare l'uso di una memoria condivisa facendo +ricorso al cosiddetto \textit{memory mapping} anonimo. In sez.~\ref{sec:file_memory_map} abbiamo visto come sia possibile mappare il contenuto di un file nella memoria di un processo, e che, quando viene usato il flag \const{MAP\_SHARED}, le modifiche effettuate al contenuto del file vengono viste da tutti i processi che lo hanno mappato. Utilizzare questa tecnica per creare una memoria condivisa fra processi diversi è estremamente -inefficiente, in quanto occorre passare attraverso il disco. Però abbiamo -visto anche che se si esegue la mappatura con il flag \const{MAP\_ANONYMOUS} -la regione mappata non viene associata a nessun file, anche se quanto scritto -rimane in memoria e può essere riletto; allora, dato che un processo figlio -mantiene nel suo spazio degli indirizzi anche le regioni mappate, esso sarà -anche in grado di accedere a quanto in esse è contenuto. +inefficiente, in quanto occorre passare attraverso il disco. + +Però abbiamo visto anche che se si esegue la mappatura con il flag +\const{MAP\_ANONYMOUS} la regione mappata non viene associata a nessun file, +anche se quanto scritto rimane in memoria e può essere riletto; allora, dato +che un processo figlio mantiene nel suo spazio degli indirizzi anche le +regioni mappate, esso sarà anche in grado di accedere a quanto in esse è +contenuto. In questo modo diventa possibile creare una memoria condivisa fra processi diversi, purché questi abbiano almeno un progenitore comune che ha effettuato @@ -3438,70 +3592,67 @@ richiesto è che: \end{itemize*} Data la assoluta genericità delle specifiche, il comportamento delle funzioni -è subordinato in maniera quasi completa alla relativa -implementazione.\footnote{tanto che Stevens in \cite{UNP2} cita questo caso - come un esempio della maniera standard usata dallo standard POSIX per - consentire implementazioni non standardizzabili.} Nel caso di Linux, sia per -quanto riguarda la memoria condivisa ed i semafori, che per quanto riguarda le -code di messaggi, tutto viene creato usando come radici delle opportune -directory (rispettivamente \file{/dev/shm} e \file{/dev/mqueue}, per i -dettagli si faccia riferimento a sez.~\ref{sec:ipc_posix_shm}, -sez.~\ref{sec:ipc_posix_sem} e sez.~\ref{sec:ipc_posix_mq}) ed i nomi -specificati nelle relative funzioni sono considerati come un -\itindsub{pathname}{assoluto} \textit{pathname} assoluto (comprendente -eventuali sottodirectory) rispetto a queste radici. +è subordinato in maniera quasi completa alla relativa implementazione, tanto +che Stevens in \cite{UNP2} cita questo caso come un esempio della maniera +standard usata dallo standard POSIX per consentire implementazioni non +standardizzabili. + +Nel caso di Linux, sia per quanto riguarda la memoria condivisa ed i semafori, +che per le code di messaggi, tutto viene creato usando come radici delle +opportune directory (rispettivamente \file{/dev/shm} e \file{/dev/mqueue}, per +i dettagli si faccia riferimento a sez.~\ref{sec:ipc_posix_shm}, +sez.~\ref{sec:ipc_posix_sem} e sez.~\ref{sec:ipc_posix_mq}). I nomi +specificati nelle relative funzioni devono essere nella forma di un +\textit{pathname} assoluto (devono cioè iniziare con ``\texttt{/}'') e +corrisponderanno ad altrettanti file creati all'interno di queste directory; +per questo motivo detti nomi non possono contenere altre ``\texttt{/}'' oltre +quella iniziale. Il vantaggio degli oggetti di IPC POSIX è comunque che essi vengono inseriti nell'albero dei file, e possono essere maneggiati con le usuali funzioni e -comandi di accesso ai file,\footnote{questo è vero nel caso di Linux, che usa - una implementazione che lo consente, non è detto che altrettanto valga per - altri kernel; in particolare, come si può facilmente verificare con uno - \cmd{strace}, sia per la memoria condivisa che per le code di messaggi le - system call utilizzate da Linux sono le stesse di quelle dei file, essendo - detti oggetti realizzati come tali in appositi filesystem.} che funzionano -come su dei file normali. +comandi di accesso ai file, che funzionano come su dei file normali; questo +però è vero nel caso di Linux, che usa una implementazione che lo consente, +non è detto che altrettanto valga per altri kernel. In particolare, come si +può facilmente verificare con uno \cmd{strace}, sia per la memoria condivisa +che per le code di messaggi varie \textit{system call} utilizzate da Linux +corrispondono in realtà a quelle ordinarie dei file, essendo detti oggetti +realizzati come tali in appositi filesystem. In particolare i permessi associati agli oggetti di IPC POSIX sono identici ai permessi dei file, ed il controllo di accesso segue esattamente la stessa semantica (quella illustrata in sez.~\ref{sec:file_access_control}), e non quella particolare (si ricordi quanto visto in sez.~\ref{sec:ipc_sysv_access_control}) che viene usata per gli oggetti del -SysV-IPC. Per quanto riguarda l'attribuzione dell'utente e del gruppo +SysV-IPC. Per quanto riguarda l'attribuzione dell'utente e del gruppo proprietari dell'oggetto alla creazione di quest'ultimo essa viene effettuata secondo la semantica SysV: corrispondono cioè a \ids{UID} e \ids{GID} effettivi del processo che esegue la creazione. -\subsection{Code di messaggi} +\subsection{Code di messaggi Posix} \label{sec:ipc_posix_mq} Le code di messaggi POSIX sono supportate da Linux a partire dalla versione -2.6.6-rc1 del kernel,\footnote{l'implementazione è dovuta a Michal Wronski e - Krzysztof Benedyczak, e le relative informazioni si possono trovare su - \url{http://www.geocities.com/wronski12/posix_ipc/index.html}.} In generale, -come le corrispettive del \textit{SysV-IPC}, le code di messaggi sono poco -usate, dato che i socket, nei casi in cui sono sufficienti, sono più comodi, e -che in casi più complessi la comunicazione può essere gestita direttamente con -mutex (o semafori) e memoria condivisa con tutta la flessibilità che occorre. +2.6.6 del kernel. In generale, come le corrispettive del \textit{SysV-IPC}, le +code di messaggi sono poco usate, dato che i socket, nei casi in cui sono +sufficienti, sono più comodi, e che in casi più complessi la comunicazione può +essere gestita direttamente con mutex (o semafori) e memoria condivisa con +tutta la flessibilità che occorre. Per poter utilizzare le code di messaggi, oltre ad utilizzare un kernel -superiore al 2.6.6 (o precedente, se sono stati opportunamente applicati i -relativi patch) occorre utilizzare la libreria \file{libmqueue}\footnote{i - programmi che usano le code di messaggi cioè devono essere compilati - aggiungendo l'opzione \code{-lmqueue} al comando \cmd{gcc}; in - corrispondenza all'inclusione del supporto nel kernel ufficiale anche - \file{libmqueue} è stata inserita nella \acr{glibc}, a partire dalla - versione 2.3.4 delle medesime.} che contiene le funzioni dell'interfaccia -POSIX.\footnote{in realtà l'implementazione è realizzata tramite delle - opportune chiamate ad \func{ioctl} sui file del filesystem speciale su cui - vengono mantenuti questi oggetti di IPC.} +superiore al 2.6.6 occorre utilizzare la libreria \file{librt} che contiene le +funzioni dell'interfaccia POSIX ed i programmi che usano le code di messaggi +devono essere compilati aggiungendo l'opzione \code{-lrt} al comando +\cmd{gcc}. In corrispondenza all'inclusione del supporto nel kernel ufficiale +le funzioni di libreria sono state inserite nella \acr{glibc}, e sono +disponibili a partire dalla versione 2.3.4 delle medesime. La libreria inoltre richiede la presenza dell'apposito filesystem di tipo -\texttt{mqueue} montato su \file{/dev/mqueue}; questo può essere fatto -aggiungendo ad \conffile{/etc/fstab} una riga come: -\begin{verbatim} +\texttt{mqueue} montato sulla directory \file{/dev/mqueue}; questo può essere +fatto aggiungendo ad \conffile{/etc/fstab} una riga come: +\begin{Example} mqueue /dev/mqueue mqueue defaults 0 0 -\end{verbatim} +\end{Example} ed esso sarà utilizzato come radice sulla quale vengono risolti i nomi delle code di messaggi che iniziano con una ``\texttt{/}''. Le opzioni di mount accettate sono \texttt{uid}, \texttt{gid} e \texttt{mode} che permettono @@ -3509,54 +3660,63 @@ rispettivamente di impostare l'utente, il gruppo ed i permessi associati al filesystem. -La funzione che permette di aprire (e crearla se non esiste ancora) una coda -di messaggi POSIX è \funcd{mq\_open}, ed il suo prototipo è: -\begin{functions} - \headdecl{mqueue.h} - - \funcdecl{mqd\_t mq\_open(const char *name, int oflag)} - - \funcdecl{mqd\_t mq\_open(const char *name, int oflag, unsigned long mode, +La funzione di sistema che permette di aprire (e crearla se non esiste ancora) +una coda di messaggi POSIX è \funcd{mq\_open}, ed il suo prototipo è: + +\begin{funcproto}{ +\fhead{fcntl.h} +\fhead{sys/stat.h} +\fhead{mqueue.h} +\fdecl{mqd\_t mq\_open(const char *name, int oflag)} +\fdecl{mqd\_t mq\_open(const char *name, int oflag, unsigned long mode, struct mq\_attr *attr)} - - Apre una coda di messaggi POSIX impostandone le caratteristiche. - - \bodydesc{La funzione restituisce il descrittore associato alla coda in caso - di successo e -1 per un errore; nel quel caso \var{errno} assumerà i - valori: - \begin{errlist} - \item[\errcode{EACCES}] il processo non ha i privilegi per accedere al - alla memoria secondo quanto specificato da \param{oflag}. - \item[\errcode{EEXIST}] si è specificato \const{O\_CREAT} e - \const{O\_EXCL} ma la coda già esiste. - \item[\errcode{EINVAL}] il file non supporta la funzione, o si è - specificato \const{O\_CREAT} con una valore non nullo di \param{attr} e - valori non validi di \var{mq\_maxmsg} e \var{mq\_msgsize}. - \item[\errcode{ENOENT}] non si è specificato \const{O\_CREAT} ma la coda - non esiste. - \end{errlist} - ed inoltre \errval{ENOMEM}, \errval{ENOSPC}, \errval{EFAULT}, - \errval{EMFILE}, \errval{EINTR} ed \errval{ENFILE}. + +\fdesc{Apre una coda di messaggi POSIX impostandone le caratteristiche.} } -\end{functions} + +{La funzione ritorna il descrittore associato alla coda in caso di successo e + $-1$ per un errore, nel qual caso \var{errno} assumerà uno dei valori: + \begin{errlist} + \item[\errcode{EACCES}] il processo non ha i privilegi per accedere alla + coda secondo quanto specificato da \param{oflag} oppure \const{name} + contiene più di una ``\texttt{/}''. + \item[\errcode{EEXIST}] si è specificato \const{O\_CREAT} e \const{O\_EXCL} + ma la coda già esiste. + \item[\errcode{EINVAL}] il file non supporta la funzione, o si è specificato + \const{O\_CREAT} con una valore non nullo di \param{attr} e valori non + validi dei campi \var{mq\_maxmsg} e \var{mq\_msgsize}; questi valori + devono essere positivi ed inferiori ai limiti di sistema se il processo + non ha privilegi amministrativi, inoltre \var{mq\_maxmsg} non può comunque + superare \const{HARD\_MAX}. + \item[\errcode{ENOENT}] non si è specificato \const{O\_CREAT} ma la coda non + esiste o si è usato il nome ``\texttt{/}''. + \item[\errcode{ENOSPC}] lo spazio è insufficiente, probabilmente per aver + superato il limite di \texttt{queues\_max}. + \end{errlist} + ed inoltre \errval{EMFILE}, \errval{ENAMETOOLONG}, \errval{ENFILE}, + \errval{ENOMEM} ed nel loro significato generico. } +\end{funcproto} La funzione apre la coda di messaggi identificata dall'argomento \param{name} restituendo il descrittore ad essa associato, del tutto analogo ad un file descriptor, con l'unica differenza che lo standard prevede un apposito tipo -\type{mqd\_t}.\footnote{nel caso di Linux si tratta in effetti proprio di un - normale file descriptor; pertanto, anche se questo comportamento non è - portabile, lo si può tenere sotto osservazione con le funzioni dell'I/O - multiplexing (vedi sez.~\ref{sec:file_multiplexing}) come possibile - alternativa all'uso dell'interfaccia di notifica di \func{mq\_notify} (che - vedremo a breve).} Se la coda esiste già il descrittore farà riferimento -allo stesso oggetto, consentendo così la comunicazione fra due processi -diversi. +\type{mqd\_t}. Nel caso di Linux si tratta in effetti proprio di un normale +file descriptor; pertanto, anche se questo comportamento non è portabile, lo +si può tenere sotto osservazione con le funzioni dell'I/O multiplexing (vedi +sez.~\ref{sec:file_multiplexing}) come possibile alternativa all'uso +dell'interfaccia di notifica di \func{mq\_notify} (che vedremo a breve). + +Se il nome indicato fa riferimento ad una coda di messaggi già esistente, il +descrittore ottenuto farà riferimento allo stesso oggetto, pertanto tutti i +processi che hanno usato \func{mq\_open} su quel nome otterranno un +riferimento alla stessa coda. Diventa così immediato costruire un canale di +comunicazione fra detti processi. La funzione è del tutto analoga ad \func{open} ed analoghi sono i valori che possono essere specificati per \param{oflag}, che deve essere specificato come maschera binaria; i valori possibili per i vari bit sono quelli visti in -sez.~\ref{sec:file_open_close} dei quali però \func{mq\_open} riconosce solo i -seguenti: +sez.~\ref{sec:file_open_close} (per questo occorre includere \texttt{fcntl.h}) +dei quali però \func{mq\_open} riconosce solo i seguenti: \begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}} \item[\const{O\_RDONLY}] Apre la coda solo per la ricezione di messaggi. Il processo potrà usare il descrittore con \func{mq\_receive} ma non con @@ -3588,15 +3748,17 @@ Se la coda non esiste e la si vuole creare si deve specificare creazione con l'argomento \param{mode};\footnote{fino al 2.6.14 per un bug i valori della \textit{umask} del processo non venivano applicati a questi permessi.} i valori di quest'ultimo sono identici a quelli usati per -\func{open}, anche se per le code di messaggi han senso solo i permessi di -lettura e scrittura. Oltre ai permessi di creazione possono essere specificati -anche gli attributi specifici della coda tramite l'argomento \param{attr}; -quest'ultimo è un puntatore ad una apposita struttura \struct{mq\_attr}, la -cui definizione è riportata in fig.~\ref{fig:ipc_mq_attr}. +\func{open} (per questo occorre includere \texttt{sys/stat.h}), anche se per +le code di messaggi han senso solo i permessi di lettura e scrittura. + +Oltre ai permessi di creazione possono essere specificati anche gli attributi +specifici della coda tramite l'argomento \param{attr}; quest'ultimo è un +puntatore ad una apposita struttura \struct{mq\_attr}, la cui definizione è +riportata in fig.~\ref{fig:ipc_mq_attr}. \begin{figure}[!htb] \footnotesize \centering - \begin{minipage}[c]{\textwidth} + \begin{minipage}[c]{0.90\textwidth} \includestruct{listati/mq_attr.h} \end{minipage} \normalsize @@ -3609,51 +3771,96 @@ Per la creazione della coda i campi della struttura che devono essere specificati sono \var{mq\_maxmsg} e \var{mq\_msgsize}, che indicano rispettivamente il numero massimo di messaggi che può contenere e la dimensione massima di un messaggio. Il valore dovrà essere positivo e minore -dei rispettivi limiti di sistema \const{MQ\_MAXMSG} e \const{MQ\_MSGSIZE}, -altrimenti la funzione fallirà con un errore di \errcode{EINVAL}. -Se \param{attr} è un puntatore nullo gli attributi della coda saranno -impostati ai valori predefiniti. +dei rispettivi limiti di sistema altrimenti la funzione fallirà con un errore +di \errcode{EINVAL}. Se \param{attr} è un puntatore nullo gli attributi della +coda saranno impostati ai valori predefiniti. + +I suddetti limiti di sistema sono impostati attraverso altrettanti file in +\texttt{/proc/sys/fs/mqueue}, in particolare i file che controllano i valori +dei limiti sono: +\begin{basedescript}{\desclabelwidth{1.5cm}\desclabelstyle{\nextlinelabel}} +\item[\sysctlfile{fs/mqueue/msg\_max}] Indica il valore massimo del numero di + messaggi in una coda e agisce come limite superiore per il valore di + \var{attr->mq\_maxmsg} in \func{mq\_open}. Il suo valore di default è 10. Il + valore massimo è \const{HARD\_MAX} che vale \code{(131072/sizeof(void *))}, + ed il valore minimo 1 (ma era 10 per i kernel precedenti il 2.6.28). Questo + limite viene ignorato per i processi con privilegi amministrativi (più + precisamente con la \itindex{capability} \textit{capability} + \const{CAP\_SYS\_RESOURCE}) ma \const{HARD\_MAX} resta comunque non + superabile. + +\item[\sysctlfile{fs/mqueue/msgsize\_max}] Indica il valore massimo della + dimensione in byte di un messaggio sulla coda ed agisce come limite + superiore per il valore di \var{attr->mq\_msgsize} in \func{mq\_open}. Il + suo valore di default è 8192. Il valore massimo è 1048576 ed il valore + minimo 128 (ma per i kernel precedenti il 2.6.28 detti limiti erano + rispettivamente \const{INT\_MAX} e 8192). Questo valore viene ignorato dai + processi con privilegi amministrativi (la \itindex{capability} + \textit{capability} \const{CAP\_SYS\_RESOURCE}). + +\item[\sysctlfile{fs/mqueue/queues\_max}] Indica il numero massimo di code di + messaggi creabili in totale sul sistema, il valore di default è 256 ma si + può usare un valore qualunque fra $0$ e \const{INT\_MAX}. Il limite non + viene applicato ai processi con privilegi amministrativi (cioè con la + \itindex{capability} \textit{capability} \const{CAP\_SYS\_RESOURCE}). + +\end{basedescript} + +Infine sulle code di messaggi si applica il limite imposto sulla risorsa +\const{RLIMIT\_MSGQUEUE} (vedi sez.~\ref{sec:sys_resource_limit}) che indica +lo spazio massimo (in byte) occupabile da tutte le code di messaggi +appartenenti ai processi di uno stesso utente, identificato dal loro +\textit{real user ID}. Quando l'accesso alla coda non è più necessario si può chiudere il relativo descrittore con la funzione \funcd{mq\_close}, il cui prototipo è: -\begin{prototype}{mqueue.h} -{int mq\_close(mqd\_t mqdes)} -Chiude la coda \param{mqdes}. - -\bodydesc{La funzione restituisce 0 in caso di successo e -1 per un errore; - nel quel caso \var{errno} assumerà i valori \errval{EBADF} o - \errval{EINTR}.} -\end{prototype} +\begin{funcproto}{ +\fhead{mqueue.h} +\fdecl{int mq\_close(mqd\_t mqdes)} -La funzione è analoga a \func{close},\footnote{in Linux, dove le code sono - implementate come file su un filesystem dedicato, è esattamente la stessa - funzione.} dopo la sua esecuzione il processo non sarà più in grado di usare -il descrittore della coda, ma quest'ultima continuerà ad esistere nel sistema -e potrà essere acceduta con un'altra chiamata a \func{mq\_open}. All'uscita di -un processo tutte le code aperte, così come i file, vengono chiuse -automaticamente. Inoltre se il processo aveva agganciato una richiesta di -notifica sul descrittore che viene chiuso, questa sarà rilasciata e potrà -essere richiesta da qualche altro processo. +\fdesc{Chiude una coda di messaggi.} +} + +{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual + caso \var{errno} assumerà uno dei valori \errval{EBADF} o \errval{EINTR} nel + loro significato generico. +} +\end{funcproto} +La funzione è analoga a \func{close},\footnote{su Linux, dove le code sono + implementate come file su un filesystem dedicato, è esattamente la stessa + funzione, per cui non esiste una \textit{system call} autonoma e la funzione + viene rimappata su \func{close} dalle \acr{glibc}.} dopo la sua esecuzione +il processo non sarà più in grado di usare il descrittore della coda, ma +quest'ultima continuerà ad esistere nel sistema e potrà essere acceduta con +un'altra chiamata a \func{mq\_open}. All'uscita di un processo tutte le code +aperte, così come i file, vengono chiuse automaticamente. Inoltre se il +processo aveva agganciato una richiesta di notifica sul descrittore che viene +chiuso, questa sarà rilasciata e potrà essere richiesta da qualche altro +processo. Quando si vuole effettivamente rimuovere una coda dal sistema occorre usare la -funzione \funcd{mq\_unlink}, il cui prototipo è: -\begin{prototype}{mqueue.h} -{int mq\_unlink(const char *name)} +funzione di sistema \funcd{mq\_unlink}, il cui prototipo è: -Rimuove una coda di messaggi. - -\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di - errore; nel quel caso \var{errno} assumerà gli stessi valori riportati da - \func{unlink}.} -\end{prototype} +\begin{funcproto}{ +\fhead{mqueue.h} +\fdecl{int mq\_unlink(const char *name)} + +\fdesc{Rimuove una coda di messaggi.} +} + +{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual + caso \var{errno} assumerà gli stessi valori riportati da \func{unlink}. +} +\end{funcproto} Anche in questo caso il comportamento della funzione è analogo a quello di -\func{unlink} per i file,\footnote{di nuovo l'implementazione di Linux usa - direttamente \func{unlink}.} la funzione rimuove la coda \param{name}, così -che una successiva chiamata a \func{mq\_open} fallisce o crea una coda -diversa. +\func{unlink} per i file, la funzione rimuove la coda \param{name} (ed il +relativo file sotto \texttt{/dev/mqueue}), così che una successiva chiamata a +\func{mq\_open} fallisce o crea una coda diversa. + +% TODO, verificare se mq_unlink è davvero una system call indipendente. Come per i file ogni coda di messaggi ha un contatore di riferimenti, per cui la coda non viene effettivamente rimossa dal sistema fin quando questo non si @@ -3670,20 +3877,21 @@ riavvio del sistema. Come accennato ad ogni coda di messaggi è associata una struttura \struct{mq\_attr}, che può essere letta e modificata attraverso le due funzioni \funcd{mq\_getattr} e \funcd{mq\_setattr}, i cui prototipi sono: -\begin{functions} - \headdecl{mqueue.h} - - \funcdecl{int mq\_getattr(mqd\_t mqdes, struct mq\_attr *mqstat)} - Legge gli attributi di una coda di messaggi POSIX. - - \funcdecl{int mq\_setattr(mqd\_t mqdes, const struct mq\_attr *mqstat, + +\begin{funcproto}{ +\fhead{mqueue.h} +\fdecl{int mq\_getattr(mqd\_t mqdes, struct mq\_attr *mqstat)} +\fdesc{Legge gli attributi di una coda di messaggi POSIX.} +\fdecl{int mq\_setattr(mqd\_t mqdes, const struct mq\_attr *mqstat, struct mq\_attr *omqstat)} - Modifica gli attributi di una coda di messaggi POSIX. - - \bodydesc{Entrambe le funzioni restituiscono 0 in caso di successo e -1 in - caso di errore; nel quel caso \var{errno} assumerà i valori \errval{EBADF} - o \errval{EINVAL}.} -\end{functions} +\fdesc{Modifica gli attributi di una coda di messaggi POSIX.} +} + +{Entrambe le funzioni ritornano $0$ in caso di successo e $-1$ per un errore, + nel qual caso \var{errno} assumerà i valori \errval{EBADF} + o \errval{EINVAL} nel loro significato generico. +} +\end{funcproto} La funzione \func{mq\_getattr} legge i valori correnti degli attributi della coda nella struttura puntata da \param{mqstat}; di questi l'unico relativo @@ -3705,22 +3913,21 @@ della funzione. Per inserire messaggi su di una coda sono previste due funzioni, \funcd{mq\_send} e \funcd{mq\_timedsend}, i cui prototipi sono: -\begin{functions} - \headdecl{mqueue.h} - - \funcdecl{int mq\_send(mqd\_t mqdes, const char *msg\_ptr, size\_t msg\_len, - unsigned int msg\_prio)} - Esegue l'inserimento di un messaggio su una coda. - - \funcdecl{int mq\_timedsend(mqd\_t mqdes, const char *msg\_ptr, size\_t - msg\_len, unsigned msg\_prio, const struct timespec *abs\_timeout)} - Esegue l'inserimento di un messaggio su una coda entro il tempo - \param{abs\_timeout}. - - \bodydesc{Le funzioni restituiscono 0 in caso di successo e $-1$ per un - errore; nel quel caso \var{errno} assumerà i valori: - \begin{errlist} +\begin{funcproto}{ +\fhead{mqueue.h} +\fdecl{int mq\_send(mqd\_t mqdes, const char *msg\_ptr, size\_t msg\_len, + unsigned int msg\_prio)} +\fdesc{Esegue l'inserimento di un messaggio su una coda.} +\fdecl{int mq\_timedsend(mqd\_t mqdes, const char *msg\_ptr, size\_t + msg\_len, unsigned msg\_prio, const struct timespec *abs\_timeout)} +\fdesc{Esegue l'inserimento di un messaggio su una coda entro un tempo + specificato} +} + +{Entrambe le funzioni ritornano $0$ in caso di successo e $-1$ per un errore, + nel qual caso \var{errno} assumerà uno dei valori: + \begin{errlist} \item[\errcode{EAGAIN}] si è aperta la coda con \const{O\_NONBLOCK}, e la coda è piena. \item[\errcode{EMSGSIZE}] la lunghezza del messaggio \param{msg\_len} @@ -3730,9 +3937,11 @@ Per inserire messaggi su di una coda sono previste due funzioni, un valore non valido per \param{abs\_timeout}. \item[\errcode{ETIMEDOUT}] l'inserimento del messaggio non è stato effettuato entro il tempo stabilito. - \end{errlist} - ed inoltre \errval{EBADF}, \errval{ENOMEM} ed \errval{EINTR}.} -\end{functions} + \end{errlist} + ed inoltre \errval{EBADF}, \errval{ENOMEM} ed \errval{EINTR} nel loro + significato generico. +} +\end{funcproto} Entrambe le funzioni richiedono un puntatore al testo del messaggio nell'argomento \param{msg\_ptr} e la relativa lunghezza in \param{msg\_len}. @@ -3818,8 +4027,6 @@ selezionare quale messaggio estrarre con delle condizioni sulla priorità, a differenza di quanto avveniva con le code di messaggi di SysV che permettono invece la selezione in base al valore del campo \var{mtype}. -% TODO inserire i dati di /proc/sys/fs/mqueue - Qualora la coda sia vuota entrambe le funzioni si bloccano, a meno che non si sia selezionata la modalità non bloccante; in tal caso entrambe ritornano immediatamente con l'errore \errcode{EAGAIN}. Anche in questo caso la sola @@ -4121,8 +4328,8 @@ sincronizzazione completamente nuovo, basato sui cosiddetti \textit{futex},\footnote{la sigla sta per \textit{fast user mode mutex}.} con il quale è stato possibile implementare una versione nativa dei semafori POSIX. Grazie a questo con i kernel della serie 2.6 e le nuove versioni della -\acr{glibc} che usano questa nuova infrastruttura per quella che viene quella -che viene chiamata \textit{New Posix Thread Library}, sono state implementate +\acr{glibc} che usano questa nuova infrastruttura per quella che viene che +viene chiamata \textit{New Posix Thread Library}, sono state implementate anche tutte le funzioni dell'interfaccia dei semafori POSIX. Anche in questo caso è necessario appoggiarsi alla libreria per le estensioni @@ -4241,7 +4448,7 @@ Si tenga presente che la funzione può sempre essere interrotta da un segnale (nel qual caso si avrà un errore di \const{EINTR}) e che questo avverrà comunque, anche se si è richiesta la semantica BSD installando il relativo gestore con \const{SA\_RESTART} (vedi sez.~\ref{sec:sig_sigaction}) per -riavviare le system call interrotte. +riavviare le \textit{system call} interrotte. Della funzione \func{sem\_wait} esistono due varianti che consentono di gestire diversamente le modalità di attesa in caso di risorsa occupata, la @@ -4730,7 +4937,7 @@ testo alla terminazione di quest'ultimo. % LocalWords: FortuneServer FortuneParse FortuneClient pid libgapil LD librt % LocalWords: PATH linker pathname ps tmp killall fortuned crash socket domain % LocalWords: socketpair BSD sys protocol sv EAFNOSUPPORT EPROTONOSUPPORT AF -% LocalWords: EOPNOTSUPP SOCK Process Comunication ipc perm key exec +% LocalWords: EOPNOTSUPP SOCK Process Comunication ipc perm key exec pipefd SZ % LocalWords: header ftok proj stat libc SunOS glibc XPG dell'inode number uid % LocalWords: cuid cgid gid tab MSG shift group umask seq MSGMNI SEMMNI SHMMNI % LocalWords: shmmni msgmni sem sysctl IPCMNI IPCTestId msgget EACCES EEXIST @@ -4752,7 +4959,7 @@ testo alla terminazione di quest'ultimo. % LocalWords: dtime lpid cpid nattac shmall shmmax SHMLBA SHMSEG EOVERFLOW brk % LocalWords: memory shmat shmdt void shmaddr shmflg SVID RND RDONLY rounded % LocalWords: SIGSEGV nattch exit SharedMem ShmCreate memset fill ShmFind home -% LocalWords: ShmRemove DirMonitor DirProp chdir GaPiL shmptr ipcs NFS +% LocalWords: ShmRemove DirMonitor DirProp chdir GaPiL shmptr ipcs NFS SETPIPE % LocalWords: ComputeValues ReadMonitor touch SIGTERM dirmonitor unlink fcntl % LocalWords: LockFile UnlockFile CreateMutex FindMutex LockMutex SETLKW GETLK % LocalWords: UnlockMutex RemoveMutex ReadMutex UNLCK WRLCK RDLCK mapping MAP @@ -4765,17 +4972,20 @@ testo alla terminazione di quest'ultimo. % LocalWords: EBUSY sigev SIGNAL signo value sigval siginfo all'userid MESGQ % LocalWords: Konstantin Knizhnik futex tmpfs ramfs cache shared swap CONFIG % LocalWords: lrt blocks PAGECACHE TRUNC CLOEXEC mmap ftruncate munmap FindShm -% LocalWords: CreateShm RemoveShm LIBRARY Library libmqueue FAILED has +% LocalWords: CreateShm RemoveShm LIBRARY Library libmqueue FAILED has fclose % LocalWords: ENAMETOOLONG qualchenome RESTART trywait XOPEN SOURCE timedwait % LocalWords: process getvalue sval execve pshared ENOSYS heap PAGE destroy it % LocalWords: xffffffff Arrays owner perms Queues used bytes messages device % LocalWords: Cannot find such Segments getter Signal MSGMAXSIZE been stable -% LocalWords: for now it's break Berlin sources Let's an accidental feature +% LocalWords: for now it's break Berlin sources Let's an accidental feature fs % LocalWords: Larry Wall Escape the Hell William ipctestid Identifier segment -% LocalWords: violation dell'I SIGINT setter Fri Dec Sleeping seconds +% LocalWords: violation dell'I SIGINT setter Fri Dec Sleeping seconds ECHILD +% LocalWords: SysV capability short RESOURCE INFO UNDEFINED EFBIG semtimedop +% LocalWords: scan HUGETLB huge page NORESERVE copy RLIMIT MEMLOCK REMAP %%% Local Variables: %%% mode: latex %%% TeX-master: "gapil" %%% End: +% LocalWords: readmon Hierarchy defaults queues MSGQUEUE