%% fileadv.tex
%%
-%% Copyright (C) 2000-2011 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2012 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",
%% license is included in the section entitled "GNU Free Documentation
%% License".
%%
+
\chapter{La gestione avanzata dei file}
\label{cha:file_advanced}
In questo capitolo affronteremo le tematiche relative alla gestione avanzata
\section{Il \textit{file locking}}
\label{sec:file_locking}
-\index{file!locking|(}
+\itindbeg{file~locking}
In sez.~\ref{sec:file_sharing} abbiamo preso in esame le modalità in cui un
sistema unix-like gestisce la condivisione dei file da parte di processi
\end{table}
I primi due valori, \const{LOCK\_SH} e \const{LOCK\_EX} permettono di
-richiedere un \textit{file lock}, ed ovviamente devono essere usati in maniera
-alternativa. Se si specifica anche \const{LOCK\_NB} la funzione non si
-bloccherà qualora il \textit{file lock} non possa essere acquisito, ma
-ritornerà subito con un errore di \errcode{EWOULDBLOCK}. Per rilasciare un
-\textit{file lock} si dovrà invece usare \const{LOCK\_UN}.
+richiedere un \textit{file lock} rispettivamente condiviso o esclusivo, ed
+ovviamente non possono essere usati insieme. Se con essi si specifica anche
+\const{LOCK\_NB} la funzione non si bloccherà qualora il \textit{file lock}
+non possa essere acquisito, ma ritornerà subito con un errore di
+\errcode{EWOULDBLOCK}. Per rilasciare un \textit{file lock} si dovrà invece
+usare direttamente const{LOCK\_UN}.
Si tenga presente che non esiste una modalità per eseguire atomicamente un
cambiamento del tipo di blocco (da \textit{shared lock} a \textit{esclusive
l'interfaccia che si usa, anche se richiesto attraverso un file descriptor,
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
+inode\itindex{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.
+ \kstruct{file\_lock}. La lista è referenziata dall'indirizzo di partenza
+ mantenuto dal campo \var{i\_flock} della struttura \kstruct{inode} (per le
+ definizioni esatte si faccia riferimento al file \file{include/linux/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]
+\begin{figure}[!htb]
\centering
\includegraphics[width=15.5cm]{img/file_flock}
\caption{Schema dell'architettura del \textit{file locking}, nel caso
La richiesta di un \textit{file lock} prevede una scansione della lista per
determinare se l'acquisizione è possibile, ed in caso positivo l'aggiunta di
-un nuovo elemento.\footnote{cioè una nuova struttura \struct{file\_lock}.}
+un nuovo elemento.\footnote{cioè una nuova struttura \kstruct{file\_lock}.}
Nel caso dei blocchi creati con \func{flock} la semantica della funzione
prevede che sia \func{dup} che \func{fork} non creino ulteriori istanze di un
\textit{file lock} quanto piuttosto degli ulteriori riferimenti allo
stesso. Questo viene realizzato dal kernel secondo lo schema di
fig.~\ref{fig:file_flock_struct}, associando ad ogni nuovo \textit{file lock}
un puntatore\footnote{il puntatore è mantenuto nel campo \var{fl\_file} di
- \struct{file\_lock}, e viene utilizzato solo per i \textit{file lock} creati
+ \kstruct{file\_lock}, e viene utilizzato solo per i \textit{file lock} creati
con la semantica BSD.} alla voce nella \itindex{file~table} \textit{file
table} da cui si è richiesto il blocco, che così ne identifica il titolare.
potrà avere un conflitto anche se c'è soltanto una sovrapposizione parziale
con un'altra regione bloccata.
-\begin{figure}[!bht]
+\begin{figure}[!htb]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
+ \begin{minipage}[c]{\textwidth}
\includestruct{listati/flock.h}
\end{minipage}
\normalsize
rispettivamente uno \textit{shared lock}, un \textit{esclusive lock}, e la
rimozione di un blocco precedentemente acquisito. Infine il campo \var{l\_pid}
viene usato solo in caso di lettura, quando si chiama \func{fcntl} con
-\const{F\_GETLK}, e riporta il \acr{pid} del processo che detiene il
+\const{F\_GETLK}, e riporta il \ids{PID} del processo che detiene il
\textit{file lock}.
Oltre a quanto richiesto tramite i campi di \struct{flock}, l'operazione
quando la si invoca con \const{F\_SETLK}, per controllare che il blocco sia
stato effettivamente acquisito.
-\begin{figure}[htb]
+\begin{figure}[!htb]
\centering \includegraphics[width=9cm]{img/file_lock_dead}
\caption{Schema di una situazione di \itindex{deadlock} \textit{deadlock}.}
\label{fig:file_flock_dead}
kernel. Lo schema delle strutture utilizzate è riportato in
fig.~\ref{fig:file_posix_lock}; come si vede esso è molto simile all'analogo
di fig.~\ref{fig:file_flock_struct}:\footnote{in questo caso nella figura si
- sono evidenziati solo i campi di \struct{file\_lock} significativi per la
+ sono evidenziati solo i campi di \kstruct{file\_lock} significativi per la
semantica POSIX, in particolare adesso ciascuna struttura contiene, oltre al
- \acr{pid} del processo in \var{fl\_pid}, la sezione di file che viene
+ \ids{PID} del processo in \var{fl\_pid}, la sezione di file che viene
bloccata grazie ai campi \var{fl\_start} e \var{fl\_end}. La struttura è
comunque la stessa, solo che in questo caso nel campo \var{fl\_flags} è
impostato il bit \const{FL\_POSIX} ed il campo \var{fl\_file} non viene
- usato.} il blocco è sempre associato \index{inode} all'inode, solo che in
+ usato.} il blocco è sempre associato \itindex{inode} all'inode, solo che in
questo caso la titolarità non viene identificata con il riferimento ad una
voce nella \itindex{file~table} \textit{file table}, ma con il valore del
-\acr{pid} del processo.
+\ids{PID} del processo.
-\begin{figure}[!bht]
- \centering \includegraphics[width=13cm]{img/file_posix_lock}
+\begin{figure}[!htb]
+ \centering \includegraphics[width=12cm]{img/file_posix_lock}
\caption{Schema dell'architettura del \textit{file locking}, nel caso
particolare del suo utilizzo secondo l'interfaccia standard POSIX.}
\label{fig:file_posix_lock}
Quando si richiede un \textit{file lock} il kernel effettua una scansione di
tutti i blocchi presenti sul file\footnote{scandisce cioè la
\itindex{linked~list} \textit{linked list} delle strutture
- \struct{file\_lock}, scartando automaticamente quelle per cui
+ \kstruct{file\_lock}, scartando automaticamente quelle per cui
\var{fl\_flags} non è \const{FL\_POSIX}, così che le due interfacce restano
ben separate.} per verificare se la regione richiesta non si sovrappone ad
una già bloccata, in caso affermativo decide in base al tipo di blocco, in
caso negativo il nuovo blocco viene comunque acquisito ed aggiunto alla lista.
Nel caso di rimozione invece questa viene effettuata controllando che il
-\acr{pid} del processo richiedente corrisponda a quello contenuto nel blocco.
+\ids{PID} del processo richiedente corrisponda a quello contenuto nel blocco.
Questa diversa modalità ha delle conseguenze precise riguardo il comportamento
dei \textit{file lock} POSIX. La prima conseguenza è che un \textit{file lock}
POSIX non viene mai ereditato attraverso una \func{fork}, dato che il processo
-figlio avrà un \acr{pid} diverso, mentre passa indenne attraverso una
-\func{exec} in quanto il \acr{pid} resta lo stesso. Questo comporta che, al
+figlio avrà un \ids{PID} diverso, mentre passa indenne attraverso una
+\func{exec} in quanto il \ids{PID} resta lo stesso. Questo comporta che, al
contrario di quanto avveniva con la semantica BSD, quando un processo termina
tutti i \textit{file lock} da esso detenuti vengono immediatamente rilasciati.
La seconda conseguenza è che qualunque file descriptor che faccia riferimento
allo stesso file (che sia stato ottenuto con una \func{dup} o con una
\func{open} in questo caso non fa differenza) può essere usato per rimuovere
-un blocco, dato che quello che conta è solo il \acr{pid} del processo. Da
+un blocco, dato che quello che conta è solo il \ids{PID} del processo. Da
questo deriva una ulteriore sottile differenza di comportamento: dato che alla
chiusura di un file i blocchi ad esso associati vengono rimossi, nella
semantica POSIX basterà chiudere un file descriptor qualunque per cancellare
fossero stati creati usando altri file descriptor che restano aperti.
Dato che il controllo sull'accesso ai blocchi viene eseguito sulla base del
-\acr{pid} del processo, possiamo anche prendere in considerazione un altro
+\ids{PID} del processo, possiamo anche prendere in considerazione un altro
degli aspetti meno chiari di questa interfaccia e cioè cosa succede quando si
richiedono dei blocchi su regioni che si sovrappongono fra loro all'interno
stesso processo. Siccome il controllo, come nel caso della rimozione, si basa
-solo sul \acr{pid} del processo che chiama la funzione, queste richieste
+solo sul \ids{PID} del processo che chiama la funzione, queste richieste
avranno sempre successo.
Nel caso della semantica BSD, essendo i lock relativi a tutto un file e non
lock} per far si che le regioni bloccate da essa risultanti siano coerenti
con quanto necessario a soddisfare l'operazione richiesta.
-\begin{figure}[!htb]
+\begin{figure}[!htbp]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
+ \begin{minipage}[c]{\codesamplewidth}
\includecodesample{listati/Flock.c}
\end{minipage}
\normalsize
permette di bloccare una sezione di un file usando la semantica POSIX, o un
intero file usando la semantica BSD; in fig.~\ref{fig:file_flock_code} è
riportata il corpo principale del codice del programma, (il testo completo è
-allegato nella directory dei sorgenti).
+allegato nella directory dei sorgenti, nel file \texttt{Flock.c}).
La sezione relativa alla gestione delle opzioni al solito si è omessa, come la
funzione che stampa le istruzioni per l'uso del programma, essa si cura di
\subsection{Il \textit{mandatory locking}}
\label{sec:file_mand_locking}
-\itindbeg{mandatory~locking|(}
+\itindbeg{mandatory~locking}
Il \textit{mandatory locking} è una opzione introdotta inizialmente in SVr4,
per introdurre un \textit{file locking} che, come dice il nome, fosse
Per poter utilizzare il \textit{mandatory locking} è stato introdotto un
utilizzo particolare del bit \itindex{sgid~bit} \acr{sgid}. Se si ricorda
quanto esposto in sez.~\ref{sec:file_special_perm}), esso viene di norma
-utilizzato per cambiare il group-ID effettivo con cui viene eseguito un
+utilizzato per cambiare il \ids{GID} effettivo con cui viene eseguito un
programma, ed è pertanto sempre associato alla presenza del permesso di
esecuzione per il gruppo. Impostando questo bit su un file senza permesso di
esecuzione in un sistema che supporta il \textit{mandatory locking}, fa sì che
è attivo un blocco. Per questo motivo l'abilitazione del \textit{mandatory
locking} è di norma disabilitata, e deve essere attivata filesystem per
filesystem in fase di montaggio (specificando l'apposita opzione di
-\func{mount} riportata in tab.~\ref{tab:sys_mount_flags}, o con l'opzione
+\func{mount} riportata in sez.~\ref{sec:filesystem_mounting}), o con l'opzione
\code{-o mand} per il comando omonimo).
Si tenga presente inoltre che il \textit{mandatory locking} funziona solo
qual caso la funzione fallisce con il solito \errcode{EAGAIN}) che comporta la
possibilità di modificare il file.
-\index{file!locking|)}
+\itindend{file~locking}
-\itindend{mandatory~locking|(}
+\itindend{mandatory~locking}
\section{L'\textit{I/O multiplexing}}
quando, come nelle versioni più recenti del kernel, questo limite è stato
rimosso, esso indica le dimensioni massime dei numeri usati nei \textit{file
descriptor set}.\footnote{il suo valore, secondo lo standard POSIX
- 1003.1-2001, è definito in \file{sys/select.h}, ed è pari a 1024.}
+ 1003.1-2001, è definito in \headfile{sys/select.h}, ed è pari a 1024.}
Si tenga presente che i \textit{file descriptor set} devono sempre essere
inizializzati con \macro{FD\_ZERO}; passare a \func{select} un valore non
multiplexing}, introdotto solo con le ultime revisioni dello standard (POSIX
1003.1g-2000 e POSIX 1003.1-2001). La scelta è stata quella di seguire
l'interfaccia creata da BSD, ma prevede che tutte le funzioni ad esso relative
-vengano dichiarate nell'header \file{sys/select.h}, che sostituisce i
+vengano dichiarate nell'header \headfile{sys/select.h}, che sostituisce i
precedenti, ed inoltre aggiunge a \func{select} una nuova funzione
\funcd{pselect},\footnote{il supporto per lo standard POSIX 1003.1-2001, ed
- l'header \file{sys/select.h}, compaiono in Linux a partire dalle \acr{glibc}
- 2.1. Le \acr{libc4} e \acr{libc5} non contengono questo header, le
- \acr{glibc} 2.0 contengono una definizione sbagliata di \func{psignal},
+ l'header \headfile{sys/select.h}, compaiono in Linux a partire dalle
+ \acr{glibc} 2.1. Le \acr{libc4} e \acr{libc5} non contengono questo header,
+ le \acr{glibc} 2.0 contengono una definizione sbagliata di \func{psignal},
senza l'argomento \param{sigmask}, la definizione corretta è presente dalle
\acr{glibc} 2.1-2.2.1 se si è definito \macro{\_GNU\_SOURCE} e nelle
\acr{glibc} 2.2.2-2.2.4 se si è definito \macro{\_XOPEN\_SOURCE} con valore
L'uso di \param{sigmask} è stato introdotto allo scopo di prevenire possibili
\textit{race condition} \itindex{race~condition} quando ci si deve porre in
attesa sia di un segnale che di dati. La tecnica classica è quella di
-utilizzare il gestore per impostare una variabile globale e controllare questa
-nel corpo principale del programma; abbiamo visto in
-sez.~\ref{sec:sig_example} come questo lasci spazio a possibili race
-condition, per cui diventa essenziale utilizzare \func{sigprocmask} per
-disabilitare la ricezione del segnale prima di eseguire il controllo e
-riabilitarlo dopo l'esecuzione delle relative operazioni, onde evitare
-l'arrivo di un segnale immediatamente dopo il controllo, che andrebbe perso.
+utilizzare il gestore per impostare una \index{variabili!globali} variabile
+globale e controllare questa nel corpo principale del programma; abbiamo visto
+in sez.~\ref{sec:sig_example} come questo lasci spazio a possibili
+\itindex{race~condition} \textit{race condition}, per cui diventa essenziale
+utilizzare \func{sigprocmask} per disabilitare la ricezione del segnale prima
+di eseguire il controllo e riabilitarlo dopo l'esecuzione delle relative
+operazioni, onde evitare l'arrivo di un segnale immediatamente dopo il
+controllo, che andrebbe perso.
Nel nostro caso il problema si pone quando oltre al segnale si devono tenere
sotto controllo anche dei file descriptor con \func{select}, in questo caso si
degli insiemi.
\item[\errcode{EINTR}] la funzione è stata interrotta da un segnale.
\item[\errcode{EINVAL}] il valore di \param{nfds} eccede il limite
- \macro{RLIMIT\_NOFILE}.
+ \const{RLIMIT\_NOFILE}.
\end{errlist}
ed inoltre \errval{EFAULT} e \errval{ENOMEM}.}
\end{prototype}
\begin{figure}[!htb]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
+ \begin{minipage}[c]{\textwidth}
\includestruct{listati/pollfd.h}
\end{minipage}
\normalsize
in stile SysV (in particolare le ultime due non vengono usate su Linux), e
sono utilizzabili soltanto qualora si sia definita la macro
\macro{\_XOPEN\_SOURCE}.\footnote{e ci si ricordi di farlo sempre in testa al
- file, definirla soltanto prima di includere \file{sys/poll.h} non è
+ file, definirla soltanto prima di includere \headfile{sys/poll.h} non è
sufficiente.}
In caso di successo funzione ritorna restituendo il numero di file (un valore
degli insiemi.
\item[\errcode{EINTR}] la funzione è stata interrotta da un segnale.
\item[\errcode{EINVAL}] il valore di \param{nfds} eccede il limite
- \macro{RLIMIT\_NOFILE}.
+ \const{RLIMIT\_NOFILE}.
\end{errlist}
ed inoltre \errval{EFAULT} e \errval{ENOMEM}.}
\end{prototype}
nel sistema.
\item[\errcode{EMFILE}] si è raggiunto il limite sul numero massimo di
istanze di \textit{epoll} per utente stabilito da
- \procfile{/proc/sys/fs/epoll/max\_user\_instances}.
+ \sysctlfile{fs/epoll/max\_user\_instances}.
\item[\errcode{ENOMEM}] non c'è sufficiente memoria nel kernel per creare
l'istanza.
\end{errlist}
\item[\errcode{EPERM}] il file \param{fd} non supporta \textit{epoll}.
\item[\errcode{ENOSPC}] si è raggiunto il limite massimo di registrazioni
per utente di file descriptor da osservare imposto da
- \procfile{/proc/sys/fs/epoll/max\_user\_watches}.
+ \sysctlfile{fs/epoll/max\_user\_watches}.
\end{errlist}
}
\end{prototype}
sotto controllo. L'argomento viene ignorato con l'operazione
\const{EPOLL\_CTL\_DEL}.\footnote{fino al kernel 2.6.9 era comunque richiesto
che questo fosse un puntatore valido, anche se poi veniva ignorato; a
- partire dal 2.6.9 si può specificare anche un valore \texttt{NULL} ma se si
+ partire dal 2.6.9 si può specificare anche un valore \val{NULL} ma se si
vuole mantenere la compatibilità con le versioni precedenti occorre usare un
puntatore valido.}
\begin{figure}[!htb]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
+ \begin{minipage}[c]{\textwidth}
\includestruct{listati/epoll_event.h}
\end{minipage}
\normalsize
Il primo campo, \var{events}, è una maschera binaria in cui ciascun bit
corrisponde o ad un tipo di evento, o una modalità di notifica; detto campo
deve essere specificato come OR aritmetico delle costanti riportate in
-tab.~\ref{tab:epoll_events}. Il secondo campo, \var{data}, è una \ctyp{union}
+tab.~\ref{tab:epoll_events}. Il secondo campo, \var{data}, è una \direct{union}
che serve a identificare il file descriptor a cui si intende fare riferimento,
ed in astratto può contenere un valore qualsiasi (specificabile in diverse
forme) che ne permetta una indicazione univoca. Il modo più comune di usarlo
chiamate devono essere ripetute per ciascun file descriptor, incorrendo in
una perdita di prestazioni qualora il numero di file descriptor sia molto
grande; per questo è stato proposto di introdurre come estensione una
- funzione \func{epoll\_ctlv} che consenta di effettuare con una sola chiamata
+ funzione \code{epoll\_ctlv} che consenta di effettuare con una sola chiamata
le impostazioni per un blocco di file descriptor.} L'uso di
\const{EPOLL\_CTL\_MOD} consente in seguito di modificare le modalità di
osservazione di un file descriptor che sia già stato aggiunto alla lista di
osservazione.
+% TODO verificare se prima o poi epoll_ctlv verrà introdotta
+
Le impostazioni di default prevedono che la notifica degli eventi richiesti
sia effettuata in modalità \textit{level triggered}, a meno che sul file
descriptor non si sia impostata la modalità \textit{edge triggered},
rispettive funzioni consente di fare contemporaneamente entrambe le cose.
Per risolvere questo problema nello sviluppo del kernel si è pensato di
-introdurre un meccanismo alternativo alla notifica dei segnali (esteso anche
+introdurre un meccanismo alternativo per la notifica dei segnali (esteso anche
ad altri eventi generici) che, ispirandosi di nuovo alla filosofia di Unix per
cui tutto è un file, consentisse di eseguire la notifica con l'uso di
opportuni file descriptor.\footnote{ovviamente si tratta di una funzionalità
versioni diverse della \textit{system call}; una prima versione,
\func{signalfd}, introdotta nel kernel 2.6.22 e disponibile con le
\acr{glibc} 2.8 che non supporta l'argomento \texttt{flags}, ed una seconda
- versione, \func{signalfd4}, introdotta con il kernel 2.6.27 e che è quella
+ versione, \funcm{signalfd4}, introdotta con il kernel 2.6.27 e che è quella
che viene sempre usata a partire dalle \acr{glibc} 2.9, che prende un
argomento aggiuntivo \code{size\_t sizemask} che indica la dimensione della
maschera dei segnali, il cui valore viene impostato automaticamente dalle
puntatore ad una maschera di segnali creata con l'uso delle apposite macro già
illustrate in sez.~\ref{sec:sig_sigset}. La maschera deve indicare su quali
segnali si intende operare con \func{signalfd}; l'elenco può essere modificato
-con una successiva chiamata a \func{signalfd}. Dato che \const{SIGKILL} e
-\const{SIGSTOP} non possono essere intercettati (e non prevedono neanche la
+con una successiva chiamata a \func{signalfd}. Dato che \signal{SIGKILL} e
+\signal{SIGSTOP} non possono essere intercettati (e non prevedono neanche la
possibilità di un gestore) un loro inserimento nella maschera verrà ignorato
senza generare errori.
\begin{figure}[!htb]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
+ \begin{minipage}[c]{\textwidth}
\includestruct{listati/signalfd_siginfo.h}
\end{minipage}
\normalsize
che per un bug i kernel fino al 2.6.25 non avvalorano correttamente i campi
\var{ssi\_ptr} e \var{ssi\_int} per segnali inviati con \func{sigqueue}.}
+Come esempio di questa nuova interfaccia ed anche come esempio di applicazione
+della interfaccia di \itindex{epoll} \textit{epoll}, si è scritto un programma
+elementare che stampi sullo standard output sia quanto viene scritto da terzi
+su una \textit{named fifo}, che l'avvenuta ricezione di alcuni segnali. Il
+codice completo si trova al solito nei sorgenti allegati alla guida (nel file
+\texttt{FifoReporter.c}).
+
+In fig.~\ref{fig:fiforeporter_code_init} si è riportata la parte iniziale del
+programma in cui vengono effettuate le varie inizializzazioni necessarie per
+l'uso di \itindex{epoll} \textit{epoll} e \func{signalfd}, a partire
+(\texttt{\small 12--16}) dalla definizione delle varie variabili e strutture
+necessarie. Al solito si è tralasciata la parte dedicata alla decodifica delle
+opzioni che consentono ad esempio di cambiare il nome del file associato alla
+fifo.
+
+\begin{figure}[!htbp]
+ \footnotesize \centering
+ \begin{minipage}[c]{\codesamplewidth}
+ \includecodesample{listati/FifoReporter-init.c}
+ \end{minipage}
+ \normalsize
+ \caption{Sezione di inizializzazione del codice del programma
+ \file{FifoReporter.c}.}
+ \label{fig:fiforeporter_code_init}
+\end{figure}
+
+Il primo passo (\texttt{\small 19--20}) è la crezione di un file descriptor
+\texttt{epfd} di \itindex{epoll} \textit{epoll} con \func{epoll\_create} che è
+quello che useremo per il controllo degli altri. É poi necessario
+disabilitare la ricezione dei segnali (nel caso \signal{SIGINT},
+\signal{SIGQUIT} e \signal{SIGTERM}) per i quali si vuole la notifica tramite
+file descriptor. Per questo prima li si inseriscono (\texttt{\small 22--25}) in
+una maschera di segnali \texttt{sigmask} che useremo con (\texttt{\small 26})
+\func{sigprocmask} per disabilitarli. Con la stessa maschera si potrà per
+passare all'uso (\texttt{\small 28--29}) di \func{signalfd} per abilitare la
+notifica sul file descriptor \var{sigfd}. Questo poi (\texttt{\small 30--33})
+dovrà essere aggiunto con \func{epoll\_ctl} all'elenco di file descriptor
+controllati con \texttt{epfd}.
+
+Occorrerà infine (\texttt{\small 35--38}) creare la \textit{named fifo} se
+questa non esiste ed aprirla per la lettura (\texttt{\small 39--40}); una
+volta fatto questo sarà necessario aggiungere il relativo file descriptor
+(\var{fifofd}) a quelli osservati da \itindex{epoll} \textit{epoll} in maniera
+del tutto analoga a quanto fatto con quello relativo alla notifica dei
+segnali.
+
+\begin{figure}[!htbp]
+ \footnotesize \centering
+ \begin{minipage}[c]{\codesamplewidth}
+ \includecodesample{listati/FifoReporter-main.c}
+ \end{minipage}
+ \normalsize
+ \caption{Ciclo principale del codice del programma \file{FifoReporter.c}.}
+ \label{fig:fiforeporter_code_body}
+\end{figure}
+
+Una volta completata l'inizializzazione verrà eseguito indefinitamente il
+ciclo principale del programma (\texttt{\small 2--45}) che si è riportato in
+fig.~\ref{fig:fiforeporter_code_body}, fintanto che questo non riceva un
+segnale di \signal{SIGINT} (ad esempio con la pressione di \texttt{C-c}). Il
+ciclo prevede che si attenda (\texttt{\small 2--3}) la presenza di un file
+descriptor pronto in lettura con \func{epoll\_wait},\footnote{si ricordi che
+ entrambi i file descriptor \var{fifofd} e \var{sigfd} sono stati posti in
+ osservazioni per eventi di tipo \const{EPOLLIN}.} che si bloccherà fintanto
+che non siano stati scritti dati sulla fifo o che non sia arrivato un
+segnale.\footnote{per semplificare il codice non si è trattato il caso in cui
+ \func{epoll\_wait} viene interrotta da un segnale, assumendo che tutti
+ quelli che possano interessare siano stati predisposti per la notifica
+ tramite file descriptor, per gli altri si otterrà semplicemente l'uscita dal
+ programma.}
+
+Anche se in questo caso i file descriptor pronti possono essere al più due, si
+è comunque adottato un approccio generico in cui questi verranno letti
+all'interno di un opportuno ciclo (\texttt{\small 5--44}) sul numero
+restituito da \func{epoll\_wait}, esaminando i risultati presenti nel vettore
+\var{events} all'interno di una catena di condizionali alternativi sul valore
+del file descriptor riconosciuto come pronto.\footnote{controllando cioè a
+ quale dei due file descriptor possibili corrisponde il campo relativo,
+ \var{events[i].data.fd}.}
+
+Il primo condizionale (\texttt{\small 6--24}) è relativo al caso che si sia
+ricevuto un segnale e che il file descriptor pronto corrisponda
+(\texttt{\small 6}) a \var{sigfd}. Dato che in generale si possono ricevere
+anche notifiche relativi a più di un singolo segnale, si è scelto di leggere
+una struttura \struct{signalfd\_siginfo} alla volta, eseguendo la lettura
+all'interno di un ciclo (\texttt{\small 8--24}) che prosegue fintanto che vi
+siano dati da leggere.
+
+Per questo ad ogni lettura si esamina (\texttt{\small 9--14}) se il valore di
+ritorno della funzione \func{read} è negativo, uscendo dal programma
+(\texttt{\small 11}) in caso di errore reale, o terminando il ciclo
+(\texttt{\small 13}) con un \texttt{break} qualora si ottenga un errore di
+\errcode{EAGAIN} per via dell'esaurimento dei dati.\footnote{si ricordi come
+ sia la fifo che il file descriptor per i segnali siano stati aperti in
+ modalità non-bloccante, come previsto per l’\textit{I/O multiplexing},
+ pertanto ci si aspetta di ricevere un errore di \errcode{EAGAIN} quando non
+ vi saranno più dati da leggere.}
+
+In presenza di dati invece il programma proseguirà l'esecuzione stampando
+(\texttt{\small 19--20}) il nome del segnale ottenuto all'interno della
+struttura \struct{signalfd\_siginfo} letta in \var{siginf}\footnote{per la
+ stampa si è usato il vettore \var{sig\_names} a ciascun elemento del quale
+ corrisponde il nome del segnale avente il numero corrispondente, la cui
+ definizione si è omessa dal codice di fig.~\ref{fig:fiforeporter_code_init}
+ per brevità.} ed il \textit{pid} del processo da cui lo ha ricevuto; inoltre
+(\texttt{\small 21--24}) si controllerà anche se il segnale ricevuto è
+\signal{SIGINT}, che si è preso come segnale da utilizzare per la terminazione
+del programma, che verrà eseguita dopo aver rimosso il file della \textit{name
+ fifo}.
+
+Il secondo condizionale (\texttt{\small 26--39}) è invece relativo al caso in
+cui ci siano dati pronti in lettura sulla fifo e che il file descriptor pronto
+corrisponda (\texttt{\small 26}) a \var{fifofd}. Di nuovo si effettueranno le
+letture in un ciclo (\texttt{\small 28--39}) ripetendole fin tanto che la
+funzione \func{read} non resituisce un errore di \errcode{EAGAIN}
+(\texttt{\small 29--35}).\footnote{il procedimento è lo stesso adottato per il
+ file descriptor associato al segnale, in cui si esce dal programma in caso
+ di errore reale, in questo caso però alla fine dei dati prima di uscire si
+ stampa anche (\texttt{\small 32}) un messaggio di chiusura.} Se invece vi
+sono dati validi letti dalla fifo si inserirà (\texttt{\small 36}) una
+terminazione di stringa sul buffer e si stamperà il tutto (\texttt{\small
+ 37--38}) sullo \textit{standard output}. L'ultimo condizionale
+(\texttt{\small 40--44}) è semplicemente una condizione di cattura per una
+eventualità che comunque non dovrebbe mai verificarsi, e che porta alla uscita
+dal programma con una opportuna segnalazione di errore.
+
+A questo punto si potrà eseguire il comando lanciandolo su un terminale, ed
+osservarne le reazioni agli eventi generati da un altro terminale; lanciando
+il programma otterremo qualcosa del tipo:
+\begin{Verbatim}
+piccardi@hain:~/gapil/sources$ ./a.out
+FifoReporter starting, pid 4568
+\end{Verbatim}
+%$
+e scrivendo qualcosa sull'altro terminale con:
+\begin{Verbatim}
+root@hain:~# echo prova > /tmp/reporter.fifo
+\end{Verbatim}
+si otterrà:
+\begin{Verbatim}
+Message from fifo:
+prova
+end message
+\end{Verbatim}
+mentre inviando un segnale:
+\begin{Verbatim}
+root@hain:~# kill 4568
+\end{Verbatim}
+si avrà:
+\begin{Verbatim}
+Signal received:
+Got SIGTERM
+From pid 3361
+\end{Verbatim}
+ed infine premendo \texttt{C-\bslash} sul terminale in cui è in esecuzione si
+vedrà:
+\begin{Verbatim}
+^\Signal received:
+Got SIGQUIT
+From pid 0
+\end{Verbatim}
+e si potrà far uscire il programma con \texttt{C-c} ottenendo:
+\begin{Verbatim}
+^CSignal received:
+Got SIGINT
+From pid 0
+SIGINT means exit
+\end{Verbatim}
+
+
Lo stesso paradigma di notifica tramite file descriptor usato per i segnali è
-stato adottato anche per i timer; in questo caso, rispetto a quanto visto in
+stato adottato anche per i timer. In questo caso, rispetto a quanto visto in
sez.~\ref{sec:sig_timer_adv}, la scadenza di un timer potrà essere letta da un
-file descriptor, senza dover ricorrere ad altri meccanismi di notifica come un
+file descriptor senza dover ricorrere ad altri meccanismi di notifica come un
segnale o un \textit{thread}. Di nuovo questo ha il vantaggio di poter
utilizzare le funzioni dell'\textit{I/O multiplexing} per attendere allo
-stesso tempo la disponibilità di dati o la ricezione scadenza di un
+stesso tempo la disponibilità di dati o la ricezione della scadenza di un
timer.\footnote{in realtà per questo sarebbe già sufficiente \func{signalfd}
per ricevere i segnali associati ai timer, ma la nuova interfaccia
semplifica notevolmente la gestione e consente di fare tutto con una sola
\textit{system call}.}
-Le funzioni di questa interfaccia ricalcano da vicino la struttura di quelle
-introdotte da POSIX.1-2001, che abbiamo illustrato in
-sez.~\ref{sec:sig_timer_adv}.\footnote{questa interfaccia è stata introdotta
- in forma considerata difettosa con il kernel 2.6.22, per cui è stata
- immediatamente tolta nel successivo 2.6.23 e reintrodotta in una forma
- considerata adeguata nel kernel 2.6.25, il supporto nelle \acr{glibc} è
- stato introdotto a partire dalla versione 2.8.6, la versione del kernel
- 2.6.22 non è supportata e non deve essere usata.} La prima funzione
-prevista, che consente di creare un \textit{timer}, è \funcd{timerfd\_create},
-il cui prototipo è:
+Le funzioni di questa nuova interfaccia ricalcano da vicino la struttura delle
+analoghe versioni ordinarie introdotte con lo standard POSIX.1-2001, che
+abbiamo già illustrato in sez.~\ref{sec:sig_timer_adv}.\footnote{questa
+ interfaccia è stata introdotta in forma considerata difettosa con il kernel
+ 2.6.22, per cui è stata immediatamente tolta nel successivo 2.6.23 e
+ reintrodotta in una forma considerata adeguata nel kernel 2.6.25, il
+ supporto nelle \acr{glibc} è stato introdotto a partire dalla versione
+ 2.8.6, la versione del kernel 2.6.22, presente solo su questo kernel, non è
+ supportata e non deve essere usata.} La prima funzione prevista, quella che
+consente di creare un timer, è \funcd{timerfd\_create}, il cui prototipo è:
\begin{prototype}{sys/timerfd.h}
{int timerfd\_create(int clockid, int flags)}
\label{tab:timerfd_flags}
\end{table}
-In caso di successo la funzione restituisce un file descriptor che può essere
-usato per leggere le notifiche delle scadenze dei timer. Come per quelli
-restituiti da \func{signalfd} anche questo file descriptor segue la semantica
-dei sistemi unix-like, in particolare resta aperto attraverso una \func{exec}
-(a meno che non si sia impostato il flag di \textit{close-on exex} con
-\const{TFD\_CLOEXEC}) e viene duplicato attraverso una \func{fork}, mantenendo
-il riferimento allo stesso \textit{timer}, così che anche il processo figlio
+In caso di successo la funzione restituisce un file descriptor sul quale
+verranno notificate le scadenze dei timer. Come per quelli restituiti da
+\func{signalfd} anche questo file descriptor segue la semantica dei sistemi
+unix-like, in particolare resta aperto attraverso una \func{exec},\footnote{a
+ meno che non si sia impostato il flag di \textit{close-on exec} con
+ \const{TFD\_CLOEXEC}.} e viene duplicato attraverso una \func{fork}; questa
+ultima caratteristica comporta però che anche il figlio può utilizzare i dati
+di un timer creato nel padre, a differenza di quanto avviene invece con i
+timer impostati con le funzioni ordinarie.\footnote{si ricordi infatti che,
+ come illustrato in sez.~\ref{sec:proc_fork}, allarmi, timer e segnali
+ pendenti nel padre vengono cancellati per il figlio dopo una \func{fork}.}
+
+Una volta creato il timer con \func{timerfd\_create} per poterlo utilizzare
+occorre \textsl{armarlo} impostandone un tempo di scadenza ed una eventuale
+periodicità di ripetizione, per farlo si usa la funzione omologa di
+\func{timer\_settime} per la nuova interfaccia; questa è
+\funcd{timerfd\_settime} ed il suo prototipo è:
+\begin{prototype}{sys/timerfd.h}
+ {int timerfd\_settime(int fd, int flags,
+ const struct itimerspec *new\_value,
+ struct itimerspec *old\_value)}
+ Crea un timer associato ad un file descriptor per la notifica.
-per cui
-anche un processo figlio potrà ricevere informazioni sulla scadenza di un
-timer attraverso
+ \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}] l'argomento \param{fd} non corrisponde ad un file
+ descriptor.
+ \item[\errcode{EINVAL}] il file descriptor \param{fd} non è stato ottenuto
+ con \func{timerfd\_create}, o i valori di \param{flag} o dei campi
+ \var{tv\_nsec} in \param{new\_value} non sono validi.
+ \item[\errcode{EFAULT}] o \param{new\_value} o \param{old\_value} non sono
+ puntatori validi.
+ \end{errlist}
+}
+\end{prototype}
+In questo caso occorre indicare su quale timer si intende operare specificando
+come primo argomento il file descriptor ad esso associato, che deve essere
+stato ottenuto da una precedente chiamata a \func{timerfd\_create}. I restanti
+argomenti sono del tutto analoghi a quelli della omologa funzione
+\func{timer\_settime}, e prevedono l'uso di strutture \struct{itimerspec}
+(vedi fig.~\ref{fig:struct_itimerspec}) per le indicazioni di temporizzazione.
+
+I valori ed il significato di questi argomenti sono gli stessi che sono già
+stati illustrati in dettaglio in sez.~\ref{sec:sig_timer_adv} e non staremo a
+ripetere quanto detto in quell'occasione;\footnote{per brevità si ricordi che
+ con \param{new\_value.it\_value} si indica la prima scadenza del timer e
+ con \param{new\_value.it\_interval} la sua periodicità.} l'unica differenza
+riguarda l'argomento \param{flags} che serve sempre ad indicare se il tempo di
+scadenza del timer è da considerarsi relativo o assoluto rispetto al valore
+corrente dell'orologio associato al timer, ma che in questo caso ha come
+valori possibili rispettivamente soltanto $0$ e
+\const{TFD\_TIMER\_ABSTIME}.\footnote{anche questo valore, che è l'analogo di
+ \const{TIMER\_ABSTIME} è l'unico attualmente possibile per \param{flags}.}
+
+L'ultima funzione prevista dalla nuova interfaccia è \funcd{timerfd\_gettime},
+che è l'analoga di \func{timer\_gettime}, il suo prototipo è:
+\begin{prototype}{sys/timerfd.h}
+ {int timerfd\_gettime(int fd, struct itimerspec *curr\_value)}
-% TODO trattare qui eventfd, 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/
-% http://lwn.net/Articles/245533/
-% http://lwn.net/Articles/267331/
+ Crea un timer associato ad un file descriptor per la notifica.
+ \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}] l'argomento \param{fd} non corrisponde ad un file
+ descriptor.
+ \item[\errcode{EINVAL}] il file descriptor \param{fd} non è stato ottenuto
+ con \func{timerfd\_create}.
+ \item[\errcode{EFAULT}] o \param{curr\_value} non è un puntatore valido.
+ \end{errlist}
+}
+\end{prototype}
-\begin{figure}[!htb]
- \footnotesize \centering
- \begin{minipage}[c]{15cm}
- \includecodesample{listati/FifoReporter-init.c}
- \end{minipage}
- \normalsize
- \caption{Sezione di inizializzazione del codice del programma
- \file{FifoReporter.c}.}
- \label{fig:fiforeporter_code}
-\end{figure}
-\begin{figure}[!htb]
- \footnotesize \centering
- \begin{minipage}[c]{15cm}
- \includecodesample{listati/FifoReporter-main.c}
- \end{minipage}
- \normalsize
- \caption{Ciclo principale del codice del programma \file{FifoReporter.c}.}
- \label{fig:fiforeporter_code}
-\end{figure}
+
+Questo infatti diverrà pronto in lettura per tutte le varie funzioni dell'I/O
+multiplexing in presenza di una o più scadenze del timer ad esso associato.
+
+Inoltre sarà possibile ottenere il numero di volte che il timer è scaduto
+dalla ultima impostazione
+
+che può essere
+usato per leggere le notifiche delle scadenze dei timer. Queste possono essere
+ottenute leggendo in maniera ordinaria il file descriptor con una \func{read},
+
+% TODO trattare qui eventfd, 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/
+% http://lwn.net/Articles/245533/
+% http://lwn.net/Articles/267331/
+
+
\section{L'accesso \textsl{asincrono} ai file}
\label{sec:file_asyncronous_access}
tenga presente però che essa non è utilizzabile con i file ordinari ma solo
con socket, file di terminale o pseudo terminale, ed anche, a partire dal
kernel 2.6, anche per fifo e pipe.} il sistema genera un apposito segnale,
-\const{SIGIO}, tutte le volte che diventa possibile leggere o scrivere dal
+\signal{SIGIO}, tutte le volte che diventa possibile leggere o scrivere dal
file descriptor che si è posto in questa modalità. Inoltre è possibile, come
illustrato in sez.~\ref{sec:file_fcntl}, selezionare con il comando
\const{F\_SETOWN} di \func{fcntl} quale processo o quale gruppo di processi
Per far questo però occorre utilizzare le funzionalità dei segnali real-time
(vedi sez.~\ref{sec:sig_real_time}) impostando esplicitamente con il comando
\const{F\_SETSIG} di \func{fcntl} un segnale real-time da inviare in caso di
-I/O asincrono (il segnale predefinito è \const{SIGIO}). In questo caso il
+I/O asincrono (il segnale predefinito è \signal{SIGIO}). In questo caso il
gestore, tutte le volte che riceverà \const{SI\_SIGIO} come valore del campo
\var{si\_code}\footnote{il valore resta \const{SI\_SIGIO} qualunque sia il
segnale che si è associato all'I/O, ed indica appunto che il segnale è stato
Se infatti si eccedono le dimensioni di quest'ultima, il kernel, non potendo
più assicurare il comportamento corretto per un segnale real-time, invierà al
-suo posto un solo \const{SIGIO}, su cui si saranno accumulati tutti i segnali
+suo posto un solo \signal{SIGIO}, su cui si saranno accumulati tutti i segnali
in eccesso, e si dovrà allora determinare con un ciclo quali sono i file
diventati attivi. L'unico modo per essere sicuri che questo non avvenga è di
impostare la lunghezza della coda dei segnali real-time ad una dimensione
identica al valore massimo del numero di file descriptor
utilizzabili.\footnote{vale a dire impostare il contenuto di
- \procfile{/proc/sys/kernel/rtsig-max} allo stesso valore del contenuto di
- \procfile{/proc/sys/fs/file-max}.}
+ \sysctlfile{kernel/rtsig-max} allo stesso valore del contenuto di
+ \sysctlfile{fs/file-max}.}
% TODO fare esempio che usa O_ASYNC
\textsl{notificato} di eventuali modifiche avvenute su un file. Questo è il
motivo per cui i demoni devono essere \textsl{avvisati} in qualche
modo\footnote{in genere questo vien fatto inviandogli un segnale di
- \const{SIGHUP} che, per una convenzione adottata dalla gran parte di detti
+ \signal{SIGHUP} che, per una convenzione adottata dalla gran parte di detti
programmi, causa la rilettura della configurazione.} se il loro file di
configurazione è stato modificato, perché possano rileggerlo e riconoscere le
modifiche.
partire dalla versione 2.4 del kernel, attraverso l'uso di alcuni
\textsl{comandi} aggiuntivi per la funzione \func{fcntl} (vedi
sez.~\ref{sec:file_fcntl}), che divengono disponibili soltanto se si è
-definita la macro \macro{\_GNU\_SOURCE} prima di includere \file{fcntl.h}.
+definita la macro \macro{\_GNU\_SOURCE} prima di includere \headfile{fcntl.h}.
-\index{file!lease|(}
+\itindbeg{file~lease}
La prima di queste funzionalità è quella del cosiddetto \textit{file lease};
questo è un meccanismo che consente ad un processo, detto \textit{lease
\textit{lease}.
La notifica avviene in maniera analoga a come illustrato in precedenza per
l'uso di \const{O\_ASYNC}: di default viene inviato al \textit{lease holder}
-il segnale \const{SIGIO}, ma questo segnale può essere modificato usando il
+il segnale \signal{SIGIO}, ma questo segnale può essere modificato usando il
comando \const{F\_SETSIG} di \func{fcntl}.\footnote{anche in questo caso si
- può rispecificare lo stesso \const{SIGIO}.} Se si è fatto questo\footnote{è
+ può rispecificare lo stesso \signal{SIGIO}.} Se si è fatto questo\footnote{è
in genere è opportuno farlo, come in precedenza, per utilizzare segnali
real-time.} e si è installato il gestore del segnale con \const{SA\_SIGINFO}
si riceverà nel campo \var{si\_fd} della struttura \struct{siginfo\_t} il
su un file, e che un \textit{lease} può essere ottenuto solo su file di dati
(pipe e dispositivi sono quindi esclusi). Inoltre un processo non privilegiato
può ottenere un \textit{lease} soltanto per un file appartenente ad un
-\acr{uid} corrispondente a quello del processo. Soltanto un processo con
+\ids{UID} corrispondente a quello del processo. Soltanto un processo con
privilegi di amministratore (cioè con la \itindex{capabilities} capability
\const{CAP\_LEASE}, vedi sez.~\ref{sec:proc_capabilities}) può acquisire
\textit{lease} su qualunque file.
Se il \textit{lease holder} non provvede a rilasciare il \textit{lease} entro
il numero di secondi specificato dal parametro di sistema mantenuto in
-\procfile{/proc/sys/fs/lease-break-time} sarà il kernel stesso a rimuoverlo (o
+\sysctlfile{fs/lease-break-time} sarà il kernel stesso a rimuoverlo (o
declassarlo) automaticamente.\footnote{questa è una misura di sicurezza per
evitare che un processo blocchi indefinitamente l'accesso ad un file
acquisendo un \textit{lease}.} Una volta che un \textit{lease} è stato
stata definita la macro \macro{\_GNU\_SOURCE}.} chiamata \textit{dnotify},
che consente di richiedere una notifica quando una directory, o uno qualunque
dei file in essa contenuti, viene modificato. Come per i \textit{file lease}
-la notifica avviene di default attraverso il segnale \const{SIGIO}, ma se ne
+la notifica avviene di default attraverso il segnale \signal{SIGIO}, ma se ne
può utilizzare un altro.\footnote{e di nuovo, per le ragioni già esposte in
precedenza, è opportuno che si utilizzino dei segnali real-time.} Inoltre,
come in precedenza, si potrà ottenere nel gestore del segnale il file
descriptor che è stato modificato tramite il contenuto della struttura
\struct{siginfo\_t}.
-\index{file!lease|)}
+\itindend{file~lease}
\begin{table}[htb]
\centering
di sistema è previsto che un utente possa utilizzare un numero limitato di
istanze di \textit{inotify}; il valore di default del limite è di 128, ma
questo valore può essere cambiato con \func{sysctl} o usando il file
- \procfile{/proc/sys/fs/inotify/max\_user\_instances}.} si tratta di un file
+ \sysctlfile{fs/inotify/max\_user\_instances}.} si tratta di un file
descriptor speciale che non è associato a nessun file su disco, e che viene
utilizzato solo per notificare gli eventi che sono stati posti in
osservazione. Dato che questo file descriptor non è associato a nessun file o
\bodydesc{La funzione restituisce un valore positivo in caso di successo, o
$-1$ in caso di errore, nel qual caso \var{errno} assumerà uno dei valori:
\begin{errlist}
- \item[\errcode{EACCESS}] non si ha accesso in lettura al file indicato.
+ \item[\errcode{EACCES}] non si ha accesso in lettura al file indicato.
\item[\errcode{EINVAL}] \param{mask} non contiene eventi legali o \param{fd}
non è un file descriptor di \textit{inotify}.
\item[\errcode{ENOSPC}] si è raggiunto il numero massimo di voci di
directory che si vogliono tenere sotto osservazione,\footnote{anche in questo
caso c'è un limite massimo che di default è pari a 8192, ed anche questo
valore può essere cambiato con \func{sysctl} o usando il file
- \procfile{/proc/sys/fs/inotify/max\_user\_watches}.} e si utilizzerà sempre
+ \sysctlfile{fs/inotify/max\_user\_watches}.} e si utilizzerà sempre
un solo file descriptor.
Il tipo di evento che si vuole osservare deve essere specificato
\begin{figure}[!htb]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
+ \begin{minipage}[c]{\textwidth}
\includestruct{listati/inotify_event.h}
\end{minipage}
\normalsize
\end{table}
\footnotetext{la coda di notifica ha una dimensione massima specificata dal
- parametro di sistema \procfile{/proc/sys/fs/inotify/max\_queued\_events} che
+ parametro di sistema \sysctlfile{fs/inotify/max\_queued\_events} che
indica il numero massimo di eventi che possono essere mantenuti sulla
stessa; quando detto valore viene ecceduto gli ulteriori eventi vengono
scartati, ma viene comunque generato un evento di tipo
Infine due campi \var{name} e \var{len} sono utilizzati soltanto quando
l'evento è relativo ad un file presente in una directory posta sotto
osservazione, in tal caso essi contengono rispettivamente il nome del file
-(come pathname relativo alla directory osservata) e la relativa dimensione in
-byte. Il campo \var{name} viene sempre restituito come stringa terminata da
-NUL, con uno o più zeri di terminazione, a seconda di eventuali necessità di
-allineamento del risultato, ed il valore di \var{len} corrisponde al totale
-della dimensione di \var{name}, zeri aggiuntivi compresi. La stringa con il
-nome del file viene restituita nella lettura subito dopo la struttura
-\struct{inotify\_event}; questo significa che le dimensioni di ciascun evento
-di \textit{inotify} saranno pari a \code{sizeof(\struct{inotify\_event}) +
- len}.
+(come \itindsub{pathname}{relativo} \textit{pathname} relativo alla directory
+osservata) e la relativa dimensione in byte. Il campo \var{name} viene sempre
+restituito come stringa terminata da NUL, con uno o più zeri di terminazione,
+a seconda di eventuali necessità di allineamento del risultato, ed il valore
+di \var{len} corrisponde al totale della dimensione di \var{name}, zeri
+aggiuntivi compresi. La stringa con il nome del file viene restituita nella
+lettura subito dopo la struttura \struct{inotify\_event}; questo significa che
+le dimensioni di ciascun evento di \textit{inotify} saranno pari a
+\code{sizeof(\struct{inotify\_event}) + len}.
Vediamo allora un esempio dell'uso dell'interfaccia di \textit{inotify} con un
semplice programma che permette di mettere sotto osservazione uno o più file e
\begin{figure}[!htbp]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
+ \begin{minipage}[c]{\codesamplewidth}
\includecodesample{listati/inotify_monitor.c}
\end{minipage}
\normalsize
\subsection{L'interfaccia POSIX per l'I/O asincrono}
\label{sec:file_asyncronous_io}
+% vedere anche http://davmac.org/davpage/linux/async-io.html
+
Una modalità alternativa all'uso dell'\textit{I/O multiplexing} per gestione
dell'I/O simultaneo su molti file è costituita dal cosiddetto \textsl{I/O
asincrono}. Il concetto base dell'\textsl{I/O asincrono} è che le funzioni
attraverso l'uso di una apposita struttura \struct{aiocb} (il cui nome sta per
\textit{asyncronous I/O control block}), che viene passata come argomento a
tutte le funzioni dell'interfaccia. La sua definizione, come effettuata in
-\file{aio.h}, è riportata in fig.~\ref{fig:file_aiocb}. Nello steso file è
+\headfile{aio.h}, è riportata in fig.~\ref{fig:file_aiocb}. Nello steso file è
definita la macro \macro{\_POSIX\_ASYNCHRONOUS\_IO}, che dichiara la
disponibilità dell'interfaccia per l'I/O asincrono.
\begin{figure}[!htb]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
+ \begin{minipage}[c]{\textwidth}
\includestruct{listati/aiocb.h}
\end{minipage}
\normalsize
operazione può dar luogo a risultati impredicibili, perché l'accesso ai vari
campi per eseguire l'operazione può avvenire in un momento qualsiasi dopo la
richiesta. Questo comporta che non si devono usare per \param{aiocbp}
-variabili automatiche e che non si deve riutilizzare la stessa struttura per
-un'altra operazione fintanto che la precedente non sia stata ultimata. In
-generale per ogni operazione si deve utilizzare una diversa struttura
-\struct{aiocb}.
+\index{variabili!automatiche} variabili automatiche e che non si deve
+riutilizzare la stessa struttura per un'altra operazione fintanto che la
+precedente non sia stata ultimata. In generale per ogni operazione si deve
+utilizzare una diversa struttura \struct{aiocb}.
Dato che si opera in modalità asincrona, il successo di \func{aio\_read} o
\func{aio\_write} non implica che le operazioni siano state effettivamente
di notifica non verrà invocato. Se si specifica una operazione relativa ad un
altro file descriptor il risultato è indeterminato. In caso di successo, i
possibili valori di ritorno per \func{aio\_cancel} (anch'essi definiti in
-\file{aio.h}) sono tre:
+\headfile{aio.h}) sono tre:
\begin{basedescript}{\desclabelwidth{3.0cm}}
\item[\const{AIO\_ALLDONE}] indica che le operazioni di cui si è richiesta la
cancellazione sono state già completate,
pagine di memoria reale, ed le modalità di accesso (lettura, esecuzione,
scrittura); una loro violazione causa quella una \itindex{segment~violation}
\textit{segment violation}, e la relativa emissione del segnale
- \const{SIGSEGV}.} da applicare al segmento di memoria e deve essere
+ \signal{SIGSEGV}.} da applicare al segmento di memoria e deve essere
specificato come maschera binaria ottenuta dall'OR di uno o più dei valori
riportati in tab.~\ref{tab:file_mmap_prot}; il valore specificato deve essere
compatibile con la modalità di accesso con cui si è aperto il file.
modifiche fatte alla regione mappata, in
questo caso dopo una scrittura, se non c'è più
memoria disponibile, si ha l'emissione di
- un \const{SIGSEGV}.\\
+ un \signal{SIGSEGV}.\\
\const{MAP\_LOCKED} & Se impostato impedisce lo swapping delle pagine
mappate.\\
\const{MAP\_GROWSDOWN} & Usato per gli \itindex{stack} \textit{stack}.
tutto quanto è comunque basato sul meccanismo della \index{memoria~virtuale}
memoria virtuale. Questo comporta allora una serie di conseguenze. La più
ovvia è che se si cerca di scrivere su una zona mappata in sola lettura si
-avrà l'emissione di un segnale di violazione di accesso (\const{SIGSEGV}),
+avrà l'emissione di un segnale di violazione di accesso (\signal{SIGSEGV}),
dato che i permessi sul segmento di memoria relativo non consentono questo
tipo di accesso.
bordo della pagina successiva.
In questo caso è possibile accedere a quella zona di memoria che eccede le
-dimensioni specificate da \param{length}, senza ottenere un \const{SIGSEGV}
+dimensioni specificate da \param{length}, senza ottenere un \signal{SIGSEGV}
poiché essa è presente nello spazio di indirizzi del processo, anche se non è
mappata sul file. Il comportamento del sistema è quello di restituire un
valore nullo per quanto viene letto, e di non riportare su file quanto viene
In questa situazione, per la sezione di pagina parzialmente coperta dal
contenuto del file, vale esattamente quanto visto in precedenza; invece per la
parte che eccede, fino alle dimensioni date da \param{length}, l'accesso non
-sarà più possibile, ma il segnale emesso non sarà \const{SIGSEGV}, ma
-\const{SIGBUS}, come illustrato in fig.~\ref{fig:file_mmap_exceed}.
+sarà più possibile, ma il segnale emesso non sarà \signal{SIGSEGV}, ma
+\signal{SIGBUS}, come illustrato in fig.~\ref{fig:file_mmap_exceed}.
Non tutti i file possono venire mappati in memoria, dato che, come illustrato
in fig.~\ref{fig:file_mmap_layout}, la mappatura introduce una corrispondenza
\begin{errlist}
\item[\errcode{EINVAL}] il valore di \param{addr} non è valido o non è un
multiplo di \const{PAGE\_SIZE}.
- \item[\errcode{EACCESS}] l'operazione non è consentita, ad esempio si è
+ \item[\errcode{EACCES}] l'operazione non è consentita, ad esempio si è
cercato di marcare con \const{PROT\_WRITE} un segmento di memoria cui si
ha solo accesso in lettura.
% \item[\errcode{ENOMEM}] non è stato possibile allocare le risorse
maschera binaria per i flag che controllano il comportamento della funzione.
Il solo valore utilizzato è \const{MREMAP\_MAYMOVE}\footnote{per poter
utilizzare questa costante occorre aver definito \macro{\_GNU\_SOURCE} prima
- di includere \file{sys/mman.h}.} che consente di eseguire l'espansione
+ di includere \headfile{sys/mman.h}.} che consente di eseguire l'espansione
anche quando non è possibile utilizzare il precedente indirizzo. Per questo
motivo, se si è usato questo flag, la funzione può restituire un indirizzo
della nuova zona di memoria che non è detto coincida con \param{old\_address}.
\begin{figure}[!htb]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
+ \begin{minipage}[c]{\textwidth}
\includestruct{listati/iovec.h}
\end{minipage}
\normalsize
POSIX.1-2001 prevede anche che sia possibile avere un limite al numero di
elementi del vettore \param{vector}. Qualora questo sussista, esso deve essere
indicato dal valore dalla costante \const{IOV\_MAX}, definita come le altre
-costanti analoghe (vedi sez.~\ref{sec:sys_limits}) in \file{limits.h}; lo
+costanti analoghe (vedi sez.~\ref{sec:sys_limits}) in \headfile{limits.h}; lo
stesso valore deve essere ottenibile in esecuzione tramite la funzione
\func{sysconf} richiedendo l'argomento \const{\_SC\_IOV\_MAX} (vedi
sez.~\ref{sec:sys_sysconf}).
partire dal kernel 2.6.30 sono state introdotte anche per l'\textsl{I/O
vettorizzato} le analoghe delle funzioni \func{pread} e \func{pwrite} (vedi
sez.~\ref{sec:file_read} e \ref{sec:file_write}); le due funzioni sono
-\funcd{preadv} e \func{pwritev} ed i rispettivi prototipi sono:\footnote{le
+\funcd{preadv} e \funcd{pwritev} ed i rispettivi prototipi sono:\footnote{le
due funzioni sono analoghe alle omonime presenti in BSD; le \textit{system
call} usate da Linux (introdotte a partire dalla versione 2.6.30)
utilizzano degli argomenti diversi per problemi collegati al formato a 64
per \var{errno} anche i valori:
\begin{errlist}
\item[\errcode{EOVERFLOW}] \param{offset} ha un valore che non può essere
- usato come \ctyp{off\_t}.
+ usato come \type{off\_t}.
\item[\errcode{ESPIPE}] \param{fd} è associato ad un socket o una pipe.
\end{errlist}
}
che anzi in certi casi si potevano avere anche dei peggioramenti. Questo ha
portato, per i kernel della serie 2.6,\footnote{per alcune motivazioni di
questa scelta si può fare riferimento a quanto illustrato da Linus Torvalds
- in \href{http://www.cs.helsinki.fi/linux/linux-kernel/2001-03/0200.html}
- {\textsf{http://www.cs.helsinki.fi/linux/linux-kernel/2001-03/0200.html}}.}
+ in \url{http://www.cs.helsinki.fi/linux/linux-kernel/2001-03/0200.html}.}
alla decisione di consentire l'uso della funzione soltanto quando il file da
cui si legge supporta le operazioni di \textit{memory mapping} (vale a dire
non è un socket) e quello su cui si scrive è un socket; in tutti gli altri
scopi da \func{sendfile}, quello che rende \func{splice} davvero diversa è
stata la reinterpretazione che ne è stata fatta nell'implementazione su
Linux realizzata da Jens Anxboe, concetti che sono esposti sinteticamente
- dallo stesso Linus Torvalds in \href{http://kerneltrap.org/node/6505}
- {\textsf{http://kerneltrap.org/node/6505}}.} si tratta semplicemente di una
-funzione che consente di fare in maniera del tutto generica delle operazioni
-di trasferimento di dati fra un file e un buffer gestito interamente in kernel
-space. In questo caso il cuore della funzione (e delle affini \func{vmsplice}
-e \func{tee}, che tratteremo più avanti) è appunto l'uso di un buffer in
-kernel space, e questo è anche quello che ne ha semplificato l'adozione,
-perché l'infrastruttura per la gestione di un tale buffer è presente fin dagli
-albori di Unix per la realizzazione delle \textit{pipe} (vedi
-sez.~\ref{sec:ipc_unix}). Dal punto di vista concettuale allora \func{splice}
-non è altro che una diversa interfaccia (rispetto alle \textit{pipe}) con cui
-utilizzare in user space l'oggetto ``\textsl{buffer in kernel space}''.
+ dallo stesso Linus Torvalds in \url{http://kerneltrap.org/node/6505}.} si
+tratta semplicemente di una funzione che consente di fare in maniera del tutto
+generica delle operazioni di trasferimento di dati fra un file e un buffer
+gestito interamente in kernel space. In questo caso il cuore della funzione (e
+delle affini \func{vmsplice} e \func{tee}, che tratteremo più avanti) è
+appunto l'uso di un buffer in kernel space, e questo è anche quello che ne ha
+semplificato l'adozione, perché l'infrastruttura per la gestione di un tale
+buffer è presente fin dagli albori di Unix per la realizzazione delle
+\textit{pipe} (vedi sez.~\ref{sec:ipc_unix}). Dal punto di vista concettuale
+allora \func{splice} non è altro che una diversa interfaccia (rispetto alle
+\textit{pipe}) con cui utilizzare in user space l'oggetto ``\textsl{buffer in
+ kernel space}''.
Così se per una \textit{pipe} o una \textit{fifo} il buffer viene utilizzato
come area di memoria (vedi fig.~\ref{fig:ipc_pipe_singular}) dove appoggiare i
\func{splice}, oppure nessuno dei file descriptor è una pipe, oppure si
è dato un valore a \param{off\_in} o \param{off\_out} ma il
corrispondente file è un dispositivo che non supporta la funzione
- \func{seek}.
+ \func{lseek}.
\item[\errcode{ENOMEM}] non c'è memoria sufficiente per l'operazione
richiesta.
\item[\errcode{ESPIPE}] o \param{off\_in} o \param{off\_out} non sono
- \const{NULL} ma il corrispondente file descriptor è una \textit{pipe}.
+ \val{NULL} ma il corrispondente file descriptor è una \textit{pipe}.
\end{errlist}
}
\end{functions}
(\texttt{\small 18--22}), quello di destinazione (\texttt{\small 23--27}) ed
infine (\texttt{\small 28--31}) la \textit{pipe} che verrà usata come buffer.
-\begin{figure}[!phtb]
+\begin{figure}[!htbp]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
+ \begin{minipage}[c]{\codesamplewidth}
\includecodesample{listati/splicecp.c}
\end{minipage}
\normalsize
un'altra; \param{fd\_in} deve essere il capo in lettura della \textit{pipe}
sorgente e \param{fd\_out} il capo in scrittura della \textit{pipe}
destinazione; a differenza di quanto avviene con \func{read} i dati letti con
-\func{tee} da \func{fd\_in} non vengono \textsl{consumati} e restano
+\func{tee} da \param{fd\_in} non vengono \textsl{consumati} e restano
disponibili sulla \textit{pipe} per una successiva lettura (di nuovo per il
comportamento delle \textit{pipe} si veda sez.~\ref{sec:ipc_unix}). Al
momento\footnote{quello della stesura di questo paragrafo, avvenuta il Gennaio
\begin{figure}[!htbp]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
+ \begin{minipage}[c]{\codesamplewidth}
\includecodesample{listati/tee.c}
\end{minipage}
\normalsize
detto che i dati vengono effettivamente spostati o copiati, il kernel infatti
realizza le \textit{pipe} come un insieme di puntatori\footnote{per essere
precisi si tratta di un semplice buffer circolare, un buon articolo sul tema
- si trova su \href{http://lwn.net/Articles/118750/}
- {\textsf{http://lwn.net/Articles/118750/}}.} alle pagine di memoria interna
-che contengono i dati, per questo una volta che i dati sono presenti nella
-memoria del kernel tutto quello che viene fatto è creare i suddetti puntatori
-ed aumentare il numero di referenze; questo significa che anche con \func{tee}
-non viene mai copiato nessun byte, vengono semplicemente copiati i puntatori.
+ si trova su \url{http://lwn.net/Articles/118750/}.} alle pagine di memoria
+interna che contengono i dati, per questo una volta che i dati sono presenti
+nella memoria del kernel tutto quello che viene fatto è creare i suddetti
+puntatori ed aumentare il numero di referenze; questo significa che anche con
+\func{tee} non viene mai copiato nessun byte, vengono semplicemente copiati i
+puntatori.
% TODO?? dal 2.6.25 splice ha ottenuto il supporto per la ricezione su rete
Il concetto di \func{readahead} viene generalizzato nello standard
POSIX.1-2001 dalla funzione \func{posix\_fadvise},\footnote{anche se
- l'argomento \param{len} è stato modificato da \ctyp{size\_t} a \ctyp{off\_t}
+ l'argomento \param{len} è stato modificato da \type{size\_t} a \type{off\_t}
nella revisione POSIX.1-2003 TC5.} che consente di ``\textsl{avvisare}'' il
kernel sulle modalità con cui si intende accedere nel futuro ad una certa
porzione di un file,\footnote{la funzione però è stata introdotta su Linux
esclusivamente su Linux, inizialmente \funcd{fallocate} non era stata definita
come funzione di libreria,\footnote{pertanto poteva essere invocata soltanto
in maniera indiretta con l'ausilio di \func{syscall}, vedi
- sez.~\ref{sec:intro_syscall}, come \code{long fallocate(int fd, int mode,
+ sez.~\ref{sec:proc_syscall}, come \code{long fallocate(int fd, int mode,
loff\_t offset, loff\_t len)}.} ma a partire dalle \acr{glibc} 2.10 è
stato fornito un supporto esplicito; il suo prototipo è:
\begin{functions}
-%\subsection{L'utilizzo delle porte di I/O}
-%\label{sec:file_io_port}
-%
-% TODO l'I/O sulle porte di I/O
-% consultare le manpage di ioperm, iopl e outb
% TODO non so dove trattarli, ma dal 2.6.39 ci sono i file handle, vedi
% http://lwn.net/Articles/432757/
% LocalWords: ENFILE lenght segment violation SIGSEGV FIXED msync munmap copy
% LocalWords: DoS Denial Service EXECUTABLE NORESERVE LOCKED swapping stack fs
% LocalWords: GROWSDOWN ANON POPULATE prefaulting SIGBUS fifo VME fork old SFD
-% LocalWords: exec atime ctime mtime mprotect addr EACCESS mremap address new
+% LocalWords: exec atime ctime mtime mprotect addr mremap address new
% LocalWords: long MAYMOVE realloc VMA virtual Ingo Molnar remap pages pgoff
% LocalWords: dall' fault cache linker prelink advisory discrectionary lock fl
% LocalWords: flock shared exclusive operation dup inode linked NFS cmd ENOLCK
% LocalWords: Jens Anxboe vmsplice seek ESPIPE GIFT TCP CORK MSG splicecp nr
% LocalWords: nwrite segs patch readahead posix fadvise TC advice FADV NORMAL
% LocalWords: SEQUENTIAL NOREUSE WILLNEED DONTNEED streaming fallocate EFBIG
-% LocalWords: POLLRDHUP half close pwait Gb madvise MADV ahead REMOVE tmpfs
+% LocalWords: POLLRDHUP half close pwait Gb madvise MADV ahead REMOVE tmpfs it
% LocalWords: DONTFORK DOFORK shmfs preadv pwritev syscall linux loff head XFS
% LocalWords: MERGEABLE EOVERFLOW prealloca hole FALLOC KEEP stat fstat union
% LocalWords: conditions sigwait CLOEXEC signalfd sizemask SIGKILL SIGSTOP ssi
-% LocalWords: sigwaitinfo FifoReporter Windows ptr sigqueue
+% LocalWords: sigwaitinfo FifoReporter Windows ptr sigqueue named timerfd TFD
+% LocalWords: clockid CLOCK MONOTONIC REALTIME itimerspec interval
+% LocalWords: ABSTIME gettime
%%% Local Variables: