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
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
\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 \\
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}
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
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)}
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}
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/