X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=ipc.tex;h=029284fb19b426022a8a2c6e5ae18b5c72e971cf;hp=e1863eebaca9fd8d9a66ea967ede33b61285be6b;hb=aee4a2e76ad7b0ed41eb06c4c70b8db5df9a4451;hpb=e0cc9bf7b67899cae825bc33819aaac05c40561e diff --git a/ipc.tex b/ipc.tex index e1863ee..029284f 100644 --- a/ipc.tex +++ b/ipc.tex @@ -3764,8 +3764,8 @@ il \textit{memory mapping} anonimo.\footnote{nei sistemi derivati da SysV una vengono ignorati (come accade qualora si scriva direttamente sul file), ma restano in memoria e possono essere riletti secondo le stesse modalità usate nel \textit{memory mapping} anonimo.} Vedremo come utilizzare questa tecnica -più avanti, quando realizzeremo il monitor visto in \secref{sec:ipc_sysv_shm} -in modo che possa restituire i suoi risultati anche via rete. +più avanti, quando realizzeremo una nuova versione del monitor visto in +\secref{sec:ipc_sysv_shm} che possa restituisca i risultati via rete. @@ -3779,30 +3779,210 @@ meccanismi di comunicazione, che vanno sotto il nome di POSIX IPC, definendo una interfaccia completamente nuova, che tratteremo in questa sezione. - \subsection{Considerazioni generali} \label{sec:ipc_posix_generic} -Il Linux non tutti gli oggetti del POSIX IPC sono supportati nel kernel -ufficiale; solo la memoria condivisa è presente, ma solo a partire dal kernel -2.4.x, per gli altri oggetti esistono patch e librerie non ufficiali. -Nonostante questo è importante esaminare questa interfaccia per la sua netta -superiorità nei confronti di quella del \textit{SysV IPC}. +In Linux non tutti gli oggetti del POSIX IPC sono pienamente supportati nel +kernel ufficiale; solo la memoria condivisa è presente con l'interfaccia +completa, ma solo a partire dal kernel 2.4.x, i semafori sono forniti dalle +\acr{glibc} nella sezione che implementa i thread POSIX, le code di messaggi +non hanno alcun tipo di supporto ufficiale. Per queste ultime esistono +tuttavia dei patch e una libreria aggiuntiva. + +La caratteristica fondamentale dell'interfaccia POSIX è l'abbandono dell'uso +degli identificatori e delle chiavi visti nel SysV IPC, per passare ai +\textit{Posix IPC names}\index{Posix IPC names}, che sono sostanzialmente +equivalenti ai nomi dei file. Tutte le funzioni che creano un oggetto di IPC +Posix prendono come primo argomento una stringa che indica uno di questi nomi; +lo standard è molto generico riguardo l'implementazione, ed i nomi stessi +possono avere o meno una corrispondenza sul filesystem; tutto quello che è +richiesto è che: +\begin{itemize} +\item i nomi devono essere conformi alle regole che caratterizzano i + \textit{pathname}, in particolare non essere più lunghi di \const{PATH\_MAX} + byte e terminati da un carattere nullo. +\item se il nome inizia per una \texttt{/} chiamate differenti allo stesso + nome fanno riferimento allo stesso oggetto, altrimenti l'interpretazione del + nome dipende dall'implementazione. +\item l'interpretazione di ulteriori \texttt{/} presenti nel nome dipende + dall'implementazione. +\end{itemize} + +Data la assoluta genericità delle specifiche, il comportamento delle funzioni +è pertanto 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 per +quanto riguarda la memoria condivisa, tutto viene creato nella directory +\file{/dev/shm}, ed i nomi sono presi come pathname assoluto (comprendente +eventuali sottodirectory) rispetto a questa radice (per maggiori dettagli si +veda quanto illustrato in \secref{sec:ipc_posix_shm}). Lo stesso accade per +l'implementazione sperimentale delle code di messaggi, che però fa riferimento +alla directory \file{/dev/mqueue}. + +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 per la memoria condivisa, come si può + facilmente evincere con uno \cmd{strace}, le system call utilizzate sono le + stesse, in quanto essa è realizzata con file in uno speciale filesystem.} +che funzionano come su dei file normali. + +In particolare i permessi associati agli oggetti di IPC POSIX sono identici ai +permessi dei file, e il controllo di accesso segue esattamente la stessa +semantica (quella illustrata in \secref{sec:file_access_control}), invece di +quella particolare (si ricordi quanto visto in +\secref{sec:ipc_sysv_access_control}) usata per gli oggetti del 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 (essi corrispondono cioè a userid e groupid effettivi del +processo che esegue la creazione). + \subsection{Code di messaggi} \label{sec:ipc_posix_mq} -Le code di messaggi non sono ancora supportate nel kernel -ufficiale;\footnote{esiste però una proposta di implementazione di Krzysztof - Benedyczak, a partire dal kernel 2.5.50.} inoltre esse possono essere -implementate, usando la memoria condivisa ed i mutex, con funzioni di -libreria. In generale, come le corrispettive del SysV IPC, sono poco usate, -dato che i socket\index{socket}, nei casi in cui sono sufficienti, sono più -comodi, e negli altri casi la comunicazione può essere gestita direttamente -con mutex e memoria condivisa. Per questo ci limiteremo ad una descrizione -essenziale. +Le code di messaggi non sono ancora supportate nel kernel ufficiale, esiste +però una implementazione sperimentale di Michal Wronski e Krzysztof +Benedyczak,\footnote{i patch al kernel e la relativa libreria possono essere + trovati \href{http://www.mat.uni.torun.pl/~wrona/posix_ipc} + {http://www.mat.uni.torun.pl/\~{}wrona/posix\_ipc}.}. In generale, come le +corrispettive del SysV IPC, le code di messaggi sono poco usate, dato che i +socket\index{socket}, nei casi in cui sono sufficienti, sono più comodi, e che +in casi più complessi la comunicazione può essere gestita direttamente con +mutex e memoria condivisa con tutta la flessibilità che occorre. + +Per poter utilizzare le code di messaggi, oltre ad utilizzare un kernel cui +siano stati opportunamente applicati i relativi patch, occorre utilizzare la +libreria \file{mqueue}\footnote{i programmi che usano le code di messaggi cioè + devono essere compilati aggiungendo l'opzione \code{-lmqueue} al comando + \cmd{gcc}, dato che le funzioni non fanno parte della libreria standard.} +che contiene le funzioni dell'interfaccia POSIX.\footnote{in realtà + l'implementazione è realizzata tramite delle speciali chiamate ad + \func{ioctl} sui file del filesystem speciale su cui vengono mantenuti + questi oggetti di IPC.} + + +La libreria inoltre richiede la presenza dell'apposito filesystem di tipo +\texttt{mqueue} montato su \file{/dev/mqueue}; questo può essere fatto +aggiungendo ad \file{/etc/fstab} una riga come: +\begin{verbatim} +mqueue /dev/mqueue mqueue defaults 0 0 +\end{verbatim} +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 +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 è \func{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, + 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 in caso di errore; nel quel caso \var{errno} assumerà i + valori: + \begin{errlist} + \item[\errcode{EACCESS}] 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{EINTR}] La funzione è stata interrotta da un segnale. + \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} ed \errval{ENFILE}.} +\end{prototype} + +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{nella implementazione citata questo è definito come + \ctyp{int}.} Se la coda esiste già il descrittore farà riferimento allo +stesso oggetto, consentendo così la comunicazione fra due processi diversi. + +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 +\tabref{tab:file_open_flags} dei quali però \func{mq\_open} riconosce solo i +seguenti: +\begin{basedescript}{\desclabelwidth{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 + \func{mq\_send}. +\item[\const{O\_WRONLY}] Apre la coda solo per la trasmissione di messaggi. Il + processo potrà usare il descrittore con \func{mq\_send} ma non con + \func{mq\_receive}. +\item[\const{O\_RDWR}] Apre la coda solo sia per la trasmissione che per la + ricezione. +\item[\const{O\_CREAT}] Necessario qualora si debba creare la coda; la + presenza di questo bit richiede la presenza degli ulteriori argomenti + \param{mode} e \param{attr}. +\item[\const{O\_EXCL}] Se usato insieme a \const{O\_CREAT} fa fallire la + chiamata se la coda esiste già, altrimenti esegue la creazione atomicamente. +\item[\const{O\_NONBLOCK}] Imposta la coda in modalità non bloccante, le + funzioni di ricezione e trasmissione non si bloccano quando non ci sono le + risorse richieste, ma ritornano immediatamente con un errore di + \errval{EAGAIN}. +\end{basedescript} + +I primi tre bit specificano la modalità di apertura della coda, e sono fra +loro esclusivi; qualunque sia la modalità in cui si è aperta una coda, questa +potrà essere riaperta più volte in una modalità diversa, e vi si potrà +accedere attraverso descrittori diversi, esattamente come si può fare per i +file normali. + +Se la coda non esiste si deve specificare \const{O\_CREAT} per creare una +nuova, in tal caso come accennato occorre anche specificare i permessi di +creazione con l'argomento \param{mode}; 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 della coda tramite l'argomento +\param{attr} che è il puntatore ad una struttura \struct{mq\_attr}, la cui +definizione è riportata in \figref{fig:ipc_mq_attr}. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{15cm} + \begin{lstlisting}[labelstep=0]{} +struct mq_attr { + long mq_flags; /* message queue flags */ + long mq_maxmsg; /* maximum number of messages */ + long mq_msgsize; /* maximum message size */ + long mq_curmsgs; /* number of messages currently queued */ +}; + \end{lstlisting} + \end{minipage} + \normalsize + \caption{La struttura \structd{mq\_attr}, contenente gli attributi di una + coda di messaggi POSIX.} + \label{fig:ipc_mq_attr} +\end{figure} +Quando si crea la coda possono essere specificati solo i campi +\var{mq\_msgsize} e \var{mq\_maxmsg}, che indicano rispettivamente la +dimensione massima di un messaggio ed il numero massimo di messaggi che essa +può contenere; 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 \errval{EINVAL}. Qualora si specifichi per +\param{attr} un puntatore nullo gli attributi della coda saranno impostati ai +valori predefiniti. \subsection{Semafori} @@ -3810,16 +3990,50 @@ essenziale. Dei semafori POSIX esistono sostanzialmente due implementazioni; una è fatta a livello di libreria ed è fornita dalla libreria dei thread; questa però li -implementa solo a livello di thread e non di processi. Esiste un'altra -versione, realizzata da Konstantin Knizhnik, che reimplementa l'interfaccia -POSIX usando i semafori di SysV IPC. +implementa solo a livello di thread e non di processi.\footnote{questo + significa che i semafori sono visibili solo all'interno dei thread creati da + un singolo processo, e non possono essere usati come meccanismo di + sincronizzazione fra processi diversi.} Esiste però anche una libreria +realizzata da Konstantin Knizhnik, che reimplementa l'interfaccia POSIX usando +i semafori di SysV IPC, e che non vale comunque la pena di usare visto che i +problemi sottolineati in \secref{sec:ipc_sysv_sem} rimangono, anche se +mascherati. + + \subsection{Memoria condivisa} \label{sec:ipc_posix_shm} La memoria condivisa è l'unico degli oggetti di IPC POSIX già presente nel -kernel ufficiale. +kernel ufficiale. Per poterla utilizzare occorre abilitare il filesystem +\texttt{tmpfs}, uno speciale filesystem che mantiene tutti i suoi contenuti in +memoria,\footnote{il filesystem \texttt{tmpfs} è diverso da un normale RAM + disk, anch'esso disponibile attraverso il filesystem \texttt{ramfs}, proprio + perché realizza una interfaccia utilizzabile anche per la memoria condivisa; + esso infatti non ha dimensione fissa, ed usa direttamente la cache interna + del kernel (viene usato anche per la SysV shared memory). In più i suoi + contenuti, essendo trattati direttamente dalla memoria + virtuale\index{memoria virtuale} e possono essere salvati sullo swap + automaticamente.} abilitando l'opzione \texttt{CONFIG\_TMPFS} in fase di +compilazione del kernel, e montando il filesystem aggiungendo una riga tipo: +\begin{verbatim} +tmpfs /dev/shm tmpfs defaults 0 0 +\end{verbatim} +ad \file{/etc/fstab}, oppure dove si preferisce con un comando del +tipo:\footnote{il filesystem riconosce, oltre quelle mostrate, le opzioni + \texttt{uid} e \texttt{gid} che identificano rispettivamente utente e gruppo + cui assegnarne la titolarità, e \texttt{nr\_blocks} che permette di + specificarne la dimensione in blocchi, cioè in multipli di + \const{PAGECACHE\_SIZE}.} +\begin{verbatim} +mount -t tmpfs -o size=10G,nr_inodes=10k,mode=700 tmpfs /mytmpfs +\end{verbatim} + + + la memoria +condivisa è trattata come un filesystem separato, con tutte le caratteristiche +di un qualunque filesystem, %%% Local Variables: