\label{cha:file_advanced}
In questo capitolo affronteremo le tematiche relative alla gestione avanzata
dei file. Inizieremo con la trattazione delle problematiche del \textit{file
\label{cha:file_advanced}
In questo capitolo affronteremo le tematiche relative alla gestione avanzata
dei file. Inizieremo con la trattazione delle problematiche del \textit{file
- locking} e poi prenderemo in esame le varie funzionalità avanzate che
-permettono una gestione più sofisticata dell'I/O su file, a partire da quelle
-che consentono di gestire l'accesso contemporaneo a più file esaminando le
-varie modalità alternative di gestire l'I/O per concludere con la gestione dei
+ locking} e poi prenderemo in esame le varie funzionalità avanzate che
+permettono una gestione più sofisticata dell'I/O su file, a partire da quelle
+che consentono di gestire l'accesso contemporaneo a più file esaminando le
+varie modalità alternative di gestire l'I/O per concludere con la gestione dei
-diversi. In quell'occasione si è visto come, con l'eccezione dei file aperti
-in \itindex{append~mode} \textit{append mode}, quando più processi scrivono
-contemporaneamente sullo stesso file non è possibile determinare la sequenza
+diversi. In quell'occasione si è visto come, con l'eccezione dei file aperti
+in \itindex{append~mode} \textit{append mode}, quando più processi scrivono
+contemporaneamente sullo stesso file non è possibile determinare la sequenza
-Questo causa la possibilità di una \itindex{race~condition} \textit{race
- condition}; in generale le situazioni più comuni sono due: l'interazione fra
+Questo causa la possibilità di una \itindex{race~condition} \textit{race
+ condition}; in generale le situazioni più comuni sono due: l'interazione fra
un processo che scrive e altri che leggono, in cui questi ultimi possono
leggere informazioni scritte solo in maniera parziale o incompleta; o quella
in cui diversi processi scrivono, mescolando in maniera imprevedibile il loro
output sul file.
un processo che scrive e altri che leggono, in cui questi ultimi possono
leggere informazioni scritte solo in maniera parziale o incompleta; o quella
in cui diversi processi scrivono, mescolando in maniera imprevedibile il loro
output sul file.
evitare le \itindex{race~condition} \textit{race condition}, attraverso una
serie di funzioni che permettono di bloccare l'accesso al file da parte di
evitare le \itindex{race~condition} \textit{race condition}, attraverso una
serie di funzioni che permettono di bloccare l'accesso al file da parte di
delle operazioni di lettura o scrittura.
\subsection{L'\textit{advisory locking}}
\label{sec:file_record_locking}
delle operazioni di lettura o scrittura.
\subsection{L'\textit{advisory locking}}
\label{sec:file_record_locking}
-La prima modalità di \textit{file locking} che è stata implementata nei
-sistemi unix-like è quella che viene usualmente chiamata \textit{advisory
+La prima modalità di \textit{file locking} che è stata implementata nei
+sistemi unix-like è quella che viene usualmente chiamata \textit{advisory
locking},\footnote{Stevens in \cite{APUE} fa riferimento a questo argomento
come al \textit{record locking}, dizione utilizzata anche dal manuale delle
\acr{glibc}; nelle pagine di manuale si parla di \textit{discrectionary file
lock} per \func{fcntl} e di \textit{advisory locking} per \func{flock},
mentre questo nome viene usato da Stevens per riferirsi al \textit{file
locking},\footnote{Stevens in \cite{APUE} fa riferimento a questo argomento
come al \textit{record locking}, dizione utilizzata anche dal manuale delle
\acr{glibc}; nelle pagine di manuale si parla di \textit{discrectionary file
lock} per \func{fcntl} e di \textit{advisory locking} per \func{flock},
mentre questo nome viene usato da Stevens per riferirsi al \textit{file
mantenere il nome \textit{advisory locking}.} in quanto sono i singoli
processi, e non il sistema, che si incaricano di asserire e verificare se
esistono delle condizioni di blocco per l'accesso ai file.
Questo significa che le funzioni \func{read} o \func{write} vengono eseguite
comunque e non risentono affatto della presenza di un eventuale \textit{lock};
mantenere il nome \textit{advisory locking}.} in quanto sono i singoli
processi, e non il sistema, che si incaricano di asserire e verificare se
esistono delle condizioni di blocco per l'accesso ai file.
Questo significa che le funzioni \func{read} o \func{write} vengono eseguite
comunque e non risentono affatto della presenza di un eventuale \textit{lock};
\textit{file locking}, controllare esplicitamente lo stato dei file condivisi
prima di accedervi, utilizzando le relative funzioni.
In generale si distinguono due tipologie di \textit{file lock};\footnote{di
seguito ci riferiremo sempre ai blocchi di accesso ai file con la
\textit{file locking}, controllare esplicitamente lo stato dei file condivisi
prima di accedervi, utilizzando le relative funzioni.
In generale si distinguono due tipologie di \textit{file lock};\footnote{di
seguito ci riferiremo sempre ai blocchi di accesso ai file con la
- processo (cioè la condizione in cui il processo viene posto in stato di
- \textit{sleep}).} la prima è il cosiddetto \textit{shared lock}, detto anche
+ processo (cioè la condizione in cui il processo viene posto in stato di
+ \textit{sleep}).} la prima è il cosiddetto \textit{shared lock}, detto anche
-file affinché il suo contenuto non venga modificato mentre lo si legge. Si
-parla appunto di \textsl{blocco condiviso} in quanto più processi possono
+file affinché il suo contenuto non venga modificato mentre lo si legge. Si
+parla appunto di \textsl{blocco condiviso} in quanto più processi possono
richiedere contemporaneamente uno \textit{shared lock} su un file per
proteggere il loro accesso in lettura.
richiedere contemporaneamente uno \textit{shared lock} su un file per
proteggere il loro accesso in lettura.
\textit{write lock} in quanto serve a bloccare l'accesso su un file (sia in
lettura che in scrittura) da parte di altri processi mentre lo si sta
\textit{write lock} in quanto serve a bloccare l'accesso su un file (sia in
lettura che in scrittura) da parte di altri processi mentre lo si sta
-scrivendo. Si parla di \textsl{blocco esclusivo} appunto perché un solo
-processo alla volta può richiedere un \textit{exclusive lock} su un file per
+scrivendo. Si parla di \textsl{blocco esclusivo} appunto perché un solo
+processo alla volta può richiedere un \textit{exclusive lock} su un file per
proteggere il suo accesso in scrittura.
In Linux sono disponibili due interfacce per utilizzare l'\textit{advisory
proteggere il suo accesso in scrittura.
In Linux sono disponibili due interfacce per utilizzare l'\textit{advisory
- locking}, la prima è quella derivata da BSD, che è basata sulla funzione
-\func{flock}, la seconda è quella recepita dallo standard POSIX.1 (che è
-derivata dall'interfaccia usata in System V), che è basata sulla funzione
+ locking}, la prima è quella derivata da BSD, che è basata sulla funzione
+\func{flock}, la seconda è quella recepita dallo standard POSIX.1 (che è
+derivata dall'interfaccia usata in System V), che è basata sulla funzione
comportamento non bloccante) viene posto in stato di sleep. Una volta finite
le operazioni sul file si deve provvedere a rimuovere il blocco.
comportamento non bloccante) viene posto in stato di sleep. Una volta finite
le operazioni sul file si deve provvedere a rimuovere il blocco.
corrispondenza di una ulteriore richiesta da parte di un processo di un blocco
nelle due tipologie di \textit{file lock} menzionate, con un successo o meno
della richiesta.
corrispondenza di una ulteriore richiesta da parte di un processo di un blocco
nelle due tipologie di \textit{file lock} menzionate, con un successo o meno
della richiesta.
Si tenga presente infine che il controllo di accesso e la gestione dei
permessi viene effettuata quando si apre un file, l'unico controllo residuo
Si tenga presente infine che il controllo di accesso e la gestione dei
permessi viene effettuata quando si apre un file, l'unico controllo residuo
-che si può avere riguardo il \textit{file locking} è che il tipo di blocco che
-si vuole ottenere su un file deve essere compatibile con le modalità di
+che si può avere riguardo il \textit{file locking} è che il tipo di blocco che
+si vuole ottenere su un file deve essere compatibile con le modalità di
-%% la condizione per acquisire uno \textit{shared lock} è che il file non abbia
-%% già un \textit{exclusive lock} attivo, mentre per acquisire un
+%% la condizione per acquisire uno \textit{shared lock} è che il file non abbia
+%% già un \textit{exclusive lock} attivo, mentre per acquisire un
La prima interfaccia per il \textit{file locking}, quella derivata da BSD,
permette di eseguire un blocco solo su un intero file; la funzione usata per
La prima interfaccia per il \textit{file locking}, quella derivata da BSD,
permette di eseguire un blocco solo su un intero file; la funzione usata per
\begin{prototype}{sys/file.h}{int flock(int fd, int operation)}
Applica o rimuove un \textit{file lock} sul file \param{fd}.
\bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
\begin{prototype}{sys/file.h}{int flock(int fd, int operation)}
Applica o rimuove un \textit{file lock} sul file \param{fd}.
\bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
a seconda di quanto specificato tramite il valore dell'argomento
\param{operation}; questo viene interpretato come maschera binaria, e deve
essere passato costruendo il valore con un OR aritmetico delle costanti
a seconda di quanto specificato tramite il valore dell'argomento
\param{operation}; questo viene interpretato come maschera binaria, e deve
essere passato costruendo il valore con un OR aritmetico delle costanti
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
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}.
+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}.
possibile che nel frattempo abbia successo un'altra richiesta pendente,
facendo fallire la riacquisizione.
possibile che nel frattempo abbia successo un'altra richiesta pendente,
facendo fallire la riacquisizione.
-Si tenga presente infine che \func{flock} non è supportata per i file
-mantenuti su NFS, in questo caso, se si ha la necessità di utilizzare il
+Si tenga presente infine che \func{flock} non è supportata per i file
+mantenuti su NFS, in questo caso, se si ha la necessità di utilizzare il
\textit{file locking} POSIX, in particolare per quanto riguarda il
comportamento dei \textit{file lock} nei confronti delle due funzioni
\func{dup} e \func{fork}. Per capire queste differenze occorre descrivere con
maggiore dettaglio come viene realizzato dal kernel il \textit{file locking}
per entrambe le interfacce.
\textit{file locking} POSIX, in particolare per quanto riguarda il
comportamento dei \textit{file lock} nei confronti delle due funzioni
\func{dup} e \func{fork}. Per capire queste differenze occorre descrivere con
maggiore dettaglio come viene realizzato dal kernel il \textit{file locking}
per entrambe le interfacce.
\textit{file lock} sono mantenute dal kernel a livello di
inode\index{inode},\footnote{in particolare, come accennato in
fig.~\ref{fig:file_flock_struct}, i \textit{file lock} sono mantenuti in una
\itindex{linked~list} \textit{linked list} di strutture
\textit{file lock} sono mantenute dal kernel a livello di
inode\index{inode},\footnote{in particolare, come accennato in
fig.~\ref{fig:file_flock_struct}, i \textit{file lock} sono mantenuti in una
\itindex{linked~list} \textit{linked list} di strutture
mantenuto dal campo \var{i\_flock} della struttura \struct{inode} (per le
definizioni esatte si faccia riferimento al file \file{fs.h} nei sorgenti
del kernel). Un bit del campo \var{fl\_flags} di specifica se si tratta di
un lock in semantica BSD (\const{FL\_FLOCK}) o POSIX (\const{FL\_POSIX}).}
mantenuto dal campo \var{i\_flock} della struttura \struct{inode} (per le
definizioni esatte si faccia riferimento al file \file{fs.h} nei sorgenti
del kernel). Un bit del campo \var{fl\_flags} di specifica se si tratta di
un lock in semantica BSD (\const{FL\_FLOCK}) o POSIX (\const{FL\_POSIX}).}
-determinare se l'acquisizione è possibile, ed in caso positivo l'aggiunta di
-un nuovo elemento.\footnote{cioè una nuova struttura \struct{file\_lock}.}
+determinare se l'acquisizione è possibile, ed in caso positivo l'aggiunta di
+un nuovo elemento.\footnote{cioè una nuova struttura \struct{file\_lock}.}
Nel caso dei blocchi creati con \func{flock} la semantica della funzione
prevede che sia \func{dup} che \func{fork} non creino ulteriori istanze di un
\textit{file lock} quanto piuttosto degli ulteriori riferimenti allo
stesso. Questo viene realizzato dal kernel secondo lo schema di
fig.~\ref{fig:file_flock_struct}, associando ad ogni nuovo \textit{file lock}
Nel caso dei blocchi creati con \func{flock} la semantica della funzione
prevede che sia \func{dup} che \func{fork} non creino ulteriori istanze di un
\textit{file lock} quanto piuttosto degli ulteriori riferimenti allo
stesso. Questo viene realizzato dal kernel secondo lo schema di
fig.~\ref{fig:file_flock_struct}, associando ad ogni nuovo \textit{file lock}
\struct{file\_lock}, e viene utilizzato solo per i \textit{file lock} creati
con la semantica BSD.} alla voce nella \itindex{file~table} \textit{file
\struct{file\_lock}, e viene utilizzato solo per i \textit{file lock} creati
con la semantica BSD.} alla voce nella \itindex{file~table} \textit{file
Questa struttura prevede che, quando si richiede la rimozione di un
\textit{file lock}, il kernel acconsenta solo se la richiesta proviene da un
file descriptor che fa riferimento ad una voce nella \itindex{file~table}
\textit{file table} corrispondente a quella registrata nel blocco. Allora se
ricordiamo quanto visto in sez.~\ref{sec:file_dup} e
Questa struttura prevede che, quando si richiede la rimozione di un
\textit{file lock}, il kernel acconsenta solo se la richiesta proviene da un
file descriptor che fa riferimento ad una voce nella \itindex{file~table}
\textit{file table} corrispondente a quella registrata nel blocco. Allora se
ricordiamo quanto visto in sez.~\ref{sec:file_dup} e
-\itindex{file~table} \textit{file table}, anche se questo è diverso da quello
-con cui lo si è creato,\footnote{attenzione, questo non vale se il file
+\itindex{file~table} \textit{file table}, anche se questo è diverso da quello
+con cui lo si è creato,\footnote{attenzione, questo non vale se il file
descriptor fa riferimento allo stesso file, ma attraverso una voce diversa
della \itindex{file~table} \textit{file table}, come accade tutte le volte
descriptor fa riferimento allo stesso file, ma attraverso una voce diversa
della \itindex{file~table} \textit{file table}, come accade tutte le volte
voce nella \itindex{file~table} \textit{file table}, e quindi, nel caso di
file descriptor ereditati attraverso una \func{fork}, anche per processi
diversi.
voce nella \itindex{file~table} \textit{file table}, e quindi, nel caso di
file descriptor ereditati attraverso una \func{fork}, anche per processi
diversi.
dei \textit{file lock}, quando un file viene chiuso il kernel provvede anche a
rimuovere tutti i blocchi ad esso associati. Anche in questo caso occorre
tenere presente cosa succede quando si hanno file descriptor duplicati; in tal
dei \textit{file lock}, quando un file viene chiuso il kernel provvede anche a
rimuovere tutti i blocchi ad esso associati. Anche in questo caso occorre
tenere presente cosa succede quando si hanno file descriptor duplicati; in tal
fanno riferimento alla stessa voce sono stati chiusi. Quindi, nel caso ci
siano duplicati o processi figli che mantengono ancora aperto un file
descriptor, il \textit{file lock} non viene rilasciato.
fanno riferimento alla stessa voce sono stati chiusi. Quindi, nel caso ci
siano duplicati o processi figli che mantengono ancora aperto un file
descriptor, il \textit{file lock} non viene rilasciato.
sez.~\ref{sec:file_fcntl}. Quando la si impiega per il \textit{file locking}
essa viene usata solo secondo il seguente prototipo:
\begin{prototype}{fcntl.h}{int fcntl(int fd, int cmd, struct flock *lock)}
sez.~\ref{sec:file_fcntl}. Quando la si impiega per il \textit{file locking}
essa viene usata solo secondo il seguente prototipo:
\begin{prototype}{fcntl.h}{int fcntl(int fd, int cmd, struct flock *lock)}
Applica o rimuove un \textit{file lock} sul file \param{fd}.
\bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
Applica o rimuove un \textit{file lock} sul file \param{fd}.
\bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
\textit{file lock} da parte di altri processi.
\item[\errcode{ENOLCK}] il sistema non ha le risorse per il blocco: ci
\textit{file lock} da parte di altri processi.
\item[\errcode{ENOLCK}] il sistema non ha le risorse per il blocco: ci
- sono troppi segmenti di \textit{lock} aperti, si è esaurita la tabella
- dei \textit{file lock}, o il protocollo per il blocco remoto è fallito.
- \item[\errcode{EDEADLK}] si è richiesto un \textit{lock} su una regione
- bloccata da un altro processo che è a sua volta in attesa dello sblocco
+ sono troppi segmenti di \textit{lock} aperti, si è esaurita la tabella
+ dei \textit{file lock}, o il protocollo per il blocco remoto è fallito.
+ \item[\errcode{EDEADLK}] si è richiesto un \textit{lock} su una regione
+ bloccata da un altro processo che è a sua volta in attesa dello sblocco
di poter acquisire un \textit{file lock}.
\end{errlist}
ed inoltre \errval{EBADF}, \errval{EFAULT}.
di poter acquisire un \textit{file lock}.
\end{errlist}
ed inoltre \errval{EBADF}, \errval{EFAULT}.
al singolo byte. Inoltre la funzione permette di ottenere alcune informazioni
relative agli eventuali blocchi preesistenti. Per poter fare tutto questo la
funzione utilizza come terzo argomento una apposita struttura \struct{flock}
al singolo byte. Inoltre la funzione permette di ottenere alcune informazioni
relative agli eventuali blocchi preesistenti. Per poter fare tutto questo la
funzione utilizza come terzo argomento una apposita struttura \struct{flock}
inserire tutti i dati relativi ad un determinato blocco. Si tenga presente poi
che un \textit{file lock} fa sempre riferimento ad una regione, per cui si
inserire tutti i dati relativi ad un determinato blocco. Si tenga presente poi
che un \textit{file lock} fa sempre riferimento ad una regione, per cui si
\const{SEEK\_SET}, \const{SEEK\_CUR} e \const{SEEK\_END}, (si vedano le
relative descrizioni in sez.~\ref{sec:file_lseek}).
\const{SEEK\_SET}, \const{SEEK\_CUR} e \const{SEEK\_END}, (si vedano le
relative descrizioni in sez.~\ref{sec:file_lseek}).
-Si tenga presente che un \textit{file lock} può essere richiesto anche per una
-regione al di là della corrente fine del file, così che una eventuale
+Si tenga presente che un \textit{file lock} può essere richiesto anche per una
+regione al di là della corrente fine del file, così che una eventuale
estensione dello stesso resti coperta dal blocco. Inoltre se si specifica un
valore nullo per \var{l\_len} il blocco si considera esteso fino alla
estensione dello stesso resti coperta dal blocco. Inoltre se si specifica un
valore nullo per \var{l\_len} il blocco si considera esteso fino alla
regione a partire da un certo punto fino alla fine del file, coprendo
automaticamente quanto eventualmente aggiunto in coda allo stesso.
regione a partire da un certo punto fino alla fine del file, coprendo
automaticamente quanto eventualmente aggiunto in coda allo stesso.
riportate in tab.~\ref{tab:file_flock_type}, che permettono di richiedere
rispettivamente uno \textit{shared lock}, un \textit{esclusive lock}, e la
rimozione di un blocco precedentemente acquisito. Infine il campo \var{l\_pid}
riportate in tab.~\ref{tab:file_flock_type}, che permettono di richiedere
rispettivamente uno \textit{shared lock}, un \textit{esclusive lock}, e la
rimozione di un blocco precedentemente acquisito. Infine il campo \var{l\_pid}
-effettivamente svolta dalla funzione è stabilita dal valore dall'argomento
-\param{cmd} che, come già riportato in sez.~\ref{sec:file_fcntl}, specifica
+effettivamente svolta dalla funzione è stabilita dal valore dall'argomento
+\param{cmd} che, come già riportato in sez.~\ref{sec:file_fcntl}, specifica
l'azione da compiere; i valori relativi al \textit{file locking} sono tre:
\begin{basedescript}{\desclabelwidth{2.0cm}}
\item[\const{F\_GETLK}] verifica se il \textit{file lock} specificato dalla
l'azione da compiere; i valori relativi al \textit{file locking} sono tre:
\begin{basedescript}{\desclabelwidth{2.0cm}}
\item[\const{F\_GETLK}] verifica se il \textit{file lock} specificato dalla
- struttura puntata da \param{lock} può essere acquisito: in caso negativo
- sovrascrive la struttura \param{flock} con i valori relativi al blocco già
+ struttura puntata da \param{lock} può essere acquisito: in caso negativo
+ sovrascrive la struttura \param{flock} con i valori relativi al blocco già
esistente che ne blocca l'acquisizione, altrimenti si limita a impostarne il
campo \var{l\_type} con il valore \const{F\_UNLCK}.
\item[\const{F\_SETLK}] se il campo \var{l\_type} della struttura puntata da
esistente che ne blocca l'acquisizione, altrimenti si limita a impostarne il
campo \var{l\_type} con il valore \const{F\_UNLCK}.
\item[\const{F\_SETLK}] se il campo \var{l\_type} della struttura puntata da
- \param{lock} è \const{F\_RDLCK} o \const{F\_WRLCK} richiede il
- corrispondente \textit{file lock}, se è \const{F\_UNLCK} lo rilascia. Nel
+ \param{lock} è \const{F\_RDLCK} o \const{F\_WRLCK} richiede il
+ corrispondente \textit{file lock}, se è \const{F\_UNLCK} lo rilascia. Nel
caso la richiesta non possa essere soddisfatta a causa di un blocco
preesistente la funzione ritorna immediatamente con un errore di
\errcode{EACCES} o di \errcode{EAGAIN}.
caso la richiesta non possa essere soddisfatta a causa di un blocco
preesistente la funzione ritorna immediatamente con un errore di
\errcode{EACCES} o di \errcode{EAGAIN}.
-\item[\const{F\_SETLKW}] è identica a \const{F\_SETLK}, ma se la richiesta di
- non può essere soddisfatta per la presenza di un altro blocco, mette il
+\item[\const{F\_SETLKW}] è identica a \const{F\_SETLK}, ma se la richiesta di
+ non può essere soddisfatta per la presenza di un altro blocco, mette il
processo in stato di attesa fintanto che il blocco precedente non viene
rilasciato. Se l'attesa viene interrotta da un segnale la funzione ritorna
con un errore di \errcode{EINTR}.
\end{basedescript}
Si noti che per quanto detto il comando \const{F\_GETLK} non serve a rilevare
processo in stato di attesa fintanto che il blocco precedente non viene
rilasciato. Se l'attesa viene interrotta da un segnale la funzione ritorna
con un errore di \errcode{EINTR}.
\end{basedescript}
Si noti che per quanto detto il comando \const{F\_GETLK} non serve a rilevare
compatibili con quello richiesto, la funzione ritorna comunque impostando
\var{l\_type} a \const{F\_UNLCK}. Inoltre a seconda del valore di
compatibili con quello richiesto, la funzione ritorna comunque impostando
\var{l\_type} a \const{F\_UNLCK}. Inoltre a seconda del valore di
-\var{l\_type} si potrà controllare o l'esistenza di un qualunque tipo di
-blocco (se è \const{F\_WRLCK}) o di \textit{write lock} (se è
-\const{F\_RDLCK}). Si consideri poi che può esserci più di un blocco che
+\var{l\_type} si potrà controllare o l'esistenza di un qualunque tipo di
+blocco (se è \const{F\_WRLCK}) o di \textit{write lock} (se è
+\const{F\_RDLCK}). Si consideri poi che può esserci più di un blocco che
operazione atomica (un altro processo potrebbe acquisire un blocco fra le due
chiamate) per cui si deve sempre verificare il codice di ritorno di
\func{fcntl}\footnote{controllare il codice di ritorno delle funzioni invocate
operazione atomica (un altro processo potrebbe acquisire un blocco fra le due
chiamate) per cui si deve sempre verificare il codice di ritorno di
\func{fcntl}\footnote{controllare il codice di ritorno delle funzioni invocate
- è comunque una buona norma di programmazione, che permette di evitare un
- sacco di errori difficili da tracciare proprio perché non vengono rilevati.}
+ è comunque una buona norma di programmazione, che permette di evitare un
+ sacco di errori difficili da tracciare proprio perché non vengono rilevati.}
quando la si invoca con \const{F\_SETLK}, per controllare che il blocco sia
stato effettivamente acquisito.
quando la si invoca con \const{F\_SETLK}, per controllare che il blocco sia
stato effettivamente acquisito.
introduce un'ulteriore complicazione; consideriamo la situazione illustrata in
fig.~\ref{fig:file_flock_dead}, in cui il processo A blocca la regione 1 e il
processo B la regione 2. Supponiamo che successivamente il processo A richieda
introduce un'ulteriore complicazione; consideriamo la situazione illustrata in
fig.~\ref{fig:file_flock_dead}, in cui il processo A blocca la regione 1 e il
processo B la regione 2. Supponiamo che successivamente il processo A richieda
-un lock sulla regione 2 che non può essere acquisito per il preesistente lock
-del processo 2; il processo 1 si bloccherà fintanto che il processo 2 non
+un lock sulla regione 2 che non può essere acquisito per il preesistente lock
+del processo 2; il processo 1 si bloccherà fintanto che il processo 2 non
porta ad un \itindex{deadlock} \textit{deadlock}, dato che a quel punto anche
il processo 2 si bloccherebbe, e niente potrebbe sbloccare l'altro processo.
Per questo motivo il kernel si incarica di rilevare situazioni di questo tipo,
porta ad un \itindex{deadlock} \textit{deadlock}, dato che a quel punto anche
il processo 2 si bloccherebbe, e niente potrebbe sbloccare l'altro processo.
Per questo motivo il kernel si incarica di rilevare situazioni di questo tipo,
Per capire meglio il funzionamento del \textit{file locking} in semantica
POSIX (che differisce alquanto rispetto da quello di BSD, visto
Per capire meglio il funzionamento del \textit{file locking} in semantica
POSIX (che differisce alquanto rispetto da quello di BSD, visto
-sez.~\ref{sec:file_flock}) esaminiamo più in dettaglio come viene gestito dal
-kernel. Lo schema delle strutture utilizzate è riportato in
-fig.~\ref{fig:file_posix_lock}; come si vede esso è molto simile all'analogo
+sez.~\ref{sec:file_flock}) esaminiamo più in dettaglio come viene gestito dal
+kernel. Lo schema delle strutture utilizzate è riportato in
+fig.~\ref{fig:file_posix_lock}; come si vede esso è molto simile all'analogo
di fig.~\ref{fig:file_flock_struct}:\footnote{in questo caso nella figura si
sono evidenziati solo i campi di \struct{file\_lock} significativi per la
semantica POSIX, in particolare adesso ciascuna struttura contiene, oltre al
\acr{pid} del processo in \var{fl\_pid}, la sezione di file che viene
di fig.~\ref{fig:file_flock_struct}:\footnote{in questo caso nella figura si
sono evidenziati solo i campi di \struct{file\_lock} significativi per la
semantica POSIX, in particolare adesso ciascuna struttura contiene, oltre al
\acr{pid} del processo in \var{fl\_pid}, la sezione di file che viene
- bloccata grazie ai campi \var{fl\_start} e \var{fl\_end}. La struttura è
- comunque la stessa, solo che in questo caso nel campo \var{fl\_flags} è
+ bloccata grazie ai campi \var{fl\_start} e \var{fl\_end}. La struttura è
+ comunque la stessa, solo che in questo caso nel campo \var{fl\_flags} è
- usato.} il blocco è sempre associato \index{inode} all'inode, solo che in
-questo caso la titolarità non viene identificata con il riferimento ad una
+ usato.} il blocco è sempre associato \index{inode} all'inode, solo che in
+questo caso la titolarità non viene identificata con il riferimento ad una
\itindex{linked~list} \textit{linked list} delle strutture
\struct{file\_lock}, scartando automaticamente quelle per cui
\itindex{linked~list} \textit{linked list} delle strutture
\struct{file\_lock}, scartando automaticamente quelle per cui
caso negativo il nuovo blocco viene comunque acquisito ed aggiunto alla lista.
Nel caso di rimozione invece questa viene effettuata controllando che il
\acr{pid} del processo richiedente corrisponda a quello contenuto nel blocco.
caso negativo il nuovo blocco viene comunque acquisito ed aggiunto alla lista.
Nel caso di rimozione invece questa viene effettuata controllando che il
\acr{pid} del processo richiedente corrisponda a quello contenuto nel blocco.
-Questa diversa modalità ha delle conseguenze precise riguardo il comportamento
-dei \textit{file lock} POSIX. La prima conseguenza è che un \textit{file lock}
+Questa diversa modalità ha delle conseguenze precise riguardo il comportamento
+dei \textit{file lock} POSIX. La prima conseguenza è che un \textit{file lock}
\func{exec} in quanto il \acr{pid} resta lo stesso. Questo comporta che, al
contrario di quanto avveniva con la semantica BSD, quando un processo termina
tutti i \textit{file lock} da esso detenuti vengono immediatamente rilasciati.
\func{exec} in quanto il \acr{pid} resta lo stesso. Questo comporta che, al
contrario di quanto avveniva con la semantica BSD, quando un processo termina
tutti i \textit{file lock} da esso detenuti vengono immediatamente rilasciati.
-\func{open} in questo caso non fa differenza) può essere usato per rimuovere
-un blocco, dato che quello che conta è solo il \acr{pid} del processo. Da
+\func{open} in questo caso non fa differenza) può essere usato per rimuovere
+un blocco, dato che quello che conta è solo il \acr{pid} del processo. Da
questo deriva una ulteriore sottile differenza di comportamento: dato che alla
chiusura di un file i blocchi ad esso associati vengono rimossi, nella
questo deriva una ulteriore sottile differenza di comportamento: dato che alla
chiusura di un file i blocchi ad esso associati vengono rimossi, nella
tutti i blocchi relativi al file cui esso faceva riferimento, anche se questi
fossero stati creati usando altri file descriptor che restano aperti.
Dato che il controllo sull'accesso ai blocchi viene eseguito sulla base del
\acr{pid} del processo, possiamo anche prendere in considerazione un altro
tutti i blocchi relativi al file cui esso faceva riferimento, anche se questi
fossero stati creati usando altri file descriptor che restano aperti.
Dato che il controllo sull'accesso ai blocchi viene eseguito sulla base del
\acr{pid} del processo, possiamo anche prendere in considerazione un altro
richiedono dei blocchi su regioni che si sovrappongono fra loro all'interno
stesso processo. Siccome il controllo, come nel caso della rimozione, si basa
solo sul \acr{pid} del processo che chiama la funzione, queste richieste
avranno sempre successo.
Nel caso della semantica BSD, essendo i lock relativi a tutto un file e non
richiedono dei blocchi su regioni che si sovrappongono fra loro all'interno
stesso processo. Siccome il controllo, come nel caso della rimozione, si basa
solo sul \acr{pid} del processo che chiama la funzione, queste richieste
avranno sempre successo.
Nel caso della semantica BSD, essendo i lock relativi a tutto un file e non
-accumulandosi,\footnote{questa ultima caratteristica è vera in generale, se
- cioè si richiede più volte lo stesso \textit{file lock}, o più blocchi sulla
+accumulandosi,\footnote{questa ultima caratteristica è vera in generale, se
+ cioè si richiede più volte lo stesso \textit{file lock}, o più blocchi sulla
stessa sezione di file, le richieste non si cumulano e basta una sola
richiesta di rilascio per cancellare il blocco.} la cosa non ha alcun
effetto; la funzione ritorna con successo, senza che il kernel debba
modificare la lista dei \textit{file lock}. In questo caso invece si possono
stessa sezione di file, le richieste non si cumulano e basta una sola
richiesta di rilascio per cancellare il blocco.} la cosa non ha alcun
effetto; la funzione ritorna con successo, senza che il kernel debba
modificare la lista dei \textit{file lock}. In questo caso invece si possono
-avere una serie di situazioni diverse: ad esempio è possibile rimuovere con
-una sola chiamata più \textit{file lock} distinti (indicando in una regione
+avere una serie di situazioni diverse: ad esempio è possibile rimuovere con
+una sola chiamata più \textit{file lock} distinti (indicando in una regione
che si sovrapponga completamente a quelle di questi ultimi), o rimuovere solo
una parte di un blocco preesistente (indicando una regione contenuta in quella
di un altro blocco), creando un buco, o coprire con un nuovo blocco altri
che si sovrapponga completamente a quelle di questi ultimi), o rimuovere solo
una parte di un blocco preesistente (indicando una regione contenuta in quella
di un altro blocco), creando un buco, o coprire con un nuovo blocco altri
sovrappongono le regioni richieste e del tipo di operazione richiesta. Il
comportamento seguito in questo caso che la funzione ha successo ed esegue
sovrappongono le regioni richieste e del tipo di operazione richiesta. Il
comportamento seguito in questo caso che la funzione ha successo ed esegue
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.
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.
-intero file usando la semantica BSD; in fig.~\ref{fig:file_flock_code} è
-riportata il corpo principale del codice del programma, (il testo completo è
+intero file usando la semantica BSD; in fig.~\ref{fig:file_flock_code} è
+riportata il corpo principale del codice del programma, (il testo completo è
funzione che stampa le istruzioni per l'uso del programma, essa si cura di
impostare le variabili \var{type}, \var{start} e \var{len}; queste ultime due
vengono inizializzate al valore numerico fornito rispettivamente tramite gli
switch \code{-s} e \cmd{-l}, mentre il valore della prima viene impostato con
le opzioni \cmd{-w} e \cmd{-r} si richiede rispettivamente o un \textit{write
lock} o \textit{read lock} (i due valori sono esclusivi, la variabile
funzione che stampa le istruzioni per l'uso del programma, essa si cura di
impostare le variabili \var{type}, \var{start} e \var{len}; queste ultime due
vengono inizializzate al valore numerico fornito rispettivamente tramite gli
switch \code{-s} e \cmd{-l}, mentre il valore della prima viene impostato con
le opzioni \cmd{-w} e \cmd{-r} si richiede rispettivamente o un \textit{write
lock} o \textit{read lock} (i due valori sono esclusivi, la variabile
-si invoca l'opzione \cmd{-f} (il valore preimpostato è nullo, ad indicare la
-semantica POSIX), e la variabile \var{cmd} che specifica la modalità di
+si invoca l'opzione \cmd{-f} (il valore preimpostato è nullo, ad indicare la
+semantica POSIX), e la variabile \var{cmd} che specifica la modalità di
reimpostare il valore di \var{cmd} per l'uso con \func{flock}; infatti il
valore preimpostato fa riferimento alla semantica POSIX e vale rispettivamente
\const{F\_SETLKW} o \const{F\_SETLK} a seconda che si sia impostato o meno la
reimpostare il valore di \var{cmd} per l'uso con \func{flock}; infatti il
valore preimpostato fa riferimento alla semantica POSIX e vale rispettivamente
\const{F\_SETLKW} o \const{F\_SETLK} a seconda che si sia impostato o meno la
Nel caso si sia scelta la semantica BSD (\texttt{\small 25--34}) prima si
controlla (\texttt{\small 27--31}) il valore di \var{cmd} per determinare se
Nel caso si sia scelta la semantica BSD (\texttt{\small 25--34}) prima si
controlla (\texttt{\small 27--31}) il valore di \var{cmd} per determinare se
opportunamente, dopo di che a seconda del tipo di blocco al valore viene
aggiunta la relativa opzione (con un OR aritmetico, dato che \func{flock}
vuole un argomento \param{operation} in forma di maschera binaria. Nel caso
opportunamente, dopo di che a seconda del tipo di blocco al valore viene
aggiunta la relativa opzione (con un OR aritmetico, dato che \func{flock}
vuole un argomento \param{operation} in forma di maschera binaria. Nel caso
immediate, si prepara (\texttt{\small 36--40}) la struttura per il lock, e lo
esegue (\texttt{\small 41}).
In entrambi i casi dopo aver richiesto il blocco viene controllato il
risultato uscendo (\texttt{\small 44--46}) in caso di errore, o stampando un
messaggio (\texttt{\small 47--49}) in caso di successo. Infine il programma si
immediate, si prepara (\texttt{\small 36--40}) la struttura per il lock, e lo
esegue (\texttt{\small 41}).
In entrambi i casi dopo aver richiesto il blocco viene controllato il
risultato uscendo (\texttt{\small 44--46}) in caso di errore, o stampando un
messaggio (\texttt{\small 47--49}) in caso di successo. Infine il programma si
dato da tastiera) non lo interrompa; in questo caso il programma termina, e
tutti i blocchi vengono rilasciati.
dato da tastiera) non lo interrompa; in questo caso il programma termina, e
tutti i blocchi vengono rilasciati.
-il programma segnalerà di aver acquisito un blocco e si bloccherà; in questo
-caso si è usato il \textit{file locking} POSIX e non avendo specificato niente
+il programma segnalerà di aver acquisito un blocco e si bloccherà; in questo
+caso si è usato il \textit{file locking} POSIX e non avendo specificato niente
riguardo alla sezione che si vuole bloccare sono stati usati i valori
preimpostati che bloccano tutto il file. A questo punto se proviamo ad
eseguire lo stesso comando in un altro terminale, e avremo lo stesso
riguardo alla sezione che si vuole bloccare sono stati usati i valori
preimpostati che bloccano tutto il file. A questo punto se proviamo ad
eseguire lo stesso comando in un altro terminale, e avremo lo stesso
-come ci aspettiamo il programma terminerà segnalando l'indisponibilità del
-blocco, dato che il file è bloccato dal precedente \textit{read lock}. Si noti
-che il risultato è lo stesso anche se si richiede il blocco su una sola parte
+come ci aspettiamo il programma terminerà segnalando l'indisponibilità del
+blocco, dato che il file è bloccato dal precedente \textit{read lock}. Si noti
+che il risultato è lo stesso anche se si richiede il blocco su una sola parte
-Il programma di norma esegue il tentativo di acquisire il lock in modalità non
-bloccante, se però usiamo l'opzione \cmd{-b} possiamo impostare la modalità
+Il programma di norma esegue il tentativo di acquisire il lock in modalità non
+bloccante, se però usiamo l'opzione \cmd{-b} possiamo impostare la modalità
\end{minipage}\vspace{1mm}
\par\noindent
il primo comando acquisisce subito un \textit{read lock}, e quindi non cambia
\end{minipage}\vspace{1mm}
\par\noindent
il primo comando acquisisce subito un \textit{read lock}, e quindi non cambia
punto rilasciamo il precedente blocco (terminando il primo comando un
\texttt{C-c} sul terminale) potremo verificare che sull'altro terminale il
blocco viene acquisito, con la comparsa di una nuova riga:
punto rilasciamo il precedente blocco (terminando il primo comando un
\texttt{C-c} sul terminale) potremo verificare che sull'altro terminale il
blocco viene acquisito, con la comparsa di una nuova riga:
-Un'altra cosa che si può controllare con il nostro programma è l'interazione
-fra i due tipi di blocco; se ripartiamo dal primo comando con cui si è
+Un'altra cosa che si può controllare con il nostro programma è l'interazione
+fra i due tipi di blocco; se ripartiamo dal primo comando con cui si è
ottenuto un blocco in lettura sull'intero file, possiamo verificare cosa
succede quando si cerca di ottenere un blocco in scrittura con la semantica
BSD:
ottenuto un blocco in lettura sull'intero file, possiamo verificare cosa
succede quando si cerca di ottenere un blocco in scrittura con la semantica
BSD:
-più potente e flessibile di quella di BSD, questo comporta anche una maggiore
-complessità per via delle varie opzioni da passare a \func{fcntl}. Per questo
-motivo è disponibile anche una interfaccia semplificata (ripresa da System V)
-che utilizza la funzione \funcd{lockf}, il cui prototipo è:
+più potente e flessibile di quella di BSD, questo comporta anche una maggiore
+complessità per via delle varie opzioni da passare a \func{fcntl}. Per questo
+motivo è disponibile anche una interfaccia semplificata (ripresa da System V)
+che utilizza la funzione \funcd{lockf}, il cui prototipo è:
\begin{prototype}{sys/file.h}{int lockf(int fd, int cmd, off\_t len)}
Applica, controlla o rimuove un \textit{file lock} sul file \param{fd}.
\bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
\begin{prototype}{sys/file.h}{int lockf(int fd, int cmd, off\_t len)}
Applica, controlla o rimuove un \textit{file lock} sul file \param{fd}.
\bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
- \item[\errcode{EWOULDBLOCK}] non è possibile acquisire il lock, e si è
- selezionato \const{LOCK\_NB}, oppure l'operazione è proibita perché il
- file è mappato in memoria.
+ \item[\errcode{EWOULDBLOCK}] non è possibile acquisire il lock, e si è
+ selezionato \const{LOCK\_NB}, oppure l'operazione è proibita perché il
+ file è mappato in memoria.
mantenere un blocco condiviso sullo stesso file.\\
\const{LOCK\_EX}& Richiede un \textit{exclusive lock}. Un solo processo
mantenere un blocco condiviso sullo stesso file.\\
\const{LOCK\_EX}& Richiede un \textit{exclusive lock}. Un solo processo
-\const{LOCK\_NB}, la funzione si blocca fino alla disponibilità dello stesso.
-Dato che la funzione è implementata utilizzando \func{fcntl} la semantica
-delle operazioni è la stessa di quest'ultima (pertanto la funzione non è
+\const{LOCK\_NB}, la funzione si blocca fino alla disponibilità dello stesso.
+Dato che la funzione è implementata utilizzando \func{fcntl} la semantica
+delle operazioni è la stessa di quest'ultima (pertanto la funzione non è
per introdurre un \textit{file locking} che, come dice il nome, fosse
effettivo indipendentemente dai controlli eseguiti da un processo. Con il
per introdurre un \textit{file locking} che, come dice il nome, fosse
effettivo indipendentemente dai controlli eseguiti da un processo. Con il
-\textit{mandatory locking} infatti è possibile far eseguire il blocco del file
-direttamente al sistema, così che, anche qualora non si predisponessero le
+\textit{mandatory locking} infatti è possibile far eseguire il blocco del file
+direttamente al sistema, così che, anche qualora non si predisponessero le
utilizzo particolare del bit \itindex{sgid~bit} \acr{sgid}. Se si ricorda
quanto esposto in sez.~\ref{sec:file_special_perm}), esso viene di norma
utilizzato per cambiare il group-ID effettivo con cui viene eseguito un
utilizzo particolare del bit \itindex{sgid~bit} \acr{sgid}. Se si ricorda
quanto esposto in sez.~\ref{sec:file_special_perm}), esso viene di norma
utilizzato per cambiare il group-ID effettivo con cui viene eseguito un
quest'ultimo venga attivato per il file in questione. In questo modo una
combinazione dei permessi originariamente non contemplata, in quanto senza
significato, diventa l'indicazione della presenza o meno del \textit{mandatory
locking}.\footnote{un lettore attento potrebbe ricordare quanto detto in
quest'ultimo venga attivato per il file in questione. In questo modo una
combinazione dei permessi originariamente non contemplata, in quanto senza
significato, diventa l'indicazione della presenza o meno del \textit{mandatory
locking}.\footnote{un lettore attento potrebbe ricordare quanto detto in
cancellato (come misura di sicurezza) quando di scrive su un file, questo
non vale quando esso viene utilizzato per attivare il \textit{mandatory
locking}.}
L'uso del \textit{mandatory locking} presenta vari aspetti delicati, dato che
cancellato (come misura di sicurezza) quando di scrive su un file, questo
non vale quando esso viene utilizzato per attivare il \textit{mandatory
locking}.}
L'uso del \textit{mandatory locking} presenta vari aspetti delicati, dato che
-neanche l'amministratore può passare sopra ad un \textit{file lock}; pertanto
-un processo che blocchi un file cruciale può renderlo completamente
+neanche l'amministratore può passare sopra ad un \textit{file lock}; pertanto
+un processo che blocchi un file cruciale può renderlo completamente
inaccessibile, rendendo completamente inutilizzabile il sistema\footnote{il
problema si potrebbe risolvere rimuovendo il bit \itindex{sgid~bit}
inaccessibile, rendendo completamente inutilizzabile il sistema\footnote{il
problema si potrebbe risolvere rimuovendo il bit \itindex{sgid~bit}
- \acr{sgid}, ma non è detto che sia così facile fare questa operazione con un
- sistema bloccato.} inoltre con il \textit{mandatory locking} si può
+ \acr{sgid}, ma non è detto che sia così facile fare questa operazione con un
+ sistema bloccato.} inoltre con il \textit{mandatory locking} si può
-è attivo un blocco. Per questo motivo l'abilitazione del \textit{mandatory
- locking} è di norma disabilitata, e deve essere attivata filesystem per
+è attivo un blocco. Per questo motivo l'abilitazione del \textit{mandatory
+ locking} è di norma disabilitata, e deve essere attivata filesystem per
filesystem in fase di montaggio (specificando l'apposita opzione di
\func{mount} riportata in tab.~\ref{tab:sys_mount_flags}, o con l'opzione
\code{-o mand} per il comando omonimo).
filesystem in fase di montaggio (specificando l'apposita opzione di
\func{mount} riportata in tab.~\ref{tab:sys_mount_flags}, o con l'opzione
\code{-o mand} per il comando omonimo).
Si tenga presente inoltre che il \textit{mandatory locking} funziona solo
sull'interfaccia POSIX di \func{fcntl}. Questo ha due conseguenze: che non si
ha nessun effetto sui \textit{file lock} richiesti con l'interfaccia di
Si tenga presente inoltre che il \textit{mandatory locking} funziona solo
sull'interfaccia POSIX di \func{fcntl}. Questo ha due conseguenze: che non si
ha nessun effetto sui \textit{file lock} richiesti con l'interfaccia di
-La sintassi di acquisizione dei blocchi è esattamente la stessa vista in
-precedenza per \func{fcntl} e \func{lockf}, la differenza è che in caso di
-\textit{mandatory lock} attivato non è più necessario controllare la
-disponibilità di accesso al file, ma si potranno usare direttamente le
-ordinarie funzioni di lettura e scrittura e sarà compito del kernel gestire
+La sintassi di acquisizione dei blocchi è esattamente la stessa vista in
+precedenza per \func{fcntl} e \func{lockf}, la differenza è che in caso di
+\textit{mandatory lock} attivato non è più necessario controllare la
+disponibilità di accesso al file, ma si potranno usare direttamente le
+ordinarie funzioni di lettura e scrittura e sarà compito del kernel gestire
-Questo significa che in caso di \textit{read lock} la lettura dal file potrà
-avvenire normalmente con \func{read}, mentre una \func{write} si bloccherà
+Questo significa che in caso di \textit{read lock} la lettura dal file potrà
+avvenire normalmente con \func{read}, mentre una \func{write} si bloccherà
scrivere sulla regione del file bloccata fermeranno il processo fino al
rilascio del blocco, a meno che il file non sia stato aperto con
scrivere sulla regione del file bloccata fermeranno il processo fino al
rilascio del blocco, a meno che il file non sia stato aperto con
con l'errore di \errcode{EAGAIN}.
Infine occorre ricordare che le funzioni di lettura e scrittura non sono le
sole ad operare sui contenuti di un file, e che sia \func{creat} che
\func{open} (quando chiamata con \const{O\_TRUNC}) effettuano dei cambiamenti,
con l'errore di \errcode{EAGAIN}.
Infine occorre ricordare che le funzioni di lettura e scrittura non sono le
sole ad operare sui contenuti di un file, e che sia \func{creat} che
\func{open} (quando chiamata con \const{O\_TRUNC}) effettuano dei cambiamenti,
casi, a quanto specificato nel secondo). Queste operazioni sono assimilate a
degli accessi in scrittura e pertanto non potranno essere eseguite (fallendo
con un errore di \errcode{EAGAIN}) su un file su cui sia presente un qualunque
casi, a quanto specificato nel secondo). Queste operazioni sono assimilate a
degli accessi in scrittura e pertanto non potranno essere eseguite (fallendo
con un errore di \errcode{EAGAIN}) su un file su cui sia presente un qualunque
dimensioni del file vada a sovrapporsi ad una regione bloccata).
L'ultimo aspetto della interazione del \textit{mandatory locking} con le
dimensioni del file vada a sovrapporsi ad una regione bloccata).
L'ultimo aspetto della interazione del \textit{mandatory locking} con le
abbiamo trattato in sez.~\ref{sec:file_memory_map}); anche in tal caso
infatti, quando si esegue la mappatura con l'opzione \const{MAP\_SHARED}, si
ha un accesso al contenuto del file. Lo standard SVID prevede che sia
impossibile eseguire il memory mapping di un file su cui sono presenti dei
abbiamo trattato in sez.~\ref{sec:file_memory_map}); anche in tal caso
infatti, quando si esegue la mappatura con l'opzione \const{MAP\_SHARED}, si
ha un accesso al contenuto del file. Lo standard SVID prevede che sia
impossibile eseguire il memory mapping di un file su cui sono presenti dei
impediscono anche in caso di \textit{advisory locking}, anche se questo
comportamento non ha molto senso, dato che comunque qualunque accesso
impediscono anche in caso di \textit{advisory locking}, anche se questo
comportamento non ha molto senso, dato che comunque qualunque accesso
implementativa\footnote{per i dettagli si possono leggere le note relative
all'implementazione, mantenute insieme ai sorgenti del kernel nel file
\file{Documentation/mandatory.txt}.} di seguire questo comportamento
soltanto quando si chiama \func{mmap} con l'opzione \const{MAP\_SHARED} (nel
qual caso la funzione fallisce con il solito \errcode{EAGAIN}) che comporta la
implementativa\footnote{per i dettagli si possono leggere le note relative
all'implementazione, mantenute insieme ai sorgenti del kernel nel file
\file{Documentation/mandatory.txt}.} di seguire questo comportamento
soltanto quando si chiama \func{mmap} con l'opzione \const{MAP\_SHARED} (nel
qual caso la funzione fallisce con il solito \errcode{EAGAIN}) che comporta la
Uno dei problemi che si presentano quando si deve operare contemporaneamente
su molti file usando le funzioni illustrate in
Uno dei problemi che si presentano quando si deve operare contemporaneamente
su molti file usando le funzioni illustrate in
-cap.~\ref{cha:file_unix_interface} e cap.~\ref{cha:files_std_interface} è che
-si può essere bloccati nelle operazioni su un file mentre un altro potrebbe
+cap.~\ref{cha:file_unix_interface} e cap.~\ref{cha:files_std_interface} è che
+si può essere bloccati nelle operazioni su un file mentre un altro potrebbe
essere disponibile. L'\textit{I/O multiplexing} nasce risposta a questo
problema. In questa sezione forniremo una introduzione a questa problematica
essere disponibile. L'\textit{I/O multiplexing} nasce risposta a questo
problema. In questa sezione forniremo una introduzione a questa problematica
Abbiamo visto in sez.~\ref{sec:sig_gen_beha}, affrontando la suddivisione fra
\textit{fast} e \textit{slow} system call,\index{system~call~lente} che in
certi casi le funzioni di I/O possono bloccarsi indefinitamente.\footnote{si
Abbiamo visto in sez.~\ref{sec:sig_gen_beha}, affrontando la suddivisione fra
\textit{fast} e \textit{slow} system call,\index{system~call~lente} che in
certi casi le funzioni di I/O possono bloccarsi indefinitamente.\footnote{si
file di dispositivo\index{file!di~dispositivo}; sui file normali le funzioni
di lettura e scrittura ritornano sempre subito.} Ad esempio le operazioni
di lettura possono bloccarsi quando non ci sono dati disponibili sul
descrittore su cui si sta operando.
file di dispositivo\index{file!di~dispositivo}; sui file normali le funzioni
di lettura e scrittura ritornano sempre subito.} Ad esempio le operazioni
di lettura possono bloccarsi quando non ci sono dati disponibili sul
descrittore su cui si sta operando.
-più file descriptor eseguendo funzioni che possono bloccarsi senza che sia
-possibile prevedere quando questo può avvenire (il caso più classico è quello
-di un server in attesa di dati in ingresso da vari client). Quello che può
-accadere è di restare bloccati nell'eseguire una operazione su un file
-descriptor che non è ``\textsl{pronto}'', quando ce ne potrebbe essere un
+più file descriptor eseguendo funzioni che possono bloccarsi senza che sia
+possibile prevedere quando questo può avvenire (il caso più classico è quello
+di un server in attesa di dati in ingresso da vari client). Quello che può
+accadere è di restare bloccati nell'eseguire una operazione su un file
+descriptor che non è ``\textsl{pronto}'', quando ce ne potrebbe essere un
altro disponibile. Questo comporta nel migliore dei casi una operazione
ritardata inutilmente nell'attesa del completamento di quella bloccata, mentre
nel peggiore dei casi (quando la conclusione della operazione bloccata dipende
da quanto si otterrebbe dal file descriptor ``\textsl{disponibile}'') si
potrebbe addirittura arrivare ad un \itindex{deadlock} \textit{deadlock}.
altro disponibile. Questo comporta nel migliore dei casi una operazione
ritardata inutilmente nell'attesa del completamento di quella bloccata, mentre
nel peggiore dei casi (quando la conclusione della operazione bloccata dipende
da quanto si otterrebbe dal file descriptor ``\textsl{disponibile}'') si
potrebbe addirittura arrivare ad un \itindex{deadlock} \textit{deadlock}.
nella chiamata di \func{open}. In questo caso le funzioni di input/output
eseguite sul file che si sarebbero bloccate, ritornano immediatamente,
nella chiamata di \func{open}. In questo caso le funzioni di input/output
eseguite sul file che si sarebbero bloccate, ritornano immediatamente,
permette di risolvere il problema controllando a turno i vari file descriptor,
in un ciclo in cui si ripete l'accesso fintanto che esso non viene garantito.
permette di risolvere il problema controllando a turno i vari file descriptor,
in un ciclo in cui si ripete l'accesso fintanto che esso non viene garantito.
estremamente inefficiente: si tiene costantemente impiegata la CPU solo per
eseguire in continuazione delle system call che nella gran parte dei casi
falliranno.
estremamente inefficiente: si tiene costantemente impiegata la CPU solo per
eseguire in continuazione delle system call che nella gran parte dei casi
falliranno.
-Per superare questo problema è stato introdotto il concetto di \textit{I/O
- multiplexing}, una nuova modalità di operazioni che consente di tenere sotto
-controllo più file descriptor in contemporanea, permettendo di bloccare un
+Per superare questo problema è stato introdotto il concetto di \textit{I/O
+ multiplexing}, una nuova modalità di operazioni che consente di tenere sotto
+controllo più file descriptor in contemporanea, permettendo di bloccare un
processo quando le operazioni volute non sono possibili, e di riprenderne
l'esecuzione una volta che almeno una di quelle richieste sia effettuabile, in
modo da poterla eseguire con la sicurezza di non restare bloccati.
processo quando le operazioni volute non sono possibili, e di riprenderne
l'esecuzione una volta che almeno una di quelle richieste sia effettuabile, in
modo da poterla eseguire con la sicurezza di non restare bloccati.
-Dato che, come abbiamo già accennato, per i normali file su disco non si ha
-mai un accesso bloccante, l'uso più comune delle funzioni che esamineremo nei
-prossimi paragrafi è per i server di rete, in cui esse vengono utilizzate per
+Dato che, come abbiamo già accennato, per i normali file su disco non si ha
+mai un accesso bloccante, l'uso più comune delle funzioni che esamineremo nei
+prossimi paragrafi è per i server di rete, in cui esse vengono utilizzate per
tenere sotto controllo dei socket; pertanto ritorneremo su di esse con
ulteriori dettagli e qualche esempio di utilizzo concreto in
sez.~\ref{sec:TCP_sock_multiplexing}.
tenere sotto controllo dei socket; pertanto ritorneremo su di esse con
ulteriori dettagli e qualche esempio di utilizzo concreto in
sez.~\ref{sec:TCP_sock_multiplexing}.
- multiplexing} è stato BSD,\footnote{la funzione \func{select} è apparsa in
- BSD4.2 e standardizzata in BSD4.4, ma è stata portata su tutti i sistemi che
+ multiplexing} è stato BSD,\footnote{la funzione \func{select} è apparsa in
+ BSD4.2 e standardizzata in BSD4.4, ma è stata portata su tutti i sistemi che
\bodydesc{La funzione in caso di successo restituisce il numero di file
descriptor (anche nullo) che sono attivi, e -1 in caso di errore, nel qual
\bodydesc{La funzione in caso di successo restituisce il numero di file
descriptor (anche nullo) che sono attivi, e -1 in caso di errore, nel qual
- \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale.
- \item[\errcode{EINVAL}] si è specificato per \param{ndfs} un valore negativo
+ \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale.
+ \item[\errcode{EINVAL}] si è specificato per \param{ndfs} un valore negativo
Rimuove il file descriptor \param{fd} dall'insieme.
\funcdecl{int \macro{FD\_ISSET}(int fd, fd\_set *set)}
Rimuove il file descriptor \param{fd} dall'insieme.
\funcdecl{int \macro{FD\_ISSET}(int fd, fd\_set *set)}
\const{FD\_SETSIZE} file descriptor. Questo valore in origine corrispondeva
al limite per il numero massimo di file aperti\footnote{ad esempio in Linux,
fino alla serie 2.0.x, c'era un limite di 256 file per processo.}, ma da
\const{FD\_SETSIZE} file descriptor. Questo valore in origine corrispondeva
al limite per il numero massimo di file aperti\footnote{ad esempio in Linux,
fino alla serie 2.0.x, c'era un limite di 256 file per processo.}, ma da
rimosso, esso indica le dimensioni massime dei numeri usati nei \textit{file
descriptor set}.\footnote{il suo valore, secondo lo standard POSIX
rimosso, esso indica le dimensioni massime dei numeri usati nei \textit{file
descriptor set}.\footnote{il suo valore, secondo lo standard POSIX
Si tenga presente che i \textit{file descriptor set} devono sempre essere
inizializzati con \macro{FD\_ZERO}; passare a \func{select} un valore non
Si tenga presente che i \textit{file descriptor set} devono sempre essere
inizializzati con \macro{FD\_ZERO}; passare a \func{select} un valore non
-il primo, \param{readfds}, verrà osservato per rilevare la disponibilità di
-effettuare una lettura,\footnote{per essere precisi la funzione ritornerà in
+il primo, \param{readfds}, verrà osservato per rilevare la disponibilità di
+effettuare una lettura,\footnote{per essere precisi la funzione ritornerà in
tutti i casi in cui la successiva esecuzione di \func{read} risulti non
bloccante, quindi anche in caso di \textit{end-of-file}; inoltre con Linux
possono verificarsi casi particolari, ad esempio quando arrivano dati su un
tutti i casi in cui la successiva esecuzione di \func{read} risulti non
bloccante, quindi anche in caso di \textit{end-of-file}; inoltre con Linux
possono verificarsi casi particolari, ad esempio quando arrivano dati su un
accadere che \func{select} riporti il relativo file descriptor come
leggibile, ma una successiva \func{read} si blocchi.} il secondo,
accadere che \func{select} riporti il relativo file descriptor come
leggibile, ma una successiva \func{read} si blocchi.} il secondo,
il terzo, \param{exceptfds}, per verificare l'esistenza di eccezioni (come i
dati urgenti \itindex{out-of-band} su un socket, vedi
sez.~\ref{sec:TCP_urgent_data}).
Dato che in genere non si tengono mai sotto controllo fino a
\const{FD\_SETSIZE} file contemporaneamente la funzione richiede di
il terzo, \param{exceptfds}, per verificare l'esistenza di eccezioni (come i
dati urgenti \itindex{out-of-band} su un socket, vedi
sez.~\ref{sec:TCP_urgent_data}).
Dato che in genere non si tengono mai sotto controllo fino a
\const{FD\_SETSIZE} file contemporaneamente la funzione richiede di
necessaria. Questo limite viene indicato tramite l'argomento \param{ndfs}, che
deve corrispondere al valore massimo aumentato di uno.\footnote{si ricordi che
i file descriptor sono numerati progressivamente a partire da zero, ed il
necessaria. Questo limite viene indicato tramite l'argomento \param{ndfs}, che
deve corrispondere al valore massimo aumentato di uno.\footnote{si ricordi che
i file descriptor sono numerati progressivamente a partire da zero, ed il
- valore indica il numero più alto fra quelli da tenere sotto controllo;
- dimenticarsi di aumentare di uno il valore di \param{ndfs} è un errore
+ valore indica il numero più alto fra quelli da tenere sotto controllo;
+ dimenticarsi di aumentare di uno il valore di \param{ndfs} è un errore
comune.}
Infine l'argomento \param{timeout}, espresso con una struttura di tipo
\struct{timeval} (vedi fig.~\ref{fig:sys_timeval_struct}) specifica un tempo
massimo di attesa prima che la funzione ritorni; se impostato a \val{NULL} la
comune.}
Infine l'argomento \param{timeout}, espresso con una struttura di tipo
\struct{timeval} (vedi fig.~\ref{fig:sys_timeval_struct}) specifica un tempo
massimo di attesa prima che la funzione ritorni; se impostato a \val{NULL} la
-funzione attende indefinitamente. Si può specificare anche un tempo nullo
-(cioè una struttura \struct{timeval} con i campi impostati a zero), qualora si
+funzione attende indefinitamente. Si può specificare anche un tempo nullo
+(cioè una struttura \struct{timeval} con i campi impostati a zero), qualora si
comportano in questo modo.} e ciascun insieme viene sovrascritto per
indicare quali sono i file descriptor pronti per le operazioni ad esso
relative, in modo da poterli controllare con \macro{FD\_ISSET}. Se invece si
ha un timeout viene restituito un valore nullo e gli insiemi non vengono
modificati. In caso di errore la funzione restituisce -1, ed i valori dei tre
comportano in questo modo.} e ciascun insieme viene sovrascritto per
indicare quali sono i file descriptor pronti per le operazioni ad esso
relative, in modo da poterli controllare con \macro{FD\_ISSET}. Se invece si
ha un timeout viene restituito un valore nullo e gli insiemi non vengono
modificati. In caso di errore la funzione restituisce -1, ed i valori dei tre
-Una volta ritornata la funzione si potrà controllare quali sono i file
-descriptor pronti ed operare su di essi, si tenga presente però che si tratta
+Una volta ritornata la funzione si potrà controllare quali sono i file
+descriptor pronti ed operare su di essi, si tenga presente però che si tratta
- quando su un socket arrivano dei dati che poi vengono scartati perché
- corrotti.} in cui \func{select} può riportare in maniera spuria che un file
-descriptor è pronto in lettura, quando una successiva lettura si bloccherebbe.
-Per questo quando si usa \textit{I/O multiplexing} è sempre raccomandato l'uso
-delle funzioni di lettura e scrittura in modalità non bloccante.
+ quando su un socket arrivano dei dati che poi vengono scartati perché
+ corrotti.} in cui \func{select} può riportare in maniera spuria che un file
+descriptor è pronto in lettura, quando una successiva lettura si bloccherebbe.
+Per questo quando si usa \textit{I/O multiplexing} è sempre raccomandato l'uso
+delle funzioni di lettura e scrittura in modalità non bloccante.
In Linux \func{select} modifica anche il valore di \param{timeout},
impostandolo al tempo restante, quando la funzione viene interrotta da un
segnale. In tal caso infatti si ha un errore di \errcode{EINTR}, ed occorre
In Linux \func{select} modifica anche il valore di \param{timeout},
impostandolo al tempo restante, quando la funzione viene interrotta da un
segnale. In tal caso infatti si ha un errore di \errcode{EINTR}, ed occorre
-rilanciare la funzione; in questo modo non è necessario ricalcolare tutte le
-volte il tempo rimanente. Questo può causare problemi di portabilità sia
+rilanciare la funzione; in questo modo non è necessario ricalcolare tutte le
+volte il tempo rimanente. Questo può causare problemi di portabilità sia
quando si usa codice scritto su Linux che legge questo valore, sia quando si
usano programmi scritti per altri sistemi che non dispongono di questa
caratteristica e ricalcolano \param{timeout} tutte le volte.\footnote{in
quando si usa codice scritto su Linux che legge questo valore, sia quando si
usano programmi scritti per altri sistemi che non dispongono di questa
caratteristica e ricalcolano \param{timeout} tutte le volte.\footnote{in
- genere questa caratteristica è disponibile nei sistemi che derivano da
- System V e non è disponibile per quelli che derivano da BSD; lo standard
+ genere questa caratteristica è disponibile nei sistemi che derivano da
+ System V e non è disponibile per quelli che derivano da BSD; lo standard
comportamento dipende dal valore del file descriptor che si vuole tenere sotto
controllo. Infatti il kernel riceve con \param{ndfs} un limite massimo per
tale valore, e per capire quali sono i file descriptor da tenere sotto
comportamento dipende dal valore del file descriptor che si vuole tenere sotto
controllo. Infatti il kernel riceve con \param{ndfs} un limite massimo per
tale valore, e per capire quali sono i file descriptor da tenere sotto
-controllo dovrà effettuare una scansione su tutto l'intervallo, che può anche
-essere molto ampio anche se i file descriptor sono solo poche unità; tutto ciò
+controllo dovrà effettuare una scansione su tutto l'intervallo, che può anche
+essere molto ampio anche se i file descriptor sono solo poche unità; tutto ciò
-Inoltre c'è anche il problema che il numero massimo dei file che si possono
-tenere sotto controllo, la funzione è nata quando il kernel consentiva un
-numero massimo di 1024 file descriptor per processo, adesso che il numero può
+Inoltre c'è anche il problema che il numero massimo dei file che si possono
+tenere sotto controllo, la funzione è nata quando il kernel consentiva un
+numero massimo di 1024 file descriptor per processo, adesso che il numero può
l'interfaccia creata da BSD, ma prevede che tutte le funzioni ad esso relative
vengano dichiarate nell'header \file{sys/select.h}, che sostituisce i
precedenti, ed inoltre aggiunge a \func{select} una nuova funzione
l'interfaccia creata da BSD, ma prevede che tutte le funzioni ad esso relative
vengano dichiarate nell'header \file{sys/select.h}, che sostituisce i
precedenti, ed inoltre aggiunge a \func{select} una nuova funzione
l'header \file{sys/select.h}, compaiono in Linux a partire dalle \acr{glibc}
2.1. Le \acr{libc4} e \acr{libc5} non contengono questo header, le
\acr{glibc} 2.0 contengono una definizione sbagliata di \func{psignal},
l'header \file{sys/select.h}, compaiono in Linux a partire dalle \acr{glibc}
2.1. Le \acr{libc4} e \acr{libc5} non contengono questo header, le
\acr{glibc} 2.0 contengono una definizione sbagliata di \func{psignal},
- senza l'argomento \param{sigmask}, la definizione corretta è presente dalle
- \acr{glibc} 2.1-2.2.1 se si è definito \macro{\_GNU\_SOURCE} e nelle
- \acr{glibc} 2.2.2-2.2.4 se si è definito \macro{\_XOPEN\_SOURCE} con valore
- maggiore di 600.} il cui prototipo è:
+ senza l'argomento \param{sigmask}, la definizione corretta è presente dalle
+ \acr{glibc} 2.1-2.2.1 se si è definito \macro{\_GNU\_SOURCE} e nelle
+ \acr{glibc} 2.2.2-2.2.4 se si è definito \macro{\_XOPEN\_SOURCE} con valore
+ maggiore di 600.} il cui prototipo è:
\begin{prototype}{sys/select.h}
{int pselect(int n, fd\_set *readfds, fd\_set *writefds, fd\_set *exceptfds,
struct timespec *timeout, sigset\_t *sigmask)}
\begin{prototype}{sys/select.h}
{int pselect(int n, fd\_set *readfds, fd\_set *writefds, fd\_set *exceptfds,
struct timespec *timeout, sigset\_t *sigmask)}
\bodydesc{La funzione in caso di successo restituisce il numero di file
descriptor (anche nullo) che sono attivi, e -1 in caso di errore, nel qual
\bodydesc{La funzione in caso di successo restituisce il numero di file
descriptor (anche nullo) che sono attivi, e -1 in caso di errore, nel qual
- \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale.
- \item[\errcode{EINVAL}] si è specificato per \param{ndfs} un valore negativo
+ \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale.
+ \item[\errcode{EINVAL}] si è specificato per \param{ndfs} un valore negativo
struttura \struct{timespec} (vedi fig.~\ref{fig:sys_timespec_struct}) per
indicare con maggiore precisione il timeout e non ne aggiorna il valore in
struttura \struct{timespec} (vedi fig.~\ref{fig:sys_timespec_struct}) per
indicare con maggiore precisione il timeout e non ne aggiorna il valore in
valore al tempo rimanente, ma la funzione fornita dalle \acr{glibc} modifica
questo comportamento passando alla system call una variabile locale, in modo
da mantenere l'aderenza allo standard POSIX che richiede che il valore di
\param{timeout} non sia modificato.} Inoltre prende un argomento aggiuntivo
valore al tempo rimanente, ma la funzione fornita dalle \acr{glibc} modifica
questo comportamento passando alla system call una variabile locale, in modo
da mantenere l'aderenza allo standard POSIX che richiede che il valore di
\param{timeout} non sia modificato.} Inoltre prende un argomento aggiuntivo
sez.~\ref{sec:sig_sigmask}). La maschera corrente viene sostituita da questa
immediatamente prima di eseguire l'attesa, e ripristinata al ritorno della
funzione.
sez.~\ref{sec:sig_sigmask}). La maschera corrente viene sostituita da questa
immediatamente prima di eseguire l'attesa, e ripristinata al ritorno della
funzione.
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
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
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
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
e si potrebbero eseguire di conseguenza le operazioni relative al segnale e
alla gestione dati con un ciclo del tipo:
\includecodesnip{listati/select_race.c}
e si potrebbero eseguire di conseguenza le operazioni relative al segnale e
alla gestione dati con un ciclo del tipo:
\includecodesnip{listati/select_race.c}
-qui però emerge una \itindex{race~condition} \textit{race condition}, perché
-se il segnale arriva prima della chiamata a \func{select}, questa non verrà
-interrotta, e la ricezione del segnale non sarà rilevata.
+qui però emerge una \itindex{race~condition} \textit{race condition}, perché
+se il segnale arriva prima della chiamata a \func{select}, questa non verrà
+interrotta, e la ricezione del segnale non sarà rilevata.
kernel 2.6.16, non era presente la relativa system call, e la funzione era
implementata nelle \acr{glibc} attraverso \func{select} (vedi \texttt{man
kernel 2.6.16, non era presente la relativa system call, e la funzione era
implementata nelle \acr{glibc} attraverso \func{select} (vedi \texttt{man
- select\_tut}) per cui la possibilità di \itindex{race~condition}
- \textit{race condition} permaneva; in tale situazione si può ricorrere ad una
+ 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 sez.~\ref{sec:ipc_pipes})
soluzione alternativa, chiamata \itindex{self-pipe trick} \textit{self-pipe
trick}, che consiste nell'aprire una pipe (vedi sez.~\ref{sec:ipc_pipes})
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
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ì
+ 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:
\includecodesnip{listati/pselect_norace.c}
in questo caso utilizzando \var{oldmask} durante l'esecuzione di
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{select}, che è una estensione tipica di BSD, è stata introdotta un'altra
-interfaccia, basata sulla funzione \funcd{poll},\footnote{la funzione è
- prevista dallo standard XPG4, ed è stata introdotta in Linux come system
+\func{select}, che è una estensione tipica di BSD, è stata introdotta un'altra
+interfaccia, basata sulla funzione \funcd{poll},\footnote{la funzione è
+ prevista dallo standard XPG4, ed è stata introdotta in Linux come system
\begin{prototype}{sys/poll.h}
{int poll(struct pollfd *ufds, unsigned int nfds, int timeout)}
La funzione attende un cambiamento di stato su un insieme di file
descriptor.
\begin{prototype}{sys/poll.h}
{int poll(struct pollfd *ufds, unsigned int nfds, int timeout)}
La funzione attende un cambiamento di stato su un insieme di file
descriptor.
- \bodydesc{La funzione restituisce il numero di file descriptor con attività
- in caso di successo, o 0 se c'è stato un timeout e -1 in caso di errore,
- ed in quest'ultimo caso \var{errno} assumerà uno dei valori:
+ \bodydesc{La funzione restituisce il numero di file descriptor con attività
+ in caso di successo, o 0 se c'è stato un timeout e -1 in caso di errore,
+ ed in quest'ultimo caso \var{errno} assumerà uno dei valori:
La funzione permette di tenere sotto controllo contemporaneamente \param{ndfs}
file descriptor, specificati attraverso il puntatore \param{ufds} ad un
La funzione permette di tenere sotto controllo contemporaneamente \param{ndfs}
file descriptor, specificati attraverso il puntatore \param{ufds} ad un
interrompere l'attesa dopo un certo tempo, questo deve essere specificato con
l'argomento \param{timeout} in numero di millisecondi: un valore negativo
indica un'attesa indefinita, mentre un valore nullo comporta il ritorno
interrompere l'attesa dopo un certo tempo, questo deve essere specificato con
l'argomento \param{timeout} in numero di millisecondi: un valore negativo
indica un'attesa indefinita, mentre un valore nullo comporta il ritorno
\textsl{non-bloccante}).
Per ciascun file da controllare deve essere inizializzata una struttura
\struct{pollfd} nel vettore indicato dall'argomento \param{ufds}. La
\textsl{non-bloccante}).
Per ciascun file da controllare deve essere inizializzata una struttura
\struct{pollfd} nel vettore indicato dall'argomento \param{ufds}. La
prevede tre campi: in \var{fd} deve essere indicato il numero del file
descriptor da controllare, in \var{events} deve essere specificata una
maschera binaria di flag che indichino il tipo di evento che si vuole
prevede tre campi: in \var{fd} deve essere indicato il numero del file
descriptor da controllare, in \var{events} deve essere specificata una
maschera binaria di flag che indichino il tipo di evento che si vuole
binarie dei campi \var{events} e \var{revents} sono riportati in
tab.~\ref{tab:file_pollfd_flags}, insieme al loro significato. Le si sono
suddivise in tre gruppi, nel primo gruppo si sono indicati i bit utilizzati
binarie dei campi \var{events} e \var{revents} sono riportati in
tab.~\ref{tab:file_pollfd_flags}, insieme al loro significato. Le si sono
suddivise in tre gruppi, nel primo gruppo si sono indicati i bit utilizzati
uscita, mentre il terzo gruppo contiene dei valori che vengono utilizzati solo
nel campo \var{revents} per notificare delle condizioni di errore.
uscita, mentre il terzo gruppo contiene dei valori che vengono utilizzati solo
nel campo \var{revents} per notificare delle condizioni di errore.
\const{POLLRDNORM}& Sono disponibili in lettura dati normali.\\
\const{POLLRDBAND}& Sono disponibili in lettura dati prioritari.\\
\const{POLLRDNORM}& Sono disponibili in lettura dati normali.\\
\const{POLLRDBAND}& Sono disponibili in lettura dati prioritari.\\
- \const{POLLOUT} & È possibile la scrittura immediata.\\
- \const{POLLWRNORM}& È possibile la scrittura di dati normali.\\
- \const{POLLWRBAND}& È possibile la scrittura di dati prioritari.\\
+ \const{POLLOUT} & È possibile la scrittura immediata.\\
+ \const{POLLWRNORM}& È possibile la scrittura di dati normali.\\
+ \const{POLLWRBAND}& È possibile la scrittura di dati prioritari.\\
- \const{POLLERR} & C'è una condizione di errore.\\
- \const{POLLHUP} & Si è verificato un hung-up.\\
- \const{POLLRDHUP} & Si è avuta una \textsl{half-close} su un
+ \const{POLLERR} & C'è una condizione di errore.\\
+ \const{POLLHUP} & Si è verificato un hung-up.\\
+ \const{POLLRDHUP} & Si è avuta una \textsl{half-close} su un
\textit{half-close} (\textsl{mezza chiusura}) su cui torneremo con maggiori
dettagli in sez.~\ref{sec:TCP_shutdown}.}
\textit{half-close} (\textsl{mezza chiusura}) su cui torneremo con maggiori
dettagli in sez.~\ref{sec:TCP_shutdown}.}
-Il valore \const{POLLMSG} non viene utilizzato ed è definito solo per
-compatibilità con l'implementazione di SysV che usa gli
+Il valore \const{POLLMSG} non viene utilizzato ed è definito solo per
+compatibilità con l'implementazione di SysV che usa gli
\textit{stream};\footnote{essi sono una interfaccia specifica di SysV non
presente in Linux, e non hanno nulla a che fare con i file \textit{stream}
\textit{stream};\footnote{essi sono una interfaccia specifica di SysV non
presente in Linux, e non hanno nulla a che fare con i file \textit{stream}
costanti, in quanto per essi sono definite tre classi di dati:
\textsl{normali}, \textit{prioritari} ed \textit{urgenti}. In Linux la
distinzione ha senso solo per i dati urgenti \itindex{out-of-band} dei socket
costanti, in quanto per essi sono definite tre classi di dati:
\textsl{normali}, \textit{prioritari} ed \textit{urgenti}. In Linux la
distinzione ha senso solo per i dati urgenti \itindex{out-of-band} dei socket
in stile SysV (in particolare le ultime due non vengono usate su Linux), e
sono utilizzabili soltanto qualora si sia definita la macro
\macro{\_XOPEN\_SOURCE}.\footnote{e ci si ricordi di farlo sempre in testa al
in stile SysV (in particolare le ultime due non vengono usate su Linux), e
sono utilizzabili soltanto qualora si sia definita la macro
\macro{\_XOPEN\_SOURCE}.\footnote{e ci si ricordi di farlo sempre in testa al
-positivo) per i quali si è verificata una delle condizioni di attesa richieste
-o per i quali si è verificato un errore, nel qual caso vengono utilizzati i
+positivo) per i quali si è verificata una delle condizioni di attesa richieste
+o per i quali si è verificato un errore, nel qual caso vengono utilizzati i
\textit{file descriptor set} e la dimensione dei dati passati al kernel
dipende solo dal numero dei file descriptor che si vogliono controllare, non
dal loro valore.\footnote{anche se usando dei bit un \textit{file descriptor
\textit{file descriptor set} e la dimensione dei dati passati al kernel
dipende solo dal numero dei file descriptor che si vogliono controllare, non
dal loro valore.\footnote{anche se usando dei bit un \textit{file descriptor
-da capo. Questa operazione, che può essere molto onerosa se i file descriptor
-da tenere sotto osservazione sono molti, non è invece necessaria con
+da capo. Questa operazione, che può essere molto onerosa se i file descriptor
+da tenere sotto osservazione sono molti, non è invece necessaria con
\func{poll}.
Abbiamo visto in sez.~\ref{sec:file_select} come lo standard POSIX preveda una
variante di \func{select} che consente di gestire correttamente la ricezione
dei segnali nell'attesa su un file descriptor. Con l'introduzione di una
\func{poll}.
Abbiamo visto in sez.~\ref{sec:file_select} come lo standard POSIX preveda una
variante di \func{select} che consente di gestire correttamente la ricezione
dei segnali nell'attesa su un file descriptor. Con l'introduzione di una
-In questo caso si tratta di una estensione che è specifica di Linux e non è
-prevista da nessuno standard; essa può essere utilizzata esclusivamente se si
+In questo caso si tratta di una estensione che è specifica di Linux e non è
+prevista da nessuno standard; essa può essere utilizzata esclusivamente se si
\begin{prototype}{sys/poll.h}
{int ppoll(struct pollfd *fds, nfds\_t nfds, const struct timespec *timeout,
const sigset\_t *sigmask)}
\begin{prototype}{sys/poll.h}
{int ppoll(struct pollfd *fds, nfds\_t nfds, const struct timespec *timeout,
const sigset\_t *sigmask)}
- \bodydesc{La funzione restituisce il numero di file descriptor con attività
- in caso di successo, o 0 se c'è stato un timeout e -1 in caso di errore,
- ed in quest'ultimo caso \var{errno} assumerà uno dei valori:
+ \bodydesc{La funzione restituisce il numero di file descriptor con attività
+ in caso di successo, o 0 se c'è stato un timeout e -1 in caso di errore,
+ ed in quest'ultimo caso \var{errno} assumerà uno dei valori:
\item[\errcode{EINVAL}] il valore di \param{nfds} eccede il limite
\macro{RLIMIT\_NOFILE}.
\end{errlist}
ed inoltre \errval{EFAULT} e \errval{ENOMEM}.}
\end{prototype}
\item[\errcode{EINVAL}] il valore di \param{nfds} eccede il limite
\macro{RLIMIT\_NOFILE}.
\end{errlist}
ed inoltre \errval{EFAULT} e \errval{ENOMEM}.}
\end{prototype}
-segnali; questa sarà la maschera utilizzata per tutto il tempo che la funzione
-resterà in attesa, all'uscita viene ripristinata la maschera originale. L'uso
-di questa funzione è cioè equivalente, come illustrato nella pagina di
+segnali; questa sarà la maschera utilizzata per tutto il tempo che la funzione
+resterà in attesa, all'uscita viene ripristinata la maschera originale. L'uso
+di questa funzione è cioè equivalente, come illustrato nella pagina di
manuale, all'esecuzione atomica del seguente codice:
\includecodesnip{listati/ppoll_means.c}
manuale, all'esecuzione atomica del seguente codice:
\includecodesnip{listati/ppoll_means.c}
descriptor ecceda le dimensioni massime di un \itindex{file~descriptor~set}
\textit{file descriptor set}.} in particolare nel caso in cui solo pochi di
descriptor ecceda le dimensioni massime di un \itindex{file~descriptor~set}
\textit{file descriptor set}.} in particolare nel caso in cui solo pochi di
-questi diventano attivi. Il problema in questo caso è che il tempo impiegato
-da \func{poll} a trasferire i dati da e verso il kernel è proporzionale al
-numero di file descriptor osservati, non a quelli che presentano attività.
+questi diventano attivi. Il problema in questo caso è che il tempo impiegato
+da \func{poll} a trasferire i dati da e verso il kernel è proporzionale al
+numero di file descriptor osservati, non a quelli che presentano attività.
-eventi al secondo,\footnote{il caso classico è quello di un server web di un
- sito con molti accessi.} l'uso di \func{poll} comporta la necessità di
+eventi al secondo,\footnote{il caso classico è quello di un server web di un
+ sito con molti accessi.} l'uso di \func{poll} comporta la necessità di
trasferire avanti ed indietro da user space a kernel space la lunga lista
delle strutture \struct{pollfd} migliaia di volte al secondo. A questo poi si
trasferire avanti ed indietro da user space a kernel space la lunga lista
delle strutture \struct{pollfd} migliaia di volte al secondo. A questo poi si
ad eseguire una scansione su tutti i file descriptor tenuti sotto controllo
per determinare quali di essi (in genere una piccola percentuale) sono
diventati attivi. In una situazione come questa l'uso delle funzioni classiche
ad eseguire una scansione su tutti i file descriptor tenuti sotto controllo
per determinare quali di essi (in genere una piccola percentuale) sono
diventati attivi. In una situazione come questa l'uso delle funzioni classiche
Per risolvere questo tipo di situazioni sono state ideate delle interfacce
specialistiche\footnote{come \texttt{/dev/poll} in Solaris, o \texttt{kqueue}
Per risolvere questo tipo di situazioni sono state ideate delle interfacce
specialistiche\footnote{come \texttt{/dev/poll} in Solaris, o \texttt{kqueue}
prevedono che si registrino una sola volta i file descriptor da tenere sotto
osservazione, e forniscono un meccanismo che notifica quali di questi
prevedono che si registrino una sola volta i file descriptor da tenere sotto
osservazione, e forniscono un meccanismo che notifica quali di questi
descriptor che sono \textsl{pronti} per l'operazione richiesta, e questo
avviene indipendentemente dalle operazioni che possono essere state fatte su
di essi a partire dalla precedente notifica. Per chiarire meglio il concetto
ricorriamo ad un esempio: se su un file descriptor sono diventati disponibili
descriptor che sono \textsl{pronti} per l'operazione richiesta, e questo
avviene indipendentemente dalle operazioni che possono essere state fatte su
di essi a partire dalla precedente notifica. Per chiarire meglio il concetto
ricorriamo ad un esempio: se su un file descriptor sono diventati disponibili
-in lettura 2000 byte ma dopo la notifica ne sono letti solo 1000 (ed è quindi
-possibile eseguire una ulteriore lettura dei restanti 1000), in modalità
-\textit{level triggered} questo sarà nuovamente notificato come
+in lettura 2000 byte ma dopo la notifica ne sono letti solo 1000 (ed è quindi
+possibile eseguire una ulteriore lettura dei restanti 1000), in modalità
+\textit{level triggered} questo sarà nuovamente notificato come
notificato come pronto, nonostante siano ancora disponibili in lettura 1000
byte. Solo una volta che si saranno esauriti tutti i dati disponibili, e che
notificato come pronto, nonostante siano ancora disponibili in lettura 1000
byte. Solo una volta che si saranno esauriti tutti i dati disponibili, e che
ulteriore notifica qualora ritornasse pronto.
Nel caso di Linux al momento la sola interfaccia che fornisce questo tipo di
ulteriore notifica qualora ritornasse pronto.
Nel caso di Linux al momento la sola interfaccia che fornisce questo tipo di
-servizio è \textit{epoll},\footnote{l'interfaccia è stata creata da Davide
- Libenzi, ed è stata introdotta per la prima volta nel kernel 2.5.44, ma la
- sua forma definitiva è stata raggiunta nel kernel 2.5.66.} anche se sono in
+servizio è \textit{epoll},\footnote{l'interfaccia è stata creata da Davide
+ Libenzi, ed è stata introdotta per la prima volta nel kernel 2.5.44, ma la
+ sua forma definitiva è stata raggiunta nel kernel 2.5.66.} anche se sono in
discussione altre interfacce con le quali si potranno effettuare lo stesso
tipo di operazioni;\footnote{al momento della stesura di queste note (Giugno
discussione altre interfacce con le quali si potranno effettuare lo stesso
tipo di operazioni;\footnote{al momento della stesura di queste note (Giugno
- stesse funzionalità di \textit{epoll}, esiste però una forte discussione
- intorno a tutto ciò e niente di definito.} \textit{epoll} è in grado di
-operare sia in modalità \textit{level triggered} che \textit{edge triggered}.
+ stesse funzionalità di \textit{epoll}, esiste però una forte discussione
+ intorno a tutto ciò e niente di definito.} \textit{epoll} è in grado di
+operare sia in modalità \textit{level triggered} che \textit{edge triggered}.
La prima versione \textit{epoll} prevedeva l'apertura di uno speciale file di
dispositivo, \texttt{/dev/epoll}, per ottenere un file descriptor da
utilizzare con le funzioni dell'interfaccia,\footnote{il backporting
dell'interfaccia per il kernel 2.4, non ufficiale, utilizza sempre questo
La prima versione \textit{epoll} prevedeva l'apertura di uno speciale file di
dispositivo, \texttt{/dev/epoll}, per ottenere un file descriptor da
utilizzare con le funzioni dell'interfaccia,\footnote{il backporting
dell'interfaccia per il kernel 2.4, non ufficiale, utilizza sempre questo
- file.} ma poi si è passati all'uso di apposite \textit{system call}. Il
-primo passo per usare l'interfaccia di \textit{epoll} è pertanto quello
+ file.} ma poi si è passati all'uso di apposite \textit{system call}. Il
+primo passo per usare l'interfaccia di \textit{epoll} è pertanto quello
ottenere detto file descriptor chiamando una delle funzioni
\funcd{epoll\_create} e \funcd{epoll\_create1},\footnote{l'interfaccia di
ottenere detto file descriptor chiamando una delle funzioni
\funcd{epoll\_create} e \funcd{epoll\_create1},\footnote{l'interfaccia di
- \textit{epoll} è stata inserita nel kernel a partire dalla versione 2.5.44,
- ed il supporto è stato aggiunto alle \acr{glibc} 2.3.2.} i cui prototipi
+ \textit{epoll} è stata inserita nel kernel a partire dalla versione 2.5.44,
+ ed il supporto è stato aggiunto alle \acr{glibc} 2.3.2.} i cui prototipi
\bodydesc{Le funzioni restituiscono un file descriptor per \textit{epoll} in
caso di successo, o $-1$ in caso di errore, nel qual caso \var{errno}
\bodydesc{Le funzioni restituiscono un file descriptor per \textit{epoll} in
caso di successo, o $-1$ in caso di errore, nel qual caso \var{errno}
istanze di \textit{epoll} per utente stabilito da
\procfile{/proc/sys/fs/epoll/max\_user\_instances}.
istanze di \textit{epoll} per utente stabilito da
\procfile{/proc/sys/fs/epoll/max\_user\_instances}.
- non è associato a nessun file su disco, inoltre a differenza dei normali
- file descriptor non può essere inviato ad un altro processo attraverso un
+ non è associato a nessun file su disco, inoltre a differenza dei normali
+ file descriptor non può essere inviato ad un altro processo attraverso un
socket locale (vedi sez.~\ref{sec:sock_fd_passing}).} detto anche
\textit{epoll descriptor}, che viene associato alla infrastruttura utilizzata
dal kernel per gestire la notifica degli eventi. Nel caso di
socket locale (vedi sez.~\ref{sec:sock_fd_passing}).} detto anche
\textit{epoll descriptor}, che viene associato alla infrastruttura utilizzata
dal kernel per gestire la notifica degli eventi. Nel caso di
numero di file descriptor che si vorranno tenere sotto controllo, e costituiva
solo un suggerimento per semplificare l'allocazione di risorse sufficienti,
non un valore massimo.\footnote{ma a partire dal kernel 2.6.8 esso viene
numero di file descriptor che si vorranno tenere sotto controllo, e costituiva
solo un suggerimento per semplificare l'allocazione di risorse sufficienti,
non un valore massimo.\footnote{ma a partire dal kernel 2.6.8 esso viene
-La seconda versione della funzione, \func{epoll\_create1} è stata
-introdotta\footnote{è disponibile solo a partire dal kernel 2.6.27.} come
+La seconda versione della funzione, \func{epoll\_create1} è stata
+introdotta\footnote{è disponibile solo a partire dal kernel 2.6.27.} come
estensione della precedente, per poter passare dei flag di controllo come
maschera binaria in fase di creazione del file descriptor. Al momento l'unico
estensione della precedente, per poter passare dei flag di controllo come
maschera binaria in fase di creazione del file descriptor. Al momento l'unico
che consente di impostare in maniera atomica sul file descriptor il flag di
\itindex{close-on-exec} \textit{close-on-exec} (si veda il significato di
\const{O\_CLOEXEC} in tab.~\ref{tab:file_open_flags}), senza che sia
necessaria una successiva chiamata a \func{fcntl}.
che consente di impostare in maniera atomica sul file descriptor il flag di
\itindex{close-on-exec} \textit{close-on-exec} (si veda il significato di
\const{O\_CLOEXEC} in tab.~\ref{tab:file_open_flags}), senza che sia
necessaria una successiva chiamata a \func{fcntl}.
indicare quali file descriptor mettere sotto osservazione e quali operazioni
controllare, per questo si deve usare la seconda funzione dell'interfaccia,
indicare quali file descriptor mettere sotto osservazione e quali operazioni
controllare, per questo si deve usare la seconda funzione dell'interfaccia,
\begin{prototype}{sys/epoll.h}
{int epoll\_ctl(int epfd, int op, int fd, struct epoll\_event *event)}
Esegue le operazioni di controllo di \textit{epoll}.
\bodydesc{La funzione restituisce $0$ in caso di successo o $-1$ in caso di
\begin{prototype}{sys/epoll.h}
{int epoll\_ctl(int epfd, int op, int fd, struct epoll\_event *event)}
Esegue le operazioni di controllo di \textit{epoll}.
\bodydesc{La funzione restituisce $0$ in caso di successo o $-1$ in caso di
- \item[\errcode{EEXIST}] l'operazione richiesta è \const{EPOLL\_CTL\_ADD} ma
- \param{fd} è già stato inserito in \param{epfd}.
- \item[\errcode{EINVAL}] il file descriptor \param{epfd} non è stato ottenuto
- con \func{epoll\_create}, o \param{fd} è lo stesso \param{epfd} o
- l'operazione richiesta con \param{op} non è supportata.
- \item[\errcode{ENOENT}] l'operazione richiesta è \const{EPOLL\_CTL\_MOD} o
- \const{EPOLL\_CTL\_DEL} ma \param{fd} non è inserito in \param{epfd}.
- \item[\errcode{ENOMEM}] non c'è sufficiente memoria nel kernel gestire
+ \item[\errcode{EEXIST}] l'operazione richiesta è \const{EPOLL\_CTL\_ADD} ma
+ \param{fd} è già stato inserito in \param{epfd}.
+ \item[\errcode{EINVAL}] il file descriptor \param{epfd} non è stato ottenuto
+ con \func{epoll\_create}, o \param{fd} è lo stesso \param{epfd} o
+ l'operazione richiesta con \param{op} non è supportata.
+ \item[\errcode{ENOENT}] l'operazione richiesta è \const{EPOLL\_CTL\_MOD} o
+ \const{EPOLL\_CTL\_DEL} ma \param{fd} non è inserito in \param{epfd}.
+ \item[\errcode{ENOMEM}] non c'è sufficiente memoria nel kernel gestire
per utente di file descriptor da osservare imposto da
\procfile{/proc/sys/fs/epoll/max\_user\_watches}.
\end{errlist}
per utente di file descriptor da osservare imposto da
\procfile{/proc/sys/fs/epoll/max\_user\_watches}.
\end{errlist}
\param{fd} alla lista dei file descriptor
controllati tramite \param{epfd}, in
\param{event} devono essere specificate le
\param{fd} alla lista dei file descriptor
controllati tramite \param{epfd}, in
\param{event} devono essere specificate le
- modalità di osservazione.\\
- \const{EPOLL\_CTL\_MOD}& Modifica le modalità di osservazione del file
+ modalità di osservazione.\\
+ \const{EPOLL\_CTL\_MOD}& Modifica le modalità di osservazione del file
descriptor \param{fd} secondo il contenuto di
\param{event}.\\
\const{EPOLL\_CTL\_DEL}& Rimuove il file descriptor \param{fd} dalla lista
descriptor \param{fd} secondo il contenuto di
\param{event}.\\
\const{EPOLL\_CTL\_DEL}& Rimuove il file descriptor \param{fd} dalla lista
La funzione prende sempre come primo argomento un file descriptor di
\textit{epoll}, \param{epfd}, che deve essere stato ottenuto in precedenza con
una chiamata a \func{epoll\_create}. L'argomento \param{fd} indica invece il
La funzione prende sempre come primo argomento un file descriptor di
\textit{epoll}, \param{epfd}, che deve essere stato ottenuto in precedenza con
una chiamata a \func{epoll\_create}. L'argomento \param{fd} indica invece il
un qualunque file descriptor utilizzabile con \func{poll}, ed anche un altro
file descriptor di \textit{epoll}, ma non lo stesso \param{epfd}.
un qualunque file descriptor utilizzabile con \func{poll}, ed anche un altro
file descriptor di \textit{epoll}, ma non lo stesso \param{epfd}.
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
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
- vuole mantenere la compatibilità con le versioni precedenti occorre usare un
+ partire dal 2.6.9 si può specificare anche un valore \texttt{NULL} ma se si
+ vuole mantenere la compatibilità con le versioni precedenti occorre usare un
quest'ultima serve sia in ingresso (quando usata con \func{epoll\_ctl}) ad
impostare quali eventi osservare, che in uscita (nei risultati ottenuti con
\func{epoll\_wait}) per ricevere le notifiche degli eventi avvenuti. La sua
quest'ultima serve sia in ingresso (quando usata con \func{epoll\_ctl}) ad
impostare quali eventi osservare, che in uscita (nei risultati ottenuti con
\func{epoll\_wait}) per ricevere le notifiche degli eventi avvenuti. La sua
-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
+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
-ed in astratto può contenere un valore qualsiasi (specificabile in diverse
-forme) che ne permetta una indicazione univoca. Il modo più comune di usarlo
-però è quello in cui si specifica il terzo argomento di \func{epoll\_ctl}
+ed in astratto può contenere un valore qualsiasi (specificabile in diverse
+forme) che ne permetta una indicazione univoca. Il modo più comune di usarlo
+però è quello in cui si specifica il terzo argomento di \func{epoll\_ctl}
nella forma \var{event.data.fd}, assegnando come valore di questo campo lo
stesso valore dell'argomento \param{fd}, cosa che permette una immediata
identificazione del file descriptor.
nella forma \var{event.data.fd}, assegnando come valore di questo campo lo
stesso valore dell'argomento \param{fd}, cosa che permette una immediata
identificazione del file descriptor.
(analogo di \const{POLLOUT}).\\
\const{EPOLLRDHUP} & L'altro capo di un socket di tipo
\const{SOCK\_STREAM} (vedi sez.~\ref{sec:sock_type})
(analogo di \const{POLLOUT}).\\
\const{EPOLLRDHUP} & L'altro capo di un socket di tipo
\const{SOCK\_STREAM} (vedi sez.~\ref{sec:sock_type})
\const{EPOLLPRI} & Ci sono \itindex{out-of-band} dati urgenti
disponibili in lettura (analogo di
\const{POLLPRI}); questa condizione viene comunque
\const{EPOLLPRI} & Ci sono \itindex{out-of-band} dati urgenti
disponibili in lettura (analogo di
\const{POLLPRI}); questa condizione viene comunque
- è necessaria impostarla in ingresso.\\
- \const{EPOLLET} & Imposta la notifica in modalità \textit{edge
+ è necessaria impostarla in ingresso.\\
+ \const{EPOLLET} & Imposta la notifica in modalità \textit{edge
-\footnotetext{questa modalità è disponibile solo a partire dal kernel 2.6.17,
- ed è utile per riconoscere la chiusura di una connessione dall'altro capo
- quando si lavora in modalità \textit{edge triggered}.}
+\footnotetext{questa modalità è disponibile solo a partire dal kernel 2.6.17,
+ ed è utile per riconoscere la chiusura di una connessione dall'altro capo
+ quando si lavora in modalità \textit{edge triggered}.}
l'insieme dei file descriptor da tenere sotto controllo tramite un certo
\textit{epoll descriptor} \param{epfd} attraverso una serie di chiamate a
l'insieme dei file descriptor da tenere sotto controllo tramite un certo
\textit{epoll descriptor} \param{epfd} attraverso una serie di chiamate a
chiamate devono essere ripetute per ciascun file descriptor, incorrendo in
una perdita di prestazioni qualora il numero di file descriptor sia molto
chiamate devono essere ripetute per ciascun file descriptor, incorrendo in
una perdita di prestazioni qualora il numero di file descriptor sia molto
funzione \func{epoll\_ctlv} che consenta di effettuare con una sola chiamata
le impostazioni per un blocco di file descriptor.} L'uso di
funzione \func{epoll\_ctlv} che consenta di effettuare con una sola chiamata
le impostazioni per un blocco di file descriptor.} L'uso di
-\const{EPOLL\_CTL\_MOD} consente in seguito di modificare le modalità di
-osservazione di un file descriptor che sia già stato aggiunto alla lista di
+\const{EPOLL\_CTL\_MOD} consente in seguito di modificare le modalità di
+osservazione di un file descriptor che sia già stato aggiunto alla lista di
-sia effettuata in modalità \textit{level triggered}, a meno che sul file
-descriptor non si sia impostata la modalità \textit{edge triggered},
+sia effettuata in modalità \textit{level triggered}, a meno che sul file
+descriptor non si sia impostata la modalità \textit{edge triggered},
-Qualora non si abbia più interesse nell'osservazione di un file descriptor lo
-si può rimuovere dalla lista associata a \param{epfd} con
+Qualora non si abbia più interesse nell'osservazione di un file descriptor lo
+si può rimuovere dalla lista associata a \param{epfd} con
\const{EPOLL\_CTL\_DEL}; si tenga conto inoltre che i file descriptor sotto
osservazione che vengono chiusi sono eliminati dalla lista automaticamente e
\const{EPOLL\_CTL\_DEL}; si tenga conto inoltre che i file descriptor sotto
osservazione che vengono chiusi sono eliminati dalla lista automaticamente e
-quando si è in modalità \textit{edge triggered} l'arrivo in rapida successione
-di dati in blocchi separati\footnote{questo è tipico con i socket di rete, in
- quanto i dati arrivano a pacchetti.} può causare una generazione di eventi
+quando si è in modalità \textit{edge triggered} l'arrivo in rapida successione
+di dati in blocchi separati\footnote{questo è tipico con i socket di rete, in
+ quanto i dati arrivano a pacchetti.} può causare una generazione di eventi
-Anche se la situazione è facile da gestire, la si può evitare utilizzando
-\const{EPOLLONESHOT} per impostare la modalità \textit{one-shot}, in cui la
+Anche se la situazione è facile da gestire, la si può evitare utilizzando
+\const{EPOLLONESHOT} per impostare la modalità \textit{one-shot}, in cui la
notifica di un evento viene effettuata una sola volta, dopo di che il file
descriptor osservato, pur restando nella lista di osservazione, viene
automaticamente disattivato,\footnote{la cosa avviene contestualmente al
ritorno di \func{epoll\_wait} a causa dell'evento in questione.} e per
notifica di un evento viene effettuata una sola volta, dopo di che il file
descriptor osservato, pur restando nella lista di osservazione, viene
automaticamente disattivato,\footnote{la cosa avviene contestualmente al
ritorno di \func{epoll\_wait} a causa dell'evento in questione.} e per
chiamata con \const{EPOLL\_CTL\_MOD}.
Una volta impostato l'insieme di file descriptor che si vogliono osservare con
i relativi eventi, la funzione che consente di attendere l'occorrenza di uno
chiamata con \const{EPOLL\_CTL\_MOD}.
Una volta impostato l'insieme di file descriptor che si vogliono osservare con
i relativi eventi, la funzione che consente di attendere l'occorrenza di uno
\begin{prototype}{sys/epoll.h}
{int epoll\_wait(int epfd, struct epoll\_event * events, int maxevents, int
timeout)}
\begin{prototype}{sys/epoll.h}
{int epoll\_wait(int epfd, struct epoll\_event * events, int maxevents, int
timeout)}
\bodydesc{La funzione restituisce il numero di file descriptor pronti in
caso di successo o $-1$ in caso di errore, nel qual caso \var{errno}
\bodydesc{La funzione restituisce il numero di file descriptor pronti in
caso di successo o $-1$ in caso di errore, nel qual caso \var{errno}
- \item[\errcode{EBADF}] il file descriptor \param{epfd} non è valido.
- \item[\errcode{EFAULT}] il puntatore \param{events} non è valido.
- \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale prima
+ \item[\errcode{EBADF}] il file descriptor \param{epfd} non è valido.
+ \item[\errcode{EFAULT}] il puntatore \param{events} non è valido.
+ \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale prima
- \item[\errcode{EINVAL}] il file descriptor \param{epfd} non è stato ottenuto
- con \func{epoll\_create}, o \param{maxevents} non è maggiore di zero.
+ \item[\errcode{EINVAL}] il file descriptor \param{epfd} non è stato ottenuto
+ con \func{epoll\_create}, o \param{maxevents} non è maggiore di zero.
La funzione ritorna il numero di eventi rilevati, o un valore nullo qualora
sia scaduto il tempo massimo impostato con \param{timeout}. Per quest'ultimo,
La funzione ritorna il numero di eventi rilevati, o un valore nullo qualora
sia scaduto il tempo massimo impostato con \param{timeout}. Per quest'ultimo,
- caso il valore di ritorno sarà nullo.} o il valore $-1$, che indica
-un'attesa indefinita. L'argomento \param{maxevents} dovrà invece essere sempre
+ caso il valore di ritorno sarà nullo.} o il valore $-1$, che indica
+un'attesa indefinita. L'argomento \param{maxevents} dovrà invece essere sempre
un intero positivo.
Come accennato la funzione restituisce i suoi risultati nel vettore di
strutture \struct{epoll\_event} puntato da \param{events}; in tal caso nel
campo \param{events} di ciascuna di esse saranno attivi i flag relativi agli
un intero positivo.
Come accennato la funzione restituisce i suoi risultati nel vettore di
strutture \struct{epoll\_event} puntato da \param{events}; in tal caso nel
campo \param{events} di ciascuna di esse saranno attivi i flag relativi agli
-eventi accaduti, mentre nel campo \var{data} sarà restituito il valore che era
-stato impostato per il file descriptor per cui si è verificato l'evento quando
+eventi accaduti, mentre nel campo \var{data} sarà restituito il valore che era
+stato impostato per il file descriptor per cui si è verificato l'evento quando
questo era stato registrato con le operazioni \const{EPOLL\_CTL\_MOD} o
\const{EPOLL\_CTL\_ADD}, in questo modo il campo \var{data} consente di
questo era stato registrato con le operazioni \const{EPOLL\_CTL\_MOD} o
\const{EPOLL\_CTL\_ADD}, in questo modo il campo \var{data} consente di
-identificare il file descriptor.\footnote{ed è per questo che, come accennato,
- è consuetudine usare per \var{data} il valore del file descriptor stesso.}
+identificare il file descriptor.\footnote{ed è per questo che, come accennato,
+ è consuetudine usare per \var{data} il valore del file descriptor stesso.}
questi vengano combinati. Inoltre qualora su un file descriptor fossero
presenti eventi non ancora notificati, e si effettuasse una modifica
dell'osservazione con \const{EPOLL\_CTL\_MOD}, questi verrebbero riletti alla
luce delle modifiche.
questi vengano combinati. Inoltre qualora su un file descriptor fossero
presenti eventi non ancora notificati, e si effettuasse una modifica
dell'osservazione con \const{EPOLL\_CTL\_MOD}, questi verrebbero riletti alla
luce delle modifiche.
-Si tenga presente infine che con l'uso della modalità \textit{edge triggered}
-il ritorno di \func{epoll\_wait} indica che un file descriptor è pronto e
-resterà tale fintanto che non si sono completamente esaurite le operazioni su
+Si tenga presente infine che con l'uso della modalità \textit{edge triggered}
+il ritorno di \func{epoll\_wait} indica che un file descriptor è pronto e
+resterà tale fintanto che non si sono completamente esaurite le operazioni su
di esso. Questa condizione viene generalmente rilevata dall'occorrere di un
errore di \errcode{EAGAIN} al ritorno di una \func{read} o una
di esso. Questa condizione viene generalmente rilevata dall'occorrere di un
errore di \errcode{EAGAIN} al ritorno di una \func{read} o una
-\func{write},\footnote{è opportuno ricordare ancora una volta che l'uso
- dell'\textit{I/O multiplexing} richiede di operare sui file in modalità non
- bloccante.} ma questa non è la sola modalità possibile, ad esempio la
-condizione può essere riconosciuta anche per il fatto che sono stati
+\func{write},\footnote{è opportuno ricordare ancora una volta che l'uso
+ dell'\textit{I/O multiplexing} richiede di operare sui file in modalità non
+ bloccante.} ma questa non è la sola modalità possibile, ad esempio la
+condizione può essere riconosciuta anche per il fatto che sono stati
\textit{epoll} si pone il problema di gestire l'attesa di segnali e di dati
contemporaneamente per le osservazioni fatte in sez.~\ref{sec:file_select},
\textit{epoll} si pone il problema di gestire l'attesa di segnali e di dati
contemporaneamente per le osservazioni fatte in sez.~\ref{sec:file_select},
che consenta di reimpostare all'uscita una maschera di segnali, analoga alle
estensioni \func{pselect} e \func{ppoll} che abbiamo visto in precedenza per
\func{select} e \func{poll}; in questo caso la funzione si chiama
che consenta di reimpostare all'uscita una maschera di segnali, analoga alle
estensioni \func{pselect} e \func{ppoll} che abbiamo visto in precedenza per
\func{select} e \func{poll}; in questo caso la funzione si chiama
-\funcd{epoll\_pwait}\footnote{la funziona è stata introdotta a partire dal
- kernel 2.6.19, ed è come tutta l'interfaccia di \textit{epoll}, specifica di
- Linux.} ed il suo prototipo è:
+\funcd{epoll\_pwait}\footnote{la funziona è stata introdotta a partire dal
+ kernel 2.6.19, ed è come tutta l'interfaccia di \textit{epoll}, specifica di
+ Linux.} ed il suo prototipo è:
\begin{prototype}{sys/epoll.h}
{int epoll\_pwait(int epfd, struct epoll\_event * events, int maxevents,
int timeout, const sigset\_t *sigmask)}
\begin{prototype}{sys/epoll.h}
{int epoll\_pwait(int epfd, struct epoll\_event * events, int maxevents,
int timeout, const sigset\_t *sigmask)}
\bodydesc{La funzione restituisce il numero di file descriptor pronti in
caso di successo o $-1$ in caso di errore, nel qual caso \var{errno}
\bodydesc{La funzione restituisce il numero di file descriptor pronti in
caso di successo o $-1$ in caso di errore, nel qual caso \var{errno}
uscita viene ripristinata la maschera di segnali originale, sostituita durante
l'esecuzione da quella impostata con l'argomento \param{sigmask}; in sostanza
uscita viene ripristinata la maschera di segnali originale, sostituita durante
l'esecuzione da quella impostata con l'argomento \param{sigmask}; in sostanza
prevalentemente con i server di rete, quando si devono tenere sotto
osservazione un gran numero di socket; per questo motivo rimandiamo anche in
questo caso la trattazione di un esempio concreto a quando avremo esaminato in
prevalentemente con i server di rete, quando si devono tenere sotto
osservazione un gran numero di socket; per questo motivo rimandiamo anche in
questo caso la trattazione di un esempio concreto a quando avremo esaminato in
estensioni dello standard POSIX e funzioni apposite come \func{pselect},
\func{ppoll} e \funcd{epoll\_pwait}.
estensioni dello standard POSIX e funzioni apposite come \func{pselect},
\func{ppoll} e \funcd{epoll\_pwait}.
processi, la loro interfaccia di programmazione, che comporta l'esecuzione di
una funzione di gestione in maniera asincrona e totalmente scorrelata
processi, la loro interfaccia di programmazione, che comporta l'esecuzione di
una funzione di gestione in maniera asincrona e totalmente scorrelata
-dall'ordinario flusso di esecuzione del processo, si è però dimostrata quasi
-subito assai problematica. Oltre ai limiti relativi ai limiti al cosa si può
+dall'ordinario flusso di esecuzione del processo, si è però dimostrata quasi
+subito assai problematica. Oltre ai limiti relativi ai limiti al cosa si può
-sez.~\ref{sec:sig_signal_handler}), c'è il problema più generale consistente
-nel fatto che questa modalità di funzionamento cozza con altre interfacce di
+sez.~\ref{sec:sig_signal_handler}), c'è il problema più generale consistente
+nel fatto che questa modalità di funzionamento cozza con altre interfacce di
programmazione previste dal sistema in cui si opera in maniera
\textsl{sincrona}, come quelle dell'I/O multiplexing appena illustrate.
In questo tipo di interfacce infatti ci si aspetta che il processo gestisca
gli eventi a cui vuole rispondere in maniera sincrona generando le opportune
risposte, mentre con l'arrivo di un segnale si possono avere interruzioni
programmazione previste dal sistema in cui si opera in maniera
\textsl{sincrona}, come quelle dell'I/O multiplexing appena illustrate.
In questo tipo di interfacce infatti ci si aspetta che il processo gestisca
gli eventi a cui vuole rispondere in maniera sincrona generando le opportune
risposte, mentre con l'arrivo di un segnale si possono avere interruzioni
gestire, quando si deve tener conto di entrambi i tipi di eventi, le
interruzioni delle funzioni di attesa sincrone, ed evitare possibili
\itindex{race~condition} \textit{race conditions}.\footnote{in sostanza se non
fossero per i segnali non ci sarebbe da doversi preoccupare, fintanto che si
gestire, quando si deve tener conto di entrambi i tipi di eventi, le
interruzioni delle funzioni di attesa sincrone, ed evitare possibili
\itindex{race~condition} \textit{race conditions}.\footnote{in sostanza se non
fossero per i segnali non ci sarebbe da doversi preoccupare, fintanto che si
\textit{real-time} sono state introdotte anche delle interfacce di gestione
sincrona dei segnali con la funzione \func{sigwait} e le sue affini. Queste
funzioni consentono di gestire i segnali bloccando un processo fino alla
avvenuta ricezione e disabilitando l'esecuzione asincrona rispetto al resto
del programma del gestore del segnale. Questo consente di risolvere i problemi
\textit{real-time} sono state introdotte anche delle interfacce di gestione
sincrona dei segnali con la funzione \func{sigwait} e le sue affini. Queste
funzioni consentono di gestire i segnali bloccando un processo fino alla
avvenuta ricezione e disabilitando l'esecuzione asincrona rispetto al resto
del programma del gestore del segnale. Questo consente di risolvere i problemi
-di atomicità nella gestione degli eventi associati ai segnali, avendo tutto il
-controllo nel flusso principale del programma, ottenendo così una gestione
+di atomicità nella gestione degli eventi associati ai segnali, avendo tutto il
+controllo nel flusso principale del programma, ottenendo così una gestione
segnale o si aspetta che un file descriptor sia accessibile e nessuna delle
rispettive funzioni consente di fare contemporaneamente entrambe le cose.
segnale o si aspetta che un file descriptor sia accessibile e nessuna delle
rispettive funzioni consente di fare contemporaneamente entrambe le cose.
introdurre un meccanismo alternativo alla notifica dei segnali (esteso anche
ad altri eventi generici) che, ispirandosi di nuovo alla filosofia di Unix per
introdurre un meccanismo alternativo alla 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à
+cui tutto è un file, consentisse di eseguire la notifica con l'uso di
+opportuni file descriptor.\footnote{ovviamente si tratta di una funzionalità
gestore in occasione dell'arrivo di un segnale, e rilevarne l'avvenuta
ricezione leggendone la notifica tramite l'uso di uno speciale file
gestore in occasione dell'arrivo di un segnale, e rilevarne l'avvenuta
ricezione leggendone la notifica tramite l'uso di uno speciale file
osservazione con le ordinarie funzioni dell'\textit{I/O multiplexing} (vale a
dire con le solite \func{select}, \func{poll} e \funcd{epoll\_wait}) allo
osservazione con le ordinarie funzioni dell'\textit{I/O multiplexing} (vale a
dire con le solite \func{select}, \func{poll} e \funcd{epoll\_wait}) allo
-stesso modo di quelli associati a file o socket, per cui alla fine si potrà
-attendere in contemporanea sia l'arrivo del segnale che la disponibilità di
+stesso modo di quelli associati a file o socket, per cui alla fine si potrà
+attendere in contemporanea sia l'arrivo del segnale che la disponibilità di
accesso ai dati relativi a questi ultimi.
La funzione che permette di abilitare la ricezione dei segnali tramite file
accesso ai dati relativi a questi ultimi.
La funzione che permette di abilitare la ricezione dei segnali tramite file
l'interfaccia alla funzione fornita dalle \acr{glibc}, esistono infatti due
versioni diverse della \textit{system call}; una prima versione,
\func{signalfd}, introdotta nel kernel 2.6.22 e disponibile con le
\acr{glibc} 2.8 che non supporta l'argomento \texttt{flags}, ed una seconda
l'interfaccia alla funzione fornita dalle \acr{glibc}, esistono infatti due
versioni diverse della \textit{system call}; una prima versione,
\func{signalfd}, introdotta nel kernel 2.6.22 e disponibile con le
\acr{glibc} 2.8 che non supporta l'argomento \texttt{flags}, ed una seconda
che viene sempre usata a partire dalle \acr{glibc} 2.9, che prende un
argomento aggiuntivo \code{size\_t sizemask} che indica la dimensione della
maschera dei segnali, il cui valore viene impostato automaticamente dalle
che viene sempre usata a partire dalle \acr{glibc} 2.9, che prende un
argomento aggiuntivo \code{size\_t sizemask} che indica la dimensione della
maschera dei segnali, il cui valore viene impostato automaticamente dalle
\begin{prototype}{sys/signalfd.h}
{int signalfd(int fd, const sigset\_t *mask, int flags)}
Crea o modifica un file descriptor per la ricezione dei segnali.
\bodydesc{La funzione restituisce un numero di file descriptor in caso di
\begin{prototype}{sys/signalfd.h}
{int signalfd(int fd, const sigset\_t *mask, int flags)}
Crea o modifica un file descriptor per la ricezione dei segnali.
\bodydesc{La funzione restituisce un numero di file descriptor in caso di
- \item[\errcode{EINVAL}] il file descriptor \param{fd} non è stato ottenuto
- con \func{signalfd} o il valore di \param{flags} non è valido.
- \item[\errcode{ENOMEM}] non c'è memoria sufficiente per creare un nuovo file
+ \item[\errcode{EINVAL}] il file descriptor \param{fd} non è stato ottenuto
+ con \func{signalfd} o il valore di \param{flags} non è valido.
+ \item[\errcode{ENOMEM}] non c'è memoria sufficiente per creare un nuovo file
La funzione consente di creare o modificare le caratteristiche di un file
descriptor speciale su cui ricevere le notifiche della ricezione di
La funzione consente di creare o modificare le caratteristiche di un file
descriptor speciale su cui ricevere le notifiche della ricezione di
-segnali. Per creare ex-novo uno di questi file descriptor è necessario passare
-$-1$ come valore per l'argomento \param{fd}, ogni altro valore positivo verrà
+segnali. Per creare ex-novo uno di questi file descriptor è necessario passare
+$-1$ come valore per l'argomento \param{fd}, ogni altro valore positivo verrà
invece interpretato come il numero del file descriptor (che deve esser stato
precedentemente creato sempre con \func{signalfd}) di cui si vogliono
invece interpretato come il numero del file descriptor (che deve esser stato
precedentemente creato sempre con \func{signalfd}) di cui si vogliono
L'elenco dei segnali che si vogliono gestire con \func{signalfd} deve essere
specificato tramite l'argomento \param{mask}. Questo deve essere passato come
L'elenco dei segnali che si vogliono gestire con \func{signalfd} deve essere
specificato tramite l'argomento \param{mask}. Questo deve essere passato come
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 \const{SIGKILL} e
\const{SIGSTOP} non possono essere intercettati (e non prevedono neanche la
senza generare errori.
L'argomento \param{flags} consente di impostare direttamente in fase di
creazione due flag per il file descriptor analoghi a quelli che si possono
impostare con una creazione ordinaria con \func{open}, evitando una
senza generare errori.
L'argomento \param{flags} consente di impostare direttamente in fase di
creazione due flag per il file descriptor analoghi a quelli che si possono
impostare con una creazione ordinaria con \func{open}, evitando una
aggiuntivo, introdotto con la versione fornita a partire dal kernel 2.6.27,
per kernel precedenti il valore deve essere nullo.} L'argomento deve essere
specificato come maschera binaria dei valori riportati in
aggiuntivo, introdotto con la versione fornita a partire dal kernel 2.6.27,
per kernel precedenti il valore deve essere nullo.} L'argomento deve essere
specificato come maschera binaria dei valori riportati in
Si tenga presente che la chiamata a \func{signalfd} non disabilita la gestione
ordinaria dei segnali indicati da \param{mask}; questa, se si vuole effettuare
Si tenga presente che la chiamata a \func{signalfd} non disabilita la gestione
ordinaria dei segnali indicati da \param{mask}; questa, se si vuole effettuare
esplicitamente bloccando gli stessi segnali con \func{sigprocmask}, altrimenti
verranno comunque eseguite le azioni di default (o un eventuale gestore
installato in precedenza).\footnote{il blocco non ha invece nessun effetto sul
esplicitamente bloccando gli stessi segnali con \func{sigprocmask}, altrimenti
verranno comunque eseguite le azioni di default (o un eventuale gestore
installato in precedenza).\footnote{il blocco non ha invece nessun effetto sul
pertanto ricevere qualunque segnale, anche se questo risultasse bloccato.}
Si tenga presente inoltre che la lettura di una struttura
pertanto ricevere qualunque segnale, anche se questo risultasse bloccato.}
Si tenga presente inoltre che la lettura di una struttura
-\struct{signalfd\_siginfo} relativa ad un segnale pendente è equivalente alla
-esecuzione di un gestore, vale a dire che una volta letta il segnale non sarà
-più pendente e non potrà essere ricevuto, qualora si ripristino le normali
-condizioni di gestione, né da un gestore né dalla funzione \func{sigwaitinfo}.
+\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}.
-\func{poll} e \funcd{epoll\_wait}), e risulterà accessibile in lettura quando
-uno o più dei segnali indicati tramite \param{mask} sarà pendente.
-
-La funzione può essere chiamata più volte dallo stesso processo, consentendo
-così di tenere sotto osservazione segnali diversi tramite file descriptor
-diversi. Inoltre è anche possibile tenere sotto osservazione lo stesso segnale
-con più file descriptor, anche se la pratica è sconsigliata; in tal caso la
-ricezione del segnale potrà essere effettuata con una lettura da uno qualunque
-dei file descriptor a cui è associato, ma questa potrà essere eseguita
+\func{poll} e \funcd{epoll\_wait}), e risulterà accessibile in lettura quando
+uno o più dei segnali indicati tramite \param{mask} sarà pendente.
+
+La funzione può essere chiamata più volte dallo stesso processo, consentendo
+così di tenere sotto osservazione segnali diversi tramite file descriptor
+diversi. Inoltre è anche possibile tenere sotto osservazione lo stesso segnale
+con più file descriptor, anche se la pratica è sconsigliata; in tal caso la
+ricezione del segnale potrà essere effettuata con una lettura da uno qualunque
+dei file descriptor a cui è associato, ma questa potrà essere eseguita
- uno di essi il segnale sarà considerato ricevuto ed i relativi dati non
- saranno più disponibili sugli altri file descriptor, che (a meno di una
- ulteriore occorrenza del segnale nel frattempo) di non saranno più pronti.}
+ uno di essi il segnale sarà considerato ricevuto ed i relativi dati non
+ saranno più disponibili sugli altri file descriptor, che (a meno di una
+ ulteriore occorrenza del segnale nel frattempo) di non saranno più pronti.}
essere chiuso con \func{close} liberando tutte le risorse da esso allocate. In
tal caso qualora vi fossero segnali pendenti questi resteranno tali, e
potranno essere ricevuti normalmente una volta che si rimuova il blocco
essere chiuso con \func{close} liberando tutte le risorse da esso allocate. In
tal caso qualora vi fossero segnali pendenti questi resteranno tali, e
potranno essere ricevuti normalmente una volta che si rimuova il blocco
pendenti attraverso una \func{exec}.
Analogamente il file descriptor resta sempre disponibile attraverso una
pendenti attraverso una \func{exec}.
Analogamente il file descriptor resta sempre disponibile attraverso una
-\func{fork} per il processo figlio, che ne riceve una copia; in tal caso però
-il figlio potrà leggere dallo stesso soltanto i dati relativi ai segnali
+\func{fork} per il processo figlio, che ne riceve una copia; in tal caso però
+il figlio potrà leggere dallo stesso soltanto i dati relativi ai segnali
ricevuti da lui stesso. Nel caso di \textit{thread} viene nuovamente seguita
la semantica ordinaria dei segnali, che prevede che un singolo \textit{thread}
possa ricevere dal file descriptor solo le notifiche di segnali inviati
ricevuti da lui stesso. Nel caso di \textit{thread} viene nuovamente seguita
la semantica ordinaria dei segnali, che prevede che un singolo \textit{thread}
possa ricevere dal file descriptor solo le notifiche di segnali inviati
L'interfaccia fornita da \func{signalfd} prevede che la ricezione dei segnali
sia eseguita leggendo i dati relativi ai segnali pendenti dal file descriptor
restituito dalla funzione con una normalissima \func{read}. Qualora non vi
L'interfaccia fornita da \func{signalfd} prevede che la ricezione dei segnali
sia eseguita leggendo i dati relativi ai segnali pendenti dal file descriptor
restituito dalla funzione con una normalissima \func{read}. Qualora non vi
-siano segnali pendenti la \func{read} si bloccherà a meno di non aver
-impostato la modalità di I/O non bloccante sul file descriptor, o direttamente
+siano segnali pendenti la \func{read} si bloccherà a meno di non aver
+impostato la modalità di I/O non bloccante sul file descriptor, o direttamente
in fase di creazione con il flag \const{SFD\_NONBLOCK}, o in un momento
successivo con \func{fcntl}.
in fase di creazione con il flag \const{SFD\_NONBLOCK}, o in un momento
successivo con \func{fcntl}.
-secondo argomento di \func{read} nella forma di una sequenza di una o più
-strutture \struct{signalfd\_siginfo} (la cui definizione si è riportata in
+secondo argomento di \func{read} nella forma di una sequenza di una o più
+strutture \struct{signalfd\_siginfo} (la cui definizione si è riportata in
fig.~\ref{fig:signalfd_siginfo}) a seconda sia della dimensione del buffer che
del numero di segnali pendenti. Per questo motivo il buffer deve essere almeno
di dimensione pari a quella di \struct{signalfd\_siginfo}, qualora sia di
dimensione maggiore potranno essere letti in unica soluzione i dati relativi
fig.~\ref{fig:signalfd_siginfo}) a seconda sia della dimensione del buffer che
del numero di segnali pendenti. Per questo motivo il buffer deve essere almeno
di dimensione pari a quella di \struct{signalfd\_siginfo}, qualora sia di
dimensione maggiore potranno essere letti in unica soluzione i dati relativi
\struct{signalfd\_siginfo} che possono rientrare nel buffer.
Il contenuto di \struct{signalfd\_siginfo} ricalca da vicino quella della
analoga struttura \struct{siginfo\_t} (illustrata in
fig.~\ref{fig:sig_siginfo_t}) usata dall'interfaccia ordinaria dei segnali, e
restituisce dati simili. Come per \struct{siginfo\_t} i campi che vengono
\struct{signalfd\_siginfo} che possono rientrare nel buffer.
Il contenuto di \struct{signalfd\_siginfo} ricalca da vicino quella della
analoga struttura \struct{siginfo\_t} (illustrata in
fig.~\ref{fig:sig_siginfo_t}) usata dall'interfaccia ordinaria dei segnali, e
restituisce dati simili. Come per \struct{siginfo\_t} i campi che vengono
-avvalorati dipendono dal tipo di segnale e ricalcano i valori che abbiamo già
-illustrato in sez.~\ref{sec:sig_sigaction}.\footnote{si tenga presente però
+avvalorati dipendono dal tipo di segnale e ricalcano i valori che abbiamo già
+illustrato in sez.~\ref{sec:sig_sigaction}.\footnote{si tenga presente però
che per un bug i kernel fino al 2.6.25 non avvalorano correttamente i campi
\var{ssi\_ptr} e \var{ssi\_int} per segnali inviati con \func{sigqueue}.}
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}.}
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
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 di un segnale
-qualunque.\footnote{in realtà per questo sarebbe già sufficiente
- \func{signalfd} per ricevere i segnali associati ai timer, ma la nuova
- interfaccia semplifica notevolmente la gestione.}
+stesso tempo la disponibilità di dati o la ricezione 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 diminuisce l'\textit{overhead}.}
Le funzioni di questa interfaccia riprendono da vicino quelle introdotte da
POSIX.1-2001 illustrate sez.~\ref{sec:sig_timer_adv}. La prima funzione, che
Le funzioni di questa interfaccia riprendono da vicino quelle introdotte da
POSIX.1-2001 illustrate sez.~\ref{sec:sig_timer_adv}. La prima funzione, che
\begin{prototype}{sys/timerfd.h}
{int timerfd\_create(int clockid, int flags)}
Crea un timer associato ad un file descriptor per la notifica.
\bodydesc{La funzione restituisce un numero di file descriptor in caso di
\begin{prototype}{sys/timerfd.h}
{int timerfd\_create(int clockid, int flags)}
Crea un timer associato ad un file descriptor per la notifica.
\bodydesc{La funzione restituisce un numero di file descriptor in caso di
-deve fare riferimento, ed i soli valori validi sono \const{CLOCK\_REALTIME},
-per indicare
+deve fare riferimento, il cui significato è già stato illustrato in
+tab.~\ref{tab:sig_timer_clockid_types}, ma i soli valori validi sono
+\const{CLOCK\_REALTIME} e \const{CLOCK\_MONOTONIC}.
% vedi: http://lwn.net/Articles/233462/
% http://lwn.net/Articles/245533/
% http://lwn.net/Articles/267331/
% vedi: http://lwn.net/Articles/233462/
% http://lwn.net/Articles/245533/
% http://lwn.net/Articles/267331/
-Benché l'\textit{I/O multiplexing} sia stata la prima, e sia tutt'ora una fra
-le più diffuse modalità di gestire l'I/O in situazioni complesse in cui si
-debba operare su più file contemporaneamente, esistono altre modalità di
+Benché l'\textit{I/O multiplexing} sia stata la prima, e sia tutt'ora una fra
+le più diffuse modalità di gestire l'I/O in situazioni complesse in cui si
+debba operare su più file contemporaneamente, esistono altre modalità di
-contesto le modalità di accesso ai file eseguibili in maniera
-\textsl{asincrona}, quelle cioè in cui un processo non deve bloccarsi in
-attesa della disponibilità dell'accesso al file, ma può proseguire
+contesto le modalità di accesso ai file eseguibili in maniera
+\textsl{asincrona}, quelle cioè in cui un processo non deve bloccarsi in
+attesa della disponibilità dell'accesso al file, ma può proseguire
nell'esecuzione utilizzando invece un meccanismo di notifica asincrono (di
norma un segnale, ma esistono anche altre interfacce, come \itindex{inotify}
nell'esecuzione utilizzando invece un meccanismo di notifica asincrono (di
norma un segnale, ma esistono anche altre interfacce, come \itindex{inotify}
- dei comandi \const{F\_SETOWN} e \const{F\_GETOWN} per \func{fcntl} è
- specifico di Linux e BSD.} aprire un file in modalità asincrona, così come è
-possibile attivare in un secondo tempo questa modalità impostando questo flag
+ dei comandi \const{F\_SETOWN} e \const{F\_GETOWN} per \func{fcntl} è
+ specifico di Linux e BSD.} aprire un file in modalità asincrona, così come è
+possibile attivare in un secondo tempo questa modalità impostando questo flag
propriamente viene chiamato \textsl{I/O asincrono}, in
sez.~\ref{sec:file_asyncronous_io}), quanto dell'attivazione un meccanismo di
notifica asincrona delle variazione dello stato del file descriptor aperto in
questo modo.
propriamente viene chiamato \textsl{I/O asincrono}, in
sez.~\ref{sec:file_asyncronous_io}), quanto dell'attivazione un meccanismo di
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
+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
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
illustrato in sez.~\ref{sec:file_fcntl}, selezionare con il comando
\const{F\_SETOWN} di \func{fcntl} quale processo o quale gruppo di processi
illustrato in sez.~\ref{sec:file_fcntl}, 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
+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
Per questo motivo Stevens, ed anche le pagine di manuale di Linux, chiamano
file.
% TODO: per i thread l'uso di F_SETOWN ha un significato diverso
Per questo motivo Stevens, ed anche le pagine di manuale di Linux, chiamano
-questa modalità ``\textit{Signal driven I/O}''. Si tratta di un'altra
-modalità di gestione dell'I/O, alternativa all'uso di \itindex{epoll}
+questa modalità ``\textit{Signal driven I/O}''. Si tratta di un'altra
+modalità di gestione dell'I/O, alternativa all'uso di \itindex{epoll}
kernel che non supportano \textit{epoll}, come quelli della serie 2.4,
ottenendo comunque prestazioni superiori a quelle che si hanno con
\func{poll} e \func{select}.} che consente di evitare l'uso delle funzioni
kernel che non supportano \textit{epoll}, come quelli della serie 2.4,
ottenendo comunque prestazioni superiori a quelle che si hanno con
\func{poll} e \func{select}.} che consente di evitare l'uso delle funzioni
-Tuttavia con l'implementazione classica dei segnali questa modalità di I/O
-presenta notevoli problemi, dato che non è possibile determinare, quando i
-file descriptor sono più di uno, qual è quello responsabile dell'emissione del
+Tuttavia con l'implementazione classica dei segnali questa modalità di I/O
+presenta notevoli problemi, dato che non è possibile determinare, quando i
+file descriptor sono più di uno, qual è quello responsabile dell'emissione del
-illustrato in sez.~\ref{sec:sig_notification}), in presenza di più file
-descriptor attivi contemporaneamente, più segnali emessi nello stesso momento
+illustrato in sez.~\ref{sec:sig_notification}), in presenza di più file
+descriptor attivi contemporaneamente, più segnali emessi nello stesso momento
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}).
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}).
(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
(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
-gestore, tutte le volte che riceverà \const{SI\_SIGIO} come valore del campo
+I/O asincrono (il segnale predefinito è \const{SIGIO}). In questo caso il
+gestore, tutte le volte che riceverà \const{SI\_SIGIO} come valore del campo
- 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
+ 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
-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
+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
-anche questa funzionalità. In questo modo si può identificare immediatamente
-un file su cui l'accesso è diventato possibile evitando completamente l'uso di
+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
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
-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
+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
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
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
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
possibile. Al contrario di altri sistemi operativi infatti un kernel unix-like
classico non prevedeva alcun meccanismo per cui un processo possa essere
possibile. Al contrario di altri sistemi operativi infatti un kernel unix-like
classico non prevedeva alcun meccanismo per cui un processo possa essere
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
programmi, causa la rilettura della configurazione.} se il loro file di
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
programmi, causa la rilettura della configurazione.} se il loro file di
-Questa scelta è stata fatta perché provvedere un simile meccanismo a livello
-generico per qualunque file comporterebbe un notevole aumento di complessità
+Questa scelta è stata fatta perché provvedere un simile meccanismo a livello
+generico per qualunque file comporterebbe un notevole aumento di complessità
all'origine di Unix i soli programmi che potevano avere una tale esigenza
erano i demoni, attenendosi a uno dei criteri base della progettazione, che
era di far fare al kernel solo le operazioni strettamente necessarie e
lasciare tutto il resto a processi in user space, non era stata prevista
all'origine di Unix i soli programmi che potevano avere una tale esigenza
erano i demoni, attenendosi a uno dei criteri base della progettazione, che
era di far fare al kernel solo le operazioni strettamente necessarie e
lasciare tutto il resto a processi in user space, non era stata prevista
-Visto però il crescente interesse nei confronti di una funzionalità di questo
-tipo, che è molto richiesta specialmente nello sviluppo dei programmi ad
+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
filesystem, sono state successivamente introdotte delle estensioni che
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
+permettessero la creazione di meccanismi di notifica più efficienti dell'unica
+soluzione disponibile con l'interfaccia tradizionale, che è quella del
standardizzate, che sono disponibili soltanto su Linux (anche se altri kernel
supportano meccanismi simili). Alcune di esse sono realizzate, e solo a
partire dalla versione 2.4 del kernel, attraverso l'uso di alcuni
\textsl{comandi} aggiuntivi per la funzione \func{fcntl} (vedi
standardizzate, che sono disponibili soltanto su Linux (anche se altri kernel
supportano meccanismi simili). Alcune di esse sono realizzate, e solo a
partire dalla versione 2.4 del kernel, attraverso l'uso di alcuni
\textsl{comandi} aggiuntivi per la funzione \func{fcntl} (vedi
-La prima di queste funzionalità è quella del cosiddetto \textit{file lease};
-questo è un meccanismo che consente ad un processo, detto \textit{lease
+La prima di queste funzionalità è quella del cosiddetto \textit{file lease};
+questo è un meccanismo che consente ad un processo, detto \textit{lease
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}
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}
- può rispecificare lo stesso \const{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}.
+ può rispecificare lo stesso \const{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}.
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
un altro processo esegue l'apertura del file in scrittura o usa
\func{truncate} per troncarlo. Nel secondo caso la notifica avviene anche se
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
un altro processo esegue l'apertura del file in scrittura o usa
\func{truncate} per troncarlo. Nel secondo caso la notifica avviene anche se
-il file viene aperto in lettura; in quest'ultimo caso però il \textit{lease}
-può essere ottenuto solo se nessun altro processo ha aperto lo stesso file.
+il file viene aperto in lettura; in quest'ultimo caso però il \textit{lease}
+può essere ottenuto solo se nessun altro processo ha aperto lo stesso file.
-occorrerà chiamare \func{fcntl} sul relativo file descriptor \param{fd} con il
-comando \const{F\_GETLEASE}, e si otterrà indietro nell'argomento \param{arg}
+occorrerà chiamare \func{fcntl} sul relativo file descriptor \param{fd} con il
+comando \const{F\_GETLEASE}, e si otterrà indietro nell'argomento \param{arg}
uno dei valori di tab.~\ref{tab:file_lease_fctnl}, che indicheranno la
presenza del rispettivo tipo di \textit{lease}, o, nel caso di
\const{F\_UNLCK}, l'assenza di qualunque \textit{file lease}.
uno dei valori di tab.~\ref{tab:file_lease_fctnl}, che indicheranno la
presenza del rispettivo tipo di \textit{lease}, o, nel caso di
\const{F\_UNLCK}, l'assenza di qualunque \textit{file lease}.
-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
+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
-privilegi di amministratore (cioè con la \itindex{capabilities} capability
-\const{CAP\_LEASE}, vedi sez.~\ref{sec:proc_capabilities}) può acquisire
+privilegi di amministratore (cioè con la \itindex{capabilities} capability
+\const{CAP\_LEASE}, vedi sez.~\ref{sec:proc_capabilities}) può acquisire
-esso,\footnote{in realtà \func{truncate} confligge sempre, mentre \func{open},
+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
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
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
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
altro processo inizi con le sue operazioni di scrittura o di lettura su di
esso. In genere un \textit{lease holder} che riceve una notifica deve
provvedere a completare le necessarie operazioni (ad esempio scaricare
altro processo inizi con le sue operazioni di scrittura o di lettura su di
esso. In genere un \textit{lease holder} che riceve una notifica deve
provvedere a completare le necessarie operazioni (ad esempio scaricare
\textit{lease breaker} possa eseguire le sue operazioni. Questo si fa con il
comando \const{F\_SETLEASE}, o rimuovendo il \textit{lease} con
\const{F\_UNLCK}, o, nel caso di \textit{write lease} che confligge con una
\textit{lease breaker} possa eseguire le sue operazioni. Questo si fa con il
comando \const{F\_SETLEASE}, o rimuovendo il \textit{lease} con
\const{F\_UNLCK}, o, nel caso di \textit{write lease} che confligge con una
Se il \textit{lease holder} non provvede a rilasciare il \textit{lease} entro
il numero di secondi specificato dal parametro di sistema mantenuto in
Se il \textit{lease holder} non provvede a rilasciare il \textit{lease} entro
il numero di secondi specificato dal parametro di sistema mantenuto in
-\procfile{/proc/sys/fs/lease-break-time} sarà il kernel stesso a rimuoverlo (o
-declassarlo) automaticamente.\footnote{questa è una misura di sicurezza per
+\procfile{/proc/sys/fs/lease-break-time} sarà il kernel stesso a rimuoverlo (o
+declassarlo) automaticamente.\footnote{questa è una misura di sicurezza per
-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
+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
principalmente ad uso di Samba per poter facilitare l'emulazione del
comportamento di Windows sui file, ma ad oggi viene considerata una
principalmente ad uso di Samba per poter facilitare l'emulazione del
comportamento di Windows sui file, ma ad oggi viene considerata una
- interfaccia mal progettata ed il suo uso è fortemente sconsigliato a favore
- di \textit{inotify}.} che è quanto necessario ad esempio ai programma di
+ interfaccia mal progettata ed il suo uso è fortemente sconsigliato a favore
+ di \textit{inotify}.} che è quanto necessario ad esempio ai programma di
-Per risolvere questo problema a partire dal kernel 2.4 è stata allora creata
-un'altra interfaccia,\footnote{si ricordi che anche questa è una interfaccia
+Per risolvere questo problema a partire dal kernel 2.4 è stata allora creata
+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
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
-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.\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
fra \func{write}, \func{pwrite}, \func{writev},
\func{truncate}, \func{ftruncate}.\\
fra \func{write}, \func{pwrite}, \func{writev},
\func{truncate}, \func{ftruncate}.\\
l'esecuzione di una fra \func{open}, \func{creat},
\func{mknod}, \func{mkdir}, \func{link},
\func{symlink}, \func{rename} (da un'altra
directory).\\
l'esecuzione di una fra \func{open}, \func{creat},
\func{mknod}, \func{mkdir}, \func{link},
\func{symlink}, \func{rename} (da un'altra
directory).\\
l'esecuzione di una fra \func{unlink}, \func{rename}
(su un'altra directory), \func{rmdir}.\\
l'esecuzione di una fra \func{unlink}, \func{rename}
(su un'altra directory), \func{rmdir}.\\
l'esecuzione di una fra \func{chown}, \func{chmod},
\func{utime}.\\
\const{DN\_MULTISHOT}& Richiede una notifica permanente di tutti gli
l'esecuzione di una fra \func{chown}, \func{chmod},
\func{utime}.\\
\const{DN\_MULTISHOT}& Richiede una notifica permanente di tutti gli
certa directory eseguendo la funzione \func{fcntl} su un file descriptor
associato alla stessa con il comando \const{F\_NOTIFY}. In questo caso
l'argomento \param{arg} di \func{fcntl} serve ad indicare per quali classi
eventi si vuole ricevere la notifica, e prende come valore una maschera
certa directory eseguendo la funzione \func{fcntl} su un file descriptor
associato alla stessa con il comando \const{F\_NOTIFY}. In questo caso
l'argomento \param{arg} di \func{fcntl} serve ad indicare per quali classi
eventi si vuole ricevere la notifica, e prende come valore una maschera
tab.~\ref{tab:file_notify}.
A meno di non impostare in maniera esplicita una notifica permanente usando il
tab.~\ref{tab:file_notify}.
A meno di non impostare in maniera esplicita una notifica permanente usando il
-valore \const{DN\_MULTISHOT}, la notifica è singola: viene cioè inviata una
-sola volta quando si verifica uno qualunque fra gli eventi per i quali la si è
+valore \const{DN\_MULTISHOT}, la notifica è singola: viene cioè inviata una
+sola volta quando si verifica uno qualunque fra gli eventi per i quali la si è
richiesta. Questo significa che un programma deve registrarsi un'altra volta
se desidera essere notificato di ulteriori cambiamenti. Se si eseguono diverse
chiamate con \const{F\_NOTIFY} e con valori diversi per \param{arg} questi
richiesta. Questo significa che un programma deve registrarsi un'altra volta
se desidera essere notificato di ulteriori cambiamenti. Se si eseguono diverse
chiamate con \const{F\_NOTIFY} e con valori diversi per \param{arg} questi
-ultimi si \textsl{accumulano}; cioè eventuali nuovi classi di eventi
-specificate in chiamate successive vengono aggiunte a quelle già impostate
+ultimi si \textsl{accumulano}; cioè eventuali nuovi classi di eventi
+specificate in chiamate successive vengono aggiunte a quelle già impostate
usare un file descriptor per ciascuna directory che si vuole tenere sotto
controllo, il che porta facilmente ad avere un eccesso di file aperti. Inoltre
usare un file descriptor per ciascuna directory che si vuole tenere sotto
controllo, il che porta facilmente ad avere un eccesso di file aperti. Inoltre
-viene segnalata, ma poi è necessario verificare di quale file si tratta
-(operazione che può essere molto onerosa quando una directory contiene un gran
+viene segnalata, ma poi è necessario verificare di quale file si tratta
+(operazione che può essere molto onerosa quando una directory contiene un gran
numero di file). Infine l'uso dei segnali come interfaccia di notifica
comporta tutti i problemi di gestione visti in sez.~\ref{sec:sig_management} e
sez.~\ref{sec:sig_adv_control}. Per tutta questa serie di motivi in generale
numero di file). Infine l'uso dei segnali come interfaccia di notifica
comporta tutti i problemi di gestione visti in sez.~\ref{sec:sig_management} e
sez.~\ref{sec:sig_adv_control}. Per tutta questa serie di motivi in generale
-quella di \textit{dnotify} viene considerata una interfaccia di usabilità
-problematica ed il suo uso oggi è fortemente sconsigliato.
+quella di \textit{dnotify} viene considerata una interfaccia di usabilità
+problematica ed il suo uso oggi è fortemente sconsigliato.
-questa è una interfaccia specifica di Linux (pertanto non deve essere usata se
-si devono scrivere programmi portabili), ed è basata sull'uso di una coda di
+questa è una interfaccia specifica di Linux (pertanto non deve essere usata se
+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
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
\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
\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
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
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
+ 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
directory reale, l'inconveniente di non poter smontare un filesystem i cui
file sono tenuti sotto osservazione viene completamente
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.}
+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.}
stato introdotto anche il supporto per il \itindex{signal~driven~I/O}
\texttt{signal-driven I/O} trattato in
sez.~\ref{sec:file_asyncronous_operation}.} siccome gli eventi vengono
notificati come dati disponibili in lettura, dette funzioni ritorneranno tutte
stato introdotto anche il supporto per il \itindex{signal~driven~I/O}
\texttt{signal-driven I/O} trattato in
sez.~\ref{sec:file_asyncronous_operation}.} siccome gli eventi vengono
notificati come dati disponibili in lettura, dette funzioni ritorneranno tutte
- dell'interfaccia utente.} si potrà gestire l'osservazione degli eventi con
-una qualunque delle modalità di \textit{I/O multiplexing} illustrate in
+ dell'interfaccia utente.} si potrà gestire l'osservazione degli eventi con
+una qualunque delle modalità di \textit{I/O multiplexing} illustrate in
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}
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 è:
+(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
\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
\begin{errlist}
\item[\errcode{EACCESS}] non si ha accesso in lettura al file indicato.
\item[\errcode{EINVAL}] \param{mask} non contiene eventi legali o \param{fd}
\begin{errlist}
\item[\errcode{EACCESS}] non si ha accesso in lettura al file indicato.
\item[\errcode{EINVAL}] \param{mask} non contiene eventi legali o \param{fd}
- non è un file descriptor di \textit{inotify}.
- \item[\errcode{ENOSPC}] si è raggiunto il numero massimo di voci di
+ non è un file descriptor di \textit{inotify}.
+ \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}.}
osservazione o il kernel non ha potuto allocare una risorsa necessaria.
\end{errlist}
ed inoltre \errval{EFAULT}, \errval{ENOMEM} e \errval{EBADF}.}
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
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
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
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
- caso c'è un limite massimo che di default è pari a 8192, ed anche questo
- valore può essere cambiato con \func{sysctl} o usando il file
- \procfile{/proc/sys/fs/inotify/max\_user\_watches}.} e si utilizzerà sempre
+ caso c'è un limite massimo che di default è pari a 8192, ed anche questo
+ valore può essere cambiato con \func{sysctl} o usando il file
+ \procfile{/proc/sys/fs/inotify/max\_user\_watches}.} e si utilizzerà sempre
lettura.\\
\const{IN\_ATTRIB} &$\bullet$& Ci sono stati cambiamenti sui dati
dell'inode (o sugli attributi
estesi, vedi
sez.~\ref{sec:file_xattr}).\\
lettura.\\
\const{IN\_ATTRIB} &$\bullet$& Ci sono stati cambiamenti sui dati
dell'inode (o sugli attributi
estesi, vedi
sez.~\ref{sec:file_xattr}).\\
- \const{IN\_MODIFY} &$\bullet$& È stato modificato il file.\\
- \const{IN\_MOVE\_SELF} & & È stato rinominato il file (o la
+ \const{IN\_MODIFY} &$\bullet$& È stato modificato il file.\\
+ \const{IN\_MOVE\_SELF} & & È stato rinominato il file (o la
tipo di evento avvenuto, \func{inotify\_add\_watch} supporta ulteriori
flag,\footnote{i flag \const{IN\_DONT\_FOLLOW}, \const{IN\_MASK\_ADD} e
\const{IN\_ONLYDIR} sono stati introdotti a partire dalle glibc 2.5, se si
tipo di evento avvenuto, \func{inotify\_add\_watch} supporta ulteriori
flag,\footnote{i flag \const{IN\_DONT\_FOLLOW}, \const{IN\_MASK\_ADD} e
\const{IN\_ONLYDIR} sono stati introdotti a partire dalle glibc 2.5, se si
- usa la versione 2.4 è necessario definirli a mano.} riportati in
-tab.~\ref{tab:inotify_add_watch_flag}, che indicano le modalità di
+ usa la versione 2.4 è necessario definirli a mano.} riportati in
+tab.~\ref{tab:inotify_add_watch_flag}, che indicano le modalità di
osservazione (da passare sempre nell'argomento \param{mask}) e che al
contrario dei precedenti non vengono mai impostati nei risultati in uscita.
osservazione (da passare sempre nell'argomento \param{mask}) e che al
contrario dei precedenti non vengono mai impostati nei risultati in uscita.
nell'argomento \param{mask}, invece di
sovrascriverli.\\
\const{IN\_ONESHOT} & Esegue l'osservazione su \param{pathname} per una
sola volta, rimuovendolo poi dalla \textit{watch
list}.\\
nell'argomento \param{mask}, invece di
sovrascriverli.\\
\const{IN\_ONESHOT} & Esegue l'osservazione su \param{pathname} per una
sola volta, rimuovendolo poi dalla \textit{watch
list}.\\
soltanto gli eventi ad essa relativi e non
quelli per i file che contiene.\\
\hline
\end{tabular}
\caption{Le costanti che identificano i bit della maschera binaria
dell'argomento \param{mask} di \func{inotify\_add\_watch} che indicano le
soltanto gli eventi ad essa relativi e non
quelli per i file che contiene.\\
\hline
\end{tabular}
\caption{Le costanti che identificano i bit della maschera binaria
dell'argomento \param{mask} di \func{inotify\_add\_watch} che indicano le
\label{tab:inotify_add_watch_flag}
\end{table}
Se non esiste nessun \textit{watch} per il file o la directory specificata
\label{tab:inotify_add_watch_flag}
\end{table}
Se non esiste nessun \textit{watch} per il file o la directory specificata
-questo verrà creato per gli eventi specificati dall'argomento \param{mask},
-altrimenti la funzione sovrascriverà le impostazioni precedenti, a meno che
+questo verrà creato per gli eventi specificati dall'argomento \param{mask},
+altrimenti la funzione sovrascriverà le impostazioni precedenti, a meno che
Come accennato quando si tiene sotto osservazione una directory vengono
restituite le informazioni sia riguardo alla directory stessa che ai file che
Come accennato quando si tiene sotto osservazione una directory vengono
restituite le informazioni sia riguardo alla directory stessa che ai file che
flag \const{IN\_ONLYDIR}, che richiede di riportare soltanto gli eventi
relativi alla directory stessa. Si tenga presente inoltre che quando si
osserva una directory vengono riportati solo gli eventi sui file che essa
contiene direttamente, non quelli relativi a file contenuti in eventuali
flag \const{IN\_ONLYDIR}, che richiede di riportare soltanto gli eventi
relativi alla directory stessa. Si tenga presente inoltre che quando si
osserva una directory vengono riportati solo gli eventi sui file che essa
contiene direttamente, non quelli relativi a file contenuti in eventuali
-Infine usando il flag \const{IN\_ONESHOT} è possibile richiedere una notifica
-singola;\footnote{questa funzionalità però è disponibile soltanto a partire dal
+Infine usando il flag \const{IN\_ONESHOT} è possibile richiedere una notifica
+singola;\footnote{questa funzionalità però è disponibile soltanto a partire dal
In caso di successo \func{inotify\_add\_watch} ritorna un intero positivo,
detto \textit{watch descriptor}, che identifica univocamente un
In caso di successo \func{inotify\_add\_watch} ritorna un intero positivo,
detto \textit{watch descriptor}, che identifica univocamente un
la eventuale rimozione dello stesso.
La seconda funzione per la gestione delle code di notifica, che permette di
la eventuale rimozione dello stesso.
La seconda funzione per la gestione delle code di notifica, che permette di
\begin{prototype}{sys/inotify.h}
{int inotify\_rm\_watch(int fd, uint32\_t wd)}
Rimuove un \textsl{osservatore} da una coda di notifica.
\bodydesc{La funzione restituisce 0 in caso di successo, o $-1$ in caso di
\begin{prototype}{sys/inotify.h}
{int inotify\_rm\_watch(int fd, uint32\_t wd)}
Rimuove un \textsl{osservatore} da una coda di notifica.
\bodydesc{La funzione restituisce 0 in caso di successo, o $-1$ in caso di
- \item[\errcode{EINVAL}] il valore di \param{wd} non è corretto, o \param{fd}
- non è associato ad una coda di notifica.
+ \item[\errcode{EINVAL}] il valore di \param{wd} non è corretto, o \param{fd}
+ non è associato ad una coda di notifica.
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
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
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
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
\func{inotify\_rm\_watch}.
Come accennato l'interfaccia di \textit{inotify} prevede che gli eventi siano
notificati come dati presenti in lettura sul file descriptor associato alla
\func{inotify\_rm\_watch}.
Come accennato l'interfaccia di \textit{inotify} prevede che gli eventi siano
notificati come dati presenti in lettura sul file descriptor associato alla
-coda di notifica. Una applicazione pertanto dovrà leggere i dati da detto file
-con una \func{read}, che ritornerà sul buffer i dati presenti nella forma di
-una o più strutture di tipo \struct{inotify\_event} (la cui definizione è
+coda di notifica. Una applicazione pertanto dovrà leggere i dati da detto file
+con una \func{read}, che ritornerà sul buffer i dati presenti nella forma di
+una o più strutture di tipo \struct{inotify\_event} (la cui definizione è
-\func{read} si bloccherà (a meno di non aver impostato il file descriptor in
-modalità non bloccante) fino all'arrivo di almeno un evento.
+\func{read} si bloccherà (a meno di non aver impostato il file descriptor in
+modalità non bloccante) fino all'arrivo di almeno un evento.
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
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
-\const{FIONREAD}.\footnote{questa è una delle operazioni speciali per i file
- (vedi sez.~\ref{sec:file_ioctl}), che è disponibile solo per i socket e per
- i file descriptor creati con \func{inotify\_init}.} Si può così utilizzare
+\const{FIONREAD}.\footnote{questa è una delle operazioni speciali per i file
+ (vedi sez.~\ref{sec:file_ioctl}), che è disponibile solo per i socket e per
+ i file descriptor creati con \func{inotify\_init}.} Si può così utilizzare
questa operazione, oltre che per predisporre una operazione di lettura con un
buffer di dimensioni adeguate, anche per ottenere rapidamente il numero di
file che sono cambiati.
questa operazione, oltre che per predisporre una operazione di lettura con un
buffer di dimensioni adeguate, anche per ottenere rapidamente il numero di
file che sono cambiati.
associata una struttura \struct{inotify\_event} contenente i rispettivi dati.
Per identificare a quale file o directory l'evento corrisponde viene
restituito nel campo \var{wd} il \textit{watch descriptor} con cui il relativo
associata una struttura \struct{inotify\_event} contenente i rispettivi dati.
Per identificare a quale file o directory l'evento corrisponde viene
restituito nel campo \var{wd} il \textit{watch descriptor} con cui il relativo
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
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
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
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
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
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
\const{IN\_MOVED\_TO} e \const{IN\_MOVED\_FROM}.
Infine due campi \var{name} e \var{len} sono utilizzati soltanto quando
\const{IN\_MOVED\_TO} e \const{IN\_MOVED\_FROM}.
Infine due campi \var{name} e \var{len} sono utilizzati soltanto quando
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
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
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
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
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
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
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
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
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
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
-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
+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
-approssimativamente 512 eventi.\footnote{si ricordi che la quantità di dati
- restituita da \textit{inotify} è variabile a causa della diversa lunghezza
+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.
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.
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
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
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
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
+ \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
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
-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
+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
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
-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
+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
garantisce automaticamente, anche quando ne sono presenti in numero maggiore,
di restituire soltanto il numero di eventi che possono rientrare completamente
garantisce automaticamente, anche quando ne sono presenti in numero maggiore,
di restituire soltanto il numero di eventi che possono rientrare completamente
-Infine un'ultima caratteristica dell'interfaccia di \textit{inotify} è che gli
-eventi restituiti nella lettura formano una sequenza ordinata, è cioè
+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
garantito che se si esegue uno spostamento di un file gli eventi vengano
generati nella sequenza corretta. L'interfaccia garantisce anche che se si
dei campi \var{wd}, \var{mask}, \var{cookie}, e \var{name}) questi vengono
raggruppati in un solo evento.
dei campi \var{wd}, \var{mask}, \var{cookie}, e \var{name}) questi vengono
raggruppati in un solo evento.
-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
+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
possibile effettuare una richiesta preventiva di dati, in modo da poter
effettuare in contemporanea le operazioni di calcolo e quelle di I/O.
possibile effettuare una richiesta preventiva di dati, in modo da poter
effettuare in contemporanea le operazioni di calcolo e quelle di I/O.
-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
+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.
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.
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},
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
+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
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
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
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
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.
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
+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
piattaforma supporti questa caratteristica, questo viene indicato definendo
le macro \macro{\_POSIX\_PRIORITIZED\_IO}, e
partire da quella del processo chiamante (vedi sez.~\ref{sec:proc_priority}),
cui viene sottratto il valore di questo campo. Il campo
partire da quella del processo chiamante (vedi sez.~\ref{sec:proc_priority}),
cui viene sottratto il valore di questo campo. Il campo
come vedremo, permette di eseguire con una sola chiamata una serie di
operazioni, usando un vettore di \textit{control block}. Tramite questo campo
come vedremo, permette di eseguire con una sola chiamata una serie di
operazioni, usando un vettore di \textit{control block}. Tramite questo campo
(illustrata in in fig.~\ref{fig:struct_sigevent}) che serve a specificare il
modo in cui si vuole che venga effettuata la notifica del completamento delle
(illustrata in in fig.~\ref{fig:struct_sigevent}) che serve a specificare il
modo in cui si vuole che venga effettuata la notifica del completamento delle
-operazioni richieste; per la trattazione delle modalità di utilizzo della
-stessa si veda quanto già visto in proposito in sez.~\ref{sec:sig_timer_adv}.
+operazioni richieste; per la trattazione delle modalità di utilizzo della
+stessa si veda quanto già visto in proposito in sez.~\ref{sec:sig_timer_adv}.
Le due funzioni base dell'interfaccia per l'I/O asincrono sono
\funcd{aio\_read} ed \funcd{aio\_write}. Esse permettono di richiedere una
Le due funzioni base dell'interfaccia per l'I/O asincrono sono
\funcd{aio\_read} ed \funcd{aio\_write}. Esse permettono di richiedere una
- \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
+ \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
\errcode{EINVAL} siano rilevati immediatamente al momento della chiamata,
potrebbero anche emergere nelle fasi successive delle operazioni. Lettura e
scrittura avvengono alla posizione indicata da \var{aio\_offset}, a meno che
\errcode{EINVAL} siano rilevati immediatamente al momento della chiamata,
potrebbero anche emergere nelle fasi successive delle operazioni. Lettura e
scrittura avvengono alla posizione indicata da \var{aio\_offset}, a meno che
Si tenga inoltre presente che deallocare la memoria indirizzata da
\param{aiocbp} o modificarne i valori prima della conclusione di una
Si tenga inoltre presente che deallocare la memoria indirizzata da
\param{aiocbp} o modificarne i valori prima della conclusione di una
-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
+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}.
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}.
\func{aio\_write} non implica che le operazioni siano state effettivamente
eseguite in maniera corretta; per verificarne l'esito l'interfaccia prevede
altre due funzioni, che permettono di controllare lo stato di esecuzione. La
\func{aio\_write} non implica che le operazioni siano state effettivamente
eseguite in maniera corretta; per verificarne l'esito l'interfaccia prevede
altre due funzioni, che permettono di controllare lo stato di esecuzione. La
-prima è \funcd{aio\_error}, che serve a determinare un eventuale stato di
-errore; il suo prototipo è:
+prima è \funcd{aio\_error}, che serve a determinare un eventuale stato di
+errore; il suo prototipo è:
-Se l'operazione non si è ancora completata viene restituito l'errore di
-\errcode{EINPROGRESS}. La funzione ritorna zero quando l'operazione si è
+Se l'operazione non si è ancora completata viene restituito l'errore di
+\errcode{EINPROGRESS}. La funzione ritorna zero quando l'operazione si è
conclusa con successo, altrimenti restituisce il codice dell'errore
verificatosi, ed esegue la corrispondente impostazione di \var{errno}. Il
conclusa con successo, altrimenti restituisce il codice dell'errore
verificatosi, ed esegue la corrispondente impostazione di \var{errno}. Il
errato per \param{aiocbp}, che uno degli errori possibili durante l'esecuzione
dell'operazione di I/O richiesta, nel qual caso saranno restituiti, a seconda
del caso, i codici di errore delle system call \func{read}, \func{write} e
\func{fsync}.
errato per \param{aiocbp}, che uno degli errori possibili durante l'esecuzione
dell'operazione di I/O richiesta, nel qual caso saranno restituiti, a seconda
del caso, i codici di errore delle system call \func{read}, \func{write} e
\func{fsync}.
-asincrona, essa infatti fa sì che il sistema rilasci le risorse ad essa
-associate. É per questo motivo che occorre chiamare la funzione solo dopo che
-l'operazione cui \param{aiocbp} fa riferimento si è completata. Una chiamata
+asincrona, essa infatti fa sì che il sistema rilasci le risorse ad essa
+associate. É per questo motivo che occorre chiamare la funzione solo dopo che
+l'operazione cui \param{aiocbp} fa riferimento si è completata. Una chiamata
precedente il completamento delle operazioni darebbe risultati indeterminati.
La funzione restituisce il valore di ritorno relativo all'operazione eseguita,
precedente il completamento delle operazioni darebbe risultati indeterminati.
La funzione restituisce il valore di ritorno relativo all'operazione eseguita,
-così come ricavato dalla sottostante system call (il numero di byte letti,
-scritti o il valore di ritorno di \func{fsync}). É importante chiamare sempre
+così come ricavato dalla sottostante system call (il numero di byte letti,
+scritti o il valore di ritorno di \func{fsync}). É importante chiamare sempre
questa funzione, altrimenti le risorse disponibili per le operazioni di I/O
asincrono non verrebbero liberate, rischiando di arrivare ad un loro
esaurimento.
questa funzione, altrimenti le risorse disponibili per le operazioni di I/O
asincrono non verrebbero liberate, rischiando di arrivare ad un loro
esaurimento.
disposizione un'altra operazione, quella di sincronizzazione dell'I/O,
compiuta dalla funzione \funcd{aio\_fsync}, che ha lo stesso effetto della
analoga \func{fsync}, ma viene eseguita in maniera asincrona; il suo prototipo
disposizione un'altra operazione, quella di sincronizzazione dell'I/O,
compiuta dalla funzione \funcd{aio\_fsync}, che ha lo stesso effetto della
analoga \func{fsync}, ma viene eseguita in maniera asincrona; il suo prototipo
\begin{prototype}{aio.h}
{int aio\_fsync(int op, struct aiocb *aiocbp)}
Richiede la sincronizzazione dei dati per il file indicato da \param{aiocbp}.
\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
\begin{prototype}{aio.h}
{int aio\_fsync(int op, struct aiocb *aiocbp)}
Richiede la sincronizzazione dei dati per il file indicato da \param{aiocbp}.
\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
- errore, che può essere, con le stesse modalità di \func{aio\_read},
+ errore, che può essere, con le stesse modalità di \func{aio\_read},
\errval{EAGAIN}, \errval{EBADF} o \errval{EINVAL}.}
\end{prototype}
La funzione richiede la sincronizzazione delle operazioni di I/O, ritornando
\errval{EAGAIN}, \errval{EBADF} o \errval{EINVAL}.}
\end{prototype}
La funzione richiede la sincronizzazione delle operazioni di I/O, ritornando
verificata con \func{aio\_error} e \func{aio\_return} come per le operazioni
di lettura e scrittura. L'argomento \param{op} permette di indicare la
verificata con \func{aio\_error} e \func{aio\_return} come per le operazioni
di lettura e scrittura. L'argomento \param{op} permette di indicare la
operazioni saranno completate con una chiamata a \func{fdatasync}, se si
specifica \const{O\_SYNC} con una chiamata a \func{fsync} (per i dettagli vedi
sez.~\ref{sec:file_sync}).
Il successo della chiamata assicura la sincronizzazione delle operazioni fino
operazioni saranno completate con una chiamata a \func{fdatasync}, se si
specifica \const{O\_SYNC} con una chiamata a \func{fsync} (per i dettagli vedi
sez.~\ref{sec:file_sync}).
Il successo della chiamata assicura la sincronizzazione delle operazioni fino
-allora richieste, niente è garantito riguardo la sincronizzazione dei dati
-relativi ad eventuali operazioni richieste successivamente. Se si è
-specificato un meccanismo di notifica questo sarà innescato una volta che le
+allora richieste, niente è garantito riguardo la sincronizzazione dei dati
+relativi ad eventuali operazioni richieste successivamente. Se si è
+specificato un meccanismo di notifica questo sarà innescato una volta che le
quando viene richiesta un'uscita immediata dal programma), per questo lo
standard POSIX.1b prevede una funzione apposita, \funcd{aio\_cancel}, che
permette di cancellare una operazione richiesta in precedenza; il suo
quando viene richiesta un'uscita immediata dal programma), per questo lo
standard POSIX.1b prevede una funzione apposita, \funcd{aio\_cancel}, che
permette di cancellare una operazione richiesta in precedenza; il suo
La funzione permette di cancellare una operazione specifica sul file
\param{fildes}, o tutte le operazioni pendenti, specificando \val{NULL} come
valore di \param{aiocbp}. Quando una operazione viene cancellata una
La funzione permette di cancellare una operazione specifica sul file
\param{fildes}, o tutte le operazioni pendenti, specificando \val{NULL} come
valore di \param{aiocbp}. Quando una operazione viene cancellata una
-successiva chiamata ad \func{aio\_error} riporterà \errcode{ECANCELED} come
-codice di errore, ed il suo codice di ritorno sarà -1, inoltre il meccanismo
-di notifica non verrà invocato. Se si specifica una operazione relativa ad un
-altro file descriptor il risultato è indeterminato. In caso di successo, i
+successiva chiamata ad \func{aio\_error} riporterà \errcode{ECANCELED} come
+codice di errore, ed il suo codice di ritorno sarà -1, inoltre il meccanismo
+di notifica non verrà invocato. Se si specifica una operazione relativa ad un
+altro file descriptor il risultato è indeterminato. In caso di successo, i
possibili valori di ritorno per \func{aio\_cancel} (anch'essi definiti in
\file{aio.h}) sono tre:
\begin{basedescript}{\desclabelwidth{3.0cm}}
possibili valori di ritorno per \func{aio\_cancel} (anch'essi definiti in
\file{aio.h}) sono tre:
\begin{basedescript}{\desclabelwidth{3.0cm}}
-\item[\const{AIO\_ALLDONE}] indica che le operazioni di cui si è richiesta la
- cancellazione sono state già completate,
+\item[\const{AIO\_ALLDONE}] indica che le operazioni di cui si è richiesta la
+ cancellazione sono state già completate,
\func{aio\_error} per determinare quali sono le operazioni effettivamente
cancellate. Le operazioni che non sono state cancellate proseguiranno il loro
corso normale, compreso quanto richiesto riguardo al meccanismo di notifica
del loro avvenuto completamento.
\func{aio\_error} per determinare quali sono le operazioni effettivamente
cancellate. Le operazioni che non sono state cancellate proseguiranno il loro
corso normale, compreso quanto richiesto riguardo al meccanismo di notifica
del loro avvenuto completamento.
fornisce anche una apposita funzione, \funcd{aio\_suspend}, che permette di
sospendere l'esecuzione del processo chiamante fino al completamento di una
fornisce anche una apposita funzione, \funcd{aio\_suspend}, che permette di
sospendere l'esecuzione del processo chiamante fino al completamento di una
Attende, per un massimo di \param{timeout}, il completamento di una delle
operazioni specificate da \param{list}.
Attende, per un massimo di \param{timeout}, il completamento di una delle
operazioni specificate da \param{list}.
- \bodydesc{La funzione restituisce 0 se una (o più) operazioni sono state
- completate, e -1 in caso di errore nel qual caso \var{errno} assumerà uno
+ \bodydesc{La funzione restituisce 0 se una (o più) operazioni sono state
+ completate, e -1 in caso di errore nel qual caso \var{errno} assumerà uno
- \item[\errcode{ENOSYS}] la funzione non è implementata.
- \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale.
+ \item[\errcode{ENOSYS}] la funzione non è implementata.
+ \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale.
utilizzato come meccanismo di notifica.} La lista deve essere inizializzata
con delle strutture \struct{aiocb} relative ad operazioni effettivamente
utilizzato come meccanismo di notifica.} La lista deve essere inizializzata
con delle strutture \struct{aiocb} relative ad operazioni effettivamente
-richieste, ma può contenere puntatori nulli, che saranno ignorati. In caso si
-siano specificati valori non validi l'effetto è indefinito. Un valore
+richieste, ma può contenere puntatori nulli, che saranno ignorati. In caso si
+siano specificati valori non validi l'effetto è indefinito. Un valore
\val{NULL} per \param{timout} comporta l'assenza di timeout.
Lo standard POSIX.1b infine ha previsto pure una funzione, \funcd{lio\_listio},
che permette di effettuare la richiesta di una intera lista di operazioni di
\val{NULL} per \param{timout} comporta l'assenza di timeout.
Lo standard POSIX.1b infine ha previsto pure una funzione, \funcd{lio\_listio},
che permette di effettuare la richiesta di una intera lista di operazioni di
\begin{prototype}{aio.h}
{int lio\_listio(int mode, struct aiocb * const list[], int nent, struct
sigevent *sig)}
Richiede l'esecuzione delle operazioni di I/O elencata da \param{list},
\begin{prototype}{aio.h}
{int lio\_listio(int mode, struct aiocb * const list[], int nent, struct
sigevent *sig)}
Richiede l'esecuzione delle operazioni di I/O elencata da \param{list},
- \item[\errcode{ENOSYS}] la funzione non è implementata.
- \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale.
+ \item[\errcode{ENOSYS}] la funzione non è implementata.
+ \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale.
\end{errlist}
}
\end{prototype}
La funzione esegue la richiesta delle \param{nent} operazioni indicate nella
lista \param{list} che deve contenere gli indirizzi di altrettanti
\end{errlist}
}
\end{prototype}
La funzione esegue la richiesta delle \param{nent} operazioni indicate nella
lista \param{list} che deve contenere gli indirizzi di altrettanti
\begin{basedescript}{\desclabelwidth{2.0cm}}
\item[\const{LIO\_READ}] si richiede una operazione di lettura.
\item[\const{LIO\_WRITE}] si richiede una operazione di scrittura.
\begin{basedescript}{\desclabelwidth{2.0cm}}
\item[\const{LIO\_READ}] si richiede una operazione di lettura.
\item[\const{LIO\_WRITE}] si richiede una operazione di scrittura.
usato il valore \const{LIO\_WAIT} la funzione si blocca fino al completamento
di tutte le operazioni richieste; se si usa \const{LIO\_NOWAIT} la funzione
ritorna immediatamente dopo aver messo in coda tutte le richieste. In tal caso
usato il valore \const{LIO\_WAIT} la funzione si blocca fino al completamento
di tutte le operazioni richieste; se si usa \const{LIO\_NOWAIT} la funzione
ritorna immediatamente dopo aver messo in coda tutte le richieste. In tal caso
richieste, impostando l'argomento \param{sig} in maniera analoga a come si fa
per il campo \var{aio\_sigevent} di \struct{aiocb}.
richieste, impostando l'argomento \param{sig} in maniera analoga a come si fa
per il campo \var{aio\_sigevent} di \struct{aiocb}.
-Oltre alle precedenti modalità di \textit{I/O multiplexing} e \textsl{I/O
- asincrono}, esistono altre funzioni che implementano delle modalità di
-accesso ai file più evolute rispetto alle normali funzioni di lettura e
+Oltre alle precedenti modalità di \textit{I/O multiplexing} e \textsl{I/O
+ asincrono}, esistono altre funzioni che implementano delle modalità di
+accesso ai file più evolute rispetto alle normali funzioni di lettura e
scrittura che abbiamo esaminato in sez.~\ref{sec:file_base_func}. In questa
sezione allora prenderemo in esame le interfacce per l'\textsl{I/O mappato in
memoria}, per l'\textsl{I/O vettorizzato} e altre funzioni di I/O avanzato.
scrittura che abbiamo esaminato in sez.~\ref{sec:file_base_func}. In questa
sezione allora prenderemo in esame le interfacce per l'\textsl{I/O mappato in
memoria}, per l'\textsl{I/O vettorizzato} e altre funzioni di I/O avanzato.
-Una modalità alternativa di I/O, che usa una interfaccia completamente diversa
-rispetto a quella classica vista in cap.~\ref{cha:file_unix_interface}, è il
+Una modalità alternativa di I/O, che usa una interfaccia completamente diversa
+rispetto a quella classica vista in cap.~\ref{cha:file_unix_interface}, è il
cosiddetto \textit{memory-mapped I/O}, che, attraverso il meccanismo della
\textsl{paginazione} \index{paginazione} usato dalla memoria virtuale (vedi
sez.~\ref{sec:proc_mem_gen}), permette di \textsl{mappare} il contenuto di un
cosiddetto \textit{memory-mapped I/O}, che, attraverso il meccanismo della
\textsl{paginazione} \index{paginazione} usato dalla memoria virtuale (vedi
sez.~\ref{sec:proc_mem_gen}), permette di \textsl{mappare} il contenuto di un
file viene \textsl{mappata} direttamente nello spazio degli indirizzi del
programma. Tutte le operazioni di lettura e scrittura su variabili contenute
in questa zona di memoria verranno eseguite leggendo e scrivendo dal contenuto
del file attraverso il sistema della memoria virtuale \index{memoria~virtuale}
che in maniera analoga a quanto avviene per le pagine che vengono salvate e
file viene \textsl{mappata} direttamente nello spazio degli indirizzi del
programma. Tutte le operazioni di lettura e scrittura su variabili contenute
in questa zona di memoria verranno eseguite leggendo e scrivendo dal contenuto
del file attraverso il sistema della memoria virtuale \index{memoria~virtuale}
che in maniera analoga a quanto avviene per le pagine che vengono salvate e
\textsl{memoria mappata su file}.
L'uso del \textit{memory-mapping} comporta una notevole semplificazione delle
\textsl{memoria mappata su file}.
L'uso del \textit{memory-mapping} comporta una notevole semplificazione delle
-operazioni di I/O, in quanto non sarà più necessario utilizzare dei buffer
-intermedi su cui appoggiare i dati da traferire, poiché questi potranno essere
+operazioni di I/O, in quanto non sarà più necessario utilizzare dei buffer
+intermedi su cui appoggiare i dati da traferire, poiché questi potranno essere
-Infine in situazioni in cui la memoria è scarsa, le pagine che mappano un file
-vengono salvate automaticamente, così come le pagine dei programmi vengono
+Infine in situazioni in cui la memoria è scarsa, le pagine che mappano un file
+vengono salvate automaticamente, così come le pagine dei programmi vengono
memoria su cui possono esserne lette delle porzioni.
L'interfaccia POSIX implementata da Linux prevede varie funzioni per la
gestione del \textit{memory mapped I/O}, la prima di queste, che serve ad
memoria su cui possono esserne lette delle porzioni.
L'interfaccia POSIX implementata da Linux prevede varie funzioni per la
gestione del \textit{memory mapped I/O}, la prima di queste, che serve ad
\bodydesc{La funzione restituisce il puntatore alla zona di memoria mappata
in caso di successo, e \const{MAP\_FAILED} (-1) in caso di errore, nel
\bodydesc{La funzione restituisce il puntatore alla zona di memoria mappata
in caso di successo, e \const{MAP\_FAILED} (-1) in caso di errore, nel
- o si è usato \const{MAP\_PRIVATE} ma \param{fd} non è aperto in lettura,
- o si è usato \const{MAP\_SHARED} e impostato \const{PROT\_WRITE} ed
- \param{fd} non è aperto in lettura/scrittura, o si è impostato
- \const{PROT\_WRITE} ed \param{fd} è in \textit{append-only}.
+ o si è usato \const{MAP\_PRIVATE} ma \param{fd} non è aperto in lettura,
+ o si è usato \const{MAP\_SHARED} e impostato \const{PROT\_WRITE} ed
+ \param{fd} non è aperto in lettura/scrittura, o si è impostato
+ \const{PROT\_WRITE} ed \param{fd} è in \textit{append-only}.
\item[\errcode{EINVAL}] i valori di \param{start}, \param{length} o
\param{offset} non sono validi (o troppo grandi o non allineati sulla
dimensione delle pagine).
\item[\errcode{EINVAL}] i valori di \param{start}, \param{length} o
\param{offset} non sono validi (o troppo grandi o non allineati sulla
dimensione delle pagine).
- \item[\errcode{ETXTBSY}] si è impostato \const{MAP\_DENYWRITE} ma
- \param{fd} è aperto in scrittura.
- \item[\errcode{EAGAIN}] il file è bloccato, o si è bloccata troppa memoria
+ \item[\errcode{ETXTBSY}] si è impostato \const{MAP\_DENYWRITE} ma
+ \param{fd} è aperto in scrittura.
+ \item[\errcode{EAGAIN}] il file è bloccato, o si è bloccata troppa memoria
numero di mappature possibili.
\item[\errcode{ENODEV}] il filesystem di \param{fd} non supporta il memory
mapping.
\item[\errcode{EPERM}] l'argomento \param{prot} ha richiesto
numero di mappature possibili.
\item[\errcode{ENODEV}] il filesystem di \param{fd} non supporta il memory
mapping.
\item[\errcode{EPERM}] l'argomento \param{prot} ha richiesto
\const{PROT\_EXEC} & Le pagine possono essere eseguite.\\
\const{PROT\_READ} & Le pagine possono essere lette.\\
\const{PROT\_WRITE} & Le pagine possono essere scritte.\\
\const{PROT\_EXEC} & Le pagine possono essere eseguite.\\
\const{PROT\_READ} & Le pagine possono essere lette.\\
\const{PROT\_WRITE} & Le pagine possono essere scritte.\\
- accennato in sez.~\ref{sec:proc_memory} in Linux la memoria reale è divisa
- in pagine: ogni processo vede la sua memoria attraverso uno o più segmenti
+ accennato in sez.~\ref{sec:proc_memory} in Linux la memoria reale è divisa
+ in pagine: ogni processo vede la sua memoria attraverso uno o più segmenti
lineari di memoria virtuale. Per ciascuno di questi segmenti il kernel
mantiene nella \itindex{page~table} \textit{page table} la mappatura sulle
lineari di memoria virtuale. Per ciascuno di questi segmenti il kernel
mantiene nella \itindex{page~table} \textit{page table} la mappatura sulle
- pagine di memoria reale, ed le modalità di accesso (lettura, esecuzione,
+ 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
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
-L'argomento \param{flags} specifica infine qual è il tipo di oggetto mappato,
-le opzioni relative alle modalità con cui è effettuata la mappatura e alle
-modalità con cui le modifiche alla memoria mappata vengono condivise o
+L'argomento \param{flags} specifica infine qual è il tipo di oggetto mappato,
+le opzioni relative alle modalità con cui è effettuata la mappatura e alle
+modalità con cui le modifiche alla memoria mappata vengono condivise o
\func{mmap} fallisce. Se si imposta questo flag il
valore di \param{start} deve essere allineato
alle dimensioni di una pagina.\\
\const{MAP\_SHARED} & I cambiamenti sulla memoria mappata vengono
riportati sul file e saranno immediatamente
visibili agli altri processi che mappano lo stesso
\func{mmap} fallisce. Se si imposta questo flag il
valore di \param{start} deve essere allineato
alle dimensioni di una pagina.\\
\const{MAP\_SHARED} & I cambiamenti sulla memoria mappata vengono
riportati sul file e saranno immediatamente
visibili agli altri processi che mappano lo stesso
aggiornato fino alla chiamata di \func{msync} o
\func{munmap}), e solo allora le modifiche saranno
visibili per l'I/O convenzionale. Incompatibile
aggiornato fino alla chiamata di \func{msync} o
\func{munmap}), e solo allora le modifiche saranno
visibili per l'I/O convenzionale. Incompatibile
accesso. Le modifiche sono mantenute attraverso
il meccanismo del \textit{copy on
write} \itindex{copy~on~write} e
accesso. Le modifiche sono mantenute attraverso
il meccanismo del \textit{copy on
write} \itindex{copy~on~write} e
specificato se i cambiamenti sul file originale
vengano riportati sulla regione
mappata. Incompatibile con \const{MAP\_SHARED}.\\
specificato se i cambiamenti sul file originale
vengano riportati sulla regione
mappata. Incompatibile con \const{MAP\_SHARED}.\\
\textit{copy on write} \itindex{copy~on~write}
per mantenere le
modifiche fatte alla regione mappata, in
\textit{copy on write} \itindex{copy~on~write}
per mantenere le
modifiche fatte alla regione mappata, in
memoria disponibile, si ha l'emissione di
un \const{SIGSEGV}.\\
\const{MAP\_LOCKED} & Se impostato impedisce lo swapping delle pagine
memoria disponibile, si ha l'emissione di
un \const{SIGSEGV}.\\
\const{MAP\_LOCKED} & Se impostato impedisce lo swapping delle pagine
\const{MAP\_GROWSDOWN} & Usato per gli \itindex{stack} \textit{stack}.
Indica che la mappatura deve essere effettuata
con gli indirizzi crescenti verso il basso.\\
\const{MAP\_GROWSDOWN} & Usato per gli \itindex{stack} \textit{stack}.
Indica che la mappatura deve essere effettuata
con gli indirizzi crescenti verso il basso.\\
argomenti \param{fd} e \param{offset} sono
ignorati.\footnotemark\\
\const{MAP\_ANON} & Sinonimo di \const{MAP\_ANONYMOUS}, deprecato.\\
argomenti \param{fd} e \param{offset} sono
ignorati.\footnotemark\\
\const{MAP\_ANON} & Sinonimo di \const{MAP\_ANONYMOUS}, deprecato.\\
\const{MAP\_32BIT} & Esegue la mappatura sui primi 2Gb dello spazio
degli indirizzi, viene supportato solo sulle
\const{MAP\_32BIT} & Esegue la mappatura sui primi 2Gb dello spazio
degli indirizzi, viene supportato solo sulle
- piattaforme \texttt{x86-64} per compatibilità con
- le applicazioni a 32 bit. Viene ignorato se si è
+ piattaforme \texttt{x86-64} per compatibilità con
+ le applicazioni a 32 bit. Viene ignorato se si è
richiesto \const{MAP\_FIXED}.\\
\const{MAP\_POPULATE} & Esegue il \itindex{prefaulting}
\textit{prefaulting} delle pagine di memoria
necessarie alla mappatura.\\
richiesto \const{MAP\_FIXED}.\\
\const{MAP\_POPULATE} & Esegue il \itindex{prefaulting}
\textit{prefaulting} delle pagine di memoria
necessarie alla mappatura.\\
non causa I/O.\footnotemark\\
% \const{MAP\_DONTEXPAND}& Non consente una successiva espansione dell'area
% mappata con \func{mremap}, proposto ma pare non
non causa I/O.\footnotemark\\
% \const{MAP\_DONTEXPAND}& Non consente una successiva espansione dell'area
% mappata con \func{mremap}, proposto ma pare non
implementato in Linux a partire dai kernel della serie 2.4.x; esso consente
di creare segmenti di memoria condivisa e torneremo sul suo utilizzo in
sez.~\ref{sec:ipc_mmap_anonymous}.}
\footnotetext{questo flag ed il precedente \const{MAP\_POPULATE} sono stati
introdotti nel kernel 2.5.46 insieme alla mappatura non lineare di cui
implementato in Linux a partire dai kernel della serie 2.4.x; esso consente
di creare segmenti di memoria condivisa e torneremo sul suo utilizzo in
sez.~\ref{sec:ipc_mmap_anonymous}.}
\footnotetext{questo flag ed il precedente \const{MAP\_POPULATE} sono stati
introdotti nel kernel 2.5.46 insieme alla mappatura non lineare di cui
Gli effetti dell'accesso ad una zona di memoria mappata su file possono essere
piuttosto complessi, essi si possono comprendere solo tenendo presente che
Gli effetti dell'accesso ad una zona di memoria mappata su file possono essere
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}),
+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}),
-È invece assai diversa la questione relativa agli accessi al di fuori della
-regione di cui si è richiesta la mappatura. A prima vista infatti si potrebbe
+È invece assai diversa la questione relativa agli accessi al di fuori della
+regione di cui si è richiesta la mappatura. A prima vista infatti si potrebbe
-questo però non tiene conto del fatto che, essendo basata sul meccanismo della
-\index{paginazione} paginazione, la mappatura in memoria non può che essere
+questo però non tiene conto del fatto che, essendo basata sul meccanismo della
+\index{paginazione} paginazione, la mappatura in memoria non può che essere
eseguita su un segmento di dimensioni rigorosamente multiple di quelle di una
pagina, ed in generale queste potranno non corrispondere alle dimensioni
effettive del file o della sezione che si vuole mappare.
eseguita su un segmento di dimensioni rigorosamente multiple di quelle di una
pagina, ed in generale queste potranno non corrispondere alle dimensioni
effettive del file o della sezione che si vuole mappare.
-poiché essa è presente nello spazio di indirizzi del processo, anche se non è
-mappata sul file. Il comportamento del sistema è quello di restituire un
+poiché essa è presente nello spazio di indirizzi del processo, anche se non è
+mappata sul file. Il comportamento del sistema è quello di restituire un
-Un caso più complesso è quello che si viene a creare quando le dimensioni del
-file mappato sono più corte delle dimensioni della mappatura, oppure quando il
-file è stato troncato, dopo che è stato mappato, ad una dimensione inferiore a
+Un caso più complesso è quello che si viene a creare quando le dimensioni del
+file mappato sono più corte delle dimensioni della mappatura, oppure quando il
+file è stato troncato, dopo che è stato mappato, ad una dimensione inferiore a
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
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
\const{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
biunivoca fra una sezione di un file ed una sezione di memoria. Questo
\const{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
biunivoca fra una sezione di un file ed una sezione di memoria. Questo
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
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)
+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)
Dato che passando attraverso una \func{fork} lo spazio di indirizzi viene
copiato integralmente, i file mappati in memoria verranno ereditati in maniera
trasparente dal processo figlio, mantenendo gli stessi attributi avuti nel
Dato che passando attraverso una \func{fork} lo spazio di indirizzi viene
copiato integralmente, i file mappati in memoria verranno ereditati in maniera
trasparente dal processo figlio, mantenendo gli stessi attributi avuti nel
-padre; così se si è usato \const{MAP\_SHARED} padre e figlio accederanno allo
-stesso file in maniera condivisa, mentre se si è usato \const{MAP\_PRIVATE}
-ciascuno di essi manterrà una sua versione privata indipendente. Non c'è
+padre; così se si è usato \const{MAP\_SHARED} padre e figlio accederanno allo
+stesso file in maniera condivisa, mentre se si è usato \const{MAP\_PRIVATE}
+ciascuno di essi manterrà una sua versione privata indipendente. Non c'è
invece nessun passaggio attraverso una \func{exec}, dato che quest'ultima
sostituisce tutto lo spazio degli indirizzi di un processo con quello di un
nuovo programma.
Quando si effettua la mappatura di un file vengono pure modificati i tempi ad
invece nessun passaggio attraverso una \func{exec}, dato che quest'ultima
sostituisce tutto lo spazio degli indirizzi di un processo con quello di un
nuovo programma.
Quando si effettua la mappatura di un file vengono pure modificati i tempi ad
-esso associati (di cui si è trattato in sez.~\ref{sec:file_file_times}). Il
-valore di \var{st\_atime} può venir cambiato in qualunque istante a partire
-dal momento in cui la mappatura è stata effettuata: il primo riferimento ad
+esso associati (di cui si è trattato in sez.~\ref{sec:file_file_times}). Il
+valore di \var{st\_atime} può venir cambiato in qualunque istante a partire
+dal momento in cui la mappatura è stata effettuata: il primo riferimento ad
-\var{st\_ctime} e \var{st\_mtime} possono venir cambiati solo quando si è
-consentita la scrittura sul file (cioè per un file mappato con
+\var{st\_ctime} e \var{st\_mtime} possono venir cambiati solo quando si è
+consentita la scrittura sul file (cioè per un file mappato con
\const{PROT\_WRITE} e \const{MAP\_SHARED}) e sono aggiornati dopo la scrittura
o in corrispondenza di una eventuale \func{msync}.
\const{PROT\_WRITE} e \const{MAP\_SHARED}) e sono aggiornati dopo la scrittura
o in corrispondenza di una eventuale \func{msync}.
direttamente dalla \index{memoria~virtuale}memoria virtuale, occorre essere
consapevoli delle interazioni che possono esserci con operazioni effettuate
con l'interfaccia standard dei file di cap.~\ref{cha:file_unix_interface}. Il
direttamente dalla \index{memoria~virtuale}memoria virtuale, occorre essere
consapevoli delle interazioni che possono esserci con operazioni effettuate
con l'interfaccia standard dei file di cap.~\ref{cha:file_unix_interface}. Il
scrittura saranno eseguite sulla memoria, e riportate su disco in maniera
autonoma dal sistema della memoria virtuale.
Pertanto se si modifica un file con l'interfaccia standard queste modifiche
potranno essere visibili o meno a seconda del momento in cui la memoria
scrittura saranno eseguite sulla memoria, e riportate su disco in maniera
autonoma dal sistema della memoria virtuale.
Pertanto se si modifica un file con l'interfaccia standard queste modifiche
potranno essere visibili o meno a seconda del momento in cui la memoria
-Per questo, è sempre sconsigliabile eseguire scritture su file attraverso
-l'interfaccia standard quando lo si è mappato in memoria, è invece possibile
-usare l'interfaccia standard per leggere un file mappato in memoria, purché si
+Per questo, è sempre sconsigliabile eseguire scritture su file attraverso
+l'interfaccia standard quando lo si è mappato in memoria, è invece possibile
+usare l'interfaccia standard per leggere un file mappato in memoria, purché si
abbia una certa cura; infatti l'interfaccia dell'I/O mappato in memoria mette
a disposizione la funzione \funcd{msync} per sincronizzare il contenuto della
abbia una certa cura; infatti l'interfaccia dell'I/O mappato in memoria mette
a disposizione la funzione \funcd{msync} per sincronizzare il contenuto della
Sincronizza i contenuti di una sezione di un file mappato in memoria.
\bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
Sincronizza i contenuti di una sezione di un file mappato in memoria.
\bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
- \item[\errcode{EINVAL}] o \param{start} non è multiplo di
- \const{PAGE\_SIZE}, o si è specificato un valore non valido per
+ \item[\errcode{EINVAL}] o \param{start} non è multiplo di
+ \const{PAGE\_SIZE}, o si è specificato un valore non valido per
La funzione esegue la sincronizzazione di quanto scritto nella sezione di
memoria indicata da \param{start} e \param{offset}, scrivendo le modifiche sul
La funzione esegue la sincronizzazione di quanto scritto nella sezione di
memoria indicata da \param{start} e \param{offset}, scrivendo le modifiche sul
-file (qualora questo non sia già stato fatto). Provvede anche ad aggiornare i
-relativi tempi di modifica. In questo modo si è sicuri che dopo l'esecuzione
+file (qualora questo non sia già stato fatto). Provvede anche ad aggiornare i
+relativi tempi di modifica. In questo modo si è sicuri che dopo l'esecuzione
\const{MS\_ASYNC} & richiede una sincronizzazione, ma ritorna subito
non attendendo che questa sia finita.\\
\const{MS\_INVALIDATE} & invalida le pagine per tutte le mappature
\const{MS\_ASYNC} & richiede una sincronizzazione, ma ritorna subito
non attendendo che questa sia finita.\\
\const{MS\_INVALIDATE} & invalida le pagine per tutte le mappature
-L'argomento \param{flag} è specificato come maschera binaria composta da un OR
-dei valori riportati in tab.~\ref{tab:file_mmap_msync}, di questi però
+L'argomento \param{flag} è specificato come maschera binaria composta da un OR
+dei valori riportati in tab.~\ref{tab:file_mmap_msync}, di questi però
\const{MS\_ASYNC} e \const{MS\_SYNC} sono incompatibili; con il primo valore
infatti la funzione si limita ad inoltrare la richiesta di sincronizzazione al
meccanismo della memoria virtuale, ritornando subito, mentre con il secondo
attende che la sincronizzazione sia stata effettivamente eseguita. Il terzo
\const{MS\_ASYNC} e \const{MS\_SYNC} sono incompatibili; con il primo valore
infatti la funzione si limita ad inoltrare la richiesta di sincronizzazione al
meccanismo della memoria virtuale, ritornando subito, mentre con il secondo
attende che la sincronizzazione sia stata effettivamente eseguita. Il terzo
-flag fa sì che vengano invalidate, per tutte le mappature dello stesso file,
-le pagine di cui si è richiesta la sincronizzazione, così che esse possano
+flag fa sì che vengano invalidate, per tutte le mappature dello stesso file,
+le pagine di cui si è richiesta la sincronizzazione, così che esse possano
-Una volta che si sono completate le operazioni di I/O si può eliminare la
-mappatura della memoria usando la funzione \funcd{munmap}, il suo prototipo è:
+Una volta che si sono completate le operazioni di I/O si può eliminare la
+mappatura della memoria usando la funzione \funcd{munmap}, il suo prototipo è:
Rilascia la mappatura sulla sezione di memoria specificata.
\bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
Rilascia la mappatura sulla sezione di memoria specificata.
\bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
un errore di accesso in memoria. L'argomento \param{start} deve essere
allineato alle dimensioni di una pagina, e la mappatura di tutte le pagine
un errore di accesso in memoria. L'argomento \param{start} deve essere
allineato alle dimensioni di una pagina, e la mappatura di tutte le pagine
-contenute anche parzialmente nell'intervallo indicato, verrà rimossa.
-Indicare un intervallo che non contiene mappature non è un errore. Si tenga
-presente inoltre che alla conclusione di un processo ogni pagina mappata verrà
+contenute anche parzialmente nell'intervallo indicato, verrà rimossa.
+Indicare un intervallo che non contiene mappature non è un errore. Si tenga
+presente inoltre che alla conclusione di un processo ogni pagina mappata verrà
automaticamente rilasciata, mentre la chiusura del file descriptor usato per
il \textit{memory mapping} non ha alcun effetto su di esso.
Lo standard POSIX prevede anche una funzione che permetta di cambiare le
protezioni delle pagine di memoria; lo standard prevede che essa si applichi
solo ai \textit{memory mapping} creati con \func{mmap}, ma nel caso di Linux
automaticamente rilasciata, mentre la chiusura del file descriptor usato per
il \textit{memory mapping} non ha alcun effetto su di esso.
Lo standard POSIX prevede anche una funzione che permetta di cambiare le
protezioni delle pagine di memoria; lo standard prevede che essa si applichi
solo ai \textit{memory mapping} creati con \func{mmap}, ma nel caso di Linux
-la funzione può essere usata con qualunque pagina valida nella memoria
-virtuale. Questa funzione è \funcd{mprotect} ed il suo prototipo è:
+la funzione può essere usata con qualunque pagina valida nella memoria
+virtuale. Questa funzione è \funcd{mprotect} ed il suo prototipo è:
allineato alle dimensioni delle pagine di memoria, ed una dimensione
\param{size}. La nuova protezione deve essere specificata in \param{prot} con
una combinazione dei valori di tab.~\ref{tab:file_mmap_prot}. La nuova
allineato alle dimensioni delle pagine di memoria, ed una dimensione
\param{size}. La nuova protezione deve essere specificata in \param{prot} con
una combinazione dei valori di tab.~\ref{tab:file_mmap_prot}. La nuova
dall'intervallo fra \param{addr} e \param{addr}+\param{size}-1.
Infine Linux supporta alcune operazioni specifiche non disponibili su altri
dall'intervallo fra \param{addr} e \param{addr}+\param{size}-1.
Infine Linux supporta alcune operazioni specifiche non disponibili su altri
\bodydesc{La funzione restituisce l'indirizzo alla nuova area di memoria in
caso di successo od il valore \const{MAP\_FAILED} (pari a \texttt{(void *)
\bodydesc{La funzione restituisce l'indirizzo alla nuova area di memoria in
caso di successo od il valore \const{MAP\_FAILED} (pari a \texttt{(void *)
puntatore valido.
\item[\errcode{EFAULT}] ci sono indirizzi non validi nell'intervallo
specificato da \param{old\_address} e \param{old\_size}, o ci sono altre
mappature di tipo non corrispondente a quella richiesta.
puntatore valido.
\item[\errcode{EFAULT}] ci sono indirizzi non validi nell'intervallo
specificato da \param{old\_address} e \param{old\_size}, o ci sono altre
mappature di tipo non corrispondente a quella richiesta.
- \item[\errcode{ENOMEM}] non c'è memoria sufficiente oppure l'area di
- memoria non può essere espansa all'indirizzo virtuale corrente, e non si
- è specificato \const{MREMAP\_MAYMOVE} nei flag.
- \item[\errcode{EAGAIN}] il segmento di memoria scelto è bloccato e non può
+ \item[\errcode{ENOMEM}] non c'è memoria sufficiente oppure l'area di
+ memoria non può essere espansa all'indirizzo virtuale corrente, e non si
+ è specificato \const{MREMAP\_MAYMOVE} nei flag.
+ \item[\errcode{EAGAIN}] il segmento di memoria scelto è bloccato e non può
allineato alle dimensioni di una pagina di memoria) che specifica il
precedente indirizzo del \textit{memory mapping} e \param{old\_size}, che ne
indica la dimensione. Con \param{new\_size} si specifica invece la nuova
allineato alle dimensioni di una pagina di memoria) che specifica il
precedente indirizzo del \textit{memory mapping} e \param{old\_size}, che ne
indica la dimensione. Con \param{new\_size} si specifica invece la nuova
utilizzare questa costante occorre aver definito \macro{\_GNU\_SOURCE} prima
di includere \file{sys/mman.h}.} che consente di eseguire l'espansione
utilizzare questa costante occorre aver definito \macro{\_GNU\_SOURCE} prima
di includere \file{sys/mman.h}.} che consente di eseguire l'espansione
-anche quando non è possibile utilizzare il precedente indirizzo. Per questo
-motivo, se si è usato questo flag, la funzione può restituire un indirizzo
-della nuova zona di memoria che non è detto coincida con \param{old\_address}.
+anche quando non è possibile utilizzare il precedente indirizzo. Per questo
+motivo, se si è usato questo flag, la funzione può restituire un indirizzo
+della nuova zona di memoria che non è detto coincida con \param{old\_address}.
La funzione si appoggia al sistema della \index{memoria~virtuale} memoria
virtuale per modificare l'associazione fra gli indirizzi virtuali del processo
e le pagine di memoria, modificando i dati direttamente nella
\itindex{page~table} \textit{page table} del processo. Come per
La funzione si appoggia al sistema della \index{memoria~virtuale} memoria
virtuale per modificare l'associazione fra gli indirizzi virtuali del processo
e le pagine di memoria, modificando i dati direttamente nella
\itindex{page~table} \textit{page table} del processo. Come per
-\func{mprotect} la funzione può essere usata in generale, anche per pagine di
-memoria non corrispondenti ad un \textit{memory mapping}, e consente così di
+\func{mprotect} la funzione può essere usata in generale, anche per pagine di
+memoria non corrispondenti ad un \textit{memory mapping}, e consente così di
-Una caratteristica comune a tutti i sistemi unix-like è che la mappatura in
-memoria di un file viene eseguita in maniera lineare, cioè parti successive di
+Una caratteristica comune a tutti i sistemi unix-like è che la mappatura in
+memoria di un file viene eseguita in maniera lineare, cioè parti successive di
-Esistono però delle applicazioni\footnote{in particolare la tecnica è usata
- dai database o dai programmi che realizzano macchine virtuali.} in cui è
+Esistono però delle applicazioni\footnote{in particolare la tecnica è usata
+ dai database o dai programmi che realizzano macchine virtuali.} in cui è
anche con Linux prima che fossero introdotte queste estensioni.} ma questo
approccio ha delle conseguenze molto pesanti in termini di prestazioni.
Infatti per ciascuna mappatura in memoria deve essere definita nella
anche con Linux prima che fossero introdotte queste estensioni.} ma questo
approccio ha delle conseguenze molto pesanti in termini di prestazioni.
Infatti per ciascuna mappatura in memoria deve essere definita nella
questa diventi visibile nello spazio degli indirizzi come illustrato in
fig.~\ref{fig:file_mmap_layout}.
questa diventi visibile nello spazio degli indirizzi come illustrato in
fig.~\ref{fig:file_mmap_layout}.
-non-lineare si avrà un accrescimento eccessivo della sua \itindex{page~table}
-\textit{page table}, e lo stesso accadrà per tutti gli altri processi che
+non-lineare si avrà un accrescimento eccessivo della sua \itindex{page~table}
+\textit{page table}, e lo stesso accadrà per tutti gli altri processi che
impiegare molte risorse\footnote{sia in termini di memoria interna per i dati
delle \itindex{page~table} \textit{page table}, che di CPU per il loro
impiegare molte risorse\footnote{sia in termini di memoria interna per i dati
delle \itindex{page~table} \textit{page table}, che di CPU per il loro
-Per questo motivo con il kernel 2.5.46 è stato introdotto, ad opera di Ingo
-Molnar, un meccanismo che consente la mappatura non-lineare. Anche questa è
+Per questo motivo con il kernel 2.5.46 è stato introdotto, ad opera di Ingo
+Molnar, un meccanismo che consente la mappatura non-lineare. Anche questa è
iniziale\footnote{e quindi una sola \textit{virtual memory area} nella
\itindex{page~table} \textit{page table} del processo.} e poi rimappare a
iniziale\footnote{e quindi una sola \textit{virtual memory area} nella
\itindex{page~table} \textit{page table} del processo.} e poi rimappare a
-piacere all'interno di questa i dati del file. Ciò è possibile grazie ad una
-nuova system call, \funcd{remap\_file\_pages}, il cui prototipo è:
+piacere all'interno di questa i dati del file. Ciò è possibile grazie ad una
+nuova system call, \funcd{remap\_file\_pages}, il cui prototipo è:
Permette di rimappare non linearmente un precedente \textit{memory mapping}.
\bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
Permette di rimappare non linearmente un precedente \textit{memory mapping}.
\bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
argomenti o \param{start} non fa riferimento ad un \textit{memory
mapping} valido creato con \const{MAP\_SHARED}.
\end{errlist}
argomenti o \param{start} non fa riferimento ad un \textit{memory
mapping} valido creato con \const{MAP\_SHARED}.
\end{errlist}
Per poter utilizzare questa funzione occorre anzitutto effettuare
preliminarmente una chiamata a \func{mmap} con \const{MAP\_SHARED} per
Per poter utilizzare questa funzione occorre anzitutto effettuare
preliminarmente una chiamata a \func{mmap} con \const{MAP\_SHARED} per
-definire l'area di memoria che poi sarà rimappata non linearmente. Poi di
-chiamerà questa funzione per modificare le corrispondenze fra pagine di
+definire l'area di memoria che poi sarà rimappata non linearmente. Poi di
+chiamerà questa funzione per modificare le corrispondenze fra pagine di
regione mappata.
La funzione richiede che si identifichi la sezione del file che si vuole
riposizionare all'interno del \textit{memory mapping} con gli argomenti
\param{pgoff} e \param{size}; l'argomento \param{start} invece deve indicare
un indirizzo all'interno dell'area definita dall'\func{mmap} iniziale, a
regione mappata.
La funzione richiede che si identifichi la sezione del file che si vuole
riposizionare all'interno del \textit{memory mapping} con gli argomenti
\param{pgoff} e \param{size}; l'argomento \param{start} invece deve indicare
un indirizzo all'interno dell'area definita dall'\func{mmap} iniziale, a
\param{prot} deve essere sempre nullo, mentre \param{flags} prende gli stessi
valori di \func{mmap} (quelli di tab.~\ref{tab:file_mmap_prot}) ma di tutti i
flag solo \const{MAP\_NONBLOCK} non viene ignorato.
\param{prot} deve essere sempre nullo, mentre \param{flags} prende gli stessi
valori di \func{mmap} (quelli di tab.~\ref{tab:file_mmap_prot}) ma di tutti i
flag solo \const{MAP\_NONBLOCK} non viene ignorato.
Il problema si pone tutte le volte che si vuole mappare in memoria un file di
grosse dimensioni. Il comportamento normale del sistema della
Il problema si pone tutte le volte che si vuole mappare in memoria un file di
grosse dimensioni. Il comportamento normale del sistema della
\itindex{page~fault} \textit{page fault} che li trasferisce dal disco alla
memoria) soltanto in corrispondenza dell'accesso a ciascuna delle pagine
interessate dal \textit{memory mapping}.
\itindex{page~fault} \textit{page fault} che li trasferisce dal disco alla
memoria) soltanto in corrispondenza dell'accesso a ciascuna delle pagine
interessate dal \textit{memory mapping}.
- fault}, chiaramente se si sa in anticipo che il file verrà utilizzato
-immediatamente, è molto più efficiente eseguire un \itindex{prefaulting}
+ fault}, chiaramente se si sa in anticipo che il file verrà utilizzato
+immediatamente, è molto più efficiente eseguire un \itindex{prefaulting}
\textit{prefaulting} in cui tutte le pagine di memoria interessate alla
mappatura vengono ``\textsl{popolate}'' in una sola volta, questo
comportamento viene abilitato quando si usa con \func{mmap} il flag
\const{MAP\_POPULATE}.
\textit{prefaulting} in cui tutte le pagine di memoria interessate alla
mappatura vengono ``\textsl{popolate}'' in una sola volta, questo
comportamento viene abilitato quando si usa con \func{mmap} il flag
\const{MAP\_POPULATE}.
-Dato che l'uso di \const{MAP\_POPULATE} comporta dell'I/O su disco che può
-rallentare l'esecuzione di \func{mmap} è stato introdotto anche un secondo
+Dato che l'uso di \const{MAP\_POPULATE} comporta dell'I/O su disco che può
+rallentare l'esecuzione di \func{mmap} è stato introdotto anche un secondo
-\textit{prefaulting} più limitato in cui vengono popolate solo le pagine della
-mappatura che già si trovano nella cache del kernel.\footnote{questo può
+\textit{prefaulting} più limitato in cui vengono popolate solo le pagine della
+mappatura che già si trovano nella cache del kernel.\footnote{questo può
essere utile per il linker dinamico, in particolare quando viene effettuato
il \textit{prelink} delle applicazioni.}
Per i vantaggi illustrati all'inizio del paragrafo l'interfaccia del
essere utile per il linker dinamico, in particolare quando viene effettuato
il \textit{prelink} delle applicazioni.}
Per i vantaggi illustrati all'inizio del paragrafo l'interfaccia del
-\textit{memory mapped I/O} viene usata da una grande varietà di programmi,
-spesso con esigenze molto diverse fra di loro riguardo le modalità con cui
-verranno eseguiti gli accessi ad un file; è ad esempio molto comune per i
-database effettuare accessi ai dati in maniera pressoché casuale, mentre un
-riproduttore audio o video eseguirà per lo più letture sequenziali.
+\textit{memory mapped I/O} viene usata da una grande varietà di programmi,
+spesso con esigenze molto diverse fra di loro riguardo le modalità con cui
+verranno eseguiti gli accessi ad un file; è ad esempio molto comune per i
+database effettuare accessi ai dati in maniera pressoché casuale, mentre un
+riproduttore audio o video eseguirà per lo più letture sequenziali.
disponibile una apposita funzione, \funcd{madvise},\footnote{tratteremo in
sez.~\ref{sec:file_fadvise} le funzioni che consentono di ottimizzare
l'accesso ai file con l'interfaccia classica.} che consente di fornire al
disponibile una apposita funzione, \funcd{madvise},\footnote{tratteremo in
sez.~\ref{sec:file_fadvise} le funzioni che consentono di ottimizzare
l'accesso ai file con l'interfaccia classica.} che consente di fornire al
-kernel delle indicazioni su dette modalità, così che possano essere adottate
-le opportune strategie di ottimizzazione. Il suo prototipo è:
+kernel delle indicazioni su dette modalità, così che possano essere adottate
+le opportune strategie di ottimizzazione. Il suo prototipo è:
Fornisce indicazioni sull'uso previsto di un \textit{memory mapping}.
\bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
Fornisce indicazioni sull'uso previsto di un \textit{memory mapping}.
\bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
- \item[\errcode{EINVAL}] \param{start} non è allineato alla dimensione di
- una pagina, \param{length} ha un valore negativo, o \param{advice} non è
- un valore valido, o si è richiesto il rilascio (con
+ \item[\errcode{EINVAL}] \param{start} non è allineato alla dimensione di
+ una pagina, \param{length} ha un valore negativo, o \param{advice} non è
+ un valore valido, o si è richiesto il rilascio (con
\const{MADV\_DONTNEED}) di pagine bloccate o condivise.
\item[\errcode{EIO}] la paginazione richiesta eccederebbe i limiti (vedi
sez.~\ref{sec:sys_resource_limit}) sulle pagine residenti in memoria del
processo (solo in caso di \const{MADV\_WILLNEED}).
\item[\errcode{ENOMEM}] gli indirizzi specificati non sono mappati, o, in
\const{MADV\_DONTNEED}) di pagine bloccate o condivise.
\item[\errcode{EIO}] la paginazione richiesta eccederebbe i limiti (vedi
sez.~\ref{sec:sys_resource_limit}) sulle pagine residenti in memoria del
processo (solo in caso di \const{MADV\_WILLNEED}).
\item[\errcode{ENOMEM}] gli indirizzi specificati non sono mappati, o, in
\param{length}, il valore di \param{start} deve essere allineato,
mentre \param{length} deve essere un numero positivo.\footnote{la versione di
Linux consente anche un valore nullo per \param{length}, inoltre se una
\param{length}, il valore di \param{start} deve essere allineato,
mentre \param{length} deve essere un numero positivo.\footnote{la versione di
Linux consente anche un valore nullo per \param{length}, inoltre se una
applicata alle restanti parti, anche se la funzione ritorna un errore di
\errval{ENOMEM}.} L'indicazione viene espressa dall'argomento \param{advice}
che deve essere specificato con uno dei valori\footnote{si tenga presente che
applicata alle restanti parti, anche se la funzione ritorna un errore di
\errval{ENOMEM}.} L'indicazione viene espressa dall'argomento \param{advice}
che deve essere specificato con uno dei valori\footnote{si tenga presente che
- \const{MADV\_NORMAL} & nessuna indicazione specifica, questo è il valore
- di default usato quando non si è chiamato
+ \const{MADV\_NORMAL} & nessuna indicazione specifica, questo è il valore
+ di default usato quando non si è chiamato
\func{madvise}.\\
\const{MADV\_RANDOM} & ci si aspetta un accesso casuale all'area
indicata, pertanto l'applicazione di una lettura
anticipata con il meccanismo del
\itindex{read-ahead} \textit{read-ahead} (vedi
\func{madvise}.\\
\const{MADV\_RANDOM} & ci si aspetta un accesso casuale all'area
indicata, pertanto l'applicazione di una lettura
anticipata con il meccanismo del
\itindex{read-ahead} \textit{read-ahead} (vedi
lettura anticipata, e dall'altra si potranno
scartare immediatamente le pagine una volta che
queste siano state lette.\\
lettura anticipata, e dall'altra si potranno
scartare immediatamente le pagine una volta che
queste siano state lette.\\
\const{MADV\_DONTNEED}& non ci si aspetta nessun accesso nell'immediato
futuro, pertanto le pagine possono essere
liberate dal kernel non appena necessario; l'area
\const{MADV\_DONTNEED}& non ci si aspetta nessun accesso nell'immediato
futuro, pertanto le pagine possono essere
liberate dal kernel non appena necessario; l'area
- di memoria resterà accessibile, ma un accesso
- richiederà che i dati vengano ricaricati dal file
+ di memoria resterà accessibile, ma un accesso
+ richiederà che i dati vengano ricaricati dal file
a cui la mappatura fa riferimento.\\
\hline
\const{MADV\_REMOVE} & libera un intervallo di pagine di memoria ed il
a cui la mappatura fa riferimento.\\
\hline
\const{MADV\_REMOVE} & libera un intervallo di pagine di memoria ed il
soltanto sui filesystem in RAM \textit{tmpfs} e
\textit{shmfs}.\footnotemark\\
\const{MADV\_DONTFORK}& impedisce che l'intervallo specificato venga
soltanto sui filesystem in RAM \textit{tmpfs} e
\textit{shmfs}.\footnotemark\\
\const{MADV\_DONTFORK}& impedisce che l'intervallo specificato venga
meccanismo del \itindex{copy~on~write}
\textit{copy on write} effettui la rilocazione
delle pagine quando il padre scrive sull'area
meccanismo del \itindex{copy~on~write}
\textit{copy on write} effettui la rilocazione
delle pagine quando il padre scrive sull'area
causare problemi per l'hardware che esegue
operazioni in DMA su quelle pagine.\\
\const{MADV\_DOFORK} & rimuove l'effetto della precedente
causare problemi per l'hardware che esegue
operazioni in DMA su quelle pagine.\\
\const{MADV\_DOFORK} & rimuove l'effetto della precedente
identifica pagine di memoria identiche e le accorpa in una unica pagina
(soggetta al \textit{copy-on-write} per successive modifiche); per evitare
di controllare tutte le pagine solo quelle marcate con questo flag vengono
prese in considerazione per l'accorpamento; in questo modo si possono
migliorare le prestazioni nella gestione delle macchine virtuali diminuendo
identifica pagine di memoria identiche e le accorpa in una unica pagina
(soggetta al \textit{copy-on-write} per successive modifiche); per evitare
di controllare tutte le pagine solo quelle marcate con questo flag vengono
prese in considerazione per l'accorpamento; in questo modo si possono
migliorare le prestazioni nella gestione delle macchine virtuali diminuendo
altre applicazioni in cui sian presenti numerosi processi che usano gli
stessi dati; per maggiori dettagli si veda
\href{http://kernelnewbies.org/Linux_2_6_32\#head-d3f32e41df508090810388a57efce73f52660ccb}{\texttt{http://kernelnewbies.org/Linux\_2\_6\_32}}.}
La funzione non ha, tranne il caso di \const{MADV\_DONTFORK}, nessun effetto
altre applicazioni in cui sian presenti numerosi processi che usano gli
stessi dati; per maggiori dettagli si veda
\href{http://kernelnewbies.org/Linux_2_6_32\#head-d3f32e41df508090810388a57efce73f52660ccb}{\texttt{http://kernelnewbies.org/Linux\_2\_6\_32}}.}
La funzione non ha, tranne il caso di \const{MADV\_DONTFORK}, nessun effetto
-sul comportamento di un programma, ma può influenzarne le prestazioni fornendo
-al kernel indicazioni sulle esigenze dello stesso, così che sia possibile
+sul comportamento di un programma, ma può influenzarne le prestazioni fornendo
+al kernel indicazioni sulle esigenze dello stesso, così che sia possibile
scegliere le opportune strategie per la gestione del \itindex{read-ahead}
\textit{read-ahead} e del caching dei dati. A differenza da quanto specificato
scegliere le opportune strategie per la gestione del \itindex{read-ahead}
\textit{read-ahead} e del caching dei dati. A differenza da quanto specificato
puramente indicativo, Linux considera queste richieste come imperative, per
cui ritorna un errore qualora non possa soddisfarle.\footnote{questo
comportamento differisce da quanto specificato nello standard.}
puramente indicativo, Linux considera queste richieste come imperative, per
cui ritorna un errore qualora non possa soddisfarle.\footnote{questo
comportamento differisce da quanto specificato nello standard.}
-vari buffer. Un esempio tipico è quando i dati sono strutturati nei campi di
-una struttura ed essi devono essere caricati o salvati su un file. Benché
+vari buffer. Un esempio tipico è quando i dati sono strutturati nei campi di
+una struttura ed essi devono essere caricati o salvati su un file. Benché
l'operazione sia facilmente eseguibile attraverso una serie multipla di
chiamate a \func{read} e \func{write}, ci sono casi in cui si vuole poter
l'operazione sia facilmente eseguibile attraverso una serie multipla di
chiamate a \func{read} e \func{write}, ci sono casi in cui si vuole poter
Per questo motivo fino da BSD 4.2 vennero introdotte delle nuove system call
che permettessero di effettuare con una sola chiamata una serie di letture o
Per questo motivo fino da BSD 4.2 vennero introdotte delle nuove system call
che permettessero di effettuare con una sola chiamata una serie di letture o
\bodydesc{Le funzioni restituiscono il numero di byte letti o scritti in
caso di successo, e -1 in caso di errore, nel qual caso \var{errno}
\bodydesc{Le funzioni restituiscono il numero di byte letti o scritti in
caso di successo, e -1 in caso di errore, nel qual caso \var{errno}
- \item[\errcode{EINVAL}] si è specificato un valore non valido per uno degli
- argomenti (ad esempio \param{count} è maggiore di \const{IOV\_MAX}).
- \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale prima di
+ \item[\errcode{EINVAL}] si è specificato un valore non valido per uno degli
+ argomenti (ad esempio \param{count} è maggiore di \const{IOV\_MAX}).
+ \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale prima di
\end{errlist}
ed anche \errval{EISDIR}, \errval{EBADF}, \errval{ENOMEM}, \errval{EFAULT}
(se non sono stati allocati correttamente i buffer specificati nei campi
\end{errlist}
ed anche \errval{EISDIR}, \errval{EBADF}, \errval{ENOMEM}, \errval{EFAULT}
(se non sono stati allocati correttamente i buffer specificati nei campi
\var{iov\_base}, contiene l'indirizzo del buffer ed il secondo,
\var{iov\_len}, la dimensione dello stesso.
\var{iov\_base}, contiene l'indirizzo del buffer ed il secondo,
\var{iov\_len}, la dimensione dello stesso.
-\param{vector} che è un vettore di strutture \struct{iovec}, la cui lunghezza
-è specificata dall'argomento \param{count}.\footnote{fino alle libc5, Linux
+\param{vector} che è un vettore di strutture \struct{iovec}, la cui lunghezza
+è specificata dall'argomento \param{count}.\footnote{fino alle libc5, Linux
- logica, che però è stata dismessa per restare aderenti allo standard
- POSIX.1-2001.} Ciascuna struttura dovrà essere inizializzata opportunamente
-per indicare i vari buffer da e verso i quali verrà eseguito il trasferimento
+ logica, che però è stata dismessa per restare aderenti allo standard
+ POSIX.1-2001.} Ciascuna struttura dovrà essere inizializzata opportunamente
+per indicare i vari buffer da e verso i quali verrà eseguito il trasferimento
dei dati. Essi verranno letti (o scritti) nell'ordine in cui li si sono
specificati nel vettore \param{vector}.
dei dati. Essi verranno letti (o scritti) nell'ordine in cui li si sono
specificati nel vettore \param{vector}.
verranno letti o scritti con le usuali \func{read} e \func{write} usando un
buffer di dimensioni sufficienti appositamente allocato e sufficiente a
verranno letti o scritti con le usuali \func{read} e \func{write} usando un
buffer di dimensioni sufficienti appositamente allocato e sufficiente a
-contenere tutti i dati indicati da \param{vector}. L'operazione avrà successo
-ma si perderà l'atomicità del trasferimento da e verso la destinazione finale.
+contenere tutti i dati indicati da \param{vector}. L'operazione avrà successo
+ma si perderà l'atomicità del trasferimento da e verso la destinazione finale.
l'interfaccia classica dei \textit{file stream} di
cap.~\ref{cha:files_std_interface}; a causa delle bufferizzazioni interne di
quest'ultima infatti si potrebbero avere risultati indefiniti e non
l'interfaccia classica dei \textit{file stream} di
cap.~\ref{cha:files_std_interface}; a causa delle bufferizzazioni interne di
quest'ultima infatti si potrebbero avere risultati indefiniti e non
\bodydesc{Le funzioni hanno gli stessi valori di ritorno delle
corrispondenti \func{readv} e \func{writev}; anche gli eventuali errori
\bodydesc{Le funzioni hanno gli stessi valori di ritorno delle
corrispondenti \func{readv} e \func{writev}; anche gli eventuali errori
vettorizzata a partire dalla posizione \param{offset} sul file indicato
da \param{fd}, la posizione corrente sul file, come vista da eventuali altri
processi che vi facciano riferimento, non viene alterata. A parte la presenza
vettorizzata a partire dalla posizione \param{offset} sul file indicato
da \param{fd}, la posizione corrente sul file, come vista da eventuali altri
processi che vi facciano riferimento, non viene alterata. A parte la presenza
-Uno dei problemi che si presentano nella gestione dell'I/O è quello in cui si
-devono trasferire grandi quantità di dati da un file descriptor ed un altro;
+Uno dei problemi che si presentano nella gestione dell'I/O è quello in cui si
+devono trasferire grandi quantità di dati da un file descriptor ed un altro;
questo usualmente comporta la lettura dei dati dal primo file descriptor in un
buffer in memoria, da cui essi vengono poi scritti sul secondo.
questo usualmente comporta la lettura dei dati dal primo file descriptor in un
buffer in memoria, da cui essi vengono poi scritti sul secondo.
-pone il problema di effettuare trasferimenti di grandi quantità di dati da
-kernel space a user space e all'indietro, quando in realtà potrebbe essere più
+pone il problema di effettuare trasferimenti di grandi quantità di dati da
+kernel space a user space e all'indietro, quando in realtà potrebbe essere più
efficiente mantenere tutto in kernel space. Tratteremo in questa sezione
alcune funzioni specialistiche che permettono di ottimizzare le prestazioni in
questo tipo di situazioni.
efficiente mantenere tutto in kernel space. Tratteremo in questa sezione
alcune funzioni specialistiche che permettono di ottimizzare le prestazioni in
questo tipo di situazioni.
-La prima funzione che è stata ideata per ottimizzare il trasferimento dei dati
-fra due file descriptor è \func{sendfile};\footnote{la funzione è stata
+La prima funzione che è stata ideata per ottimizzare il trasferimento dei dati
+fra due file descriptor è \func{sendfile};\footnote{la funzione è stata
- 2.1.} la funzione è presente in diverse versioni di Unix,\footnote{la si
- ritrova ad esempio in FreeBSD, HPUX ed altri Unix.} ma non è presente né in
-POSIX.1-2001 né in altri standard,\footnote{pertanto si eviti di utilizzarla
+ 2.1.} la funzione è presente in diverse versioni di Unix,\footnote{la si
+ ritrova ad esempio in FreeBSD, HPUX ed altri Unix.} ma non è presente né in
+POSIX.1-2001 né in altri standard,\footnote{pertanto si eviti di utilizzarla
se si devono scrivere programmi portabili.} per cui per essa vengono
utilizzati prototipi e semantiche differenti; nel caso di Linux il prototipo
se si devono scrivere programmi portabili.} per cui per essa vengono
utilizzati prototipi e semantiche differenti; nel caso di Linux il prototipo
Copia dei dati da un file descriptor ad un altro.
\bodydesc{La funzione restituisce il numero di byte trasferiti in caso di
Copia dei dati da un file descriptor ad un altro.
\bodydesc{La funzione restituisce il numero di byte trasferiti in caso di
\param{out\_fd} e la scrittura si bloccherebbe.
\item[\errcode{EINVAL}] i file descriptor non sono validi, o sono bloccati
\param{out\_fd} e la scrittura si bloccherebbe.
\item[\errcode{EINVAL}] i file descriptor non sono validi, o sono bloccati
- \item[\errcode{EIO}] si è avuto un errore di lettura da \param{in\_fd}.
- \item[\errcode{ENOMEM}] non c'è memoria sufficiente per la lettura da
+ \item[\errcode{EIO}] si è avuto un errore di lettura da \param{in\_fd}.
+ \item[\errcode{ENOMEM}] non c'è memoria sufficiente per la lettura da
\param{in\_fd} al file descriptor \param{out\_fd}; in caso di successo
funzione ritorna il numero di byte effettivamente copiati da \param{in\_fd} a
\param{out\_fd} o $-1$ in caso di errore; come le ordinarie \func{read} e
\param{in\_fd} al file descriptor \param{out\_fd}; in caso di successo
funzione ritorna il numero di byte effettivamente copiati da \param{in\_fd} a
\param{out\_fd} o $-1$ in caso di errore; come le ordinarie \func{read} e
-Se il puntatore \param{offset} è nullo la funzione legge i dati a partire
-dalla posizione corrente su \param{in\_fd}, altrimenti verrà usata la
+Se il puntatore \param{offset} è nullo la funzione legge i dati a partire
+dalla posizione corrente su \param{in\_fd}, altrimenti verrà usata la
-valore sarà aggiornato, come \textit{value result argument}, per indicare la
-posizione del byte successivo all'ultimo che è stato letto, mentre la
-posizione corrente sul file non sarà modificata. Se invece \param{offset} è
-nullo la posizione corrente sul file sarà aggiornata tenendo conto dei byte
+valore sarà aggiornato, come \textit{value result argument}, per indicare la
+posizione del byte successivo all'ultimo che è stato letto, mentre la
+posizione corrente sul file non sarà modificata. Se invece \param{offset} è
+nullo la posizione corrente sul file sarà aggiornata tenendo conto dei byte
descriptor, e permette di sostituire la invocazione successiva di una
\func{read} e una \func{write} (e l'allocazione del relativo buffer) con una
descriptor, e permette di sostituire la invocazione successiva di una
\func{read} e una \func{write} (e l'allocazione del relativo buffer) con una
ed infatti Apache ha una opzione per il supporto esplicito di questa
funzione.} dato che in questo caso diventa possibile effettuare il
trasferimento diretto via DMA dal controller del disco alla scheda di rete,
ed infatti Apache ha una opzione per il supporto esplicito di questa
funzione.} dato che in questo caso diventa possibile effettuare il
trasferimento diretto via DMA dal controller del disco alla scheda di rete,
\textit{zerocopy} in quanto i dati non vengono mai copiati dal kernel, che
si limita a programmare solo le operazioni di lettura e scrittura via DMA.}
ottenendo la massima efficienza possibile senza pesare neanche sul processore.
\textit{zerocopy} in quanto i dati non vengono mai copiati dal kernel, che
si limita a programmare solo le operazioni di lettura e scrittura via DMA.}
ottenendo la massima efficienza possibile senza pesare neanche sul processore.
diretto da file a socket, non sempre \func{sendfile} comportava miglioramenti
significativi delle prestazioni rispetto all'uso in sequenza di \func{read} e
\func{write},\footnote{nel caso generico infatti il kernel deve comunque
diretto da file a socket, non sempre \func{sendfile} comportava miglioramenti
significativi delle prestazioni rispetto all'uso in sequenza di \func{read} e
\func{write},\footnote{nel caso generico infatti il kernel deve comunque
user space che ha una conoscenza diretta su come questi sono strutturati.} e
che anzi in certi casi si potevano avere anche dei peggioramenti. Questo ha
portato, per i kernel della serie 2.6,\footnote{per alcune motivazioni di
user space che ha una conoscenza diretta su come questi sono strutturati.} e
che anzi in certi casi si potevano avere anche dei peggioramenti. Questo ha
portato, per i kernel della serie 2.6,\footnote{per alcune motivazioni di
in \href{http://www.cs.helsinki.fi/linux/linux-kernel/2001-03/0200.html}
{\textsf{http://www.cs.helsinki.fi/linux/linux-kernel/2001-03/0200.html}}.}
alla decisione di consentire l'uso della funzione soltanto quando il file da
cui si legge supporta le operazioni di \textit{memory mapping} (vale a dire
in \href{http://www.cs.helsinki.fi/linux/linux-kernel/2001-03/0200.html}
{\textsf{http://www.cs.helsinki.fi/linux/linux-kernel/2001-03/0200.html}}.}
alla decisione di consentire l'uso della funzione soltanto quando il file da
cui si legge supporta le operazioni di \textit{memory mapping} (vale a dire
-non è un socket) e quello su cui si scrive è un socket; in tutti gli altri
-casi l'uso di \func{sendfile} darà luogo ad un errore di \errcode{EINVAL}.
+non è un socket) e quello su cui si scrive è un socket; in tutti gli altri
+casi l'uso di \func{sendfile} darà luogo ad un errore di \errcode{EINVAL}.
Nonostante ci possano essere casi in cui \func{sendfile} non migliora le
prestazioni, resta il dubbio se la scelta di disabilitarla sempre per il
trasferimento fra file di dati sia davvero corretta. Se ci sono peggioramenti
Nonostante ci possano essere casi in cui \func{sendfile} non migliora le
prestazioni, resta il dubbio se la scelta di disabilitarla sempre per il
trasferimento fra file di dati sia davvero corretta. Se ci sono peggioramenti
lasciare a disposizione la funzione consentirebbe se non altro di semplificare
la gestione della copia dei dati fra file, evitando di dover gestire
l'allocazione di un buffer temporaneo per il loro trasferimento.
lasciare a disposizione la funzione consentirebbe se non altro di semplificare
la gestione della copia dei dati fra file, evitando di dover gestire
l'allocazione di un buffer temporaneo per il loro trasferimento.
trasferimento di dati da o verso un file utilizzando un buffer gestito
internamente dal kernel. Descritta in questi termini \func{splice} sembra
semplicemente un ``\textsl{dimezzamento}'' di \func{sendfile}.\footnote{nel
senso che un trasferimento di dati fra due file con \func{sendfile} non
sarebbe altro che la lettura degli stessi su un buffer seguita dalla
relativa scrittura, cosa che in questo caso si dovrebbe eseguire con due
trasferimento di dati da o verso un file utilizzando un buffer gestito
internamente dal kernel. Descritta in questi termini \func{splice} sembra
semplicemente un ``\textsl{dimezzamento}'' di \func{sendfile}.\footnote{nel
senso che un trasferimento di dati fra due file con \func{sendfile} non
sarebbe altro che la lettura degli stessi su un buffer seguita dalla
relativa scrittura, cosa che in questo caso si dovrebbe eseguire con due
\func{splice}, pur mantenendo disponibile la stessa interfaccia verso l'user
space.} \func{sendfile} infatti, come accennato, non necessita di avere a
\func{splice}, pur mantenendo disponibile la stessa interfaccia verso l'user
space.} \func{sendfile} infatti, come accennato, non necessita di avere a
-disposizione un buffer interno, perché esegue un trasferimento diretto di
-dati; questo la rende in generale più efficiente, ma anche limitata nelle sue
-applicazioni, dato che questo tipo di trasferimento è possibile solo in casi
+disposizione un buffer interno, perché esegue un trasferimento diretto di
+dati; questo la rende in generale più efficiente, ma anche limitata nelle sue
+applicazioni, dato che questo tipo di trasferimento è possibile solo in casi
-Il concetto che sta dietro a \func{splice} invece è diverso,\footnote{in
- realtà la proposta originale di Larry Mc Voy non differisce poi tanto negli
- scopi da \func{sendfile}, quello che rende \func{splice} davvero diversa è
- stata la reinterpretazione che ne è stata fatta nell'implementazione su
+Il concetto che sta dietro a \func{splice} invece è diverso,\footnote{in
+ realtà la proposta originale di Larry Mc Voy non differisce poi tanto negli
+ scopi da \func{sendfile}, quello che rende \func{splice} davvero diversa è
+ stata la reinterpretazione che ne è stata fatta nell'implementazione su
Linux realizzata da Jens Anxboe, concetti che sono esposti sinteticamente
dallo stesso Linus Torvalds in \href{http://kerneltrap.org/node/6505}
{\textsf{http://kerneltrap.org/node/6505}}.} si tratta semplicemente di una
funzione che consente di fare in maniera del tutto generica delle operazioni
di trasferimento di dati fra un file e un buffer gestito interamente in kernel
space. In questo caso il cuore della funzione (e delle affini \func{vmsplice}
Linux realizzata da Jens Anxboe, concetti che sono esposti sinteticamente
dallo stesso Linus Torvalds in \href{http://kerneltrap.org/node/6505}
{\textsf{http://kerneltrap.org/node/6505}}.} si tratta semplicemente di una
funzione che consente di fare in maniera del tutto generica delle operazioni
di trasferimento di dati fra un file e un buffer gestito interamente in kernel
space. In questo caso il cuore della funzione (e delle affini \func{vmsplice}
-e \func{tee}, che tratteremo più avanti) è appunto l'uso di un buffer in
-kernel space, e questo è anche quello che ne ha semplificato l'adozione,
-perché l'infrastruttura per la gestione di un tale buffer è presente fin dagli
+e \func{tee}, che tratteremo più avanti) è appunto l'uso di un buffer in
+kernel space, e questo è anche quello che ne ha semplificato l'adozione,
+perché l'infrastruttura per la gestione di un tale buffer è presente fin dagli
albori di Unix per la realizzazione delle \textit{pipe} (vedi
sez.~\ref{sec:ipc_unix}). Dal punto di vista concettuale allora \func{splice}
albori di Unix per la realizzazione delle \textit{pipe} (vedi
sez.~\ref{sec:ipc_unix}). Dal punto di vista concettuale allora \func{splice}
come area di memoria (vedi fig.~\ref{fig:ipc_pipe_singular}) dove appoggiare i
dati che vengono trasferiti da un capo all'altro della stessa per creare un
meccanismo di comunicazione fra processi, nel caso di \func{splice} il buffer
come area di memoria (vedi fig.~\ref{fig:ipc_pipe_singular}) dove appoggiare i
dati che vengono trasferiti da un capo all'altro della stessa per creare un
meccanismo di comunicazione fra processi, nel caso di \func{splice} il buffer
fornisce quindi una interfaccia generica che consente di trasferire dati da un
buffer ad un file o viceversa; il suo prototipo, accessibile solo dopo aver
definito la macro \macro{\_GNU\_SOURCE},\footnote{si ricordi che questa
fornisce quindi una interfaccia generica che consente di trasferire dati da un
buffer ad un file o viceversa; il suo prototipo, accessibile solo dopo aver
definito la macro \macro{\_GNU\_SOURCE},\footnote{si ricordi che questa
Trasferisce dati da un file verso una pipe o viceversa.
\bodydesc{La funzione restituisce il numero di byte trasferiti in caso di
Trasferisce dati da un file verso una pipe o viceversa.
\bodydesc{La funzione restituisce il numero di byte trasferiti in caso di
dei valori:
\begin{errlist}
\item[\errcode{EBADF}] uno o entrambi fra \param{fd\_in} e \param{fd\_out}
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
dei valori:
\begin{errlist}
\item[\errcode{EBADF}] uno o entrambi fra \param{fd\_in} e \param{fd\_out}
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
- è dato un valore a \param{off\_in} o \param{off\_out} ma il
- corrispondente file è un dispositivo che non supporta la funzione
+ \func{splice}, oppure nessuno dei file descriptor è una pipe, oppure si
+ è dato un valore a \param{off\_in} o \param{off\_out} ma il
+ corrispondente file è un dispositivo che non supporta la funzione
\end{errlist}
}
\end{functions}
La funzione esegue un trasferimento di \param{len} byte dal file descriptor
\param{fd\_in} al file descriptor \param{fd\_out}, uno dei quali deve essere
\end{errlist}
}
\end{functions}
La funzione esegue un trasferimento di \param{len} byte dal file descriptor
\param{fd\_in} al file descriptor \param{fd\_out}, uno dei quali deve essere
-una \textit{pipe}; l'altro file descriptor può essere
-qualunque.\footnote{questo significa che può essere, oltre che un file di
+una \textit{pipe}; l'altro file descriptor può essere
+qualunque.\footnote{questo significa che può essere, oltre che un file di
-\textit{pipe} non è altro che un buffer in kernel space, per cui a seconda che
-essa sia usata per \param{fd\_in} o \param{fd\_out} si avrà rispettivamente la
+\textit{pipe} non è altro che un buffer in kernel space, per cui a seconda che
+essa sia usata per \param{fd\_in} o \param{fd\_out} si avrà rispettivamente la
-a quelli richiesti; un valore negativo indicherà un errore mentre un valore
-nullo indicherà che non ci sono dati da trasferire (ad esempio si è giunti
+a quelli richiesti; un valore negativo indicherà un errore mentre un valore
+nullo indicherà che non ci sono dati da trasferire (ad esempio si è giunti
alla fine del file in lettura). Si tenga presente che, a seconda del verso del
trasferimento dei dati, la funzione si comporta nei confronti del file
descriptor che fa riferimento al file ordinario, come \func{read} o
alla fine del file in lettura). Si tenga presente che, a seconda del verso del
trasferimento dei dati, la funzione si comporta nei confronti del file
descriptor che fa riferimento al file ordinario, come \func{read} o
-\func{write}, e pertanto potrà anche bloccarsi (a meno che non si sia aperto
-il suddetto file in modalità non bloccante).
+\func{write}, e pertanto potrà anche bloccarsi (a meno che non si sia aperto
+il suddetto file in modalità non bloccante).
I due argomenti \param{off\_in} e \param{off\_out} consentono di specificare,
come per l'analogo \param{offset} di \func{sendfile}, la posizione all'interno
del file da cui partire per il trasferimento dei dati. Come per
\func{sendfile} un valore nullo indica di usare la posizione corrente sul
I due argomenti \param{off\_in} e \param{off\_out} consentono di specificare,
come per l'analogo \param{offset} di \func{sendfile}, la posizione all'interno
del file da cui partire per il trasferimento dei dati. Come per
\func{sendfile} un valore nullo indica di usare la posizione corrente sul
-Ovviamente soltanto uno di questi due argomenti, e più precisamente quello che
-fa riferimento al file descriptor non associato alla \textit{pipe}, può essere
+Ovviamente soltanto uno di questi due argomenti, e più precisamente quello che
+fa riferimento al file descriptor non associato alla \textit{pipe}, può essere
binaria e deve essere specificato come OR aritmetico dei valori riportati in
tab.~\ref{tab:splice_flag}. Alcuni di questi valori vengono utilizzati anche
dalle funzioni \func{vmsplice} e \func{tee} per cui la tabella riporta le
binaria e deve essere specificato come OR aritmetico dei valori riportati in
tab.~\ref{tab:splice_flag}. Alcuni di questi valori vengono utilizzati anche
dalle funzioni \func{vmsplice} e \func{tee} per cui la tabella riporta le
bloccante; questo flag influisce solo sulle
operazioni che riguardano l'I/O da e verso la
\textit{pipe}. Nel caso di \func{splice}
bloccante; questo flag influisce solo sulle
operazioni che riguardano l'I/O da e verso la
\textit{pipe}. Nel caso di \func{splice}
- successiva, questo è un suggerimento utile
- che viene usato quando \param{fd\_out} è un
+ successiva, questo è un suggerimento utile
+ che viene usato quando \param{fd\_out} è un
implementato in futuro anche per
\func{vmsplice} e \func{tee}.\\
\const{SPLICE\_F\_GIFT} & Le pagine di memoria utente sono
``\textsl{donate}'' al kernel;\footnotemark
se impostato una seguente \func{splice} che
implementato in futuro anche per
\func{vmsplice} e \func{tee}.\\
\const{SPLICE\_F\_GIFT} & Le pagine di memoria utente sono
``\textsl{donate}'' al kernel;\footnotemark
se impostato una seguente \func{splice} che
pagine con successo, altrimenti esse dovranno
essere copiate; per usare questa opzione i
dati dovranno essere opportunamente allineati
pagine con successo, altrimenti esse dovranno
essere copiate; per usare questa opzione i
dati dovranno essere opportunamente allineati
sez.~\ref{sec:net_sendmsg}.}
\footnotetext{questo significa che la cache delle pagine e i dati su disco
sez.~\ref{sec:net_sendmsg}.}
\footnotetext{questo significa che la cache delle pagine e i dati su disco
memoria.}
Per capire meglio il funzionamento di \func{splice} vediamo un esempio con un
semplice programma che usa questa funzione per effettuare la copia di un file
su un altro senza utilizzare buffer in user space. Il programma si chiama
memoria.}
Per capire meglio il funzionamento di \func{splice} vediamo un esempio con un
semplice programma che usa questa funzione per effettuare la copia di un file
su un altro senza utilizzare buffer in user space. Il programma si chiama
-Lo scopo del programma è quello di eseguire la copia dei con \func{splice},
-questo significa che si dovrà usare la funzione due volte, prima per leggere i
+Lo scopo del programma è quello di eseguire la copia dei con \func{splice},
+questo significa che si dovrà usare la funzione due volte, prima per leggere i
Una volta trattate le opzioni il programma verifica che restino
(\texttt{\small 13--16}) i due argomenti che indicano il file sorgente ed il
Una volta trattate le opzioni il programma verifica che restino
(\texttt{\small 13--16}) i due argomenti che indicano il file sorgente ed il
Il ciclo principale (\texttt{\small 33--58}) inizia con la lettura dal file
sorgente tramite la prima \func{splice} (\texttt{\small 34--35}), in questo
Il ciclo principale (\texttt{\small 33--58}) inizia con la lettura dal file
sorgente tramite la prima \func{splice} (\texttt{\small 34--35}), in questo
come terzo quello del capo in scrittura della \textit{pipe} (il funzionamento
delle \textit{pipe} e l'uso della coppia di file descriptor ad esse associati
come terzo quello del capo in scrittura della \textit{pipe} (il funzionamento
delle \textit{pipe} e l'uso della coppia di file descriptor ad esse associati
che nell'ottica dell'uso di \func{splice} questa operazione corrisponde
semplicemente al trasferimento dei dati dal file al buffer).
La lettura viene eseguita in blocchi pari alla dimensione specificata
che nell'ottica dell'uso di \func{splice} questa operazione corrisponde
semplicemente al trasferimento dei dati dal file al buffer).
La lettura viene eseguita in blocchi pari alla dimensione specificata
\func{splice} equivalente ad una \func{read} sul file, se ne controlla il
valore di uscita in \var{nread} che indica quanti byte sono stati letti, se
\func{splice} equivalente ad una \func{read} sul file, se ne controlla il
valore di uscita in \var{nread} che indica quanti byte sono stati letti, se
-detto valore è nullo (\texttt{\small 36}) questo significa che si è giunti
-alla fine del file sorgente e pertanto l'operazione di copia è conclusa e si
-può uscire dal ciclo arrivando alla conclusione del programma (\texttt{\small
- 59}). In caso di valore negativo (\texttt{\small 37--44}) c'è stato un
-errore ed allora si ripete la lettura (\texttt{\small 36}) se questo è dovuto
+detto valore è nullo (\texttt{\small 36}) questo significa che si è giunti
+alla fine del file sorgente e pertanto l'operazione di copia è conclusa e si
+può uscire dal ciclo arrivando alla conclusione del programma (\texttt{\small
+ 59}). In caso di valore negativo (\texttt{\small 37--44}) c'è stato un
+errore ed allora si ripete la lettura (\texttt{\small 36}) se questo è dovuto
ad una interruzione, o altrimenti si esce con un messaggio di errore
(\texttt{\small 41--43}).
ad una interruzione, o altrimenti si esce con un messaggio di errore
(\texttt{\small 41--43}).
del file di destinazione.
Di nuovo si controlla il numero di byte effettivamente scritti restituito in
del file di destinazione.
Di nuovo si controlla il numero di byte effettivamente scritti restituito in
dovuto a una interruzione o si esce con un messaggio negli altri casi
(\texttt{\small 48--55}). Infine si chiude il ciclo di scrittura sottraendo
dovuto a una interruzione o si esce con un messaggio negli altri casi
(\texttt{\small 48--55}). Infine si chiude il ciclo di scrittura sottraendo
- iniziale è dato dai byte letti dalla precedente chiamata a \func{splice},
- viene ad assumere il significato di byte da scrivere.} così che il ciclo di
+ iniziale è dato dai byte letti dalla precedente chiamata a \func{splice},
+ viene ad assumere il significato di byte da scrivere.} così che il ciclo di
scrittura venga ripetuto fintanto che il valore risultante sia maggiore di
zero, indice che la chiamata a \func{splice} non ha esaurito tutti i dati
presenti sul buffer.
scrittura venga ripetuto fintanto che il valore risultante sia maggiore di
zero, indice che la chiamata a \func{splice} non ha esaurito tutti i dati
presenti sul buffer.
Si noti come il programma sia concettualmente identico a quello che si sarebbe
scritto usando \func{read} al posto della prima \func{splice} e \func{write}
al posto della seconda, utilizzando un buffer in user space per eseguire la
Si noti come il programma sia concettualmente identico a quello che si sarebbe
scritto usando \func{read} al posto della prima \func{splice} e \func{write}
al posto della seconda, utilizzando un buffer in user space per eseguire la
-copia dei dati, solo che in questo caso non è stato necessario allocare nessun
-buffer e non si è trasferito nessun dato in user space.
+copia dei dati, solo che in questo caso non è stato necessario allocare nessun
+buffer e non si è trasferito nessun dato in user space.
Si noti anche come si sia usata la combinazione \texttt{SPLICE\_F\_MOVE |
SPLICE\_F\_MORE } per l'argomento \param{flags} di \func{splice}, infatti
Si noti anche come si sia usata la combinazione \texttt{SPLICE\_F\_MOVE |
SPLICE\_F\_MORE } per l'argomento \param{flags} di \func{splice}, infatti
Come accennato con l'introduzione di \func{splice} sono state realizzate anche
altre due \textit{system call}, \func{vmsplice} e \func{tee}, che utilizzano
la stessa infrastruttura e si basano sullo stesso concetto di manipolazione e
Come accennato con l'introduzione di \func{splice} sono state realizzate anche
altre due \textit{system call}, \func{vmsplice} e \func{tee}, che utilizzano
la stessa infrastruttura e si basano sullo stesso concetto di manipolazione e
attengono strettamente ad operazioni di trasferimento dati fra file
descriptor, le tratteremo qui, essendo strettamente correlate fra loro.
attengono strettamente ad operazioni di trasferimento dati fra file
descriptor, le tratteremo qui, essendo strettamente correlate fra loro.
indica il suo nome consente di trasferire i dati dalla memoria virtuale di un
processo (ad esempio per un file mappato in memoria) verso una \textit{pipe};
indica il suo nome consente di trasferire i dati dalla memoria virtuale di un
processo (ad esempio per un file mappato in memoria) verso una \textit{pipe};
Trasferisce dati dalla memoria di un processo verso una \textit{pipe}.
\bodydesc{La funzione restituisce il numero di byte trasferiti in caso di
Trasferisce dati dalla memoria di un processo verso una \textit{pipe}.
\bodydesc{La funzione restituisce il numero di byte trasferiti in caso di
- \item[\errcode{EINVAL}] si è usato un valore nullo per \param{nr\_segs}
- oppure si è usato \const{SPLICE\_F\_GIFT} ma la memoria non è allineata.
- \item[\errcode{ENOMEM}] non c'è memoria sufficiente per l'operazione
+ \item[\errcode{EINVAL}] si è usato un valore nullo per \param{nr\_segs}
+ oppure si è usato \const{SPLICE\_F\_GIFT} ma la memoria non è allineata.
+ \item[\errcode{ENOMEM}] non c'è memoria sufficiente per l'operazione
file descriptor corrispondente al suo capo aperto in scrittura (di nuovo si
faccia riferimento a sez.~\ref{sec:ipc_unix}), mentre per indicare quali
segmenti della memoria del processo devono essere trasferiti verso di essa si
file descriptor corrispondente al suo capo aperto in scrittura (di nuovo si
faccia riferimento a sez.~\ref{sec:ipc_unix}), mentre per indicare quali
segmenti della memoria del processo devono essere trasferiti verso di essa si
fig.~\ref{fig:file_iovec}), esattamente con gli stessi criteri con cui le si
usano per l'I/O vettorizzato, indicando gli indirizzi e le dimensioni di
ciascun segmento di memoria su cui si vuole operare; le dimensioni del
fig.~\ref{fig:file_iovec}), esattamente con gli stessi criteri con cui le si
usano per l'I/O vettorizzato, indicando gli indirizzi e le dimensioni di
ciascun segmento di memoria su cui si vuole operare; le dimensioni del
In caso di successo la funzione ritorna il numero di byte trasferiti sulla
\textit{pipe}. In generale, se i dati una volta creati non devono essere
In caso di successo la funzione ritorna il numero di byte trasferiti sulla
\textit{pipe}. In generale, se i dati una volta creati non devono essere
-riutilizzati (se cioè l'applicazione che chiama \func{vmsplice} non
-modificherà più la memoria trasferita), è opportuno utilizzare
-per \param{flag} il valore \const{SPLICE\_F\_GIFT}; questo fa sì che il kernel
-possa rimuovere le relative pagine dalla cache della memoria virtuale, così
-che queste possono essere utilizzate immediatamente senza necessità di
+riutilizzati (se cioè l'applicazione che chiama \func{vmsplice} non
+modificherà più la memoria trasferita), è opportuno utilizzare
+per \param{flag} il valore \const{SPLICE\_F\_GIFT}; questo fa sì che il kernel
+possa rimuovere le relative pagine dalla cache della memoria virtuale, così
+che queste possono essere utilizzate immediatamente senza necessità di
-La seconda funzione aggiunta insieme a \func{splice} è \func{tee}, che deve il
-suo nome all'omonimo comando in user space, perché in analogia con questo
+La seconda funzione aggiunta insieme a \func{splice} è \func{tee}, che deve il
+suo nome all'omonimo comando in user space, perché in analogia con questo
permette di duplicare i dati in ingresso su una \textit{pipe} su un'altra
\textit{pipe}. In sostanza, sempre nell'ottica della manipolazione dei dati su
dei buffer in kernel space, la funzione consente di eseguire una copia del
permette di duplicare i dati in ingresso su una \textit{pipe} su un'altra
\textit{pipe}. In sostanza, sempre nell'ottica della manipolazione dei dati su
dei buffer in kernel space, la funzione consente di eseguire una copia del
Duplica \param{len} byte da una \textit{pipe} ad un'altra.
\bodydesc{La funzione restituisce il numero di byte copiati in caso di
Duplica \param{len} byte da una \textit{pipe} ad un'altra.
\bodydesc{La funzione restituisce il numero di byte copiati in caso di
dei valori:
\begin{errlist}
\item[\errcode{EINVAL}] o uno fra \param{fd\_in} e \param{fd\_out} non fa
riferimento ad una \textit{pipe} o entrambi fanno riferimento alla
stessa \textit{pipe}.
dei valori:
\begin{errlist}
\item[\errcode{EINVAL}] o uno fra \param{fd\_in} e \param{fd\_out} non fa
riferimento ad una \textit{pipe} o entrambi fanno riferimento alla
stessa \textit{pipe}.
momento\footnote{quello della stesura di questo paragrafo, avvenuta il Gennaio
2010, in futuro potrebbe essere implementato anche \const{SPLICE\_F\_MORE}.}
il solo valore utilizzabile per \param{flag}, fra quelli elencati in
momento\footnote{quello della stesura di questo paragrafo, avvenuta il Gennaio
2010, in futuro potrebbe essere implementato anche \const{SPLICE\_F\_MORE}.}
il solo valore utilizzabile per \param{flag}, fra quelli elencati in
funzione non bloccante.
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
funzione non bloccante.
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 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
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
fig.~\ref{fig:tee_example}. Il programma consente di copiare il contenuto
dello standard input sullo standard output e su un file specificato come
argomento, il codice completo si trova nel file \texttt{tee.c} dei sorgenti
fig.~\ref{fig:tee_example}. Il programma consente di copiare il contenuto
dello standard input sullo standard output e su un file specificato come
argomento, il codice completo si trova nel file \texttt{tee.c} dei sorgenti
Il ciclo principale (\texttt{\small 37--58}) inizia con la chiamata a
\func{tee} che duplica il contenuto dello standard input sullo standard output
Il ciclo principale (\texttt{\small 37--58}) inizia con la chiamata a
\func{tee} che duplica il contenuto dello standard input sullo standard output
-valore di ritorno della funzione in \var{len}; se questo è nullo significa che
-non ci sono più dati da leggere e si chiude il ciclo (\texttt{\small 40}), se
-è negativo c'è stato un errore, ed allora si ripete la chiamata se questo è
+valore di ritorno della funzione in \var{len}; se questo è nullo significa che
+non ci sono più dati da leggere e si chiude il ciclo (\texttt{\small 40}), se
+è negativo c'è stato un errore, ed allora si ripete la chiamata se questo è
dovuto ad una interruzione (\texttt{\small 42--44}) o si stampa un messaggio
di errore e si esce negli altri casi (\texttt{\small 44--47}).
dovuto ad una interruzione (\texttt{\small 42--44}) o si stampa un messaggio
di errore e si esce negli altri casi (\texttt{\small 44--47}).
estrarre dalla standard input e scrivere sul file, di nuovo su usa un ciclo di
scrittura (\texttt{\small 50--58}) in cui si ripete una chiamata a
\func{splice} (\texttt{\small 51}) fintanto che non si sono scritti tutti i
estrarre dalla standard input e scrivere sul file, di nuovo su usa un ciclo di
scrittura (\texttt{\small 50--58}) in cui si ripete una chiamata a
\func{splice} (\texttt{\small 51}) fintanto che non si sono scritti tutti i
identico all'analogo ciclo di scrittura del precedente esempio di
fig.~\ref{fig:splice_example}).
Infine una nota finale riguardo \func{splice}, \func{vmsplice} e \func{tee}:
identico all'analogo ciclo di scrittura del precedente esempio di
fig.~\ref{fig:splice_example}).
Infine una nota finale riguardo \func{splice}, \func{vmsplice} e \func{tee}:
-occorre sottolineare che benché finora si sia parlato di trasferimenti o copie
-di dati in realtà nella implementazione di queste system call non è affatto
+occorre sottolineare che benché finora si sia parlato di trasferimenti o copie
+di dati in realtà nella implementazione di queste system call non è affatto
detto che i dati vengono effettivamente spostati o copiati, il kernel infatti
realizza le \textit{pipe} come un insieme di puntatori\footnote{per essere
precisi si tratta di un semplice buffer circolare, un buon articolo sul tema
si trova su \href{http://lwn.net/Articles/118750/}
{\textsf{http://lwn.net/Articles/118750/}}.} alle pagine di memoria interna
che contengono i dati, per questo una volta che i dati sono presenti nella
detto che i dati vengono effettivamente spostati o copiati, il kernel infatti
realizza le \textit{pipe} come un insieme di puntatori\footnote{per essere
precisi si tratta di un semplice buffer circolare, un buon articolo sul tema
si trova su \href{http://lwn.net/Articles/118750/}
{\textsf{http://lwn.net/Articles/118750/}}.} alle pagine di memoria interna
che contengono i dati, per questo una volta che i dati sono presenti nella
ed aumentare il numero di referenze; questo significa che anche con \func{tee}
non viene mai copiato nessun byte, vengono semplicemente copiati i puntatori.
ed aumentare il numero di referenze; questo significa che anche con \func{tee}
non viene mai copiato nessun byte, vengono semplicemente copiati i puntatori.
Nell'uso generico dell'interfaccia per l'accesso al contenuto dei file le
operazioni di lettura e scrittura non necessitano di nessun intervento di
Nell'uso generico dell'interfaccia per l'accesso al contenuto dei file le
operazioni di lettura e scrittura non necessitano di nessun intervento di
-supervisione da parte dei programmi, si eseguirà una \func{read} o una
-\func{write}, i dati verranno passati al kernel che provvederà ad effettuare
+supervisione da parte dei programmi, si eseguirà una \func{read} o una
+\func{write}, i dati verranno passati al kernel che provvederà ad effettuare
relativo all'uso generico, mentre esistono molti casi in cui ci sono esigenze
specifiche dei singoli programmi, che avendo una conoscenza diretta di come
verranno usati i file, possono necessitare di effettuare delle ottimizzazioni
relativo all'uso generico, mentre esistono molti casi in cui ci sono esigenze
specifiche dei singoli programmi, che avendo una conoscenza diretta di come
verranno usati i file, possono necessitare di effettuare delle ottimizzazioni
questa sezione una serie funzioni che consentono ai programmi di ottimizzare
il loro accesso ai dati dei file e controllare la gestione del relativo
\textit{caching}.
\itindbeg{read-ahead}
questa sezione una serie funzioni che consentono ai programmi di ottimizzare
il loro accesso ai dati dei file e controllare la gestione del relativo
\textit{caching}.
\itindbeg{read-ahead}
-Una prima funzione che può essere utilizzata per modificare la gestione
-ordinaria dell'I/O su un file è \funcd{readahead},\footnote{questa è una
+Una prima funzione che può essere utilizzata per modificare la gestione
+ordinaria dell'I/O su un file è \funcd{readahead},\footnote{questa è una
funzione specifica di Linux, introdotta con il kernel 2.4.13, e non deve
essere usata se si vogliono scrivere programmi portabili.} che consente di
funzione specifica di Linux, introdotta con il kernel 2.4.13, e non deve
essere usata se si vogliono scrivere programmi portabili.} che consente di
Esegue una lettura preventiva del contenuto di un file in cache.
\bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
Esegue una lettura preventiva del contenuto di un file in cache.
\bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
- \item[\errcode{EBADF}] l'argomento \param{fd} non è un file descriptor
- valido o non è aperto in lettura.
+ \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).
\end{errlist}
\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).
\end{errlist}
corrispondenti alle dimensioni delle pagine di memoria, ed i valori di
\param{offset} e \param{count} vengono arrotondati di conseguenza.
corrispondenti alle dimensioni delle pagine di memoria, ed i valori di
\param{offset} e \param{count} vengono arrotondati di conseguenza.
lettura anticipata viene chiamato \textit{read-ahead}, da cui deriva il nome
della funzione. La funzione \func{readahead}, per ottimizzare gli accessi a
disco, effettua la lettura in cache della sezione richiesta e si blocca
lettura anticipata viene chiamato \textit{read-ahead}, da cui deriva il nome
della funzione. La funzione \func{readahead}, per ottimizzare gli accessi a
disco, effettua la lettura in cache della sezione richiesta e si blocca
viene modificata ed indipendentemente da quanto indicato con \param{count} la
lettura dei dati si interrompe una volta raggiunta la fine del file.
viene modificata ed indipendentemente da quanto indicato con \param{count} la
lettura dei dati si interrompe una volta raggiunta la fine del file.
nelle operazioni successive.
\itindend{read-ahead}
Il concetto di \func{readahead} viene generalizzato nello standard
POSIX.1-2001 dalla funzione \func{posix\_fadvise},\footnote{anche se
nelle operazioni successive.
\itindend{read-ahead}
Il concetto di \func{readahead} viene generalizzato nello standard
POSIX.1-2001 dalla funzione \func{posix\_fadvise},\footnote{anche se
-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
- solo a partire dal kernel 2.5.60.} così che esso possa provvedere le
-opportune ottimizzazioni; il prototipo di \funcd{posix\_fadvise}, che è
-disponibile soltanto se è stata definita la macro \macro{\_XOPEN\_SOURCE} ad
-valore di almeno 600, è:
+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
+ solo a partire dal kernel 2.5.60.} così che esso possa provvedere le
+opportune ottimizzazioni; il prototipo di \funcd{posix\_fadvise}, che è
+disponibile soltanto se è stata definita la macro \macro{\_XOPEN\_SOURCE} ad
+valore di almeno 600, è:
\begin{functions}
\headdecl{fcntl.h}
\funcdecl{int posix\_fadvise(int fd, off\_t offset, off\_t len, int advice)}
\begin{functions}
\headdecl{fcntl.h}
\funcdecl{int posix\_fadvise(int fd, off\_t offset, off\_t len, int advice)}
\param{fd} si riferisce ad un tipo di file che non supporta l'operazione
(come una pipe o un socket).
\param{fd} si riferisce ad un tipo di file che non supporta l'operazione
(come una pipe o un socket).
regione del file indicato da \param{fd} che inizia alla posizione
\param{offset} e si estende per \param{len} byte. Se per \param{len} si usa un
regione del file indicato da \param{fd} che inizia alla posizione
\param{offset} e si estende per \param{len} byte. Se per \param{len} si usa un
-valore nullo la regione coperta sarà da \param{offset} alla fine del
-file.\footnote{questo è vero solo per le versioni più recenti, fino al kernel
- 2.6.6 il valore nullo veniva interpretato letteralmente.} Le modalità sono
-indicate dall'argomento \param{advice} che è una maschera binaria dei valori
+valore nullo la regione coperta sarà da \param{offset} alla fine del
+file.\footnote{questo è vero solo per le versioni più recenti, fino al kernel
+ 2.6.6 il valore nullo veniva interpretato letteralmente.} Le modalità sono
+indicate dall'argomento \param{advice} che è una maschera binaria dei valori
-degli analoghi già visti in sez.~\ref{sec:file_memory_map} per
-\func{madvise}.\footnote{dato che si tratta dello stesso tipo di funzionalità,
+degli analoghi già visti in sez.~\ref{sec:file_memory_map} per
+\func{madvise}.\footnote{dato che si tratta dello stesso tipo di funzionalità,
in questo caso applicata direttamente al sistema ai contenuti di un file
invece che alla sua mappatura in memoria.} Si tenga presente comunque che la
in questo caso applicata direttamente al sistema ai contenuti di un file
invece che alla sua mappatura in memoria.} Si tenga presente comunque che la
- riguardo le modalità di accesso, il
- comportamento sarà identico a quello che si
+ riguardo le modalità di accesso, il
+ comportamento sarà identico a quello che si
avrebbe senza nessun avviso.\\
\const{POSIX\_FADV\_SEQUENTIAL}& L'applicazione si aspetta di accedere di
accedere ai dati specificati in maniera
avrebbe senza nessun avviso.\\
\const{POSIX\_FADV\_SEQUENTIAL}& L'applicazione si aspetta di accedere di
accedere ai dati specificati in maniera
dal kernel; in particolare utilizzando il valore
\const{POSIX\_FADV\_SEQUENTIAL} si raddoppia la dimensione dell'ammontare di
dati letti preventivamente rispetto al default, aspettandosi appunto una
dal kernel; in particolare utilizzando il valore
\const{POSIX\_FADV\_SEQUENTIAL} si raddoppia la dimensione dell'ammontare di
dati letti preventivamente rispetto al default, aspettandosi appunto una
gli attuali; infine l'uso di \const{POSIX\_FADV\_NORMAL} consente di
riportarsi al comportamento di default.
gli attuali; infine l'uso di \const{POSIX\_FADV\_NORMAL} consente di
riportarsi al comportamento di default.
-viene non ha più alcun effetto, mentre la seconda dà inizio ad una lettura in
-cache della regione del file indicata. La quantità di dati che verranno letti
-è ovviamente limitata in base al carico che si viene a creare sul sistema
+viene non ha più alcun effetto, mentre la seconda dà inizio ad una lettura in
+cache della regione del file indicata. La quantità di dati che verranno letti
+è ovviamente limitata in base al carico che si viene a creare sul sistema
-sempre soddisfatta (ed un valore superiore è solo raramente di qualche
-utilità). In particolare l'uso di \const{POSIX\_FADV\_WILLNEED} si può
+sempre soddisfatta (ed un valore superiore è solo raramente di qualche
+utilità). In particolare l'uso di \const{POSIX\_FADV\_WILLNEED} si può
considerare l'equivalente POSIX di \func{readahead}.
Infine con \const{POSIX\_FADV\_DONTNEED} si dice al kernel di liberare le
pagine di cache occupate dai dati presenti nella regione di file indicata.
considerare l'equivalente POSIX di \func{readahead}.
Infine con \const{POSIX\_FADV\_DONTNEED} si dice al kernel di liberare le
pagine di cache occupate dai dati presenti nella regione di file indicata.
-Questa è una indicazione utile che permette di alleggerire il carico sulla
-cache, ed un programma può utilizzare periodicamente questa funzione per
-liberare pagine di memoria da dati che non sono più utilizzati per far posto a
+Questa è una indicazione utile che permette di alleggerire il carico sulla
+cache, ed un programma può utilizzare periodicamente questa funzione per
+liberare pagine di memoria da dati che non sono più utilizzati per far posto a
inviati possono essere tranquillamente scartate.}
Sia \func{posix\_fadvise} che \func{readahead} attengono alla ottimizzazione
dell'accesso in lettura; lo standard POSIX.1-2001 prevede anche una funzione
specifica per le operazioni di scrittura,
inviati possono essere tranquillamente scartate.}
Sia \func{posix\_fadvise} che \func{readahead} attengono alla ottimizzazione
dell'accesso in lettura; lo standard POSIX.1-2001 prevede anche una funzione
specifica per le operazioni di scrittura,
dalle glibc 2.1.94.} che consente di preallocare dello spazio disco per
assicurarsi che una seguente scrittura non fallisca, il suo prototipo,
anch'esso disponibile solo se si definisce la macro \macro{\_XOPEN\_SOURCE} ad
dalle glibc 2.1.94.} che consente di preallocare dello spazio disco per
assicurarsi che una seguente scrittura non fallisca, il suo prototipo,
anch'esso disponibile solo se si definisce la macro \macro{\_XOPEN\_SOURCE} ad
\bodydesc{La funzione restituisce 0 in caso di successo e direttamente un
codice di errore, in caso di fallimento, in questo caso \var{errno} non
\bodydesc{La funzione restituisce 0 in caso di successo e direttamente un
codice di errore, in caso di fallimento, in questo caso \var{errno} non
- \item[\errcode{EBADF}] l'argomento \param{fd} non è un file descriptor
- valido o non è aperto in scrittura.
+ \item[\errcode{EBADF}] l'argomento \param{fd} non è un file descriptor
+ valido o non è aperto in scrittura.
\item[\errcode{EINVAL}] o \param{offset} o \param{len} sono minori di
zero.
\item[\errcode{EFBIG}] il valore di (\param{offset} + \param{len}) eccede
la dimensione massima consentita per un file.
\item[\errcode{ENODEV}] l'argomento \param{fd} non fa riferimento ad un
file regolare.
\item[\errcode{EINVAL}] o \param{offset} o \param{len} sono minori di
zero.
\item[\errcode{EFBIG}] il valore di (\param{offset} + \param{len}) eccede
la dimensione massima consentita per un file.
\item[\errcode{ENODEV}] l'argomento \param{fd} non fa riferimento ad un
file regolare.
possibile scrivere sul file indicato dall'argomento \param{fd} nella regione
che inizia dalla posizione \param{offset} e si estende per \param{len} byte;
se questa regione si estende oltre la fine del file le dimensioni di
quest'ultimo saranno incrementate di conseguenza. Dopo aver eseguito con
possibile scrivere sul file indicato dall'argomento \param{fd} nella regione
che inizia dalla posizione \param{offset} e si estende per \param{len} byte;
se questa regione si estende oltre la fine del file le dimensioni di
quest'ultimo saranno incrementate di conseguenza. Dopo aver eseguito con
-successo la funzione è garantito che una successiva scrittura nella regione
-indicata non fallirà per mancanza di spazio disco. La funzione non ha nessun
-effetto né sul contenuto, né sulla posizione corrente del file.
+successo la funzione è garantito che una successiva scrittura nella regione
+indicata non fallirà per mancanza di spazio disco. La funzione non ha nessun
+effetto né sul contenuto, né sulla posizione corrente del file.
-Ci si può chiedere a cosa possa servire una funzione come
-\func{posix\_fallocate} dato che è sempre possibile ottenere l'effetto voluto
+Ci si può chiedere a cosa possa servire una funzione come
+\func{posix\_fallocate} dato che è sempre possibile ottenere l'effetto voluto
eseguendo esplicitamente sul file la scrittura\footnote{usando \funcd{pwrite}
per evitare spostamenti della posizione corrente sul file.} di una serie di
zeri per l'estensione di spazio necessaria qualora il \itindex{sparse~file}
eseguendo esplicitamente sul file la scrittura\footnote{usando \funcd{pwrite}
per evitare spostamenti della posizione corrente sul file.} di una serie di
zeri per l'estensione di spazio necessaria qualora il \itindex{sparse~file}
buchi.\footnote{si ricordi che occorre scrivere per avere l'allocazione e che
l'uso di \func{truncate} per estendere un file creerebbe soltanto uno
\itindex{sparse~file} \textit{sparse file} (vedi sez.~\ref{sec:file_lseek})
buchi.\footnote{si ricordi che occorre scrivere per avere l'allocazione e che
l'uso di \func{truncate} per estendere un file creerebbe soltanto uno
\itindex{sparse~file} \textit{sparse file} (vedi sez.~\ref{sec:file_lseek})
- senza una effettiva allocazione dello spazio disco.} In realtà questa è la
-modalità con cui la funzione veniva realizzata nella prima versione fornita
+ senza una effettiva allocazione dello spazio disco.} In realtà questa è la
+modalità con cui la funzione veniva realizzata nella prima versione fornita
scrittura su tutto lo spazio disco necessario, da fare al momento della
richiesta di allocazione, pagandone il conseguente prezzo in termini di
scrittura su tutto lo spazio disco necessario, da fare al momento della
richiesta di allocazione, pagandone il conseguente prezzo in termini di
spazio per poi andarci a scrivere, una sola volta, quando il contenuto finale
diventa effettivamente disponibile.
spazio per poi andarci a scrivere, una sola volta, quando il contenuto finale
diventa effettivamente disponibile.
-Per poter fare tutto questo è però necessario il supporto da parte del kernel,
-e questo è divenuto disponibile solo a partire dal kernel 2.6.23 in cui è
+Per poter fare tutto questo è però necessario il supporto da parte del kernel,
+e questo è divenuto disponibile solo a partire dal kernel 2.6.23 in cui è
- è detto che la funzione sia disponibile per tutti i filesystem, ad esempio
- per XFS il supporto è stato introdotto solo a partire dal kernel 2.6.25.}
+ è detto che la funzione sia disponibile per tutti i filesystem, ad esempio
+ per XFS il supporto è stato introdotto solo a partire dal kernel 2.6.25.}
-dello spazio disco così da poter realizzare una versione di
-\func{posix\_fallocate} con prestazioni molto più elevate.\footnote{nelle
+dello spazio disco così da poter realizzare una versione di
+\func{posix\_fallocate} con prestazioni molto più elevate.\footnote{nelle
\acr{glibc} la nuova \textit{system call} viene sfruttata per la
realizzazione di \func{posix\_fallocate} a partire dalla versione 2.10.}
\acr{glibc} la nuova \textit{system call} viene sfruttata per la
realizzazione di \func{posix\_fallocate} a partire dalla versione 2.10.}
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,
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,
- loff\_t offset, loff\_t len)}.} ma a partire dalle \acr{glibc} 2.10 è
- stato fornito un supporto esplicito; il suo prototipo è:
+ loff\_t offset, loff\_t len)}.} ma a partire dalle \acr{glibc} 2.10 è
+ stato fornito un supporto esplicito; il suo prototipo è:
Prealloca dello spazio disco per un file.
\bodydesc{La funzione ritorna 0 in caso di successo e $-1$ in caso di errore,
Prealloca dello spazio disco per un file.
\bodydesc{La funzione ritorna 0 in caso di successo e $-1$ in caso di errore,
\begin{errlist}
\item[\errcode{EBADF}] \param{fd} non fa riferimento ad un file descriptor
valido aperto in scrittura.
\item[\errcode{EFBIG}] la somma di \param{offset} e \param{len} eccede le
dimensioni massime di un file.
\begin{errlist}
\item[\errcode{EBADF}] \param{fd} non fa riferimento ad un file descriptor
valido aperto in scrittura.
\item[\errcode{EFBIG}] la somma di \param{offset} e \param{len} eccede le
dimensioni massime di un file.
\item[\errcode{ENOSYS}] il filesystem contenente il file associato
a \param{fd} non supporta \func{fallocate}.
\item[\errcode{EOPNOTSUPP}] il filesystem contenente il file associato
\item[\errcode{ENOSYS}] il filesystem contenente il file associato
a \param{fd} non supporta \func{fallocate}.
\item[\errcode{EOPNOTSUPP}] il filesystem contenente il file associato
La funzione prende gli stessi argomenti di \func{posix\_fallocate} con lo
stesso significato, a cui si aggiunge l'argomento \param{mode} che indica le
La funzione prende gli stessi argomenti di \func{posix\_fallocate} con lo
stesso significato, a cui si aggiunge l'argomento \param{mode} che indica le
assumere il valore \const{FALLOC\_FL\_KEEP\_SIZE} che richiede che la
dimensione del file\footnote{quella ottenuta nel campo \var{st\_size} di una
struttura \struct{stat} dopo una chiamata a \texttt{fstat}.} non venga
modificata anche quando la somma di \param{offset} e \param{len} eccede la
dimensione corrente.
assumere il valore \const{FALLOC\_FL\_KEEP\_SIZE} che richiede che la
dimensione del file\footnote{quella ottenuta nel campo \var{st\_size} di una
struttura \struct{stat} dopo una chiamata a \texttt{fstat}.} non venga
modificata anche quando la somma di \param{offset} e \param{len} eccede la
dimensione corrente.