Correzioni
[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
32 Questo comportamento causa uno dei problemi più comuni che ci si trova ad
33 affrontare nelle operazioni di I/O, che è quello che si verifica quando si
34 devono eseguire operazioni che possono bloccarsi su più file descriptor:
35 mentre si è bloccati su uno di questi file su di un'altro potrebbero essere
36 presenti dei dati, così che nel migliore dei casi si avrebbe una lettura
37 ritardata inutilmente, e nel peggiore si potrebbe addirittura arrivare ad un
38 deadlock.
39
40 Abbiamo già accennato in \secref{sec:file_open} che però è possibile prevenire
41 questo tipo di comportamento aprendo un file in modalità
42 \textsl{non-bloccante}, attraverso l'uso del flag \macro{O\_NONBLOCK} nella
43 chiamata di \func{open}. In questo caso le funzioni di input/output che
44 altrimenti si sarebbero bloccate ritornano immediatamente, restituendo
45 l'errore \macro{EAGAIN}.
46
47 L'utilizzo di questa modalità di I/O permette di risolvere il problema
48 controllando a turno i vari file descriptor, in un ciclo in cui si ripete
49 l'accesso fintanto che esso non viene garantito.  Ovviamente questa tecnica,
50 detta \textit{polling}, è estremamente inefficiente: si tiene costantemente
51 impiegata la CPU solo per eseguire in continuazione delle system call che
52 nella gran parte dei casi falliranno. Per evitare questo, come vedremo in
53 \secref{sec:file_multiplexing}, è stata introdotta una nuova interfaccia di
54 programmazione, che comporta comunque l'uso della modalità di I/O non
55 bloccante.
56
57 \subsection{Le funzioni \func{poll} e \func{select}}
58 \label{sec:file_multiplexing}
59
60 Per superare il problema di dover usare il \textit{polling} controllare la
61 disponibilità di accesso ad un file aperto in modalità non bloccante, sia BSD
62 che SysV hanno introdotto delle nuove funzioni in grado di sospendere
63 l'esecuzione di un processo fino a che l'accesso diventi possibile; il primo
64 ad introdurre questa nuova interfaccia, chiamata usualmente \textit{I/O
65   multiplexing}, è stato BSD, con l'introduzione della funzione \func{select},
66 il cui prototipo è:
67 \begin{prototype}{sys/select.h}
68   {int select(int n, fd\_set *readfds, fd\_set *writefds, fd\_set *exceptfds,
69     struct timeval *timeout)}
70
71 Attende che un certo insieme di file descriptor cambi stato.
72   
73 \bodydesc{La funzione restituisce il numero di file descriptor, anche nullo,
74   che hanno cambiato stato in caso di successo e -1 in caso di errore, nel
75   qual caso \var{errno} viene settata ai valori:
76   \begin{errlist}
77   \item[\macro{EBADF}] Si è specificato un file descriptor sbagliato in uno
78   degeli insiemi.
79   \item[\macro{EINTR}] La funzione è stata interrotta da un segnale.
80   \item[\macro{EINVAL}] Si è specificato per \param{n} un valore negativo.
81   \end{errlist}
82   ed inoltre \macro{ENOMEM}.
83 }
84 \end{prototype}
85
86 La funzione mette il processo in stato di \textit{sleep} (vedi
87 \ref{tab:proc_proc_states})
88
89
90
91 il cui prototipo è:
92 \begin{prototype}{sys/poll.h}
93   {int poll(struct pollfd *ufds, unsigned int nfds, int timeout)}
94
95 La funzione attente un cambiamento di stato per uno dei file descriptor
96 specificati da \param{ufds}.
97   
98 \bodydesc{La funzione restituisce il numero di file descriptor con attività in
99   caso di successo, o 0 se c'è stato un timeout; in caso di errore viene
100   restituito  -1 ed \var{errno} viene .}
101 \end{prototype}
102
103
104
105
106 \subsection{L'I/O asincrono}
107 \label{sec:file_asyncronous_io}
108
109 Una modalità alternativa all'uso dell'I/O non bloccante è quella di fare
110 ricorso all'I/O asincrono. Abbiamo accennato in \secref{sec:file_open} che è
111 possibile, attraverso l'uso del flag \macro{O\_ASYNC}, aprire un file in
112 modalità asincrona, così come è possibile settare questo flag attraverso l'uso
113 di \func{fcntl}.
114
115 In tal caso il sistema genera un segnale \macro{SIGIO} tutte le volte che sono
116 presenti dei dati in input su un file aperto in questa modalità.  Uno dei
117 problemi che si presentavano con le prime implementazioni di questa modalità
118 di I/O è che essa poteva essere usata in maniera semplice aprendo un solo file
119 per processo, dato che altrimenti si sarebbe dovuto provvedere ad effettuare
120 una serie di controlli su tutti i file aperti per distinguere a quale fosse
121 dovuto l'emissione del segnale.
122
123 Tutto questo adesso può essere evitato facendo ricorso alle informazioni
124 restituite al manipolatore del segnale attraverso la struttura
125 \var{siginfo\_t} (vedi \figref{fig:sig_siginfo_t}), il cui campo \var{si\_fd}
126 riporta il file descriptor che ha generato il segnale.
127
128
129
130 \subsection{File mappati in memoria}
131 \label{sec:file_memory_map}
132
133
134 \subsection{I/O multiplo}
135 \label{sec:file_multiple_io}
136
137
138
139 \section{Il file locking}
140 \label{sec:file_locking}
141
142 In \secref{sec:file_sharing} abbiamo preso in esame le mosalità in cui un
143 sistema unix-like gestisce la condivisione dei file da parte di processi
144 diversi. In quell'occasione si è visto come, con l'eccezione dei file aperti
145 in \textit{append mode}, quando più processi scrivono contemporaneamente sullo
146 stesso file non è possibile determinare la sequenza in cui essi opereranno.
147
148 Questo causa la possibilità di race condition; in generale le situazioni più
149 comuni sono due: l'interazione fra un processo che scrive e altri che leggono,
150 in cui questi ultimi possono leggere informazioni scritte solo in maniera
151 parziale o incompleta; o quella in cui diversi processi scrivono, mescolando
152 in maniera imprevedebile il loro output sul file.
153
154 In tutti questi casi il \textit{file locking} è la tecnica che permette di
155 evitare le race condition, attraverso una serie di funzioni che permettono di
156 bloccare l'accesso al file da parte di altri processi, così da evitare le
157 sovrapposizioni, e garantire la atomicità delle operazioni di scrittura.
158
159
160 \subsection{L'\textit{advisory locking}}
161 \label{sec:file_record_locking}
162
163 La prima modalità di file locking che è stata implementata nei sistemi
164 unix-like è quella che viene usualmente chiamata \textit{advisory locking}, in
165 quanto è il processo, e non il sistema, che si incarica di verificare se
166 esiste una condizione di blocco per l'accesso ai file.
167
168
169
170
171 \subsection{Il \textit{mandatory locking}}
172 \label{sec:file_mand_locking}
173
174 Il \textit{mandatory locking} è una opzione introdotta inizialmente in SVr4, 
175
176
177
178
179
180
181 %%% Local Variables: 
182 %%% mode: latex
183 %%% TeX-master: "gapil"
184 %%% End: