-<%% ipc.tex
+%% ipc.tex
%%
%% Copyright (C) 2000-2013 Simone Piccardi. Permission is granted to
%% copy, distribute and/or modify this document under the terms of the GNU Free
sez.~\ref{sec:sys_resource_limit}).
\item[\const{SHM\_UNLOCK}] Disabilita il \itindex{memory~locking}
\textit{memory locking} sul segmento di memoria condivisa. Fino al kernel
- 2.6.9 solo l'amministratore poteva utilizzare questo comando.
+ 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
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
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
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
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}:
-\begin{itemize*}
+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.
\item il \ids{PID} \var{shm\_lpid} dell'ultimo processo che ha operato sul
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
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}
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
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
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
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
------ 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
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
------ Message Queues --------
key msqid owner perms used-bytes messages
-\end{Verbatim}
+\end{Console}
%$
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
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
+ Hyerarchy 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}
\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
\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 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.
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 le system call utilizzate da Linux sono le stesse
+di quelle 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