-\chapter{I/O avanzato}
+\chapter{La gestione avanzata dei file}
\label{cha:file_advanced}
-In questo capitolo affronteremo le tematiche della gestione avanzata delle
-funzioni di input/ouput, prenderemo in esame il \textit{file locking}, la
-gestione dell'input/output da più file, per concludere con la gestione dei
-file mappati in memoria.
+In questo capitolo affronteremo le tematiche relative alla gestione avanzata
+dei file, che non sono state trattate in \capref{cha:file_unix_interface},
+dove ci si è limitati ad una panoramica delle funzioni base. In particolare
+tratteremo delle funzioni di input/output avanzato e del \textit{file
+ locking}.
-\section{L'I/O avanzato}
+\section{Le funzioni di I/O avanzato}
\label{sec:file_advanced_io}
-Uno dei problemi che ci si trova ad affrontare con le funzioni ordinarie
-trattate in \capref{cha:file_unix_interface} è quello in cui si devono
-eseguire su più di un file descriptor delle operazioni che possono bloccarsi:
-il problema è che mentre si è bloccati su un file su di un'altro potrebbero
-essere presenti dati da leggere.
-
-In questa sezione vedremo come si possono affrontare queste problematiche,
-quali sono le soluzioni possibili e quali i meccanismi il kernel e le librerie
-ci mettono a disposizione.
+In questa sezione esamineremo le funzioni che permettono una gestione più
+sofisticata dell'I/O su file, a partire da quelle che permettono di gestire
+l'accesso contemporaneo a più file, per concludere con la gestione dell'I/O
+mappato in memoria.
\subsection{La modalità di I/O \textsl{non-bloccante}}
\label{sec:file_noblocking}
-Una prima soluzione per evitare di bloccarsi nelle operazioni di I/O è quella
-di utilizzare la modalità \textsl{non-bloccante}. Abbiamo visto in
-\secref{sec:sig_gen_beha}, affrontando la suddivisione fra \textit{fast} e
-\textit{slow} system call, che in certi casi le funzioni di I/O possono
-bloccarsi indefinitamente.\footnote{si ricordi però che questo può accadere
- solo per le pipe, i socket ed alcuni file di dispositivo; sui file normali
- le funzioni di lettura e scrittura ritornano sempre subito.}
-In particolare le operazioni di lettura possono bloccarsi quando non ci sono
-dati disponibili sul descrittore su cui si sta operando.
+Abbiamo visto in \secref{sec:sig_gen_beha}, affrontando la suddivisione fra
+\textit{fast} e \textit{slow} system call, che in certi casi le funzioni di
+I/O possono bloccarsi indefinitamente.\footnote{si ricordi però che questo può
+ accadere solo per le pipe, i socket ed alcuni 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.
+
+Uno dei problemi più comuni che ci si trova ad affrontare che non può essere
+risolto con le funzioni base trattate in \capref{cha:file_unix_interface} è
+quello in cui si devono eseguire su più di un file descriptor delle operazioni
+che possono bloccarsi: il problema è che mentre si è bloccati su uno di questi
+file su di un'altro potrebbero essere presenti dei dati.
Abbiamo già accennato in \secref{sec:file_open} che è possibile prevenire
-questo tipo di comportamento aprendo il file in modalità non bloccante,
-specificando il flag \macro{O\_NONBLOCK}. In questo caso le funzioni che si
-sarebbero bloccate ritornano immediatamente restituendo l'errore
+questo tipo di comportamento aprendo un file in modalità
+\textsl{non-bloccante}, specificando il flag \macro{O\_NONBLOCK} alla chiamata
+di \func{open}. In questo caso le funzioni di input/output che altrimenti si
+sarebbero bloccate ritornano immediatamente, restituendo l'errore
\macro{EAGAIN}.
-L'utilizzo di questa modalità di I/O permette allora di risolvere il problema
+L'utilizzo di questa modalità di I/O permette allora 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. Ovviamente questa tecnica,
+detta \textit{polling}, è estremamente inefficiente: si tiene costantemente
+impiegata la CPU solo per eseguire in continuazione delle system call che
+nella gran parte dei casi falliranno.
+
+Per questo motivo, quando come vedremo in dettaglio in
+\secref{sec:file_multiplexing}, il sistema fornisce delle funzioni apposite
+che permettono di aggirare questo problema, permettendo di attendere fino alla
+disponibilità di un accesso; per usarle però è comunque comunque necessario
+utilizzare la modalità di I/O non bloccante.
+
+\subsection{Le funzioni \func{poll} e \func{select}}
+\label{sec:file_multiplexing}
%\section{I/O asincrono}
%\label{sec:file_asynchronous}
%Non supportato in Linux, in BSD e SRv4 c'è, ma usando il segnale \macro{SIGIO}
-%per indicare che i dati sono disponibili, può essere usato in maniera semplice
-%con un solo file per processo (altrimenti non sarebbe più possibile
-%distinguere da quale file proviene l'attività che ha causato l'emissione del
-%segnale).
+%per indicare che i dati sono disponibili,
\subsection{L'I/O asincrono}
\label{sec:file_asyncronous_io}
+Una modalità alternativa all'uso dell'I/O non bloccante è quella di fare
+ricorso all'I/O asincrono. Abbiamo accennato in \secref{sec:file_open} che è
+possibile, attraverso l'uso del flag \macro{O\_ASYNC}, aprire un file in
+modalità asincrona, così come è possibile settare questo flag attraverso l'uso
+di \func{fcntl}.
+
+In tal caso il sistema genera un segnale \macro{SIGIO} tutte le volte che sono
+presenti dei dati in input sul file.
-\subsection{Le funzioni \func{poll} e \func{select}}
-\label{sec:file_multiplexing}
+Un dei problemi che si presentavano con le prime implementazioni di questa
+modalità di I/O è che essa poteva essere usata in maniera semplice con un solo
+file per processo, dato che altrimenti non sarebbe stato distinguere da quale
+file proviene l'attività che ha causato l'emissione del segnale.
-\section{File locking}
+\subsection{File mappati in memoria}
+\label{sec:file_memory_map}
+
+
+\subsection{I/O multiplo}
+\label{sec:file_multiple_io}
+
+
+
+\section{Il file locking}
\label{sec:file_locking}
In \secref{sec:file_sharing} abbiamo preso in esame le mosalità in cui un
-sistema unix-like gestisce la condivisione dei file. In quell'occasione si è
-visto come, con l'eccezione dei file aperti in \textit{append mode}, quando
-più processi scrivono contemporaneamente sullo stesso file non è possibile
-determinare la sequenza in cui essi opereranno.
+sistema unix-like gestisce la condivisione dei file da parte di processi
+diversi. In quell'occasione si è visto come, con l'eccezione dei file aperti
+in \textit{append mode}, quando più processi scrivono contemporaneamente sullo
+stesso file non è possibile determinare la sequenza in cui essi opereranno.
Questo causa la possibilità di race condition; in generale le situazioni più
comuni sono due: l'interazione fra un processo che scrive e altri che leggono,
In tutti questi casi il \textit{file locking} è la tecnica che permette di
evitare le race condition, attraverso una serie di funzioni che permettono di
-bloccare l'accesso al file da parte di altri processi così da evitare le
+bloccare l'accesso al file da parte di altri processi, così da evitare le
sovrapposizioni, e garantire la atomicità delle operazioni di scrittura.
-\subsection{Il \textit{advisory locking}}
+\subsection{L'\textit{advisory locking}}
\label{sec:file_record_locking}
La prima modalità di file locking che è stata implementata nei sistemi
\subsection{Il \textit{mandatory locking}}
\label{sec:file_mand_locking}
-Il \textit{mandatory locking} è una opzione introdotta inizialmente in SVR4,
+Il \textit{mandatory locking} è una opzione introdotta inizialmente in SVr4,
-\section{File mappati in memoria}
-\label{sec:file_memory_map}
-
%%% Local Variables:
le fifo e per alcuni file di dispositivo. \\
\macro{O\_NDELAY} & in Linux\footnotemark\ è sinonimo di
\macro{O\_NONBLOCK}.\\
- \macro{O\_ASYNC} & apre il file per l'input/output in modalità
- asincrona. Quando è settato viene generato un segnale di \macro{SIGIO}
- tutte le volte che è disponibile dell'input sul file. \\
+ \macro{O\_ASYNC} & apre il file per l'I/O in modalità
+ asincrona (vedi \secref{sec:file_asyncronous_io}). Quando è settato viene
+ generato il segnale \macro{SIGIO} tutte le volte che sono disponibili
+ dati in input sul file. \\
\macro{O\_SYNC} & apre il file per l'input/output sincrono, ogni
\func{write} bloccherà fino al completamento della scrittura di tutti dati
sul sull'hardware sottostante.\\
segnali \macro{SIGIO} e \macro{SIGURG} per gli eventi associati al file
descriptor \var{fd}. I process group sono settati usando valori negativi.
\item[\macro{F\_GETSIG}] restituisce il segnale mandato quando ci sono dati
- disponibili in input sul file descriptor. Il valore 0 indica il default (che
- è \macro{SIGIO}), un valore diverso da zero indica il segnale richiesto,
- (che può essere lo stesso \macro{SIGIO}), nel qual caso al manipolatore del
- segnale, se installato con \macro{SA\_SIGINFO}, vengono rese disponibili
- informazioni ulteriori informazioni.
+ disponibili in input su un file descriptor aperto o settato in I/O
+ asincrono. Il valore 0 indica il default (che è \macro{SIGIO}), un valore
+ diverso da zero indica il segnale richiesto, (che può essere lo stesso
+ \macro{SIGIO}).\footnote{in questo caso al manipolatore del segnale, se
+ installato come \var{sa\_sigaction} con \macro{SA\_SIGINFO}, vengono rese
+ disponibili informazioni ulteriori informazioni (vedi
+ \secref{sec:sig_sigaction} e \secref{sec:file_asyncronous_io})}.
\item[\macro{F\_SETSIG}] setta il segnale da inviare quando diventa possibile
effettuare I/O sul file descriptor. Il valore zero indica il default
(\macro{SIGIO}), ogni altro valore permette di rendere disponibile al
\include{filestd}
\include{system}
\include{signal}
+\include{ipc}
\include{fileadv}
\include{session}
-\include{ipc}
\include{network}
\include{socket}
\include{elemtcp}
Uno degli aspetti fondamentali della programmazione in un sistema unix-like è
-la comunicazione fra processi. In questo capitolo affronteremo solo alcuni dei
+la comunicazione fra processi. In questo capitolo affronteremo solo i
meccanismi più elementari che permettono di mettere in comunicazione processi
diversi, come quelli tradizionali che coinvolgono \textit{pipe} e
\textit{fifo} e i meccanismi di intercomunicazione di System V.
-Esistono pure sistemi più complessi ed evoluti come le RPC (\textit{Remote
- Procedure Calls}) e CORBA (\textit{Common Object Request Brocker
- Architecture}) che non saranno affrontati qui. Inoltre tratteremo nei
-capitoli successivi tutta la problematica relativa alla comunicazione
-attraverso la rete.
+Tralasceremo invece tutte le problematiche relative alla comunicazione
+attraverso la rete (e le relative interfacce) che saranno affrontate in gran
+dettaglio in un secondo tempo. Non affronteremo invece meccanismi più
+complessi ed evoluti come le RPC (\textit{Remote Procedure Calls}) e CORBA
+(\textit{Common Object Request Brocker Architecture}) che in genere sono
+implementati con un ulteriore livello sopra i meccanismi elementari.
\subsection{Le \textit{pipe} standard}
\label{sec:ipc_pipes}
-Le \textit{pipe} nascono sostanzialmente con Unix, e sono il primo, e più
-comunemente usato, meccanismo di comunicazione fra processi. Esse sono un file
-speciale in cui un processo scrive ed un altro legge. Si viene così a
-costituire un canale di comunicazione fra i due processi, nella forma di un
-\textsl{tubo} (da cui il nome) in cui uno immette dati che arriveranno
-all'altro.
-
-Perché questo accada però, e questo è il principale limite nell'uso delle
-\textit{pipe}, è necessario che questi processi possano condividere il file
-descriptor della \textit{pipe}; per questo essi devono comunque derivare da
-uno stesso processo padre, o, più comunemente, essere nella relazione
-padre/figlio.
+Le \textit{pipe} nascono sostanzialmente con Unix, e sono il primo, ed uno dei
+più usati, meccanismi di comunicazione fra processi. Si tratta in sostanza uno
+speciale tipo di file\footnote{più precisamente un file descriptor; le pipe
+ sono create dal kernel e non risiedono su disco.} in cui un processo scrive
+ed un altro legge. Si viene così a costituire un canale di comunicazione fra i
+due processi, nella forma di un \textsl{tubo} (da cui il nome) in cui uno dei
+processi immette dati che poi arriveranno all'altro.
+
+Perché questo accada però, e questo è il principale\footnote{Stevens riporta
+ in APUE come limite anche il fatto che la comunicazione è unidirezionale, in
+ realtà questo è un limite facilemente risolvibile usando una coppia di
+ \textit{pipe}.} e limite nell'uso delle \textit{pipe}, è necessario che
+questi processi possano condividere il file descriptor della \textit{pipe};
+per questo essi devono comunque derivare da uno stesso processo padre, o, più
+comunemente, essere nella relazione padre/figlio.
+
+La funzione che permette di creare una \textit{pipe} è appunto \func{pipe}; il
+suo prototipo è:
+\begin{prototype}{unistd.h}
+{int pipe(int filedes[2])}
+
+Crea una coppia di file descriptor associati ad una \textit{pipe}.
+
+ \bodydesc{La funzione restituisce zero in caso di successo e -1 per un
+ errore, nel qual caso \var{errno} potrà assumere i valori \macro{EMFILE},
+ \macro{ENFILE} e \macro{EFAULT}.}
+\end{prototype}
+
+La funzione restituisce una coppia di file descriptor nell'array
+\param{filedes}; il primo aperto in lettura ed il secondo in scrittura
\label{sec:ipc_sysv}
Per ovviare ai vari limiti dei meccanismo tradizionale di comunicazione fra
-processi basato sulle \textit{pipe}, nello sviluppo di System V vennero
-introdotti una serie di nuovi oggetti che garantissero una maggiore
-flessibilità; in questa sezione esamineremo quello che viene ormai chiamato il
-\textit{System V Inter Process Comunication system}, più comunemente noto come
-\textit{SystemV IPC}.
+processi visto in \secref{sec:ipc_unix}, nello sviluppo di System V vennero
+introdotti una serie di nuovi oggetti e relative interdacce che garantissero
+una maggiore flessibilità; in questa sezione esamineremo quello che viene
+ormai chiamato il \textit{System V Inter-Process Comunication System}, più
+comunemente noto come \textit{SystemV IPC}.
+
\subsection{Code di messaggi}
\label{sec:ipc_messque}
Il primo oggetto introdotto dal \textit{SystemV IPC} è quello delle code di
-messaggi.
+messaggi.
\subsection{Semafori}
\label{sec:ipc_semaph}
usate in maniera alternativa (in certe implementazioni questi vengono
specificati come \ctyp{union}): la prima è quella classica usata anche con
\func{signal}, la seconda permette invece di usare un manipolatore in grado di
-ricevere informazioni più dettagliate dal sistema (ad esempio il tipo di
-errore in caso di \macro{SIGFPE}), attraverso dei parametri aggiuntivi; per i
-dettagli si consulti la man page di \func{sigaction}).
+ricevere informazioni più dettagliate dal sistema, attraverso la struttura
+\var{siginfo\_t}, riportata in \figref{fig:sig_siginfo_t}.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{}
+siginfo_t {
+ int si_signo; /* Signal number */
+ int si_errno; /* An errno value */
+ int si_code; /* Signal code */
+ pid_t si_pid; /* Sending process ID */
+ uid_t si_uid; /* Real user ID of sending process */
+ int si_status; /* Exit value or signal */
+ clock_t si_utime; /* User time consumed */
+ clock_t si_stime; /* System time consumed */
+ sigval_t si_value; /* Signal value */
+ int si_int; /* POSIX.1b signal */
+ void * si_ptr; /* POSIX.1b signal */
+ void * si_addr; /* Memory location which caused fault */
+ int si_band; /* Band event */
+ int si_fd; /* File descriptor */
+}
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{La struttura \var{siginfo\_t}.}
+ \label{fig:sig_siginfo_t}
+\end{figure}
+
+Installando un manipolatore di tipo \var{sa\_sigaction} diventa allora
+possibile accedere al risultato restituito attraverso il puntatore a questa
+struttura. Tutti i segnali settano i campi \var{si\_signo}, \var{si\_errno} e
+\var{si\_code}, ed il resto della struttura può essere definito come
+\ctyp{union} ed i valori eventualmente presenti dipendono dal segnale (ad
+esempio può essere il tipo di errore nel caso di \macro{SIGFPE}); vedremo un
+esempio di tutto ciò per \macro{SIGIO} in \secref{sec:file_asyncronous_io},
+per i dettagli degli altri segnali si consulti la man page di
+\func{sigaction}).
Il campo \var{sa\_mask} serve ad indicare l'insieme dei segnali che devono
essere bloccati durante l'esecuzione del manipolatore, ad essi viene comunque
parte l'uso di \type{sigjmp\_buf} per \param{env}, è assolutamente identica a
\func{longjmp}.
-\begin{prototype}{signal.h}
-{int sigaltstack(const stack\_t *ss, stack\_t *oss)}
-
-Installa un nuovo stack per i segnali.
-
- \bodydesc{La funzione restituisce zero in caso di successo e -1 per un
- errore, nel qual caso \var{errno} assumerà i valori:
-
- \begin{errlist}
- \item[\macro{ENOMEM}] La dimensione specificata per il nuovo stack è minore
- di \macro{MINSIGSTKSZ}.
- \item[\macro{EPERM}] Uno degli indirizzi non è valido.
- \item[\macro{EFAULT}] Si è cercato di cambiare lo stack alternativo mentre
- questo è attivo (cioè il processo è in esecuzione su di esso).
- \item[\macro{EINVAL}] \param{ss} non è nullo e \var{ss\_flags} contiene un
- valore diverso da zero che non è \macro{SS\_DISABLE}.
- \end{errlist}}
-\end{prototype}
-
-
%%% Local Variables:
%%% mode: latex