%%
\chapter{La gestione avanzata dei file}
\label{cha:file_advanced}
-
In questo capitolo affronteremo le tematiche relative alla gestione avanzata
dei file. Inizieremo con la trattazione delle problematiche del \textit{file
locking} e poi prenderemo in esame le varie funzionalità avanzate che
l'operazione richiesta.
\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 osservere imposto da
+ per utente di file descriptor da osservare imposto da
\procfile{/proc/sys/fs/epoll/max\_user\_watches}.
\end{errlist}
}
Abbiamo visto in sez.~\ref{sec:file_select} come il meccanismo classico delle
notifiche di eventi tramite i segnali, presente da sempre nei sistemi
unix-like, porti a notevoli problemi nell'interazione con le funzioni per
-l'I/O multiplexing, tanto che per evitare possibili \itindex{race~condition}
-\textit{race condition} sono state introdotte estensioni dello standard POSIX e
-funzioni apposite come \func{pselect}, \func{ppoll} e \funcd{epoll\_pwait}.
+l'\textit{I/O multiplexing}, tanto che per evitare possibili
+\itindex{race~condition} \textit{race condition} sono state introdotte
+estensioni dello standard POSIX e funzioni apposite come \func{pselect},
+\func{ppoll} e \funcd{epoll\_pwait}.
Benché i segnali siano il meccanismo più usato per effettuare notifiche ai
processi, la loro interfaccia di programmazione, che comporta l'esecuzione di
sincrona dei segnali con la funzione \func{sigwait} e le sue affini. Queste
funzioni consentono di gestire i segnali bloccando un processo fino alla
avvenuta ricezione e disabilitando l'esecuzione asincrona rispetto al resto
-del programma del gestore del segnale. Questo consente di risolvere i
-problemi di atomicità nella gestione degli eventi associati ai segnali, avendo
-tutto il controllo nel flusso principale del programma, ottenendo così una
-gestione simile a quella dell'I/O multiplexing, ma non risolve i problemi
+del programma del gestore del segnale. Questo consente di risolvere i problemi
+di atomicità nella gestione degli eventi associati ai segnali, avendo tutto il
+controllo nel flusso principale del programma, ottenendo così una gestione
+simile a quella dell'\textit{I/O multiplexing}, ma non risolve i problemi
delle interazioni con quest'ultimo, perché o si aspetta la ricezione di un
segnale o si aspetta che un file descriptor sia accessibile e nessuna delle
rispettive funzioni consente di fare contemporaneamente entrambe le cose.
gestore in occasione dell'arrivo di un segnale, e rilevarne l'avvenuta
ricezione leggendone la notifica tramite l'uso di uno speciale file
descriptor. Trattandosi di un file descriptor questo potrà essere tenuto sotto
-osservazione con le ordinarie funzioni dell'I/O multiplexing (vale a dire con
-le solite \func{select}, \func{poll} e \funcd{epoll\_wait}) allo stesso modo
-di quelli associati a file o socket, per cui alla fine si potrà attendere in
-contemporanea sia l'arrivo del segnale che la disponibilità di accesso ai dati
-relativi a questi ultimi.
+osservazione con le ordinarie funzioni dell'\textit{I/O multiplexing} (vale a
+dire con le solite \func{select}, \func{poll} e \funcd{epoll\_wait}) allo
+stesso modo di quelli associati a file o socket, per cui alla fine si potrà
+attendere in contemporanea sia l'arrivo del segnale che la disponibilità di
+accesso ai dati relativi a questi ultimi.
La funzione che permette di abilitare la ricezione dei segnali tramite file
-descriptor è \funcd{signalfd},\footnote{in realtà quella riportata è la
- interfacia alla funzione fornita dalle \acr{glibc}, esistono in realtà due
- versioni diverse della \textit{system call}, la prima versione,
+descriptor è \funcd{signalfd},\footnote{in realtà quella riportata è
+ l'interfaccia alla funzione fornita dalle \acr{glibc}, esistono infatti due
+ 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, ed una seconda versione,
- \func{signalfd4}, che prende argomenti aggiuntivi, introdotta con il kernel
- 2.6.27 che è quella che viene sempre usata a partire dalle \acr{glibc} 2.9.}
-il cui prototipo è:
+ \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
+ 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
+ \acr{glibc}.} il cui prototipo è:
\begin{prototype}{sys/signalfd.h}
{int signalfd(int fd, const sigset\_t *mask, int flags)}
- Crea o modifica un file descriptor pet la ricezione dei segnali.
+ Crea o modifica un file descriptor per la ricezione dei segnali.
\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
\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
+ \item[\errcode{ENOMEM}] 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
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 già
-illustrate in sez.~\ref{sec:sig_sigset}; la maschera deve indicare su quali
+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
-possibilità di un gestore) un loro inserimento nella maschera verrà ignorato,
-senza generare errori.
+possibilità di un gestore) un loro inserimento nella maschera verrà ignorato
+senza generare errori.
L'argomento \param{flags} consente di impostare direttamente in fase di
creazione due flag per il file descriptor analoghi a quelli che si possono
impostare con una creazione ordinaria con \func{open}, evitando una
impostazione successiva con \func{fcntl}.\footnote{questo è un argomento
aggiuntivo, introdotto con la versione fornita a partire dal kernel 2.6.27,
- per kernel precedenti il valore deve essere nullo.}
+ per kernel precedenti il valore deve essere nullo.} L'argomento deve essere
+specificato come maschera binaria dei valori riportati in
+tab.~\ref{tab:signalfd_flags}.
\begin{table}[htb]
\centering
\label{tab:signalfd_flags}
\end{table}
+Si tenga presente che la chiamata a \func{signalfd} non disabilita la gestione
+ordinaria dei segnali indicati da \param{mask}; questa, se si vuole effettuare
+la ricezione tramite il file descriptor, dovrà essere disabilitata
+esplicitamente bloccando gli stessi segnali con \func{sigprocmask}, altrimenti
+verranno comunque eseguite le azioni di default (o un eventuale gestore
+installato in precedenza).\footnote{il blocco non ha invece nessun effetto sul
+ file descriptor restituito da \func{signalfd}, dal quale sarà possibile
+ pertanto ricevere qualunque segnale, anche se questo risultasse bloccato.}
+Si tenga presente inoltre che la lettura di una struttura
+\struct{signalfd\_siginfo} relativa ad un segnale pendente è equivalente alla
+esecuzione di un gestore, vale a dire che una volta letta il segnale non sarà
+più pendente e non potrà essere ricevuto, qualora si ripristino le normali
+condizioni di gestione, né da un gestore né dalla funzione \func{sigwaitinfo}.
+
+Come anticipato, essendo questo lo scopo principale della nuova interfaccia,
+il file descriptor può essere tenuto sotto osservazione tramite le funzioni
+dell'\textit{I/O multiplexing} (vale a dire con le solite \func{select},
+\func{poll} e \funcd{epoll\_wait}), e risulterà accessibile in lettura quando
+uno o più dei segnali indicati tramite \param{mask} sarà pendente.
+
+La funzione può essere chiamata più volte dallo stesso processo, consentendo
+così di tenere sotto osservazione segnali diversi tramite file descriptor
+diversi. Inoltre è anche possibile tenere sotto osservazione lo stesso segnale
+con più file descriptor, anche se la pratica è sconsigliata; in tal caso la
+ricezione del segnale potrà essere effettuata con una lettura da uno qualunque
+dei file descriptor a cui è associato, ma questa potrà essere eseguita
+soltanto una volta.\footnote{questo significa che tutti i file descriptor su
+ cui è presente lo stesso segnale risulteranno pronti in lettura per le
+ funzioni di \textit{I/O multiplexing}, ma una volta eseguita la lettura su
+ uno di essi il segnale sarà considerato ricevuto ed i relativi dati non
+ saranno più disponibili sugli altri file descriptor, che (a meno di una
+ ulteriore occorrenza del segnale nel frattempo) di non saranno più pronti.}
+
+Quando il file descriptor per la ricezione dei segnali non serve più potrà
+essere chiuso con \func{close} liberando tutte le risorse da esso allocate. In
+tal caso qualora vi fossero segnali pendenti questi resteranno tali, e
+potranno essere ricevuti normalmente una volta che si rimuova il blocco
+imposto con \func{sigprocmask}.
+
+Oltre che con le funzioni dell'\textit{I/O multiplexing} l'uso del file
+descriptor restituito da \func{signalfd} cerca di seguire la semantica di un
+sistema unix-like anche con altre \textit{system call}; in particolare esso
+resta aperto (come ogni altro file descriptor) attraverso una chiamata ad
+\func{exec}, a meno che non lo si sia creato con il flag di
+\const{SFD\_CLOEXEC} o si sia successivamente impostato il
+\textit{close-on-exec} con \func{fcntl}. Questo comportamento corrisponde
+anche alla ordinaria semantica relativa ai segnali bloccati, che restano
+pendenti attraverso una \func{exec}.
+
+Analogamente il file descriptor resta sempre disponibile attraverso una
+\func{fork} per il processo figlio, che ne riceve una copia; in tal caso però
+il figlio potrà leggere dallo stesso soltanto i dati relativi ai segnali
+ricevuti da lui stesso. Nel caso di \textit{thread} viene nuovamente seguita
+la semantica ordinaria dei segnali, che prevede che un singolo \textit{thread}
+possa ricevere dal file descriptor solo le notifiche di segnali inviati
+direttamente a lui o al processo in generale, e non quelli relativi ad altri
+\textit{thread} appartenenti allo stesso processo.
+
L'interfaccia fornita da \func{signalfd} prevede che la ricezione dei segnali
sia eseguita leggendo i dati relativi ai segnali pendenti dal file descriptor
-restituito dalla funzione con una normalissima \func{read}. Questi dati
-vengono scritti sul buffer indicato come secondo argomento di \func{read} in
-forma di una sequenza di una o più strutture \struct{signalfd\_siginfo} (la
-cui definizione si è riportata in fig.~\ref{fig:signalfd_siginfo}) a seconda
-sia della dimensione del buffer che del numero di segnali pendenti. Per questo
-motivo il buffer deve essere almeno di dimensione pari a quella di
-\struct{signalfd\_siginfo}, qualora sia di dimensione maggiore potranno essere
-letti in unica soluzione i dati relativi ad eventuali più segnali pendenti,
-fino al numero massimo di strutture \struct{signalfd\_siginfo} che possono
-rientrare nel buffer.
+restituito dalla funzione con una normalissima \func{read}. Qualora non vi
+siano segnali pendenti la \func{read} si bloccherà a meno di non aver
+impostato la modalità di I/O non bloccante sul file descriptor, o direttamente
+in fase di creazione con il flag \const{SFD\_NONBLOCK}, o in un momento
+successivo con \func{fcntl}.
\begin{figure}[!htb]
\footnotesize \centering
\label{fig:signalfd_siginfo}
\end{figure}
-Si tenga presente che lettura di una struttura \struct{signalfd\_siginfo}
-relativa ad un segnale pendente è equivalente alla esecuzione di un gestore,
-vale a dire che una volta letta il segnale non sarà più pendente e non potrà
-essere ricevuto, qualora si ripristino le normali condizioni di gestione, né
-da un gestore né dalla funzione \func{sigwaitinfo}.
+I dati letti dal file descriptor vengono scritti sul buffer indicato come
+secondo argomento di \func{read} nella forma di una sequenza di una o più
+strutture \struct{signalfd\_siginfo} (la cui definizione si è riportata in
+fig.~\ref{fig:signalfd_siginfo}) a seconda sia della dimensione del buffer che
+del numero di segnali pendenti. Per questo motivo il buffer deve essere almeno
+di dimensione pari a quella di \struct{signalfd\_siginfo}, qualora sia di
+dimensione maggiore potranno essere letti in unica soluzione i dati relativi
+ad eventuali più segnali pendenti, fino al numero massimo di strutture
+\struct{signalfd\_siginfo} che possono rientrare nel buffer.
+
+Il contenuto di \struct{signalfd\_siginfo} ricalca da vicino quella della
+analoga struttura \struct{siginfo\_t} (illustrata in
+fig.~\ref{fig:sig_siginfo_t}) usata dall'interfaccia ordinaria dei segnali, e
+restituisce dati simili. Come per \struct{siginfo\_t} i campi che vengono
+avvalorati dipendono dal tipo di segnale e ricalcano i valori che abbiamo già
+illustrato in sez.~\ref{sec:sig_sigaction}.\footnote{si tenga presente però
+ 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}.}
+
+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
+sez.~\ref{sec:sig_timer_adv}, la scadenza di un timer potrà essere letta da un
+file descriptor, senza dover ricorrere ad altri meccanismi come un segnale o
+un \textit{thread} di notifica. 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 di un segnale
+qualunque.\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.}
+
+Le funzioni di questa interfaccia riprendono da vicino
+
+
% 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
% LocalWords: only ETXTBSY DENYWRITE ENODEV filesystem EPERM EXEC noexec table
% 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
+% LocalWords: GROWSDOWN ANON POPULATE prefaulting SIGBUS fifo VME fork old SFD
% LocalWords: exec atime ctime mtime mprotect addr EACCESS 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: SEQUENTIAL NOREUSE WILLNEED DONTNEED streaming fallocate EFBIG
% LocalWords: POLLRDHUP half close pwait Gb madvise MADV ahead REMOVE tmpfs
% LocalWords: DONTFORK DOFORK shmfs preadv pwritev syscall linux loff head XFS
-% LocalWords: MERGEABLE EOVERFLOW prealloca hole FALLOC KEEP stat fstat
-% LocalWords: conditions sigwait
+% 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
%%% Local Variables: