From 2a44ed509cb94cf27315aaa8c0b496326b7b9cbd Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Sat, 21 Feb 2015 10:08:02 +0000 Subject: [PATCH] Finito asyncronous I/O, iniziato mmap. --- fileadv.tex | 239 +++++++++++++++++++++++++++------------------------- 1 file changed, 126 insertions(+), 113 deletions(-) diff --git a/fileadv.tex b/fileadv.tex index dd0550b..38da0ec 100644 --- a/fileadv.tex +++ b/fileadv.tex @@ -3727,7 +3727,6 @@ lo standard POSIX.1b prevede una funzione apposita, \funcd{aio\_cancel}, che permette di cancellare una operazione richiesta in precedenza; il suo prototipo è: - \begin{funcproto}{ \fhead{aio.h} \fdecl{int aio\_cancel(int fd, struct aiocb *aiocbp)} @@ -3749,7 +3748,7 @@ La funzione permette di cancellare una operazione specifica sul file 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 mentre il valore di ritorno per -\func{aio\_return} sarà -1, inoltre il meccanismo di notifica non verrà +\func{aio\_return} sarà $-1$, inoltre il meccanismo di notifica non verrà invocato. Se con \param{aiocbp} si specifica una operazione relativa ad un file descriptor diverso da \param{fd} il risultato è indeterminato. In caso di successo, i possibili valori di ritorno per \func{aio\_cancel} (anch'essi @@ -3778,7 +3777,7 @@ specifica operazione; il suo prototipo è: \begin{funcproto}{ \fhead{aio.h} -\fdecl{int aio\_suspend(const struct aiocb * const list[], int nent, +\fdecl{int aio\_suspend(const struct aiocb * const list[], int nent, \\ \phantom{int aio\_suspend(}const struct timespec *timeout)} \fdesc{Attende il completamento di una operazione di I/O asincrono.} } @@ -3796,43 +3795,58 @@ specifica operazione; il suo prototipo è: La funzione permette di bloccare il processo fintanto che almeno una delle \param{nent} operazioni specificate nella lista \param{list} è completata, per -un tempo massimo specificato da \param{timout}, o fintanto che non arrivi un -segnale (si tenga conto che questo segnale potrebbe essere anche quello -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 -\val{NULL} per \param{timout} comporta l'assenza di timeout. +un tempo massimo specificato dalla struttura \struct{timespec} puntata +da \param{timout}, o fintanto che non arrivi un segnale (si tenga conto che +questo segnale potrebbe essere anche quello 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 \val{NULL} per \param{timout} comporta l'assenza di timeout, mentre +se si vuole effettuare un \textit{polling} sulle operazioni occorrerà +specificare un puntatore valido ad una struttura \texttt{timespec} (vedi +fig.~\ref{fig:sys_timespec_struct}) contenente valori nulli, e verificare poi +con \func{aio\_error} quale delle operazioni della lista \param{list} è stata +completata. 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 lettura o scrittura; il suo prototipo è: -\begin{prototype}{aio.h} - {int lio\_listio(int mode, struct aiocb * const list[], int nent, struct + + +\begin{funcproto}{ +\fhead{aio.h} +\fdecl{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}, - secondo la modalità \param{mode}. - - \bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di - errore, nel qual caso \var{errno} assumerà uno dei valori: - \begin{errlist} + +\fdesc{Richiede l'esecuzione di una serie di operazioni di I/O.} +} + +{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual + caso \var{errno} assumerà uno dei valori: + \begin{errlist} \item[\errcode{EAGAIN}] nessuna operazione è stata completata entro \param{timeout}. + \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale. \item[\errcode{EINVAL}] si è passato un valore di \param{mode} non valido o un numero di operazioni \param{nent} maggiore di \const{AIO\_LISTIO\_MAX}. \item[\errcode{ENOSYS}] la funzione non è implementata. - \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale. - \end{errlist} - } -\end{prototype} + \end{errlist} +} +\end{funcproto} La funzione esegue la richiesta delle \param{nent} operazioni indicate nella -lista \param{list} che deve contenere gli indirizzi di altrettanti -\textit{control block} opportunamente inizializzati; in particolare dovrà -essere specificato il tipo di operazione con il campo \var{aio\_lio\_opcode}, -che può prendere i valori: +lista \param{list} un vettore di puntatori a strutture \struct{aiocb} +indicanti le operazioni da compiere (che verranno eseguite senza un ordine +particolare). La lista può contenere anche puntatori nulli, che saranno +ignorati (si possono così eliminare facilmente componenti della lista senza +doverla rigenerare). + +Ciascuna struttura \struct{aiocb} della lista deve contenere un +\textit{control block} opportunamente inizializzato; in particolare per +ognuna di esse dovrà essere specificato il tipo di operazione con il campo +\var{aio\_lio\_opcode}, che può prendere i valori: \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. @@ -3841,7 +3855,7 @@ che può prendere i valori: dove \const{LIO\_NOP} viene usato quando si ha a che fare con un vettore di dimensione fissa, per poter specificare solo alcune operazioni, o quando si sono dovute cancellare delle operazioni e si deve ripetere la richiesta per -quelle non completate. +quelle non completate. L'argomento \param{mode} controlla il comportamento della funzione, se viene usato il valore \const{LIO\_WAIT} la funzione si blocca fino al completamento @@ -3876,9 +3890,9 @@ avanzato. \itindbeg{memory~mapping} Una modalità alternativa di I/O, che usa una interfaccia completamente diversa rispetto a quella classica vista in sez.~\ref{sec:file_unix_interface}, è il -cosiddetto \textit{memory-mapped I/O}, che, attraverso il meccanismo della +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 +sez.~\ref{sec:proc_mem_gen}) permette di \textsl{mappare} il contenuto di un file in una sezione dello spazio di indirizzi del processo che lo ha allocato. \begin{figure}[htb] @@ -3922,56 +3936,60 @@ scritte sulla swap; questo consente di accedere ai file su dimensioni il cui solo limite è quello dello spazio di indirizzi disponibile, e non della 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 -eseguire la mappatura in memoria di un file, è \funcd{mmap}; il suo prototipo -è: -\begin{functions} - - \headdecl{unistd.h} - \headdecl{sys/mman.h} +L'interfaccia POSIX implementata da Linux prevede varie funzioni di sistema +per la gestione del \textit{memory mapped I/O}, la prima di queste, che serve +ad eseguire la mappatura in memoria di un file, è \funcd{mmap}; il suo +prototipo è: + - \funcdecl{void * mmap(void * start, size\_t length, int prot, int flags, int +\begin{funcproto}{ +\fhead{unistd.h} +\fhead{sys/mman.h} +\fdecl{void * mmap(void * start, size\_t length, int prot, int flags, int fd, off\_t offset)} - - Esegue la mappatura in memoria della sezione specificata del file \param{fd}. - - \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 - qual caso \var{errno} assumerà uno dei valori: - \begin{errlist} - \item[\errcode{EBADF}] il file descriptor non è valido, e non si è usato - \const{MAP\_ANONYMOUS}. +\fdesc{Esegue la mappatura in memoria di una sezione di un file.} +} + +{La funzione ritorna il puntatore alla zona di memoria mappata in caso di + successo, e \const{MAP\_FAILED} ($-1$) per un errore, nel qual caso + \var{errno} assumerà uno dei valori: + \begin{errlist} \item[\errcode{EACCES}] o \param{fd} non si riferisce ad un file regolare, 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{ETXTBSY}] si è impostato \const{MAP\_DENYWRITE} ma - \param{fd} è aperto in scrittura. \item[\errcode{EAGAIN}] il file è bloccato, o si è bloccata troppa memoria rispetto a quanto consentito dai limiti di sistema (vedi sez.~\ref{sec:sys_resource_limit}). - \item[\errcode{ENOMEM}] non c'è memoria o si è superato il limite sul - numero di mappature possibili. + \item[\errcode{EBADF}] il file descriptor non è valido, e non si è usato + \const{MAP\_ANONYMOUS}. + \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{ENFILE}] si è superato il limite del sistema sul numero di + file aperti (vedi sez.~\ref{sec:sys_resource_limit}). \item[\errcode{ENODEV}] il filesystem di \param{fd} non supporta il memory mapping. + \item[\errcode{ENOMEM}] non c'è memoria o si è superato il limite sul + numero di mappature possibili. \item[\errcode{EPERM}] l'argomento \param{prot} ha richiesto \const{PROT\_EXEC}, ma il filesystem di \param{fd} è montato con l'opzione \texttt{noexec}. - \item[\errcode{ENFILE}] si è superato il limite del sistema sul numero di - file aperti (vedi sez.~\ref{sec:sys_resource_limit}). - \end{errlist} - } -\end{functions} + \item[\errcode{ETXTBSY}] si è impostato \const{MAP\_DENYWRITE} ma + \param{fd} è aperto in scrittura. + \end{errlist} +} +\end{funcproto} + La funzione richiede di mappare in memoria la sezione del file \param{fd} a partire da \param{offset} per \param{length} byte, preferibilmente -all'indirizzo \param{start}. Il valore di \param{offset} deve essere un -multiplo della dimensione di una pagina di memoria. +all'indirizzo \param{start}. Il valore \param{start} viene normalmente +considerato come un suggerimento, ma l'uso di un valore diverso da \val{NULL}, +in cui di rimette completamente al kernel la scelta dell'indirizzo, viene +sconsigliato per ragioni di portabilità. Il valore di \param{offset} deve +essere un multiplo della dimensione di una pagina di memoria. \begin{table}[htb] \centering @@ -4020,19 +4038,43 @@ tab.~\ref{tab:file_mmap_flag}. \textbf{Valore} & \textbf{Significato} \\ \hline \hline + \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 è + richiesto \const{MAP\_FIXED} (dal 2.4.20).\\ + \const{MAP\_ANON} & Sinonimo di \const{MAP\_ANONYMOUS}, deprecato.\\ + \const{MAP\_ANONYMOUS} & La mappatura non è associata a nessun file. Gli + argomenti \param{fd} e \param{offset} sono + ignorati.\\ + \const{MAP\_DENYWRITE} & In Linux viene ignorato per evitare + \textit{DoS} \itindex{Denial~of~Service~(DoS)} + (veniva usato per segnalare che tentativi di + scrittura sul file dovevano fallire con + \errcode{ETXTBSY}).\\ + \const{MAP\_EXECUTABLE}& Ignorato.\\ + \const{MAP\_FILE} & Valore di compatibilità, ignorato.\\ \const{MAP\_FIXED} & Non permette di restituire un indirizzo diverso da \param{start}, se questo non può essere usato \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 - file.\footnotemark Il file su disco però non sarà - aggiornato fino alla chiamata di \func{msync} o - \func{munmap}), e solo allora le modifiche saranno - visibili per l'I/O convenzionale. Incompatibile - con \const{MAP\_PRIVATE}.\\ + \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\_HUGETLB} & da trattare (dal 2.6.32).\\ + \const{MAP\_LOCKED} & Se impostato impedisce lo swapping delle pagine + mappate (dal 2.5.37).\\ + \const{MAP\_NONBLOCK} & Esegue un \textit{prefaulting} più limitato che + non causa I/O (dal 2.5.46).\\ + \const{MAP\_NORESERVE} & Si usa con \const{MAP\_PRIVATE}. Non riserva + delle pagine di swap ad uso del meccanismo del + \textit{copy on write} \itindex{copy~on~write} + per mantenere le + modifiche fatte alla regione mappata, in + questo caso dopo una scrittura, se non c'è più + memoria disponibile, si ha l'emissione di + un \signal{SIGSEGV}.\\ \const{MAP\_PRIVATE} & I cambiamenti sulla memoria mappata non vengono riportati sul file. Ne viene fatta una copia privata cui solo il processo chiamante ha @@ -4043,64 +4085,35 @@ tab.~\ref{tab:file_mmap_flag}. specificato se i cambiamenti sul file originale vengano riportati sulla regione mappata. Incompatibile con \const{MAP\_SHARED}.\\ - \const{MAP\_DENYWRITE} & In Linux viene ignorato per evitare - \textit{DoS} \itindex{Denial~of~Service~(DoS)} - (veniva usato per segnalare che tentativi di - scrittura sul file dovevano fallire con - \errcode{ETXTBSY}).\\ - \const{MAP\_EXECUTABLE}& Ignorato.\\ - \const{MAP\_NORESERVE} & Si usa con \const{MAP\_PRIVATE}. Non riserva - delle pagine di swap ad uso del meccanismo del - \textit{copy on write} \itindex{copy~on~write} - per mantenere le - modifiche fatte alla regione mappata, in - questo caso dopo una scrittura, se non c'è più - memoria disponibile, si ha l'emissione di - un \signal{SIGSEGV}.\\ - \const{MAP\_LOCKED} & Se impostato impedisce lo swapping delle pagine - mappate.\\ - \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\_ANONYMOUS} & La mappatura non è associata a nessun file. Gli - argomenti \param{fd} e \param{offset} sono - ignorati.\footnotemark\\ - \const{MAP\_ANON} & Sinonimo di \const{MAP\_ANONYMOUS}, deprecato.\\ - \const{MAP\_FILE} & Valore di compatibilità, ignorato.\\ - \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 è - richiesto \const{MAP\_FIXED}.\\ \const{MAP\_POPULATE} & Esegue il \itindex{prefaulting} \textit{prefaulting} delle pagine di memoria - necessarie alla mappatura.\\ - \const{MAP\_NONBLOCK} & Esegue un \textit{prefaulting} più limitato che - non causa I/O.\footnotemark\\ + necessarie alla mappatura (dal 2.5.46).\\ + \const{MAP\_SHARED} & I cambiamenti sulla memoria mappata vengono + riportati sul file e saranno immediatamente + visibili agli altri processi che mappano lo stesso + file.\footnotemark Il file su disco però non sarà + aggiornato fino alla chiamata di \func{msync} o + \func{munmap}), e solo allora le modifiche saranno + visibili per l'I/O convenzionale. Incompatibile + con \const{MAP\_PRIVATE}.\\ + \const{MAP\_STACK} & da trattare (dal 2.6.27).\\ + \const{MAP\_UNINITIALIZED}& da trattare (dal 2.6.33).\\ % \const{MAP\_DONTEXPAND}& Non consente una successiva espansione dell'area % mappata con \func{mremap}, proposto ma pare non % implementato.\\ -% \const{MAP\_HUGETLB}& da trattare.\\ -% TODO trattare MAP_HUGETLB introdotto con il kernel 2.6.32, e modifiche -% introdotte con il 3.8 per le dimensioni variabili delle huge pages - \hline \end{tabular} \caption{Valori possibili dell'argomento \param{flag} di \func{mmap}.} \label{tab:file_mmap_flag} \end{table} -\footnotetext[68]{dato che tutti faranno riferimento alle stesse pagine di - memoria.} - -\footnotetext[69]{l'uso di questo flag con \const{MAP\_SHARED} è stato +\footnotetext{l'uso di questo flag con \const{MAP\_SHARED} è stato 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 - parleremo più avanti.} +% TODO trattare MAP_HUGETLB introdotto con il kernel 2.6.32, e modifiche +% introdotte con il 3.8 per le dimensioni variabili delle huge pages Gli effetti dell'accesso ad una zona di memoria mappata su file possono essere piuttosto complessi, essi si possono comprendere solo tenendo presente che -- 2.30.2