From c23786b2033224de5b188ddcf1180e35ed9eb5af Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Sun, 21 Nov 2010 19:14:02 +0000 Subject: [PATCH] Altre modifiche e qualche aggiunte per signalfd. --- fileadv.tex | 166 ++++++++++++++++++++++++++++++++++++---------------- tcpsock.tex | 10 +++- 2 files changed, 124 insertions(+), 52 deletions(-) diff --git a/fileadv.tex b/fileadv.tex index dd197fb..77e058e 100644 --- a/fileadv.tex +++ b/fileadv.tex @@ -91,11 +91,12 @@ proteggere il suo accesso in scrittura. In Linux sono disponibili due interfacce per utilizzare l'\textit{advisory locking}, la prima è quella derivata da BSD, che è basata sulla funzione -\func{flock}, la seconda è quella standardizzata da POSIX.1 (derivata da -System V), che è basata sulla funzione \func{fcntl}. I \textit{file lock} -sono implementati in maniera completamente indipendente nelle due -interfacce,\footnote{in realtà con Linux questo avviene solo dalla serie 2.0 - dei kernel.} che pertanto possono coesistere senza interferenze. +\func{flock}, la seconda è quella recepita dallo standard POSIX.1 (che è +derivata dall'interfaccia usata in System V), che è basata sulla funzione +\func{fcntl}. I \textit{file lock} sono implementati in maniera completamente +indipendente nelle due interfacce,\footnote{in realtà con Linux questo avviene + solo dalla serie 2.0 dei kernel.} che pertanto possono coesistere senza +interferenze. Entrambe le interfacce prevedono la stessa procedura di funzionamento: si inizia sempre con il richiedere l'opportuno \textit{file lock} (un @@ -103,11 +104,14 @@ inizia sempre con il richiedere l'opportuno \textit{file lock} (un lettura) prima di eseguire l'accesso ad un file. Se il blocco viene acquisito il processo prosegue l'esecuzione, altrimenti (a meno di non aver richiesto un comportamento non bloccante) viene posto in stato di sleep. Una volta finite -le operazioni sul file si deve provvedere a rimuovere il blocco. La situazione -delle varie possibilità è riassunta in tab.~\ref{tab:file_file_lock}, dove si -sono riportati, per le varie tipologie di blocco presenti su un file, il -risultato che si ha in corrispondenza alle due tipologie di \textit{file lock} -menzionate, nel successo della richiesta. +le operazioni sul file si deve provvedere a rimuovere il blocco. + +La situazione delle varie possibilità che si possono verificare è riassunta in +tab.~\ref{tab:file_file_lock}, dove si sono riportati, a seconda delle varie +tipologie di blocco già presenti su un file, il risultato che si avrebbe in +corrispondenza di una ulteriore richiesta da parte di un processo di un blocco +nelle due tipologie di \textit{file lock} menzionate, con un successo o meno +della richiesta. \begin{table}[htb] \centering @@ -116,7 +120,7 @@ menzionate, nel successo della richiesta. \hline \textbf{Richiesta} & \multicolumn{3}{|c|}{\textbf{Stato del file}}\\ \cline{2-4} - &Nessun \textit{lock}&\textit{Read lock}&\textit{Write lock}\\ + &Nessun \textit{lock}&\textit{Read lock}&\textit{Write lock}\\ \hline \hline \textit{Read lock} & SI & SI & NO \\ @@ -216,22 +220,22 @@ In fig.~\ref{fig:file_flock_struct} si dell'implementazione del \textit{file locking} in stile BSD su Linux. Il punto fondamentale da capire è che un \textit{file lock}, qualunque sia l'interfaccia che si usa, anche se richiesto attraverso un file descriptor, -agisce sempre su un file; perciò le informazioni relative agli eventuali -\textit{file lock} sono mantenute a livello di inode\index{inode},\footnote{in - particolare, come accennato in fig.~\ref{fig:file_flock_struct}, i - \textit{file lock} sono mantenuti in una \itindex{linked~list} - \textit{linked list} di strutture \struct{file\_lock}. La lista è - referenziata dall'indirizzo di partenza mantenuto dal campo \var{i\_flock} - della struttura \struct{inode} (per le definizioni esatte si faccia - riferimento al file \file{fs.h} nei sorgenti del kernel). Un bit del campo - \var{fl\_flags} di specifica se si tratta di un lock in semantica BSD - (\const{FL\_FLOCK}) o POSIX (\const{FL\_POSIX}).} dato che questo è l'unico -riferimento in comune che possono avere due processi diversi che aprono lo -stesso file. +agisce sempre su di un file; perciò le informazioni relative agli eventuali +\textit{file lock} sono mantenute dal kernel a livello di +inode\index{inode},\footnote{in particolare, come accennato in + fig.~\ref{fig:file_flock_struct}, i \textit{file lock} sono mantenuti in una + \itindex{linked~list} \textit{linked list} di strutture + \struct{file\_lock}. La lista è referenziata dall'indirizzo di partenza + mantenuto dal campo \var{i\_flock} della struttura \struct{inode} (per le + definizioni esatte si faccia riferimento al file \file{fs.h} nei sorgenti + del kernel). Un bit del campo \var{fl\_flags} di specifica se si tratta di + un lock in semantica BSD (\const{FL\_FLOCK}) o POSIX (\const{FL\_POSIX}).} +dato che questo è l'unico riferimento in comune che possono avere due processi +diversi che aprono lo stesso file. \begin{figure}[htb] \centering - \includegraphics[width=15cm]{img/file_flock} + \includegraphics[width=15.5cm]{img/file_flock} \caption{Schema dell'architettura del \textit{file locking}, nel caso particolare del suo utilizzo da parte dalla funzione \func{flock}.} \label{fig:file_flock_struct} @@ -267,10 +271,11 @@ con cui lo si descriptor fa riferimento allo stesso file, ma attraverso una voce diversa della \itindex{file~table} \textit{file table}, come accade tutte le volte che si apre più volte lo stesso file.} o se si esegue la rimozione in un -processo figlio; inoltre una volta tolto un \textit{file lock}, la rimozione -avrà effetto su tutti i file descriptor che condividono la stessa voce nella -\itindex{file~table} \textit{file table}, e quindi, nel caso di file -descriptor ereditati attraverso una \func{fork}, anche su processi diversi. +processo figlio. Inoltre una volta tolto un \textit{file lock} su un file, la +rimozione avrà effetto su tutti i file descriptor che condividono la stessa +voce nella \itindex{file~table} \textit{file table}, e quindi, nel caso di +file descriptor ereditati attraverso una \func{fork}, anche per processi +diversi. Infine, per evitare che la terminazione imprevista di un processo lasci attivi dei \textit{file lock}, quando un file viene chiuso il kernel provvede anche a @@ -1760,26 +1765,29 @@ come si che se arrivano più eventi fra due chiamate successive ad \func{epoll\_wait} questi vengano combinati. Inoltre qualora su un file descriptor fossero presenti eventi non ancora notificati, e si effettuasse una modifica -dell'osservazione con \const{EPOLL\_CTL\_MOD} questi verrebbero riletti alla +dell'osservazione con \const{EPOLL\_CTL\_MOD}, questi verrebbero riletti alla luce delle modifiche. Si tenga presente infine che con l'uso della modalità \textit{edge triggered} -il ritorno di \func{epoll\_wait} indica un file descriptor è pronto e resterà -tale fintanto che non si sono completamente esaurite le operazioni su di esso. -Questa condizione viene generalmente rilevata dall'occorrere di un errore di -\errcode{EAGAIN} al ritorno di una \func{read} o una \func{write},\footnote{è - opportuno ricordare ancora una volta che l'uso dell'\textit{I/O multiplexing} - richiede di operare sui file in modalità non bloccante.} ma questa non è la -sola modalità possibile, ad esempio la condizione può essere riconosciuta -anche con il fatto che sono stati restituiti meno dati di quelli richiesti. +il ritorno di \func{epoll\_wait} indica che un file descriptor è pronto e +resterà tale fintanto che non si sono completamente esaurite le operazioni su +di esso. Questa condizione viene generalmente rilevata dall'occorrere di un +errore di \errcode{EAGAIN} al ritorno di una \func{read} o una +\func{write},\footnote{è opportuno ricordare ancora una volta che l'uso + dell'\textit{I/O multiplexing} richiede di operare sui file in modalità non + bloccante.} ma questa non è la sola modalità possibile, ad esempio la +condizione può essere riconosciuta anche per il fatto che sono stati +restituiti meno dati di quelli richiesti. Come già per \func{select} e \func{poll} anche per l'interfaccia di \textit{epoll} si pone il problema di gestire l'attesa di segnali e di dati contemporaneamente, per far questo di nuovo è necessaria una variante della funzione di attesa che consenta di reimpostare all'uscita una maschera di -segnali, analoga alle precedenti estensioni \func{pselect} e \func{ppoll}; in -questo caso la funzione si chiama \funcd{epoll\_pwait}\footnote{introdotta a - partire dal kernel 2.6.19.} ed il suo prototipo è: +segnali, analoga alle precedenti estensioni \func{pselect} e \func{ppoll} di +\func{select} e \func{poll}; in questo caso la funzione si chiama +\funcd{epoll\_pwait}\footnote{la funziona è stata introdotta a partire dal + kernel 2.6.19, ed è come tutta l'interfaccia di \textit{epoll}, specifica di + Linux.} ed il suo prototipo è: \begin{prototype}{sys/epoll.h} {int epoll\_pwait(int epfd, struct epoll\_event * events, int maxevents, int timeout, const sigset\_t *sigmask)} @@ -1803,10 +1811,10 @@ in maniera atomica: Si tenga presente che come le precedenti funzioni di \textit{I/O multiplexing} anche le funzioni dell'interfaccia di \textit{epoll} vengono utilizzate prevalentemente con i server di rete, quando si devono tenere sotto -osservazione un gran numero di socket; per questo motivo rimandiamo di nuovo -la trattazione di un esempio concreto a quando avremo esaminato in dettaglio -le caratteristiche dei socket, in particolare si potrà trovare un programma -che utilizza questa interfaccia in sez.~\ref{sec:TCP_sock_multiplexing}. +osservazione un gran numero di socket; per questo motivo rimandiamo anche in +questo caso la trattazione di un esempio concreto a quando avremo esaminato in +dettaglio le caratteristiche dei socket; in particolare si potrà trovare un +programma che utilizza questa interfaccia in sez.~\ref{sec:TCP_serv_epoll}. \itindend{epoll} @@ -1876,19 +1884,77 @@ contemporanea sia l'arrivo del segnale che la disponibilit relativi a questi ultimi. La funzione che permette di abilitare la ricezione dei segnali tramite file -descriptor è \funcd{signalfd}, il cui prototipo è: +descriptor è \funcd{signalfd},\footnote{in realtà questa è il nome della + funzione fornita dalle \acr{glibc}, esistono in realtà due + versioni, anche se } il cui prototipo è: \begin{prototype}{sys/signalfd.h} {int signalfd(int fd, const sigset\_t *mask, int flags)} - Attende che uno dei file descriptor osservati sia pronto, mascherando i - segnali. + Crea o modifica un file descriptor pet la ricezione dei segnali. - \bodydesc{La funzione restituisce il numero di file descriptor pronti in - caso di successo o $-1$ in caso di errore, nel qual caso \var{errno} - assumerà uno dei valori già visti con \funcd{epoll\_wait}. + \bodydesc{La funzione restituisce un numero di file descriptor in caso di + successo o $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno + dei valori: + \begin{errlist} + \item[\errcode{EBADF}] il valore \param{fd} non indica un file descriptor. + \item[\errcode{EINVAL}] il file descriptor \param{fd} non è stato ottenuto + con \func{signalfd} o il valore di \param{flags} non è valido. + \item[\errcode{ENOMEN}] non c'è memoria sufficiente per creare un nuovo file + descriptor di \func{signalfd}. + \item[\errcode{ENODEV}] il kernel non può montare internamente il + dispositivo per la gestione anonima degli inode associati al file + descriptor. + \end{errlist} + ed inoltre \errval{EMFILE} e \errval{ENFILE}. } \end{prototype} +La funzione consente di creare o modificare le caratteristiche di un file +descriptor speciale su cui ricevere le notifiche della ricezione di +segnali. Per creare un nuovo file descriptor è necessario passare $-1$ come +valore per l'argomento \param{fd}, ogni altro valore positivo verrà invece +interpretato come il numero del file descriptor (che deve esser stato +precedentemente creato sempre con \func{signalfd}) di cui si vogliono +modificare le caratteristiche. Nel primo caso la funzione ritornerà il nuovo +file descriptor e nel secondo caso \param{fd}, in caso di errore verrà invece +restituito $-1$. + +L'elenco dei segnali che si vogliono gestire con \func{signalfd} deve essere +specificato tramite l'argomento \param{mask}. Questo deve essere passato come +puntatore ad una maschera di segnali creata con l'uso delle apposite macro +illustrate in sez.~\ref{sec:sig_sigset} che indichi su quali segnali si +intende operare con \func{signalfd}, l'elenco può essere modificato da una +chiamata successiva. Dato che \const{SIGKILL} e \const{SIGSTOP} non possono +essere intercettati (e non prevedono neanche la possibilità di un gestore) un +loro inserimento nella maschera verrà semplicemente ignorato, senza generare +errori. + +Infine l'argomento \param{flags} consente di impostare direttamente in fase di +creazione due flag per il file descriptor analoghe a quelle che si possono +impostare con \func{open}, evitando una impostazione successiva con +\func{fcntl}.\footnote{questo è un argomento aggiuntivo introdotto con il + kernel 2.6.27, in precedenza il valore era nullo } + +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|p{8cm}|} + \hline + \textbf{Valore} & \textbf{Significato} \\ + \hline + \hline + \const{SFD\_NONBLOCK}& imposta sul file descriptor il flag di + \const{O\_NONBLOCK} per renderlo non bloccante.\\ + \const{SFD\_CLOEXEC}& imposta il flag di \const{O\_CLOEXEC} per la + chiusura automatica del file descriptor nella + esecuzione di \func{exec}.\\ + \hline + \end{tabular} + \caption{Valori dell'argomento \param{flags} per la funzione \func{signalfd} + che consentono di impostare fl.} + \label{tab:signalfd_flags} +\end{table} + % TODO trattare qui eventfd signalfd e timerfd introdotte con il 2.6.22 % timerfd è stata tolta nel 2.6.23 e rifatta per bene nel 2.6.25 % vedi: http://lwn.net/Articles/233462/ diff --git a/tcpsock.tex b/tcpsock.tex index 0ffa69f..9d9f02b 100644 --- a/tcpsock.tex +++ b/tcpsock.tex @@ -2775,8 +2775,6 @@ sez.~\ref{sec:file_multiplexing} e non staremo a ripetere quanto detto l sappiamo che la funzione ritorna quando uno o più dei file descriptor messi sotto controllo è pronto per la relativa operazione. - - In quell'occasione non abbiamo però definito cosa si intende per pronto, infatti per dei normali file, o anche per delle pipe, la condizione di essere pronti per la lettura o la scrittura è ovvia; invece lo è molto meno nel caso @@ -3583,6 +3581,14 @@ quanto l'uscita anche a questo server le considerazioni finali di sez.~\ref{sec:TCP_serv_select}. + + + +\subsection{I/O multiplexing con \func{epoll}} +\label{sec:TCP_serv_epoll} + +Da fare. + % TODO fare esempio con epoll -- 2.30.2