- \const{IN\_IGNORED} & L'osservatore è stato rimosso, sia in maniera
- esplicita con l'uso di \func{inotify\_rm\_watch},
- che in maniera implicita per la rimozione
- dell'oggetto osservato o per lo smontaggio del
- filesystem su cui questo si trova.\\
- \const{IN\_ISDIR} & L'evento avvenuto fa riferimento ad una directory
- (consente così di distinguere, quando si pone
- sotto osservazione una directory, fra gli eventi
- relativi ad essa e quelli relativi ai file che
- essa contiene).\\
- \const{IN\_Q\_OVERFLOW}& Si sono eccedute le dimensioni della coda degli
- eventi (\textit{overflow} della coda); in questo
- caso il valore di \var{wd} è $-1$.\footnotemark\\
- \const{IN\_UNMOUNT} & Il filesystem contenente l'oggetto posto sotto
- osservazione è stato smontato.\\
- \hline
- \end{tabular}
- \caption{Le costanti che identificano i bit aggiuntivi usati nella maschera
- binaria del campo \var{mask} di \struct{inotify\_event}.}
- \label{tab:inotify_read_event_flag}
-\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
- 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
- \const{IN\_Q\_OVERFLOW}.}
-
-Il campo \var{cookie} contiene invece un intero univoco che permette di
-identificare eventi correlati (per i quali avrà lo stesso valore), al momento
-viene utilizzato soltanto per rilevare lo spostamento di un file, consentendo
-così all'applicazione di collegare la corrispondente coppia di eventi
-\const{IN\_MOVED\_TO} e \const{IN\_MOVED\_FROM}.
-
-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}.
-
-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
-directory. Il programma si chiama \texttt{inotify\_monitor.c} ed il codice
-completo è disponibile coi sorgenti allegati alla guida, il corpo principale
-del programma, che non contiene la sezione di gestione delle opzioni e le
-funzioni di ausilio è riportato in fig.~\ref{fig:inotify_monitor_example}.
-
-\begin{figure}[!htbp]
- \footnotesize \centering
- \begin{minipage}[c]{15cm}
- \includecodesample{listati/inotify_monitor.c}
- \end{minipage}
- \normalsize
- \caption{Esempio di codice che usa l'interfaccia di \textit{inotify}.}
- \label{fig:inotify_monitor_example}
-\end{figure}
-
-Una volta completata la scansione delle opzioni il corpo principale del
-programma inizia controllando (\texttt{\small 11--15}) che sia rimasto almeno
-un argomento che indichi quale file o directory mettere sotto osservazione (e
-qualora questo non avvenga esce stampando la pagina di aiuto); dopo di che
-passa (\texttt{\small 16--20}) all'inizializzazione di \textit{inotify}
-ottenendo con \func{inotify\_init} il relativo file descriptor (oppure usce in
-caso di errore).
-
-Il passo successivo è aggiungere (\texttt{\small 21--30}) alla coda di
-notifica gli opportuni osservatori per ciascuno dei file o directory indicati
-all'invocazione del comando; questo viene fatto eseguendo un ciclo
-(\texttt{\small 22--29}) fintanto che la variabile \var{i}, inizializzata a
-zero (\texttt{\small 21}) all'inizio del ciclo, è minore del numero totale di
-argomenti rimasti. All'interno del ciclo si invoca (\texttt{\small 23})
-\func{inotify\_add\_watch} per ciascuno degli argomenti, usando la maschera
-degli eventi data dalla variabile \var{mask} (il cui valore viene impostato
-nella scansione delle opzioni), in caso di errore si esce dal programma
-altrimenti si incrementa l'indice (\texttt{\small 29}).
-
-Completa l'inizializzazione di \textit{inotify} inizia il ciclo principale
-(\texttt{\small 32--56}) del programma, nel quale si resta in attesa degli
-eventi che si intendono osservare. Questo viene fatto eseguendo all'inizio del
-ciclo (\texttt{\small 33}) una \func{read} che si bloccherà fintanto che non
-si saranno verificati eventi.
-
-Dato che l'interfaccia di \textit{inotify} può riportare anche più eventi in
-una sola lettura, si è avuto cura di passare alla \func{read} un buffer di
-dimensioni adeguate, inizializzato in (\texttt{\small 7}) ad un valore di
-approssimativamente 512 eventi.\footnote{si ricordi che la quantità di dati
- restituita da \textit{inotify} è variabile a causa della diversa lunghezza
- del nome del file restituito insieme a \struct{inotify\_event}.} In caso di
-errore di lettura (\texttt{\small 35--40}) il programma esce con un messaggio
-di errore (\texttt{\small 37--39}), a meno che non si tratti di una
-interruzione della system call, nel qual caso (\texttt{\small 36}) si ripete la
-lettura.
-
-Se la lettura è andata a buon fine invece si esegue un ciclo (\texttt{\small
- 43--52}) per leggere tutti gli eventi restituiti, al solito si inizializza
-l'indice \var{i} a zero (\texttt{\small 42}) e si ripetono le operazioni
-(\texttt{\small 43}) fintanto che esso non supera il numero di byte restituiti
-in lettura. Per ciascun evento all'interno del ciclo si assegna\footnote{si
- noti come si sia eseguito un opportuno \textit{casting} del puntatore.} alla
-variabile \var{event} l'indirizzo nel buffer della corrispondente struttura
-\struct{inotify\_event} (\texttt{\small 44}), e poi si stampano il numero di
-\textit{watch descriptor} (\texttt{\small 45}) ed il file a cui questo fa
-riferimento (\texttt{\small 46}), ricavato dagli argomenti passati a riga di
-comando sfruttando il fatto che i \textit{watch descriptor} vengono assegnati
-in ordine progressivo crescente a partire da 1.
-
-Qualora sia presente il riferimento ad un nome di file associato all'evento lo
-si stampa (\texttt{\small 47--49}); si noti come in questo caso si sia
-utilizzato il valore del campo \var{event->len} e non al fatto che
-\var{event->name} riporti o meno un puntatore nullo.\footnote{l'interfaccia
- infatti, qualora il nome non sia presente, non avvalora il campo
- \var{event->name}, che si troverà a contenere quello che era precedentemente
- presente nella rispettiva locazione di memoria, nel caso più comune il
- puntatore al nome di un file osservato in precedenza.} Si utilizza poi
-(\texttt{\small 50}) la funzione \code{printevent}, che interpreta il valore
-del campo \var{event->mask} per stampare il tipo di eventi
-accaduti.\footnote{per il relativo codice, che non riportiamo in quanto non
- essenziale alla comprensione dell'esempio, si possono utilizzare direttamente
- i sorgenti allegati alla guida.} Infine (\texttt{\small 51}) si provvede ad
-aggiornare l'indice \var{i} per farlo puntare all'evento successivo.
-
-Se adesso usiamo il programma per mettere sotto osservazione una directory, e
-da un altro terminale eseguiamo il comando \texttt{ls} otterremo qualcosa del
-tipo di:
-\begin{verbatim}
-piccardi@gethen:~/gapil/sources$ ./inotify_monitor -a /home/piccardi/gapil/
-Watch descriptor 1
-Observed event on /home/piccardi/gapil/
-IN_OPEN,
-Watch descriptor 1
-Observed event on /home/piccardi/gapil/
-IN_CLOSE_NOWRITE,
-\end{verbatim}
-
-I lettori più accorti si saranno resi conto che nel ciclo di lettura degli
-eventi appena illustrato non viene trattato il caso particolare in cui la
-funzione \func{read} restituisce in \var{nread} un valore nullo. Lo si è fatto
-perché con \textit{inotify} il ritorno di una \func{read} con un valore nullo
-avviene soltanto, come forma di avviso, quando si sia eseguita la funzione
-specificando un buffer di dimensione insufficiente a contenere anche un solo
-evento. Nel nostro caso le dimensioni erano senz'altro sufficienti, per cui
-tale evenienza non si verificherà mai.
-
-Ci si potrà però chiedere cosa succede se il buffer è sufficiente per un
-evento, ma non per tutti gli eventi verificatisi. Come si potrà notare nel
-codice illustrato in precedenza non si è presa nessuna precauzione per
-verificare che non ci fossero stati troncamenti dei dati. Anche in questo caso
-il comportamento scelto è corretto, perché l'interfaccia di \textit{inotify}
-garantisce automaticamente, anche quando ne sono presenti in numero maggiore,
-di restituire soltanto il numero di eventi che possono rientrare completamente
-nelle dimensioni del buffer specificato.\footnote{si avrà cioè, facendo
- riferimento sempre al codice di fig.~\ref{fig:inotify_monitor_example}, che
- \var{read} sarà in genere minore delle dimensioni di \var{buffer} ed uguale
- soltanto qualora gli eventi corrispondano esattamente alle dimensioni di
- quest'ultimo.} Se gli eventi sono di più saranno restituiti solo quelli che
-entrano interamente nel buffer e gli altri saranno restituiti alla successiva
-chiamata di \func{read}.
-
-Infine un'ultima caratteristica dell'interfaccia di \textit{inotify} è che gli
-eventi restituiti nella lettura formano una sequenza ordinata, è cioè
-garantito che se si esegue uno spostamento di un file gli eventi vengano
-generati nella sequenza corretta. L'interfaccia garantisce anche che se si
-verificano più eventi consecutivi identici (vale a dire con gli stessi valori
-dei campi \var{wd}, \var{mask}, \var{cookie}, e \var{name}) questi vengono
-raggruppati in un solo evento.
-
-\index{file!inotify|)}
-
-
-\subsection{L'interfaccia POSIX per l'I/O asincrono}
-\label{sec:file_asyncronous_io}
-
-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
-di I/O non attendono il completamento delle operazioni prima di ritornare,
-così che il processo non viene bloccato. In questo modo diventa ad esempio
-possibile effettuare una richiesta preventiva di dati, in modo da poter
-effettuare in contemporanea le operazioni di calcolo e quelle di I/O.
-
-Benché la modalità di apertura asincrona di un file possa risultare utile in
-varie occasioni (in particolar modo con i socket e gli altri file per i quali
-le funzioni di I/O sono \index{system~call~lente} system call lente), essa è
-comunque limitata alla notifica della disponibilità del file descriptor per le
-operazioni di I/O, e non ad uno svolgimento asincrono delle medesime. Lo
-standard POSIX.1b definisce una interfaccia apposita per l'I/O asincrono vero
-e proprio, che prevede un insieme di funzioni dedicate per la lettura e la
-scrittura dei file, completamente separate rispetto a quelle usate
-normalmente.
-
-In generale questa interfaccia è completamente astratta e può essere
-implementata sia direttamente nel kernel, che in user space attraverso l'uso
-di \itindex{thread} \textit{thread}. Per le versioni del kernel meno recenti
-esiste una implementazione di questa interfaccia fornita delle \acr{glibc},
-che è realizzata completamente in user space, ed è accessibile linkando i
-programmi con la libreria \file{librt}. Nelle versioni più recenti (a partire
-dalla 2.5.32) è stato introdotto direttamente nel kernel un nuovo layer per
-l'I/O asincrono.
-
-Lo standard prevede che tutte le operazioni di I/O asincrono siano controllate
-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 è
-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}
- \includestruct{listati/aiocb.h}
- \end{minipage}
- \normalsize
- \caption{La struttura \structd{aiocb}, usata per il controllo dell'I/O
- asincrono.}
- \label{fig:file_aiocb}
-\end{figure}
-
-Le operazioni di I/O asincrono possono essere effettuate solo su un file già
-aperto; il file deve inoltre supportare la funzione \func{lseek}, pertanto
-terminali e pipe sono esclusi. Non c'è limite al numero di operazioni
-contemporanee effettuabili su un singolo file. Ogni operazione deve
-inizializzare opportunamente un \textit{control block}. Il file descriptor su
-cui operare deve essere specificato tramite il campo \var{aio\_fildes}; dato
-che più operazioni possono essere eseguita in maniera asincrona, il concetto
-di posizione corrente sul file viene a mancare; pertanto si deve sempre
-specificare nel campo \var{aio\_offset} la posizione sul file da cui i dati
-saranno letti o scritti. Nel campo \var{aio\_buf} deve essere specificato
-l'indirizzo del buffer usato per l'I/O, ed in \var{aio\_nbytes} la lunghezza
-del blocco di dati da trasferire.
-
-Il campo \var{aio\_reqprio} permette di impostare la priorità delle operazioni
-di I/O.\footnote{in generale perché ciò sia possibile occorre che la
- piattaforma supporti questa caratteristica, questo viene indicato definendo
- le macro \macro{\_POSIX\_PRIORITIZED\_IO}, e
- \macro{\_POSIX\_PRIORITY\_SCHEDULING}.} La priorità viene impostata a
-partire da quella del processo chiamante (vedi sez.~\ref{sec:proc_priority}),
-cui viene sottratto il valore di questo campo. Il campo
-\var{aio\_lio\_opcode} è usato solo dalla funzione \func{lio\_listio}, che,
-come vedremo, permette di eseguire con una sola chiamata una serie di
-operazioni, usando un vettore di \textit{control block}. Tramite questo campo
-si specifica quale è la natura di ciascuna di esse.
-
-\begin{figure}[!htb]
- \footnotesize \centering
- \begin{minipage}[c]{15cm}
- \includestruct{listati/sigevent.h}
- \end{minipage}
- \normalsize
- \caption{La struttura \structd{sigevent}, usata per specificare le modalità
- di notifica degli eventi relativi alle operazioni di I/O asincrono.}
- \label{fig:file_sigevent}
-\end{figure}
-
-Infine il campo \var{aio\_sigevent} è una struttura di tipo \struct{sigevent}
-che serve a specificare il modo in cui si vuole che venga effettuata la
-notifica del completamento delle operazioni richieste. La struttura è
-riportata in fig.~\ref{fig:file_sigevent}; il campo \var{sigev\_notify} è
-quello che indica le modalità della notifica, esso può assumere i tre valori:
-\begin{basedescript}{\desclabelwidth{2.6cm}}
-\item[\const{SIGEV\_NONE}] Non viene inviata nessuna notifica.
-\item[\const{SIGEV\_SIGNAL}] La notifica viene effettuata inviando al processo
- chiamante il segnale specificato da \var{sigev\_signo}; se il gestore di
- questo è stato installato con \const{SA\_SIGINFO} gli verrà restituito il
- valore di \var{sigev\_value} (la cui definizione è in
- fig.~\ref{fig:sig_sigval}) come valore del campo \var{si\_value} di
- \struct{siginfo\_t}.
-\item[\const{SIGEV\_THREAD}] La notifica viene effettuata creando un nuovo
- \itindex{thread} \textit{thread} che esegue la funzione specificata da
- \var{sigev\_notify\_function} con argomento \var{sigev\_value}, e con gli
- attributi specificati da \var{sigev\_notify\_attribute}.
-\end{basedescript}
-
-Le due funzioni base dell'interfaccia per l'I/O asincrono sono
-\funcd{aio\_read} ed \funcd{aio\_write}. Esse permettono di richiedere una
-lettura od una scrittura asincrona di dati, usando la struttura \struct{aiocb}
-appena descritta; i rispettivi prototipi sono:
-\begin{functions}
- \headdecl{aio.h}
-
- \funcdecl{int aio\_read(struct aiocb *aiocbp)}
- Richiede una lettura asincrona secondo quanto specificato con \param{aiocbp}.
-
- \funcdecl{int aio\_write(struct aiocb *aiocbp)}
- Richiede una scrittura asincrona secondo quanto specificato con
- \param{aiocbp}.
-
- \bodydesc{Le funzioni restituiscono 0 in caso di successo, e -1 in caso di
- errore, nel qual caso \var{errno} assumerà uno dei valori:
- \begin{errlist}
- \item[\errcode{EBADF}] si è specificato un file descriptor sbagliato.
- \item[\errcode{ENOSYS}] la funzione non è implementata.
- \item[\errcode{EINVAL}] si è specificato un valore non valido per i campi
- \var{aio\_offset} o \var{aio\_reqprio} di \param{aiocbp}.
- \item[\errcode{EAGAIN}] la coda delle richieste è momentaneamente piena.
- \end{errlist}
-}
-\end{functions}