X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=fileadv.tex;h=f805181d3a5c0768cd326b25dd987d63bd19cb5f;hp=d744a758905558b00fe24189ce811a6b41c9a064;hb=017baa9ca8e1da7c8951d269125cfab35c427e08;hpb=38dff25efc0d3ae24d82724cd196c583c2362737 diff --git a/fileadv.tex b/fileadv.tex index d744a75..f805181 100644 --- a/fileadv.tex +++ b/fileadv.tex @@ -31,12 +31,11 @@ disponibili sul descrittore su cui si sta operando. Questo comportamento causa uno dei problemi più comuni che ci si trova ad affrontare nelle operazioni di I/O, che è quello che si verifica quando si devono eseguire operazioni che possono bloccarsi su più file descriptor: -mentre si è bloccati su uno di questi file su di un'altro potrebbero essere -presenti dei dati, così che nel migliore dei casi si avrebbe una lettura -ritardata inutilmente, e nel peggiore si potrebbe addirittura arrivare ad un -deadlock. +mentre si è bloccati su uno di essi su di un'altro potrebbero essere presenti +dei dati; così che nel migliore dei casi si avrebbe una lettura ritardata +inutilmente, e nel peggiore si potrebbe addirittura arrivare ad un deadlock. -Abbiamo già accennato in \secref{sec:file_open} che però è possibile prevenire +Abbiamo già accennato in \secref{sec:file_open} che è possibile prevenire questo tipo di comportamento aprendo un file in modalità \textsl{non-bloccante}, attraverso l'uso del flag \macro{O\_NONBLOCK} nella chiamata di \func{open}. In questo caso le funzioni di input/output che @@ -325,7 +324,7 @@ del flag \macro{O\_ASYNC},\footnote{l'uso del flag di \macro{O\_ASYNC} e dei di Linux e BSD.} aprire un file in modalità asincrona, così come è possibile attivare in un secondo tempo questa modalità settando questo flag attraverso l'uso di \func{fcntl} con il comando \macro{F\_SETFL} (vedi -\secref{sec:file_fcntl}). +\secref{sec:file_fcntl}). In realtà in questo caso non si tratta di I/O asincrono vero e proprio, quanto di un meccanismo asincrono di notifica delle variazione dello stato del file @@ -333,42 +332,49 @@ descriptor; quello che succede \macro{SIGIO}, ma è possibile usarne altri) tutte le volte che diventa possibile leggere o scrivere dal file descriptor che si è posto in questa modalità. Si può inoltre selezionare, con il comando \macro{F\_SETOWN} di -\func{fcntl}, quale processo (o gruppo di processi) riceverà il segnale. - -Uno dei problemi che si presenta con l'implementazione usuale di questa -modalità di I/O è che essa può essere usata in maniera immediata aprendo in -modalità asincrona un solo file per processo, altrimenti ad ogni segnale si -dovrebbe provvedere ad effettuare un controllo (utilizzando di nuovo -\func{select}) su tutti i file tenuti in modalità asincrona per distinguere -quelli cui è dovuta l'emissione del segnale. - -Linux però supporta una estensione che permette di evitare tutto questo -facendo ricorso alle informazioni aggiuntive restituite attraverso la -struttura \type{siginfo\_t} quando il manipolatore del segnale viene -installato come \macro{SA\_SIGINFO} (si riveda quanto illustrato in +\func{fcntl}, quale processo (o gruppo di processi) riceverà il segnale. + +In questo modo si può evitare l'uso delle funzioni \func{poll} o \func{select} +che, quando vengono usate con un numero molto grande di file descriptor, non +hanno buone prestazioni. In tal caso infatti la maggior parte del loro tempo +di esecuzione è impegato per eseguire uno scan su tutti i file descriptor +tenuti sotto controllo per determinare quali sono quelli (in genere un piccola +percentuale) che sono diventati attivi. + +Tuttavia con l'implementazione classica dei segnali questa modalità di I/O +presenta notevoli problemi, dato che non è possibile determinare, quando sono +più di uno, qual'è il file descriptor responsabile dell'emissione del segnale. +Linux però supporta le estensioni POSIX.1b dei segnali che permettono di +superare il problema facendo ricorso alle informazioni aggiuntive restituite +attraverso la struttura \type{siginfo\_t}, utilizzando la forma estesa +\var{sa\_sigaction} del manipolatore (si riveda quanto illustrato in \secref{sec:sig_sigaction}). -Per attivare questa caratteristica occorre settare esplicitamente il segnale -da inviare in caso di I/O asincrono (di norma sempre \macro{SIGIO}) con il -comando \macro{F\_SETSIG} di \func{fcntl}. In questo caso il manipolatore -tutte le volte che riceverà \macro{SI\_SIGIO} come valore del campo -\var{si\_code}\footnote{il valore resta \macro{SI\_SIGIO} qualunque sia il - segnale che si è associato all'I/O asincrono, ed indica appunto che il +Per far questo però occorre utilizzare le funzionalità dei segnali real-time +(vedi \secref{sec:sig_real_time}) settando esplicitamente con il comando +\macro{F\_SETSIG} di \func{fcntl} un segnale real-time da inviare in caso di +I/O asincrono (il segnale di default è \macro{SIGIO}). In questo caso il +manipolatorem tutte le volte che riceverà \macro{SI\_SIGIO} come valore del +campo \var{si\_code}\footnote{il valore resta \macro{SI\_SIGIO} qualunque sia + il segnale che si è associato all'I/O asincrono, ed indica appunto che il segnale è stato generato a causa di attività nell'I/O asincrono.} di \type{siginfo\_t}, troverà nel campo \var{si\_fd} il valore del file -descriptor che ha generato il segnale. In questo modo è possibile identificare -immediatamente il file evitando completamente l'uso di funzioni come -\func{poll} o \func{select}. Inoltre, a differenza degli altri segnali, il -sistema mantiene una coda per \macro{SIGIO}, in modo che arrivi un segnale per -ogni file attivo. +descriptor che ha generato il segnale. + +Un secondo vantaggio dell'uso dei segnali real-time è che essendo dotati di +una coda di consegna ogni segnale sarà associato ad uno solo file descriptor; +inoltre sarà possibile stabilire delle priorità nella risposta a seconda del +segnale usato. 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}. Benché la modalità di apertura asincrona di un file possa risultare utile in varie occasioni (in particolar modo con i socket e gli altri file per i quali le funzioni di I/O sono 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 invece una interfaccia apposita per l'I/O asincrono, che prevede un -insieme di funzioni dedicate, completamente separato rispetto a quelle usate +definisce anche una interfaccia apposita per l'I/O asincrono, che prevede un +insieme di funzioni dedicate, completamente separate rispetto a quelle usate normalmente. In generale questa interfaccia è completamente astratta e può essere @@ -376,10 +382,11 @@ implementata sia direttamente nel kernel, che in user space attraverso l'uso di thread. Al momento\footnote{fino ai kernel della serie 2.4.x, nella serie 2.5.x è però iniziato un lavoro completo di riscrittura di tutto il sistema di I/O, che prevede anche l'introduzione di un nuovo layer per l'I/O - asincrono.} esiste una sola versione stabile, quella delle \acr{glibc}, che -è realizzata completamente in user space; esistono comunque vari progetti -(come il KAIO della SGI, o i patch di Benjamin La Haise) che prevedono un -supporto diretto all'interno del kernel. + asincrono.} esiste una sola versione stabile di questa interfaccia, quella +delle \acr{glibc}, che è realizzata completamente in user space. Esistono +comunque vari progetti sperimentali (come il KAIO della SGI, o i patch di +Benjamin La Haise) che prevedono una interfaccia che utilizza un supporto +diretto da parte del kernel. @@ -396,8 +403,14 @@ vari buffer. In questo caso \subsection{File mappati in memoria} \label{sec:file_memory_map} - - +Una modalità alternativa di I/O, che usa una interfaccia completamente diversa +rispetto a quella classica, è quella dei file \textsl{mappati in memoria}. In +sostanza quello che si fa è usare il meccanismo della +\textsl{paginazione}\index{paginazione} usato per la memoria virtuale (vedi +\secref{sec:proc_mem_gen}) per trasformare vedere il file in una sezione dello +spazio di indirizzi del processo, in modo che l'accesso a quest'ultimo con le +normali operazioni di lettura e scrittura delle variabili in memoria, si +trasformi in I/O sul file stesso.