X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=fileadv.tex;h=16e7a7f820ccc0b123623ee9b5fe5c839d7c4a78;hp=c38a396892f79c152fa679bf374c1e40b458cc35;hb=4cbeb0e4fa1d31da798c8e68108eb6785586ab34;hpb=a59f46f457248921d34ba7175697a129469d6d90 diff --git a/fileadv.tex b/fileadv.tex index c38a396..16e7a7f 100644 --- a/fileadv.tex +++ b/fileadv.tex @@ -8,6 +8,7 @@ %% 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 @@ -189,11 +190,12 @@ riportate in tab.~\ref{tab:file_flock_operation}. \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 @@ -232,7 +234,7 @@ inode\index{inode},\footnote{in particolare, come accennato in 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 @@ -331,9 +333,9 @@ che un \textit{file lock} fa sempre riferimento ad una regione, per cui si 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 @@ -431,7 +433,7 @@ chiamate) per cui si deve sempre verificare il codice di ritorno di 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} @@ -469,8 +471,8 @@ 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. -\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} @@ -533,9 +535,9 @@ preoccuparsi di accorpare o dividere le voci nella lista dei \textit{file 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 @@ -547,7 +549,7 @@ Per fare qualche esempio sul \textit{file locking} si è scritto un programma ch 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 @@ -1171,13 +1173,14 @@ funzione. 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 @@ -1262,7 +1265,7 @@ strutture \struct{pollfd} a meno di non voler cambiare qualche condizione. \begin{figure}[!htb] \footnotesize \centering - \begin{minipage}[c]{15cm} + \begin{minipage}[c]{\textwidth} \includestruct{listati/pollfd.h} \end{minipage} \normalsize @@ -1623,13 +1626,13 @@ indicare quale tipo di evento relativo ad \param{fd} si vuole che sia tenuto 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 @@ -1648,7 +1651,7 @@ definizione è riportata in fig.~\ref{fig:epoll_event}. 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 @@ -1907,7 +1910,7 @@ segnale o si aspetta che un file descriptor sia accessibile e nessuna delle 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à @@ -1972,8 +1975,8 @@ 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 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. @@ -2074,7 +2077,7 @@ successivo con \func{fcntl}. \begin{figure}[!htb] \footnotesize \centering - \begin{minipage}[c]{15cm} + \begin{minipage}[c]{\textwidth} \includestruct{listati/signalfd_siginfo.h} \end{minipage} \normalsize @@ -2102,28 +2105,198 @@ 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}.} +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 \texttt{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 \const{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 \const{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 è +\var{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 delle +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 non è supportata e non deve essere - usata.} La prima funzione prevista, quella che consente di creare un -\textit{timer}, è \funcd{timerfd\_create}, il cui prototipo è: + 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)} @@ -2184,7 +2357,7 @@ 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 exex} con + 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 @@ -2192,11 +2365,11 @@ 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 \funcd{timerfd\_create} per poterlo utilizzare +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 su usa la funzione omologa di +periodicità di ripetizione, per farlo si usa la funzione omologa di \func{timer\_settime} per la nuova interfaccia; questa è -\func{timerfd\_settime}; il suo prototipo è: +\funcd{timerfd\_settime} ed il suo prototipo è: \begin{prototype}{sys/timerfd.h} {int timerfd\_settime(int fd, int flags, const struct itimerspec *new\_value, @@ -2208,37 +2381,65 @@ periodicità di ripetizione, per farlo su usa la funzione omologa di successo o $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno dei valori: \begin{errlist} - \item[\errcode{EINVAL}] l'argomento \param{clockid} non è - \const{CLOCK\_MONOTONIC} o \const{CLOCK\_REALTIME}, o - l'argomento \param{flag} non è valido, o è diverso da zero per kernel - precedenti il 2.6.27. - \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 - descriptor. + \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} - ed inoltre \errval{EMFILE} e \errval{ENFILE}. } \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)} + Crea un timer associato ad un file descriptor per la notifica. - -.\footnote{si otterranno in entrambi i casi gli stessi - risultati, il file descriptor risulterà pronto in lettura e in entrambi i - processi si potranno leggere il numero di scadenze.} + \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} -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. +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 +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 @@ -2254,31 +2455,6 @@ ottenute leggendo in maniera ordinaria il file descriptor con una \func{read}, % http://lwn.net/Articles/267331/ -\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} - - - \section{L'accesso \textsl{asincrono} ai file} \label{sec:file_asyncronous_access} @@ -2318,7 +2494,7 @@ Quello che succede è che per tutti i file posti in questa modalità\footnote{si 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 @@ -2360,7 +2536,7 @@ sez.~\ref{sec:sig_sigaction}). 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 @@ -2378,7 +2554,7 @@ la coda. 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 @@ -2406,7 +2582,7 @@ classico non prevedeva alcun meccanismo per cui un processo possa essere \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. @@ -2447,9 +2623,9 @@ 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 @@ -2562,7 +2738,7 @@ un'altra interfaccia,\footnote{si ricordi che anche questa è una interfaccia 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 @@ -2913,7 +3089,7 @@ modalità non bloccante) fino all'arrivo di almeno un evento. \begin{figure}[!htb] \footnotesize \centering - \begin{minipage}[c]{15cm} + \begin{minipage}[c]{\textwidth} \includestruct{listati/inotify_event.h} \end{minipage} \normalsize @@ -3010,7 +3186,7 @@ funzioni di ausilio è riportato in fig.~\ref{fig:inotify_monitor_example}. \begin{figure}[!htbp] \footnotesize \centering - \begin{minipage}[c]{15cm} + \begin{minipage}[c]{\codesamplewidth} \includecodesample{listati/inotify_monitor.c} \end{minipage} \normalsize @@ -3136,6 +3312,8 @@ raggruppati in un solo evento. \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 @@ -3173,7 +3351,7 @@ 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 @@ -3253,10 +3431,10 @@ Si tenga inoltre presente che deallocare la memoria indirizzata da 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 @@ -3608,7 +3786,7 @@ Il valore dell'argomento \param{prot} indica la protezione\footnote{come 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. @@ -3664,7 +3842,7 @@ tab.~\ref{tab:file_mmap_flag}. 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}. @@ -3711,7 +3889,7 @@ piuttosto complessi, essi si possono comprendere solo tenendo presente che 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. @@ -3738,7 +3916,7 @@ verrà il file sarà mappato su un segmento di memoria che si estende fino al 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 @@ -3752,8 +3930,8 @@ quella della mappatura in memoria. 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 @@ -4287,7 +4465,7 @@ essere letti o scritti ed in che quantità. Il primo campo della struttura, \begin{figure}[!htb] \footnotesize \centering - \begin{minipage}[c]{15cm} + \begin{minipage}[c]{\textwidth} \includestruct{listati/iovec.h} \end{minipage} \normalsize @@ -4360,7 +4538,7 @@ sez.~\ref{sec:file_read} e \ref{sec:file_write}); le due funzioni sono 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} } @@ -4564,7 +4742,7 @@ definito la macro \macro{\_GNU\_SOURCE},\footnote{si ricordi che questa \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} @@ -4698,9 +4876,9 @@ file destinazione. Il passo successivo è aprire il file sorgente (\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 @@ -4873,7 +5051,7 @@ allegati alla guida. \begin{figure}[!htbp] \footnotesize \centering - \begin{minipage}[c]{15cm} + \begin{minipage}[c]{\codesamplewidth} \includecodesample{listati/tee.c} \end{minipage} \normalsize @@ -4997,7 +5175,7 @@ nelle operazioni successive. 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 @@ -5179,7 +5357,7 @@ Trattandosi di una funzione di servizio, ed ovviamente disponibile 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} @@ -5231,11 +5409,6 @@ livello di kernel. -%\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/ @@ -5289,11 +5462,13 @@ livello di kernel. % 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: