\texttt{man select\_tut}) per cui la possibilità di \itindex{race~condition}
\textit{race condition} permaneva; in tale situazione si può ricorrere ad
una soluzione alternativa, chiamata \itindex{self-pipe trick}
- \textit{self-pipe trick}, che consiste nell'aprire una pipe (vedi
+ \textit{self-pipe trick}, che consiste nell'aprire una \textit{pipe} (vedi
sez.~\ref{sec:ipc_pipes}) ed usare \func{select} sul capo in lettura della
stessa; si può indicare l'arrivo di un segnale scrivendo sul capo in
scrittura all'interno del gestore dello stesso; in questo modo anche se il
segnale va perso prima della chiamata di \func{select} questa lo riconoscerà
- comunque dalla presenza di dati sulla pipe.} ribloccandolo non appena essa
-ritorna, così che il precedente codice potrebbe essere riscritto nel seguente
-modo:
+ comunque dalla presenza di dati sulla \textit{pipe}.} ribloccandolo non
+appena essa ritorna, così che il precedente codice potrebbe essere riscritto
+nel seguente modo:
\includecodesnip{listati/pselect_norace.c}
in questo caso utilizzando \var{oldmask} durante l'esecuzione di
\func{pselect} la ricezione del segnale sarà abilitata, ed in caso di
\begin{funcproto}{
\fhead{sys/epoll.h}
\fdecl{int epoll\_pwait(int epfd, struct epoll\_event * events, int maxevents,
- int timeout, const sigset\_t *sigmask)}
+ int timeout, \\
+\phantom{int epoll\_pwait(}const sigset\_t *sigmask)}
\fdesc{Attende che uno dei file descriptor osservati sia pronto, mascherando
i segnali.} }
{La funzione ritorna il numero di file descriptor pronti in caso di successo e
$-1$ per un errore, nel qual caso \var{errno} assumerà uno dei valori già
visti con \funcd{epoll\_wait}.
-
+
}
\end{funcproto}
\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}.
+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
(\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.
+\textit{fifo}.
Il primo passo (\texttt{\small 19-20}) è la creazione di un file descriptor
\texttt{epfd} di \itindex{epoll} \textit{epoll} con \func{epoll\_create} che è
descriptor pronto in lettura con \func{epoll\_wait} (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.}
+stati scritti dati sulla \textit{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
(\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. Si ricordi infatti come
-sia la fifo che il file descriptor per i segnali siano stati aperti in
+sia la \textit{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.
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 restituisce un errore di \errcode{EAGAIN}
-(\texttt{\small 29-35}). 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.
+cui ci siano dati pronti in lettura sulla \textit{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 restituisce un errore di
+\errcode{EAGAIN} (\texttt{\small 29-35}). 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 \textit{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
\errval{EAGAIN}.
-% TODO trattare qui eventfd introdotte con il 2.6.22
+% TODO trattare qui eventfd introdotto con il 2.6.22
\section{L'accesso \textsl{asincrono} ai file}
notifica asincrona delle variazione dello stato del file descriptor aperto in
questo modo.
-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,
-\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_ioctl}, selezionare con il comando
-\const{F\_SETOWN} di \func{fcntl} quale processo o quale gruppo di processi
-dovrà ricevere il segnale. In questo modo diventa possibile effettuare le
-operazioni di I/O in risposta alla ricezione del segnale, e non ci sarà più la
-necessità di restare bloccati in attesa della disponibilità di accesso ai
-file.
+Quello che succede è che per tutti i file posti in questa modalità il sistema
+genera un apposito segnale, \signal{SIGIO}, tutte le volte che diventa
+possibile leggere o scrivere dal file descriptor; 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, per
+\textit{fifo} e \textit{pipe}. Inoltre è possibile, come illustrato in
+sez.~\ref{sec:file_fcntl_ioctl}, selezionare con il comando \const{F\_SETOWN}
+di \func{fcntl} quale processo o quale gruppo di processi dovrà ricevere il
+segnale. In questo modo diventa possibile effettuare le operazioni di I/O in
+risposta alla ricezione del segnale, e non ci sarà più la necessità di restare
+bloccati in attesa della disponibilità di accesso ai file.
% TODO: per i thread l'uso di F_SETOWN ha un significato diverso
descriptor attivi contemporaneamente, più segnali emessi nello stesso momento
verrebbero notificati una volta sola.
-Linux però supporta le estensioni POSIX.1b dei segnali real-time, che vengono
-accodati e che permettono di riconoscere il file descriptor che li ha emessi.
-In questo caso infatti si può fare ricorso alle informazioni aggiuntive
-restituite attraverso la struttura \struct{siginfo\_t}, utilizzando la forma
-estesa \var{sa\_sigaction} del gestore installata con il flag
+Linux però supporta le estensioni POSIX.1b dei segnali \textit{real-time}, che
+vengono accodati e che permettono di riconoscere il file descriptor che li ha
+emessi. In questo caso infatti si può fare ricorso alle informazioni
+aggiuntive restituite attraverso la struttura \struct{siginfo\_t}, utilizzando
+la forma estesa \var{sa\_sigaction} del gestore installata con il flag
\const{SA\_SIGINFO} (si riveda quanto illustrato in
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 è \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
- generato a causa di attività di I/O.} di \struct{siginfo\_t}, troverà nel
-campo \var{si\_fd} il valore del file descriptor che ha generato il segnale.
-
-Un secondo vantaggio dell'uso dei segnali real-time è che essendo questi
-ultimi dotati di una coda di consegna ogni segnale sarà associato ad uno solo
-file descriptor; inoltre sarà possibile stabilire delle priorità nella
-risposta a seconda del segnale usato, dato che i segnali real-time supportano
-anche questa funzionalità. In questo modo si può identificare immediatamente
-un file su cui l'accesso è diventato possibile evitando completamente l'uso di
-funzioni come \func{poll} e \func{select}, almeno fintanto che non si satura
-la coda.
+Per far questo però occorre utilizzare le funzionalità dei segnali
+\textit{real-time} (vedi sez.~\ref{sec:sig_real_time}) impostando
+esplicitamente con il comando \const{F\_SETSIG} di \func{fcntl} un segnale
+\textit{real-time} da inviare in caso di 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} di \struct{siginfo\_t},
+troverà nel campo \var{si\_fd} il valore del file descriptor che ha generato
+il segnale. Si noti che il valore di\var{si\_code} resta \const{SI\_SIGIO}
+qualunque sia il segnale che si è associato all'I/O, in quanto indica che il
+segnale è stato generato a causa di attività di I/O.
+
+Un secondo vantaggio dell'uso dei segnali \textit{real-time} è che essendo
+questi ultimi dotati di una coda di consegna ogni segnale sarà associato ad
+uno solo file descriptor; inoltre sarà possibile stabilire delle priorità
+nella risposta a seconda del segnale usato, dato che i segnali
+\textit{real-time} supportano anche questa funzionalità. In questo modo si può
+identificare immediatamente un file su cui l'accesso è diventato possibile
+evitando completamente l'uso di funzioni come \func{poll} e \func{select},
+almeno fintanto che non si satura 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 \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
- \sysctlfile{kernel/rtsig-max} allo stesso valore del contenuto di
- \sysctlfile{fs/file-max}.}
+più assicurare il comportamento corretto per un segnale \textit{real-time},
+invierà al 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 \textit{real-time}
+ad una dimensione identica al valore massimo del numero di file descriptor
+utilizzabili, vale a dire impostare il contenuto di
+\sysctlfile{kernel/rtsig-max} allo stesso valore del contenuto di
+\sysctlfile{fs/file-max}.
% TODO fare esempio che usa O_ASYNC
\label{sec:file_asyncronous_lease}
Una delle domande più frequenti nella programmazione in ambiente unix-like è
-quella di come fare a sapere quando un file viene modificato. La
-risposta\footnote{o meglio la non risposta, tanto che questa nelle Unix FAQ
- \cite{UnixFAQ} viene anche chiamata una \textit{Frequently Unanswered
- Question}.} è che nell'architettura classica di Unix questo non è
-possibile. Al contrario di altri sistemi operativi infatti un kernel unix-like
-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
- \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.
+quella di come fare a sapere quando un file viene modificato. La risposta, o
+meglio la non risposta, tanto che questa nelle Unix FAQ \cite{UnixFAQ} viene
+anche chiamata una \textit{Frequently Unanswered Question}, è che
+nell'architettura classica di Unix questo non è possibile. Al contrario di
+altri sistemi operativi infatti un kernel unix-like 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 se il loro file di configurazione è stato modificato, perché possano
+rileggerlo e riconoscere le modifiche; in genere questo vien fatto inviandogli
+un segnale di \signal{SIGHUP} che, per una convenzione adottata dalla gran
+parte di detti programmi, causa la rilettura della configurazione.
Questa scelta è stata fatta perché provvedere un simile meccanismo a livello
generico per qualunque file comporterebbe un notevole aumento di complessità
Visto però il crescente interesse nei confronti di una funzionalità di questo
tipo, che è molto richiesta specialmente nello sviluppo dei programmi ad
-interfaccia grafica, quando si deve presentare all'utente lo stato del
+interfaccia grafica quando si deve presentare all'utente lo stato del
filesystem, sono state successivamente introdotte delle estensioni che
permettessero la creazione di meccanismi di notifica più efficienti dell'unica
soluzione disponibile con l'interfaccia tradizionale, che è quella del
holder}, di essere notificato quando un altro processo, chiamato a sua volta
\textit{lease breaker}, cerca di eseguire una \func{open} o una
\func{truncate} sul file del quale l'\textit{holder} detiene il
-\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 \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 \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
-valore del file descriptor del file sul quale è stato compiuto l'accesso; in
-questo modo un processo può mantenere anche più di un \textit{file 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 \signal{SIGIO}, ma questo segnale può essere
+modificato usando il comando \const{F\_SETSIG} di \func{fcntl} (anche in
+questo caso si può rispecificare lo stesso \signal{SIGIO}).
+
+Se si è fatto questo (ed in genere è opportuno farlo, come in precedenza, per
+utilizzare segnali \textit{real-time}) e se inoltre si è installato il gestore
+del segnale con \const{SA\_SIGINFO} si riceverà nel campo \var{si\_fd} della
+struttura \struct{siginfo\_t} il valore del file descriptor del file sul quale
+è stato compiuto l'accesso; in questo modo un processo può mantenere anche più
+di un \textit{file lease}.
Esistono due tipi di \textit{file lease}: di lettura (\textit{read lease}) e
di scrittura (\textit{write lease}). Nel primo caso la notifica avviene quando
Si tenga presente che un processo può mantenere solo un tipo di \textit{lease}
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
-\ids{UID} corrispondente a quello del processo. Soltanto un processo con
+(\textit{pipe} e dispositivi sono quindi esclusi). Inoltre un processo non
+privilegiato può ottenere un \textit{lease} soltanto per un file appartenente
+ad un \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.
esegue una \func{truncate} o una \func{open} che confligge con
esso,\footnote{in realtà \func{truncate} confligge sempre, mentre \func{open},
se eseguita in sola lettura, non confligge se si tratta di un \textit{read
- lease}.} la funzione si blocca\footnote{a meno di non avere aperto il file
- con \const{O\_NONBLOCK}, nel qual caso \func{open} fallirebbe con un errore
- di \errcode{EWOULDBLOCK}.} e viene eseguita la notifica al \textit{lease
- holder}, così che questo possa completare le sue operazioni sul file e
-rilasciare il \textit{lease}. In sostanza con un \textit{read lease} si
-rilevano i tentativi di accedere al file per modificarne i dati da parte di un
-altro processo, mentre con un \textit{write lease} si rilevano anche i
-tentativi di accesso in lettura. Si noti comunque che le operazioni di
-notifica avvengono solo in fase di apertura del file e non sulle singole
-operazioni di lettura e scrittura.
+ lease}.} la funzione si blocca (a meno di non avere aperto il file con
+\const{O\_NONBLOCK}, nel qual caso \func{open} fallirebbe con un errore di
+\errcode{EWOULDBLOCK}) e viene eseguita la notifica al \textit{lease holder},
+così che questo possa completare le sue operazioni sul file e rilasciare il
+\textit{lease}. In sostanza con un \textit{read lease} si rilevano i
+tentativi di accedere al file per modificarne i dati da parte di un altro
+processo, mentre con un \textit{write lease} si rilevano anche i tentativi di
+accesso in lettura. Si noti comunque che le operazioni di notifica avvengono
+solo in fase di apertura del file e non sulle singole operazioni di lettura e
+scrittura.
L'utilizzo dei \textit{file lease} consente al \textit{lease holder} di
assicurare la consistenza di un file, a seconda dei due casi, prima che un
Se il \textit{lease holder} non provvede a rilasciare il \textit{lease} entro
il numero di secondi specificato dal parametro di sistema mantenuto in
-\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
-rilasciato o declassato (che questo sia fatto dal \textit{lease holder} o dal
-kernel è lo stesso) le chiamate a \func{open} o \func{truncate} eseguite dal
-\textit{lease breaker} rimaste bloccate proseguono automaticamente.
+\sysctlfile{fs/lease-break-time} sarà il kernel stesso a rimuoverlo o
+declassarlo automaticamente (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 rilasciato o
+declassato (che questo sia fatto dal \textit{lease holder} o dal kernel è lo
+stesso) le chiamate a \func{open} o \func{truncate} eseguite dal \textit{lease
+ breaker} rimaste bloccate proseguono automaticamente.
Benché possa risultare utile per sincronizzare l'accesso ad uno stesso file da
parte di più processi, l'uso dei \textit{file lease} non consente comunque di
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 \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
+può utilizzare un altro, e di nuovo, per le ragioni già esposte in precedenza,
+è opportuno che si utilizzino dei segnali \textit{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}.
\itindend{file~lease}
si devono scrivere programmi portabili), ed è basata sull'uso di una coda di
notifica degli eventi associata ad un singolo file descriptor, il che permette
di risolvere il principale problema di \itindex{dnotify} \textit{dnotify}. La
-coda viene creata attraverso la funzione \funcd{inotify\_init}, il cui
-prototipo è:
-\begin{prototype}{sys/inotify.h}
- {int inotify\_init(void)}
-
- Inizializza una istanza di \textit{inotify}.
-
- \bodydesc{La funzione restituisce un file descriptor in caso di successo, o
- $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno dei valori:
+coda viene creata attraverso la funzione di sistema \funcd{inotify\_init}, il
+cui prototipo è:
+
+\begin{funcproto}{
+\fhead{sys/inotify.h}
+\fdecl{int inotify\_init(void)}
+\fdesc{Inizializza una istanza di \textit{inotify}.}
+}
+
+{La funzione ritornaun 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{EMFILE}] si è raggiunto il numero massimo di istanze di
\textit{inotify} consentite all'utente.
l'istanza.
\end{errlist}
}
-\end{prototype}
+\end{funcproto}
La funzione non prende alcun argomento; inizializza una istanza di
\textit{inotify} e restituisce un file descriptor attraverso il quale verranno
-effettuate le operazioni di notifica;\footnote{per evitare abusi delle risorse
- 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
- \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
-directory reale, l'inconveniente di non poter smontare un filesystem i cui
-file sono tenuti sotto osservazione viene completamente
-eliminato.\footnote{anzi, una delle capacità dell'interfaccia di
- \textit{inotify} è proprio quella di notificare il fatto che il filesystem
- su cui si trova il file o la directory osservata è stato smontato.}
+effettuate le operazioni di notifica; 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. Per evitare abusi
+delle risorse 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
+\sysctlfile{fs/inotify/max\_user\_instances}.
+
+Dato che questo file descriptor non è associato a nessun file o directory
+reale, l'inconveniente di non poter smontare un filesystem i cui file sono
+tenuti sotto osservazione viene completamente eliminato; anzi, una delle
+capacità dell'interfaccia di \textit{inotify} è proprio quella di notificare
+il fatto che il filesystem su cui si trova il file o la directory osservata è
+stato smontato.
Inoltre trattandosi di un file descriptor a tutti gli effetti, esso potrà
essere utilizzato come argomento per le funzioni \func{select} e \func{poll} e
-con l'interfaccia di \textit{epoll};\footnote{ed a partire dal kernel 2.6.25 è
- stato introdotto anche il supporto per il \itindex{signal~driven~I/O}
- \texttt{signal-driven I/O} trattato in sez.~\ref{sec:signal_driven_io}.}
-siccome gli eventi vengono notificati come dati disponibili in lettura, dette
-funzioni ritorneranno tutte le volte che si avrà un evento di notifica. Così,
-invece di dover utilizzare i segnali,\footnote{considerati una pessima scelta
- dal punto di vista dell'interfaccia utente.} si potrà gestire l'osservazione
-degli eventi con una qualunque delle modalità di \textit{I/O multiplexing}
+con l'interfaccia di \textit{epoll}, ed a partire dal kernel 2.6.25 è stato
+introdotto anche il supporto per il \itindex{signal~driven~I/O}
+\texttt{signal-driven I/O}. Siccome gli eventi vengono notificati come dati
+disponibili in lettura, dette funzioni ritorneranno tutte le volte che si avrà
+un evento di notifica.
+
+Così, invece di dover utilizzare i segnali, considerati una pessima scelta dal
+punto di vista dell'interfaccia utente, si potrà gestire l'osservazione degli
+eventi con una qualunque delle modalità di \textit{I/O multiplexing}
illustrate in sez.~\ref{sec:file_multiplexing}. Qualora si voglia cessare
l'osservazione, sarà sufficiente chiudere il file descriptor e tutte le
-risorse allocate saranno automaticamente rilasciate.
-
-Infine l'interfaccia di \textit{inotify} consente di mettere sotto
-osservazione, oltre che una directory, anche singoli file. Una volta creata
-la coda di notifica si devono definire gli eventi da tenere sotto
-osservazione; questo viene fatto attraverso una \textsl{lista di osservazione}
-(o \textit{watch list}) che è associata alla coda. Per gestire la lista di
-osservazione l'interfaccia fornisce due funzioni, la prima di queste è
-\funcd{inotify\_add\_watch}, il cui prototipo è:
-\begin{prototype}{sys/inotify.h}
- {int inotify\_add\_watch(int fd, const char *pathname, uint32\_t mask)}
-
- Aggiunge un evento di osservazione alla lista di osservazione di \param{fd}.
-
- \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:
+risorse allocate saranno automaticamente rilasciate. Infine l'interfaccia di
+\textit{inotify} consente di mettere sotto osservazione, oltre che una
+directory, anche singoli file.
+
+Una volta creata la coda di notifica si devono definire gli eventi da tenere
+sotto osservazione; questo viene fatto attraverso una \textsl{lista di
+ osservazione} (o \textit{watch list}) che è associata alla coda. Per gestire
+la lista di osservazione l'interfaccia fornisce due funzioni di sistema, la
+prima di queste è \funcd{inotify\_add\_watch}, il cui prototipo è:
+
+\begin{funcproto}{
+\fhead{sys/inotify.h}
+\fdecl{int inotify\_add\_watch(int fd, const char *pathname, uint32\_t mask)}
+\fdesc{Aggiunge un evento di osservazione a una lista di osservazione.}
+}
+
+{La funzione ritorna un valore positivo in caso di successo, o $-1$ per un
+ errore, nel qual caso \var{errno} assumerà uno dei valori:
\begin{errlist}
\item[\errcode{EACCES}] non si ha accesso in lettura al file indicato.
\item[\errcode{EINVAL}] \param{mask} non contiene eventi legali o \param{fd}
\item[\errcode{ENOSPC}] si è raggiunto il numero massimo di voci di
osservazione o il kernel non ha potuto allocare una risorsa necessaria.
\end{errlist}
- ed inoltre \errval{EFAULT}, \errval{ENOMEM} e \errval{EBADF}.}
-\end{prototype}
+ ed inoltre \errval{EFAULT}, \errval{ENOMEM} e \errval{EBADF} nel loro
+ significato generico.}
+\end{funcproto}
La funzione consente di creare un ``\textsl{osservatore}'' (il cosiddetto
``\textit{watch}'') nella lista di osservazione di una coda di notifica, che
deve essere indicata specificando il file descriptor ad essa associato
-nell'argomento \param{fd}.\footnote{questo ovviamente dovrà essere un file
- descriptor creato con \func{inotify\_init}.} Il file o la directory da
-porre sotto osservazione vengono invece indicati per nome, da passare
+nell'argomento \param{fd}, che ovviamente dovrà essere un file descriptor
+creato con \func{inotify\_init}. Il file o la directory da porre sotto
+osservazione vengono invece indicati per nome, da passare
nell'argomento \param{pathname}. Infine il terzo argomento, \param{mask},
indica che tipo di eventi devono essere tenuti sotto osservazione e le
modalità della stessa. L'operazione può essere ripetuta per tutti i file e le
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
- \sysctlfile{fs/inotify/max\_user\_watches}.} e si utilizzerà sempre
-un solo file descriptor.
+ \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
nell'argomento \param{mask} come maschera binaria, combinando i valori delle
\begin{table}[htb]
\centering
\footnotesize
- \begin{tabular}[c]{|l|c|p{10cm}|}
+ \begin{tabular}[c]{|l|c|p{8cm}|}
\hline
\textbf{Valore} & & \textbf{Significato} \\
\hline
\begin{table}[htb]
\centering
\footnotesize
- \begin{tabular}[c]{|l|p{10cm}|}
+ \begin{tabular}[c]{|l|p{8cm}|}
\hline
\textbf{Valore} & \textbf{Significato} \\
\hline
riferimento sia riguardo i risultati restituiti da \textit{inotify}, che per
la eventuale rimozione dello stesso.
-La seconda funzione per la gestione delle code di notifica, che permette di
-rimuovere un \textsl{osservatore}, è \funcd{inotify\_rm\_watch}, ed il suo
-prototipo è:
-\begin{prototype}{sys/inotify.h}
- {int inotify\_rm\_watch(int fd, uint32\_t wd)}
+La seconda funzione di sistema per la gestione delle code di notifica, che
+permette di rimuovere un \textsl{osservatore}, è \funcd{inotify\_rm\_watch},
+ed il suo prototipo è:
- Rimuove un \textsl{osservatore} da una coda di notifica.
-
- \bodydesc{La funzione restituisce 0 in caso di successo, o $-1$ in caso di
- errore, nel qual caso \var{errno} assumerà uno dei valori:
+\begin{funcproto}{
+\fhead{sys/inotify.h}
+\fdecl{int inotify\_rm\_watch(int fd, uint32\_t wd)}
+\fdesc{Rimuove un \textsl{osservatore} da una coda di notifica.}
+}
+
+{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual
+ caso \var{errno} assumerà uno dei valori:
\begin{errlist}
\item[\errcode{EBADF}] non si è specificato in \param{fd} un file descriptor
valido.
non è associato ad una coda di notifica.
\end{errlist}
}
-\end{prototype}
+\end{funcproto}
La funzione rimuove dalla coda di notifica identificata dall'argomento
\param{fd} l'osservatore identificato dal \textit{watch descriptor}
-\param{wd};\footnote{ovviamente deve essere usato per questo argomento un
- valore ritornato da \func{inotify\_add\_watch}, altrimenti si avrà un errore
- di \errval{EINVAL}.} in caso di successo della rimozione, contemporaneamente
-alla cancellazione dell'osservatore, sulla coda di notifica verrà generato un
+\param{wd}; ovviamente deve essere usato per questo argomento un valore
+ritornato da \func{inotify\_add\_watch}, altrimenti si avrà un errore di
+\errval{EINVAL}. In caso di successo della rimozione, contemporaneamente alla
+cancellazione dell'osservatore, sulla coda di notifica verrà generato un
evento di tipo \const{IN\_IGNORED} (vedi
tab.~\ref{tab:inotify_read_event_flag}). Si tenga presente che se un file
viene cancellato o un filesystem viene smontato i relativi osservatori vengono
\begin{figure}[!htb]
\footnotesize \centering
- \begin{minipage}[c]{\textwidth}
+ \begin{minipage}[c]{0.90\textwidth}
\includestruct{listati/inotify_event.h}
\end{minipage}
\normalsize
Una ulteriore caratteristica dell'interfaccia di \textit{inotify} è che essa
permette di ottenere con \func{ioctl}, come per i file descriptor associati ai
-socket (si veda sez.~\ref{sec:sock_ioctl_IP}) il numero di byte disponibili in
-lettura sul file descriptor, utilizzando su di esso l'operazione
+socket (si veda sez.~\ref{sec:sock_ioctl_IP}), il numero di byte disponibili
+in lettura sul file descriptor, utilizzando su di esso l'operazione
\const{FIONREAD}.\footnote{questa è una delle operazioni speciali per i file
(vedi sez.~\ref{sec:file_fcntl_ioctl}), che è disponibile solo per i socket
e per i file descriptor creati con \func{inotify\_init}.} Si può così
osservatore è stato registrato. Il campo \var{mask} contiene invece una
maschera di bit che identifica il tipo di evento verificatosi; in essa
compariranno sia i bit elencati nella prima parte di
-tab.~\ref{tab:inotify_event_watch}, che gli eventuali valori
-aggiuntivi\footnote{questi compaiono solo nel campo \var{mask} di
- \struct{inotify\_event}, e non utilizzabili in fase di registrazione
- dell'osservatore.} di tab.~\ref{tab:inotify_read_event_flag}.
+tab.~\ref{tab:inotify_event_watch}, che gli eventuali valori aggiuntivi di
+tab.~\ref{tab:inotify_read_event_flag} (questi compaiono solo nel campo
+\var{mask} di \struct{inotify\_event}, e non sono utilizzabili in fase di
+registrazione dell'osservatore).
\begin{table}[htb]
\centering
\label{tab:inotify_read_event_flag}
\end{table}
-\footnotetext{la coda di notifica ha una dimensione massima specificata dal
- 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
- \const{IN\_Q\_OVERFLOW}.}
+\footnotetext{la coda di notifica ha una dimensione massima che viene
+ controllata dal 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 \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
\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).
+Una volta completata la scansione delle opzioni il corpo 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 (o si esce 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
(\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.
+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 \textit{system call}, nel qual caso (\texttt{\small 36}) si
-ripete la lettura.
+approssimativamente 512 eventi (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
+\textit{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
+in lettura. Per ciascun evento all'interno del ciclo si assegna alla variabile
+\var{event} (si noti come si sia eseguito un opportuno \textit{casting} del
+puntatore) 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
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.
+controllato il valore del campo \var{event->len} e non il fatto che
+\var{event->name} riporti o meno un puntatore nullo. L'interfaccia infatti,
+qualora il nome non sia presente, non tocca il campo \var{event->name}, che
+si troverà pertanto 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
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
+terminali e \textit{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
in fig.~\ref{fig:file_mmap_layout}, la mappatura introduce una corrispondenza
biunivoca fra una sezione di un file ed una sezione di memoria. Questo
comporta che ad esempio non è possibile mappare in memoria file descriptor
-relativi a pipe, socket e fifo, per i quali non ha senso parlare di
-\textsl{sezione}. Lo stesso vale anche per alcuni file di dispositivo, che non
-dispongono della relativa operazione \func{mmap} (si ricordi quanto esposto in
-sez.~\ref{sec:file_vfs_work}). Si tenga presente però che esistono anche casi
-di dispositivi (un esempio è l'interfaccia al ponte PCI-VME del chip Universe)
-che sono utilizzabili solo con questa interfaccia.
+relativi a \textit{pipe}, socket e \textit{fifo}, per i quali non ha senso
+parlare di \textsl{sezione}. Lo stesso vale anche per alcuni file di
+dispositivo, che non dispongono della relativa operazione \func{mmap} (si
+ricordi quanto esposto in sez.~\ref{sec:file_vfs_work}). Si tenga presente
+però che esistono anche casi di dispositivi (un esempio è l'interfaccia al
+ponte PCI-VME del chip Universe) che sono utilizzabili solo con questa
+interfaccia.
\begin{figure}[htb]
\centering
\begin{errlist}
\item[\errcode{EOVERFLOW}] \param{offset} ha un valore che non può essere
usato come \type{off\_t}.
- \item[\errcode{ESPIPE}] \param{fd} è associato ad un socket o una pipe.
+ \item[\errcode{ESPIPE}] \param{fd} è associato ad un socket o una
+ \textit{pipe}.
\end{errlist}
}
\end{functions}
\funcdecl{long splice(int fd\_in, off\_t *off\_in, int fd\_out, off\_t
*off\_out, size\_t len, unsigned int flags)}
- Trasferisce dati da un file verso una pipe o viceversa.
+ Trasferisce dati da un file verso una \textit{pipe} o viceversa.
\bodydesc{La funzione restituisce il numero di byte trasferiti in caso di
successo e $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno
non sono file descriptor validi o, rispettivamente, non sono stati
aperti in lettura o scrittura.
\item[\errcode{EINVAL}] il filesystem su cui si opera non supporta
- \func{splice}, oppure nessuno dei file descriptor è una pipe, oppure si
+ \func{splice}, oppure nessuno dei file descriptor è una \textit{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{lseek}.
\footnotetext[120]{per una maggiore efficienza \func{splice} usa quando
possibile i meccanismi della memoria virtuale per eseguire i trasferimenti
di dati (in maniera analoga a \func{mmap}), qualora le pagine non possano
- essere spostate dalla pipe o il buffer non corrisponda a pagine intere esse
- saranno comunque copiate.}
+ essere spostate dalla \textit{pipe} o il buffer non corrisponda a pagine
+ intere esse saranno comunque copiate.}
\footnotetext[121]{questa opzione consente di utilizzare delle opzioni di
gestione dei socket che permettono di ottimizzare le trasmissioni via rete,
La funzione restituisce il numero di byte copiati da una \textit{pipe}
all'altra (o $-1$ in caso di errore), un valore nullo indica che non ci sono
-byte disponibili da copiare e che il capo in scrittura della pipe è stato
-chiuso.\footnote{si tenga presente però che questo non avviene se si è
+byte disponibili da copiare e che il capo in scrittura della \textit{pipe} è
+stato chiuso.\footnote{si tenga presente però che questo non avviene se si è
impostato il flag \const{SPLICE\_F\_NONBLOCK}, in tal caso infatti si
avrebbe un errore di \errcode{EAGAIN}.} Un esempio di realizzazione del
comando \texttt{tee} usando questa funzione, ripreso da quello fornito nella
\item[\errcode{EBADF}] l'argomento \param{fd} non è un file descriptor
valido o non è aperto in lettura.
\item[\errcode{EINVAL}] l'argomento \param{fd} si riferisce ad un tipo di
- file che non supporta l'operazione (come una pipe o un socket).
+ file che non supporta l'operazione (come una \textit{pipe} o un socket).
\end{errlist}
}
\end{functions}
valido.
\item[\errcode{EINVAL}] il valore di \param{advice} non è valido o
\param{fd} si riferisce ad un tipo di file che non supporta l'operazione
- (come una pipe o un socket).
- \item[\errcode{ESPIPE}] previsto dallo standard se \param{fd} è una pipe o
+ (come una \textit{pipe} o un socket).
+ \item[\errcode{ESPIPE}] previsto dallo standard se \param{fd} è una \textit{pipe} o
un socket (ma su Linux viene restituito \errcode{EINVAL}).
\end{errlist}
}
file regolare.
\item[\errcode{ENOSPC}] non c'è sufficiente spazio disco per eseguire
l'operazione.
- \item[\errcode{ESPIPE}] l'argomento \param{fd} è una pipe.
+ \item[\errcode{ESPIPE}] l'argomento \param{fd} è una \textit{pipe}.
\end{errlist}
}
\end{functions}