b376483c6c301882c1bb1698522287ff365fa29e
[gapil.git] / fileadv.tex
1 \chapter{La gestione avanzata dei file}
2 \label{cha:file_advanced}
3
4 In questo capitolo affronteremo le tematiche relative alla gestione avanzata
5 dei file, che non sono state trattate in \capref{cha:file_unix_interface},
6 dove ci si è limitati ad una panoramica delle funzioni base. In particolare
7 tratteremo delle funzioni di input/output avanzato e del \textit{file
8   locking}.
9
10
11 \section{Le funzioni di I/O avanzato}
12 \label{sec:file_advanced_io}
13
14 In questa sezione esamineremo le funzioni che permettono una gestione più
15 sofisticata dell'I/O su file, a partire da quelle che permettono di gestire
16 l'accesso contemporaneo a più file, per concludere con la gestione dell'I/O
17 mappato in memoria.
18
19
20 \subsection{La modalità di I/O \textsl{non-bloccante}}
21 \label{sec:file_noblocking}
22
23 Abbiamo visto in \secref{sec:sig_gen_beha}, affrontando la suddivisione fra
24 \textit{fast} e \textit{slow} system call, che in certi casi le funzioni di
25 I/O possono bloccarsi indefinitamente.\footnote{si ricordi però che questo può
26   accadere solo per le pipe, i socket ed alcuni file di dispositivo; sui file
27   normali le funzioni di lettura e scrittura ritornano sempre subito.}  Ad
28 esempio le operazioni di lettura possono bloccarsi quando non ci sono dati
29 disponibili sul descrittore su cui si sta operando.
30
31 Questo comportamento causa uno dei problemi più comuni che ci si trova ad
32 affrontare nelle operazioni di I/O, che è quello che si verifica quando si
33 devono eseguire operazioni che possono bloccarsi su più file descriptor:
34 mentre si è bloccati su uno di questi file su di un'altro potrebbero essere
35 presenti dei dati, così che nel migliore dei casi si avrebbe una lettura
36 ritardata inutilmente, e nel peggiore si potrebbe addirittura arrivare ad un
37 deadlock.
38
39 Abbiamo già accennato in \secref{sec:file_open} che però è possibile prevenire
40 questo tipo di comportamento aprendo un file in modalità
41 \textsl{non-bloccante}, attraverso l'uso del flag \macro{O\_NONBLOCK} nella
42 chiamata di \func{open}. In questo caso le funzioni di input/output che
43 altrimenti si sarebbero bloccate ritornano immediatamente, restituendo
44 l'errore \macro{EAGAIN}.
45
46 L'utilizzo di questa modalità di I/O permette di risolvere il problema
47 controllando a turno i vari file descriptor, in un ciclo in cui si ripete
48 l'accesso fintanto che esso non viene garantito.  Ovviamente questa tecnica,
49 detta \textit{polling}, è estremamente inefficiente: si tiene costantemente
50 impiegata la CPU solo per eseguire in continuazione delle system call che
51 nella gran parte dei casi falliranno. Per evitare questo, come vedremo in
52 \secref{sec:file_multiplexing}, è stata introdotta una nuova interfaccia di
53 programmazione, che comporta comunque l'uso della modalità di I/O non
54 bloccante.
55
56 \subsection{Le funzioni \func{poll} e \func{select}}
57 \label{sec:file_multiplexing}
58
59 Per superare il problema di dover usare il \textit{polling} controllare la
60 disponibilità di accesso ad un file aperto in modalità non bloccante, sia BSD
61 che System V hanno introdotto delle nuove funzioni in grado di sospendere
62 l'esecuzione di un processo fino a che l'accesso diventi possibile; il primo
63 ad introdurre questa nuova interfaccia, chiamata usualmente \textit{I/O
64   multiplexing}, è stato BSD, con l'introduzione della funzione \func{select},
65 il cui prototipo è:
66 \begin{prototype}{sys/select.h}
67   {int select(int n, fd\_set *readfds, fd\_set *writefds, fd\_set *exceptfds,
68     struct timeval *timeout)}
69
70 Attende che un certo insieme di file descriptor cambi stato.
71   
72 \bodydesc{La funzione restituisce il numero di file descriptor, anche nullo,
73   che hanno cambiato stato in caso di successo e -1 in caso di errore, nel
74   qual caso \var{errno} viene settata ai valori:
75   \begin{errlist}
76   \item[\macro{EBADF}] Si è specificato un file descriptor sbagliato in uno
77   degli insiemi.
78   \item[\macro{EINTR}] La funzione è stata interrotta da un segnale.
79   \item[\macro{EINVAL}] Si è specificato per \param{n} un valore negativo.
80   \end{errlist}
81   ed inoltre \macro{ENOMEM}.
82 }
83 \end{prototype}
84
85 La funzione mette il processo in stato di \textit{sleep} (vedi
86 \tabref{tab:proc_proc_states}) fintanto che non viene rilevate dell'attività
87 sull'insieme dei file descriptor specificati (\param{readfds},
88 \param{writefds} e \param{exceptfds}), per un tempo massimo specificato da
89 \param{timeout}. 
90
91 Per specificare quali file descriptor si intende selezionare, la funzione usa
92 un particolare oggetto, il \textit{file descriptor set}, identificato dal tipo
93 \type{fd\_set}, che serve ad identificare un insieme di file descriptor, in
94 maniera analoga a come un \textit{signal set} (vedi \secref{sec:sig_sigset})
95 identifica un insieme di segnali. Per la manipolazione di questi \textit{file
96   descriptor set} si possono usare delle opportune macro di preprocessore:
97 \begin{functions}
98   \headdecl{sys/select.h}
99   \funcdecl{FD\_ZERO(fd\_set *set)}
100   Inizializza l'insieme (vuoto).
101
102   \funcdecl{FD\_SET(int fd, fd\_set *set)}
103   Inserisce il file descriptor \param{fd} nell'insieme.
104
105   \funcdecl{FD\_CLR(int fd, fd\_set *set)}
106   Rimuove il file descriptor \param{fd} nell'insieme.
107   
108   \funcdecl{FD\_ISSET(int fd, fd\_set *set)}
109   Controlla se il file descriptor \param{fd} è nell'insieme.
110 \end{functions}
111
112 In genere un \textit{file descriptor set} può contenere fino ad un massimo di
113 \macro{FD\_SETSIZE} file descriptor.  Questo a seconda del sistema può essere
114 il limite del numero massimo di file aperti\footnote{ad esempio in Linux, fino
115   alla serie 2.0.x, c'era un limite di 256 file per processo.}, ma quando,
116 come nelle versioni più recenti del kernel, questo limite non c'è un massimo,
117 esso indica le dimensioni in numero di bit utilizzabili per l'insieme.
118
119 La funzione richiede di specificare tre insiemi distinti di file descriptor;
120 il primo, \param{readfds}, verrà osservato per rilevare la disponibilità di
121 input in lettura, il secondo, \param{writefds} per verificare la possibilità
122 di scrivere ed il terzo, \param{exceptfds}, per verificare l'esistenza di
123 eccezioni. I corrispondenti valori dei \textit{file descriptor set} saranno
124 modificati di conseguenza per mostrare quale dei file descriptor ha cambiato
125 stato.
126
127
128
129
130
131 Come accennato l'interfaccia di \func{select} è una estensione aggiunta BSD, e
132 poi entrata a far parte di POSIX; allo stesso tempo System V aveva introdotto
133 una interfaccia alternativa, basata sulla funzione \func{poll}, il cui
134 prototipo è:
135 \begin{prototype}{sys/poll.h}
136   {int poll(struct pollfd *ufds, unsigned int nfds, int timeout)}
137
138 La funzione attente un cambiamento di stato per uno dei file descriptor
139 specificati da \param{ufds}.
140   
141 \bodydesc{La funzione restituisce il numero di file descriptor con attività in
142   caso di successo, o 0 se c'è stato un timeout; in caso di errore viene
143   restituito  -1 ed \var{errno} viene settata ai valori:
144
145 .}
146 \end{prototype}
147
148
149
150
151 \subsection{L'I/O asincrono}
152 \label{sec:file_asyncronous_io}
153
154 Una modalità alternativa all'uso dell'I/O non bloccante è quella di fare
155 ricorso all'I/O asincrono. Abbiamo accennato in \secref{sec:file_open} che è
156 possibile, attraverso l'uso del flag \macro{O\_ASYNC}, aprire un file in
157 modalità asincrona, così come è possibile settare questo flag attraverso l'uso
158 di \func{fcntl}.
159
160 In tal caso il sistema genera un segnale \macro{SIGIO} tutte le volte che sono
161 presenti dei dati in input su un file aperto in questa modalità.  Uno dei
162 problemi che si presentavano con le prime implementazioni di questa modalità
163 di I/O è che essa poteva essere usata in maniera semplice aprendo un solo file
164 per processo, dato che altrimenti si sarebbe dovuto provvedere ad effettuare
165 una serie di controlli su tutti i file aperti per distinguere a quale fosse
166 dovuto l'emissione del segnale.
167
168 Tutto questo adesso può essere evitato facendo ricorso alle informazioni
169 restituite al manipolatore del segnale attraverso la struttura
170 \var{siginfo\_t} (vedi \figref{fig:sig_siginfo_t}), il cui campo \var{si\_fd}
171 riporta il file descriptor che ha generato il segnale.
172
173
174
175 \subsection{File mappati in memoria}
176 \label{sec:file_memory_map}
177
178
179 \subsection{I/O multiplo}
180 \label{sec:file_multiple_io}
181
182
183
184 \section{Il file locking}
185 \label{sec:file_locking}
186
187 In \secref{sec:file_sharing} abbiamo preso in esame le modalità in cui un
188 sistema unix-like gestisce la condivisione dei file da parte di processi
189 diversi. In quell'occasione si è visto come, con l'eccezione dei file aperti
190 in \textit{append mode}, quando più processi scrivono contemporaneamente sullo
191 stesso file non è possibile determinare la sequenza in cui essi opereranno.
192
193 Questo causa la possibilità di race condition\index{race condition}; in
194 generale le situazioni più comuni sono due: l'interazione fra un processo che
195 scrive e altri che leggono, in cui questi ultimi possono leggere informazioni
196 scritte solo in maniera parziale o incompleta; o quella in cui diversi
197 processi scrivono, mescolando in maniera imprevedibile il loro output sul
198 file.
199
200 In tutti questi casi il \textit{file locking} è la tecnica che permette di
201 evitare le race condition, attraverso una serie di funzioni che permettono di
202 bloccare l'accesso al file da parte di altri processi, così da evitare le
203 sovrapposizioni, e garantire la atomicità delle operazioni di scrittura.
204
205
206 \subsection{L'\textit{advisory locking}}
207 \label{sec:file_record_locking}
208
209 La prima modalità di file locking che è stata implementata nei sistemi
210 unix-like è quella che viene usualmente chiamata \textit{advisory locking}, in
211 quanto è il processo, e non il sistema, che si incarica di verificare se
212 esiste una condizione di blocco per l'accesso ai file.
213
214
215
216
217 \subsection{Il \textit{mandatory locking}}
218 \label{sec:file_mand_locking}
219
220 Il \textit{mandatory locking} è una opzione introdotta inizialmente in SVr4, 
221
222
223
224
225
226
227 %%% Local Variables: 
228 %%% mode: latex
229 %%% TeX-master: "gapil"
230 %%% End: