From b93afedb7d7b01ba1f0b5ea4caaa281f38cb8e6d Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Wed, 29 Dec 2004 00:21:23 +0000 Subject: [PATCH] Risistemazione generale degli indici e chiamati argomenti gli argomenti delle funzioni --- errors.tex | 20 +++--- fileadv.tex | 109 ++++++++++++++-------------- filedir.tex | 194 +++++++++++++++++++++++++++----------------------- fileintro.tex | 80 +++++++++++---------- filestd.tex | 35 ++++----- fileunix.tex | 169 +++++++++++++++++++++++-------------------- intro.tex | 17 ++--- ipc.tex | 119 ++++++++++++++++--------------- process.tex | 183 ++++++++++++++++++++++++----------------------- prochand.tex | 142 ++++++++++++++++++------------------ session.tex | 23 +++--- signal.tex | 97 +++++++++++++------------ sockctrl.tex | 44 ++++++------ socket.tex | 52 +++++++------- system.tex | 67 +++++++++-------- tcpsock.tex | 113 +++++++++++++++-------------- 16 files changed, 777 insertions(+), 687 deletions(-) diff --git a/errors.tex b/errors.tex index 18ec1ae..b5839b5 100644 --- a/errors.tex +++ b/errors.tex @@ -38,10 +38,11 @@ gestione dei file. \item \errcode{EPERM} \textit{Operation not permitted}. L'operazione non è permessa: solo il proprietario del file o un processo con sufficienti privilegi può eseguire l'operazione. -\item \errcode{ENOENT} \textit{No such file or directory}. Il file indicato dal - pathname non esiste: o una delle componenti non esiste o il pathname - contiene un link simbolico spezzato. Errore tipico di un riferimento ad un - file che si suppone erroneamente essere esistente. +\item \errcode{ENOENT} \textit{No such file or directory}. Il file indicato + dal \index{\textit{pathname}}\textit{pathname} non esiste: o una delle + componenti non esiste o il \textit{pathname} contiene un link simbolico + spezzato. Errore tipico di un riferimento ad un file che si suppone + erroneamente essere esistente. \item \errcode{EIO} \textit{Input/output error}. Errore di input/output: usato per riportare errori hardware in lettura/scrittura su un dispositivo. \item \errcode{ENXIO} \textit{No such device or address}. Dispositivo @@ -59,9 +60,10 @@ gestione dei file. al file non è consentito: i permessi del file o della directory non consentono l'operazione. \item \errcode{ELOOP} \textit{Too many symbolic links encountered}. Ci sono - troppi link simbolici nella risoluzione di un pathname. + troppi link simbolici nella risoluzione di un + \index{\textit{pathname}}\textit{pathname}. \item \errcode{ENAMETOOLONG} \textit{File name too long}. Si è indicato un - pathname troppo lungo. + \textit{pathname} troppo lungo. \item \errcode{ENOTBLK} \textit{Block device required}. Si è specificato un file che non è un \textit{block device} in un contesto in cui era necessario specificare un \textit{block device} (ad esempio si è tentato di montare un @@ -255,9 +257,9 @@ specificati nelle sezioni precedenti. \item \errcode{ENOMEM} \textit{No memory available}. Il kernel non è in grado di allocare ulteriore memoria per completare l'operazione richiesta. \item \errcode{EDEADLK} \textit{Deadlock avoided}. L'allocazione di una - risorsa avrebbe causato un \textit{deadlock}\index{deadlock}. Non sempre il - sistema è in grado di riconoscere queste situazioni, nel qual caso si - avrebbe in blocco. + risorsa avrebbe causato un \textit{deadlock}\index{\textit{deadlock}}. Non + sempre il sistema è in grado di riconoscere queste situazioni, nel qual caso + si avrebbe il blocco. \item \errcode{EFAULT} \textit{Bad address}. Una stringa passata come parametro è fuori dello spazio di indirizzi del processo, in genere questa situazione provoca l'emissione di un segnale di \textit{segment violation} diff --git a/fileadv.tex b/fileadv.tex index de7ae5d..def6042 100644 --- a/fileadv.tex +++ b/fileadv.tex @@ -36,14 +36,14 @@ I/O. \label{sec:file_noblocking} Abbiamo visto in sez.~\ref{sec:sig_gen_beha}, affrontando la suddivisione fra -\textit{fast} e \textit{slow} system call,\index{system call lente} che in +\textit{fast} e \textit{slow} system call,\index{system~call~lente} 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\index{socket} ed alcuni file di dispositivo\index{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. + socket\index{socket} ed alcuni file di + dispositivo\index{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. Questo comportamento causa uno dei problemi più comuni che ci si trova ad affrontare nelle operazioni di I/O, che si verifica quando si deve operare con @@ -56,7 +56,7 @@ un'altro disponibile. Questo comporta nel migliore dei casi una operazione ritardata inutilmente nell'attesa del completamento di quella bloccata, mentre nel peggiore dei casi (quando la conclusione della operazione bloccata dipende da quanto si otterrebbe dal file descriptor ``\textsl{disponibile}'') si -potrebbe addirittura arrivare ad un \textit{deadlock}\index{deadlock}. +potrebbe addirittura arrivare ad un \textit{deadlock}\index{\textit{deadlock}}. Abbiamo già accennato in sez.~\ref{sec:file_open} che è possibile prevenire questo tipo di comportamento delle funzioni di I/O aprendo un file in @@ -66,7 +66,7 @@ eseguite sul file che si sarebbero bloccate, ritornano immediatamente, restituendo l'errore \errcode{EAGAIN}. L'utilizzo di questa modalità di I/O permette 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}\index{polling}, è +Ovviamente questa tecnica, detta \textit{polling}\index{\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. @@ -123,11 +123,12 @@ degli insiemi specificati (\param{readfds}, \param{writefds} e \param{exceptfds}), non diventa attivo, per un tempo massimo specificato da \param{timeout}. +\index{\textit{file~descriptor~set}|(} Per specificare quali file descriptor si intende \textsl{selezionare}, la funzione usa un particolare oggetto, il \textit{file descriptor set}, identificato dal tipo \type{fd\_set}, che serve ad identificare un insieme di -file descriptor, in maniera analoga a come un -\index{\textit{signal set}}\textit{signal set} (vedi +file descriptor, in maniera analoga a come un +\index{\textit{signal~set}}\textit{signal set} (vedi sez.~\ref{sec:sig_sigset}) identifica un insieme di segnali. Per la manipolazione di questi \textit{file descriptor set} si possono usare delle opportune macro di preprocessore: @@ -185,6 +186,7 @@ ritorni; se impostato a \val{NULL} la funzione attende indefinitamente. Si pu specificare anche un tempo nullo (cioè una struttura \struct{timeval} con i campi impostati a zero), qualora si voglia semplicemente controllare lo stato corrente dei file descriptor. +\index{\textit{file~descriptor~set}|)} La funzione restituisce il numero di file descriptor pronti,\footnote{questo è il comportamento previsto dallo standard, ma la standardizzazione della @@ -268,15 +270,15 @@ immediatamente prima di eseguire l'attesa, e ripristinata al ritorno della funzione. L'uso di \param{sigmask} è stato introdotto allo scopo di prevenire possibili -race condition\index{race condition} quando ci si deve porre in attesa sia di -un segnale che di dati. La tecnica classica è quella di utilizzare il gestore -per impostare una variabile globale e controllare questa nel corpo principale -del programma; abbiamo visto in sez.~\ref{sec:sig_example} come questo lasci -spazio a possibili race condition, per cui diventa essenziale utilizzare -\func{sigprocmask} per disabilitare la ricezione del segnale prima di eseguire -il controllo e riabilitarlo dopo l'esecuzione delle relative operazioni, onde -evitare l'arrivo di un segnale immediatamente dopo il controllo, che andrebbe -perso. +race condition\index{\textit{race~condition}} quando ci si deve porre in +attesa sia di un segnale che di dati. La tecnica classica è quella di +utilizzare il gestore per impostare una variabile globale e controllare questa +nel corpo principale del programma; abbiamo visto in +sez.~\ref{sec:sig_example} come questo lasci spazio a possibili race +condition, per cui diventa essenziale utilizzare \func{sigprocmask} per +disabilitare la ricezione del segnale prima di eseguire il controllo e +riabilitarlo dopo l'esecuzione delle relative operazioni, onde evitare +l'arrivo di un segnale immediatamente dopo il controllo, che andrebbe perso. Nel nostro caso il problema si pone quando oltre al segnale si devono tenere sotto controllo anche dei file descriptor con \func{select}, in questo caso si @@ -284,9 +286,9 @@ pu e si potrebbero eseguire di conseguenza le operazioni relative al segnale e alla gestione dati con un ciclo del tipo: \includecodesnip{listati/select_race.c} qui però emerge una race -condition,\index{race condition} perché se il segnale arriva prima della -chiamata a \func{select}, questa non verrà interrotta, e la ricezione del -segnale non sarà rilevata. +condition,\index{\textit{race~condition}} perché se il segnale arriva prima +della chiamata a \func{select}, questa non verrà interrotta, e la ricezione +del segnale non sarà rilevata. Per questo è stata introdotta \func{pselect} che attraverso l'argomento \param{sigmask} permette di riabilitare la ricezione il segnale @@ -542,7 +544,7 @@ effettuare in contemporanea le operazioni di calcolo e quelle di I/O. Benché la modalità di apertura asincrona di un file possa risultare utile in varie occasioni (in particolar modo con i socket\index{socket} e gli altri -file per i quali le funzioni di I/O sono \index{system call lente}system call +file per i quali le funzioni di I/O sono \index{system~call~lente}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 una interfaccia apposita per l'I/O @@ -984,7 +986,7 @@ file in una sezione dello spazio di indirizzi del processo. Il meccanismo illustrato in fig.~\ref{fig:file_mmap_layout}, una sezione del file viene riportata direttamente nello spazio degli indirizzi del programma. Tutte le operazioni su questa zona verranno riportate indietro sul file dal meccanismo -della memoria virtuale\index{memoria virtuale} che trasferirà il contenuto di +della memoria virtuale\index{memoria~virtuale} che trasferirà il contenuto di quel segmento sul file invece che nella swap, per cui si può parlare tanto di file mappato in memoria, quanto di memoria mappata su file. @@ -1005,7 +1007,7 @@ memoria solo le parti del file che sono effettivamente usate ad un dato istante. Infatti, dato che l'accesso è fatto direttamente attraverso la memoria -virtuale,\index{memoria virtuale} la sezione di memoria mappata su cui si +virtuale,\index{memoria~virtuale} la sezione di memoria mappata su cui si opera sarà a sua volta letta o scritta sul file una pagina alla volta e solo per le parti effettivamente usate, il tutto in maniera completamente trasparente al processo; l'accesso alle pagine non ancora caricate avverrà @@ -1124,8 +1126,8 @@ tab.~\ref{tab:file_mmap_flag}. riportati sul file. Ne viene fatta una copia privata cui solo il processo chiamante ha accesso. Le modifiche sono mantenute attraverso - il meccanismo del - \textit{copy on write}\index{copy on write} e + il meccanismo del \textit{copy on + write}\index{\textit{copy~on~write}} e salvate su swap in caso di necessità. Non è specificato se i cambiamenti sul file originale vengano riportati sulla regione @@ -1136,8 +1138,9 @@ tab.~\ref{tab:file_mmap_flag}. 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 di - \textit{copy on write}\index{copy on write} + delle pagine di swap ad uso del meccanismo del + \textit{copy on + write}\index{\textit{copy~on~write}} per mantenere le modifiche fatte alla regione mappata, in questo caso dopo una scrittura, se non c'è più @@ -1167,7 +1170,7 @@ tab.~\ref{tab:file_mmap_flag}. Gli effetti dell'accesso ad una zona di memoria mappata su file possono essere piuttosto complessi, essi si possono comprendere solo tenendo presente che tutto quanto è comunque basato sul basato sul meccanismo della memoria -virtuale.\index{memoria virtuale} Questo comporta allora una serie di +virtuale.\index{memoria~virtuale} Questo comporta allora una serie di conseguenze. La più ovvia è che se si cerca di scrivere su una zona mappata in sola lettura si avrà l'emissione di un segnale di violazione di accesso (\const{SIGSEGV}), dato che i permessi sul segmento di memoria relativo non @@ -1252,12 +1255,12 @@ consentita la scrittura sul file (cio o in corrispondenza di una eventuale \func{msync}. Dato per i file mappati in memoria le operazioni di I/O sono gestite -direttamente dalla memoria virtuale, occorre essere consapevoli delle -interazioni che possono esserci con operazioni effettuate con l'interfaccia -standard dei file di cap.~\ref{cha:file_unix_interface}. Il problema è che una -volta che si è mappato un file, le operazioni di lettura e scrittura saranno -eseguite sulla memoria, e riportate su disco in maniera autonoma dal sistema -della memoria virtuale. +direttamente dalla \index{memoria~virtuale}memoria virtuale, occorre essere +consapevoli delle interazioni che possono esserci con operazioni effettuate +con l'interfaccia standard dei file di cap.~\ref{cha:file_unix_interface}. Il +problema è che una volta che si è mappato un file, le operazioni di lettura e +scrittura saranno eseguite sulla memoria, e riportate su disco in maniera +autonoma dal sistema della memoria virtuale. Pertanto se si modifica un file con l'interfaccia standard queste modifiche potranno essere visibili o meno a seconda del momento in cui la memoria @@ -1366,16 +1369,16 @@ diversi. In quell'occasione si 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\index{race condition}; in -generale le situazioni più comuni sono due: l'interazione fra un processo che -scrive e altri che leggono, in cui questi ultimi possono leggere informazioni -scritte solo in maniera parziale o incompleta; o quella in cui diversi -processi scrivono, mescolando in maniera imprevedibile il loro output sul -file. +Questo causa la possibilità di race condition\index{\textit{race~condition}}; +in generale le situazioni più comuni sono due: l'interazione fra un processo +che scrive e altri che leggono, in cui questi ultimi possono leggere +informazioni scritte solo in maniera parziale o incompleta; o quella in cui +diversi processi scrivono, mescolando in maniera imprevedibile il loro output +sul file. In tutti questi casi il \textit{file locking} è la tecnica che permette di -evitare le race condition\index{race condition}, attraverso una serie di -funzioni che permettono di bloccare l'accesso al file da parte di altri +evitare le race condition\index{\textit{race~condition}}, attraverso una serie +di funzioni che permettono di bloccare l'accesso al file da parte di altri processi, così da evitare le sovrapposizioni, e garantire la atomicità delle operazioni di scrittura. @@ -1625,8 +1628,8 @@ essa viene usata solo secondo il prototipo: \item[\errcode{EDEADLK}] Si è richiesto un lock su una regione bloccata da un altro processo che è a sua volta in attesa dello sblocco di un lock mantenuto dal processo corrente; si avrebbe pertanto un - \textit{deadlock}\index{deadlock}. Non è garantito che il sistema - riconosca sempre questa situazione. + \textit{deadlock}\index{\textit{deadlock}}. Non è garantito che il + sistema riconosca sempre questa situazione. \item[\errcode{EINTR}] La funzione è stata interrotta da un segnale prima di poter acquisire un lock. \end{errlist} @@ -1745,7 +1748,8 @@ stato effettivamente acquisito. \begin{figure}[htb] \centering \includegraphics[width=9cm]{img/file_lock_dead} - \caption{Schema di una situazione di \textit{deadlock}\index{deadlock}.} + \caption{Schema di una situazione di + \textit{deadlock}\index{\textit{deadlock}}.} \label{fig:file_flock_dead} \end{figure} @@ -1757,11 +1761,12 @@ un lock sulla regione 2 che non pu del processo 2; il processo 1 si bloccherà fintanto che il processo 2 non rilasci il blocco. Ma cosa accade se il processo 2 nel frattempo tenta a sua volta di ottenere un lock sulla regione A? Questa è una tipica situazione che -porta ad un \textit{deadlock}\index{deadlock}, dato che a quel punto anche il -processo 2 si bloccherebbe, e niente potrebbe sbloccare l'altro processo. Per -questo motivo il kernel si incarica di rilevare situazioni di questo tipo, ed -impedirle restituendo un errore di \errcode{EDEADLK} alla funzione che cerca -di acquisire un lock che porterebbe ad un \textit{deadlock}. +porta ad un \textit{deadlock}\index{\textit{deadlock}}, dato che a quel punto +anche il processo 2 si bloccherebbe, e niente potrebbe sbloccare l'altro +processo. Per questo motivo il kernel si incarica di rilevare situazioni di +questo tipo, ed impedirle restituendo un errore di \errcode{EDEADLK} alla +funzione che cerca di acquisire un lock che porterebbe ad un +\textit{deadlock}. \begin{figure}[!bht] \centering \includegraphics[width=13cm]{img/file_posix_lock} diff --git a/filedir.tex b/filedir.tex index 01543fa..7f0cb67 100644 --- a/filedir.tex +++ b/filedir.tex @@ -93,20 +93,20 @@ chiamare questo tipo di associazione un collegamento diretto (o \textit{hard \errval{ENOSPC}, \errval{EIO}.} \end{prototype} -La funzione crea sul pathname \param{newpath} un collegamento diretto al file -indicato da \param{oldpath}. Per quanto detto la creazione di un nuovo -collegamento diretto non copia il contenuto del file, ma si limita a creare -una voce nella directory specificata da \param{newpath} e ad aumentare di uno -il numero di riferimenti al file (riportato nel campo \var{st\_nlink} della -struttura \struct{stat}, vedi sez.~\ref{sec:file_stat}) aggiungendo il nuovo -nome ai precedenti. Si noti che uno stesso file può essere così chiamato con -vari nomi in diverse directory. +La funzione crea sul \index{\textit{pathname}}\textit{pathname} +\param{newpath} un collegamento diretto al file indicato da \param{oldpath}. +Per quanto detto la creazione di un nuovo collegamento diretto non copia il +contenuto del file, ma si limita a creare una voce nella directory specificata +da \param{newpath} e ad aumentare di uno il numero di riferimenti al file +(riportato nel campo \var{st\_nlink} della struttura \struct{stat}, vedi +sez.~\ref{sec:file_stat}) aggiungendo il nuovo nome ai precedenti. Si noti che +uno stesso file può essere così chiamato con vari nomi in diverse directory. Per quanto dicevamo in sez.~\ref{sec:file_filesystem} la creazione di un -collegamento diretto è possibile solo se entrambi i pathname sono nello stesso -filesystem; inoltre il filesystem deve supportare i collegamenti diretti (il -meccanismo non è disponibile ad esempio con il filesystem \acr{vfat} di -Windows). +collegamento diretto è possibile solo se entrambi i +\index{\textit{pathname}}\textit{pathname} sono nello stesso filesystem; +inoltre il filesystem deve supportare i collegamenti diretti (il meccanismo +non è disponibile ad esempio con il filesystem \acr{vfat} di Windows). La funzione inoltre opera sia sui file ordinari che sugli altri oggetti del filesystem, con l'eccezione delle directory. In alcune versioni di Unix solo @@ -155,9 +155,10 @@ suo prototipo La funzione cancella il nome specificato da \param{pathname} nella relativa directory e decrementa il numero di riferimenti nel relativo inode\index{inode}. Nel caso di link simbolico cancella il link simbolico; nel -caso di socket\index{socket}, fifo o file di dispositivo\index{file!di - dispositivo} rimuove il nome, ma come per i file i processi che hanno aperto -uno di questi oggetti possono continuare ad utilizzarlo. +caso di socket\index{socket}, fifo o file di +dispositivo\index{file!di~dispositivo} rimuove il nome, ma come per i file i +processi che hanno aperto uno di questi oggetti possono continuare ad +utilizzarlo. Per cancellare una voce in una directory è necessario avere il permesso di scrittura su di essa, dato che si va a rimuovere una voce dal suo contenuto, e @@ -255,8 +256,9 @@ nello stesso filesystem) si usa invece la funzione \funcd{rename},\footnote{la \item[\errcode{EINVAL}] \param{newpath} contiene un prefisso di \param{oldpath} o più in generale si è cercato di creare una directory come sotto-directory di se stessa. - \item[\errcode{ENOTDIR}] Uno dei componenti dei pathname non è una directory - o \param{oldpath} è una directory e \param{newpath} esiste e non è una + \item[\errcode{ENOTDIR}] Uno dei componenti dei + \index{\textit{pathname}}\textit{pathname} non è una directory o + \param{oldpath} è una directory e \param{newpath} esiste e non è una directory. \end{errlist} ed inoltre \errval{EACCES}, \errval{EPERM}, \errval{EMLINK}, @@ -445,9 +447,9 @@ punta di nuovo a \file{/boot}.\footnote{il loop mostrato in fig.~\ref{fig:file_link_loop} è un usato per poter permettere a \cmd{grub} (un bootloader in grado di leggere direttamente da vari filesystem il file da lanciare come sistema operativo) di vedere i file contenuti nella - directory \file{/boot} con lo stesso pathname con cui verrebbero visti dal - sistema operativo, anche se essi si trovano, come accade spesso, su una - partizione separata (che \cmd{grub}, all'avvio, vede come radice).} + directory \file{/boot} con lo stesso \textit{pathname} con cui verrebbero + visti dal sistema operativo, anche se essi si trovano, come accade spesso, + su una partizione separata (che \cmd{grub}, all'avvio, vede come radice).} Questo può causare problemi per tutti quei programmi che effettuano la scansione di una directory senza tener conto dei link simbolici, ad esempio se @@ -456,10 +458,10 @@ directory porterebbe il comando ad esaminare \file{/boot}, \file{/boot/boot}, \file{/boot/boot/boot} e così via. Per questo motivo il kernel e le librerie prevedono che nella risoluzione di -un pathname possano essere seguiti un numero limitato di link simbolici, il -cui valore limite è specificato dalla costante \const{MAXSYMLINKS}. Qualora -questo limite venga superato viene generato un errore ed \var{errno} viene -impostata al valore \errcode{ELOOP}. +un \index{\textit{pathname}}\textit{pathname} possano essere seguiti un numero +limitato di link simbolici, il cui valore limite è specificato dalla costante +\const{MAXSYMLINKS}. Qualora questo limite venga superato viene generato un +errore ed \var{errno} viene impostata al valore \errcode{ELOOP}. Un punto da tenere sempre presente è che, come abbiamo accennato, un link simbolico può fare riferimento anche ad un file che non esiste; ad esempio @@ -520,8 +522,8 @@ per creare una directory La funzione crea una nuova directory vuota, che contiene cioè solo le due voci standard (\file{.} e \file{..}), con il nome indicato dall'argomento -\param{dirname}. Il nome può essere indicato sia come pathname assoluto che -relativo. +\param{dirname}. Il nome può essere indicato sia come +\index{\textit{pathname}}\textit{pathname} assoluto che relativo. I permessi di accesso alla directory (vedi sez.~\ref{sec:file_access_control}) sono specificati da \param{mode}, i cui possibili valori sono riportati in @@ -556,7 +558,8 @@ prototipo La funzione cancella la directory \param{dirname}, che deve essere vuota (la directory deve cioè contenere soltanto le due voci standard \file{.} e -\file{..}). Il nome può essere indicato con il pathname assoluto o relativo. +\file{..}). Il nome può essere indicato con il +\index{\textit{pathname}}\textit{pathname} assoluto o relativo. La modalità con cui avviene la cancellazione è analoga a quella di \func{unlink}: fintanto che il numero di link all'inode\index{inode} della @@ -572,10 +575,9 @@ consentir Finora abbiamo parlato esclusivamente di file, directory e link simbolici; in sez.~\ref{sec:file_file_types} abbiamo visto però che il sistema prevede pure -degli altri tipi di file speciali, come i file di dispositivo -\index{file!di dispositivo} -e le fifo (i socket\index{socket} sono un caso a parte, che -vedremo in cap.~\ref{cha:socket_intro}). +degli altri tipi di file speciali, come i file di dispositivo +\index{file!di~dispositivo} e le fifo (i socket\index{socket} sono un caso a +parte, che vedremo in cap.~\ref{cha:socket_intro}). La manipolazione delle caratteristiche di questi file e la loro cancellazione può essere effettuata con le stesse funzioni che operano sui file regolari; ma @@ -1043,8 +1045,9 @@ concluse con successo. A ciascun processo è associata una directory nel filesystem che è chiamata \textsl{directory corrente} o \textsl{directory di lavoro} (in inglese \textit{current working directory}) che è quella a cui si fa riferimento -quando un pathname è espresso in forma relativa, dove il ``\textsl{relativa}'' -fa riferimento appunto a questa directory. +quando un \index{\textit{pathname}}\textit{pathname} è espresso in forma +relativa, dove il ``\textsl{relativa}'' fa riferimento appunto a questa +directory. Quando un utente effettua il login, questa directory viene impostata alla \textit{home directory} del suo account. Il comando \cmd{cd} della shell @@ -1055,10 +1058,11 @@ sez.~\ref{sec:proc_fork}), la directory corrente della shell diventa anche la directory corrente di qualunque comando da essa lanciato. In genere il kernel tiene traccia per ciascun processo dell'inode\index{inode} -della directory di lavoro, per ottenere il pathname occorre usare una apposita -funzione di libreria, \funcd{getcwd}, il cui prototipo è: +della directory di lavoro, per ottenere il +\index{\textit{pathname}}\textit{pathname} occorre usare una apposita funzione +di libreria, \funcd{getcwd}, il cui prototipo è: \begin{prototype}{unistd.h}{char *getcwd(char *buffer, size\_t size)} - Legge il pathname della directory di lavoro corrente. + Legge il \textit{pathname} della directory di lavoro corrente. \bodydesc{La funzione restituisce il puntatore \param{buffer} se riesce, \val{NULL} se fallisce, in quest'ultimo caso la variabile @@ -1067,43 +1071,46 @@ funzione di libreria, \funcd{getcwd}, il cui prototipo \item[\errcode{EINVAL}] L'argomento \param{size} è zero e \param{buffer} non è nullo. \item[\errcode{ERANGE}] L'argomento \param{size} è più piccolo della - lunghezza del pathname. + lunghezza del \textit{pathname}. \item[\errcode{EACCES}] Manca il permesso di lettura o di ricerca su uno dei - componenti del pathname (cioè su una delle directory superiori alla - corrente). + componenti del \textit{pathname} (cioè su una delle directory superiori + alla corrente). \end{errlist}} \end{prototype} -La funzione restituisce il pathname completo della directory di lavoro nella -stringa puntata da \param{buffer}, che deve essere precedentemente allocata, -per una dimensione massima di \param{size}. Il buffer deve essere -sufficientemente lungo da poter contenere il pathname completo più lo zero di -terminazione della stringa. Qualora esso ecceda le dimensioni specificate con -\param{size} la funzione restituisce un errore. +La funzione restituisce il \index{\textit{pathname}}\textit{pathname} completo +della directory di lavoro nella stringa puntata da \param{buffer}, che deve +essere precedentemente allocata, per una dimensione massima di \param{size}. +Il buffer deve essere sufficientemente lungo da poter contenere il +\textit{pathname} completo più lo zero di terminazione della stringa. Qualora +esso ecceda le dimensioni specificate con \param{size} la funzione restituisce +un errore. Si può anche specificare un puntatore nullo come \param{buffer},\footnote{questa è un'estensione allo standard POSIX.1, supportata da Linux.} nel qual caso la stringa sarà allocata automaticamente per una dimensione pari a \param{size} qualora questa sia diversa da zero, o -della lunghezza esatta del pathname altrimenti. In questo caso ci si deve -ricordare di disallocare la stringa una volta cessato il suo utilizzo. +della lunghezza esatta del \index{\textit{pathname}}\textit{pathname} +altrimenti. In questo caso ci si deve ricordare di disallocare la stringa una +volta cessato il suo utilizzo. Di questa funzione esiste una versione \code{char *getwd(char *buffer)} fatta per compatibilità all'indietro con BSD, che non consente di specificare la dimensione del buffer; esso deve essere allocato in precedenza ed avere una dimensione superiore a \const{PATH\_MAX} (di solito 256 byte, vedi sez.~\ref{sec:sys_limits}); il problema è che in Linux non esiste una -dimensione superiore per un pathname, per cui non è detto che il buffer sia -sufficiente a contenere il nome del file, e questa è la ragione principale per -cui questa funzione è deprecata. +dimensione superiore per un \index{\textit{pathname}}\textit{pathname}, per +cui non è detto che il buffer sia sufficiente a contenere il nome del file, e +questa è la ragione principale per cui questa funzione è deprecata. Una seconda funzione simile è \code{char *get\_current\_dir\_name(void)} che è sostanzialmente equivalente ad una \code{getcwd(NULL, 0)}, con la sola differenza che essa ritorna il valore della variabile di ambiente \val{PWD}, -che essendo costruita dalla shell può contenere un pathname comprendente anche -dei link simbolici. Usando \func{getcwd} infatti, essendo il pathname ricavato -risalendo all'indietro l'albero della directory, si perderebbe traccia di ogni -passaggio attraverso eventuali link simbolici. +che essendo costruita dalla shell può contenere un \textit{pathname} +comprendente anche dei link simbolici. Usando \func{getcwd} infatti, essendo +il \index{\textit{pathname}}\textit{pathname} ricavato risalendo all'indietro +l'albero della directory, si perderebbe traccia di ogni passaggio attraverso +eventuali link simbolici. Per cambiare la directory di lavoro si può usare la funzione \funcd{chdir} (equivalente del comando di shell \cmd{cd}) il cui nome sta appunto per @@ -1125,11 +1132,12 @@ Per cambiare la directory di lavoro si pu quale si hanno i permessi di accesso. Dato che anche le directory sono file, è possibile riferirsi ad esse anche -tramite il file descriptor, e non solo tramite il pathname, per fare questo si -usa \funcd{fchdir}, il cui prototipo è: +tramite il file descriptor, e non solo tramite il +\index{\textit{pathname}}\textit{pathname}, per fare questo si usa +\funcd{fchdir}, il cui prototipo è: \begin{prototype}{unistd.h}{int fchdir(int fd)} Identica a \func{chdir}, ma usa il file descriptor \param{fd} invece del - pathname. + \textit{pathname}. \bodydesc{La funzione restituisce zero in caso di successo e -1 per un errore, in caso di errore \var{errno} assumerà i valori \errval{EBADF} o @@ -1151,7 +1159,7 @@ sembri semplice, in realt prima vista. Infatti anche se sembrerebbe banale generare un nome a caso e creare il file dopo aver controllato che questo non esista, nel momento fra il controllo e la creazione si ha giusto lo spazio per una possibile \textit{race - condition}\index{race condition} (si ricordi quanto visto in + condition}\index{\textit{race~condition}} (si ricordi quanto visto in sez.~\ref{sec:proc_race_cond}). Le \acr{glibc} provvedono varie funzioni per generare nomi di file temporanei, @@ -1231,7 +1239,7 @@ automaticamente cancellato alla sua chiusura o all'uscita dal programma. Lo standard non specifica in quale directory verrà aperto il file, ma le \acr{glibc} prima tentano con \const{P\_tmpdir} e poi con \file{/tmp}. Questa funzione è rientrante e non soffre di problemi di \textit{race - condition}\index{race condition}. + condition}\index{\textit{race~condition}}. Alcune versioni meno recenti di Unix non supportano queste funzioni; in questo caso si possono usare le vecchie funzioni \funcd{mktemp} e \func{mkstemp} che @@ -1252,7 +1260,7 @@ il suo prototipo \end{prototype} \noindent dato che \param{template} deve poter essere modificata dalla funzione non si può usare una stringa costante. Tutte le avvertenze riguardo -alle possibili \textit{race condition}\index{race condition} date per +alle possibili \textit{race condition}\index{\textit{race~condition}} date per \func{tmpnam} continuano a valere; inoltre in alcune vecchie implementazioni il valore usato per sostituire le \code{XXXXXX} viene formato con il \acr{pid} del processo più una lettera, il che mette a disposizione solo 26 possibilità @@ -1301,9 +1309,9 @@ In OpenBSD più gli altri eventuali codici di errore di \func{mkdir}.} \end{prototype} \noindent la directory è creata con permessi \code{0700} (al solito si veda -cap.~\ref{cha:file_unix_interface} per i dettagli); dato che la creazione della -directory è sempre esclusiva i precedenti problemi di \textit{race - condition}\index{race condition} non si pongono. +cap.~\ref{cha:file_unix_interface} per i dettagli); dato che la creazione +della directory è sempre esclusiva i precedenti problemi di \textit{race + condition}\index{\textit{race~condition}} non si pongono. \section{La manipolazione delle caratteristiche dei files} @@ -1480,7 +1488,8 @@ poi si effettua il confronto con la combinazione di tipi scelta. Il campo \var{st\_size} contiene la dimensione del file in byte (se si tratta di un file regolare, nel caso di un link simbolico la dimensione è quella del -pathname che contiene, per le fifo è sempre nullo). +\index{\textit{pathname}}\textit{pathname} che contiene, per le fifo è sempre +nullo). Il campo \var{st\_blocks} definisce la lunghezza del file in blocchi di 512 byte. Il campo \var{st\_blksize} infine definisce la dimensione preferita per @@ -1531,7 +1540,8 @@ dimensione si possono usare le due funzioni \funcd{truncate} e per \func{truncate} si hanno: \begin{errlist} \item[\errcode{EACCES}] il file non ha permesso di scrittura o non si ha il - permesso di esecuzione una delle directory del pathname. + permesso di esecuzione una delle directory del + \index{\textit{pathname}}\textit{pathname}. \item[\errcode{ETXTBSY}] Il file è un programma in esecuzione. \end{errlist} ed anche \errval{ENOTDIR}, \errval{ENAMETOOLONG}, \errval{ENOENT}, @@ -1863,14 +1873,16 @@ che si riferiscano a dei file, dei link simbolici o delle directory; qui ci limiteremo ad un riassunto delle regole generali, entrando nei dettagli più avanti. -La prima regola è che per poter accedere ad un file attraverso il suo pathname -occorre il permesso di esecuzione in ciascuna delle directory che compongono -il pathname; lo stesso vale per aprire un file nella directory corrente (per -la quale appunto serve il diritto di esecuzione). +La prima regola è che per poter accedere ad un file attraverso il suo +\textit{pathname} occorre il permesso di esecuzione in ciascuna delle +directory che compongono il \textit{pathname}; lo stesso vale per aprire un +file nella directory corrente (per la quale appunto serve il diritto di +esecuzione). Per una directory infatti il permesso di esecuzione significa che essa può -essere attraversata nella risoluzione del pathname, ed è distinto dal permesso -di lettura che invece implica che si può leggere il contenuto della directory. +essere attraversata nella risoluzione del +\index{\textit{pathname}}\textit{pathname}, ed è distinto dal permesso di +lettura che invece implica che si può leggere il contenuto della directory. Questo significa che se si ha il permesso di esecuzione senza permesso di lettura si potrà lo stesso aprire un file in una directory (se si hanno i @@ -2501,25 +2513,27 @@ Bench programma ad una sezione limitata del filesystem, per cui ne parleremo in questa sezione. -Come accennato in sez.~\ref{sec:proc_fork} ogni processo oltre ad una directory -di lavoro, ha anche una directory \textsl{radice}\footnote{entrambe sono - contenute in due campi (rispettivamente \var{pwd} e \var{root}) di +Come accennato in sez.~\ref{sec:proc_fork} ogni processo oltre ad una +directory di lavoro, ha anche una directory \textsl{radice}\footnote{entrambe + sono contenute in due campi (rispettivamente \var{pwd} e \var{root}) di \struct{fs\_struct}; vedi fig.~\ref{fig:proc_task_struct}.} che, pur essendo di norma corrispondente alla radice dell'albero di file e directory come visto dal kernel (ed illustrato in sez.~\ref{sec:file_organization}), ha per il processo il significato specifico di directory rispetto alla quale vengono -risolti i pathname assoluti.\footnote{cioè quando un processo chiede la - risoluzione di un pathname, il kernel usa sempre questa directory come punto - di partenza.} Il fatto che questo valore sia specificato per ogni processo -apre allora la possibilità di modificare le modalità di risoluzione dei -pathname assoluti da parte di un processo cambiando questa directory, così -come si fa coi pathname relativi cambiando la directory di lavoro. +risolti i \index{\textit{pathname}!assoluto}\textit{pathname} +assoluti.\footnote{cioè quando un processo chiede la risoluzione di un + \textit{pathname}, il kernel usa sempre questa directory come punto di + partenza.} Il fatto che questo valore sia specificato per ogni processo apre +allora la possibilità di modificare le modalità di risoluzione dei +\textit{pathname} assoluti da parte di un processo cambiando questa directory, +così come si fa coi \index{\textit{pathname}!relativo}\textit{pathname} +relativi cambiando la directory di lavoro. Normalmente la directory radice di un processo coincide anche con la radice del filesystem usata dal kernel, e dato che il suo valore viene ereditato dal -padre da ogni processo figlio, in generale i processi risolvono i pathname -assoluti a partire sempre dalla stessa directory, che corrisponde alla -\file{/} del sistema. +padre da ogni processo figlio, in generale i processi risolvono i +\index{\textit{pathname}!assoluto}\textit{pathname} assoluti a partire sempre +dalla stessa directory, che corrisponde alla \file{/} del sistema. In certe situazioni però, per motivi di sicurezza, è utile poter impedire che un processo possa accedere a tutto il filesystem; per far questo si può @@ -2539,8 +2553,9 @@ prototipo \errval{EROFS} e \errval{EIO}.} \end{prototype} \noindent in questo modo la directory radice del processo diventerà -\param{path} (che ovviamente deve esistere) ed ogni pathname assoluto usato -dalle funzioni chiamate nel processo sarà risolto a partire da essa, rendendo +\param{path} (che ovviamente deve esistere) ed ogni +\index{\textit{pathname}!assoluto}\textit{pathname} assoluto usato dalle +funzioni chiamate nel processo sarà risolto a partire da essa, rendendo impossibile accedere alla parte di albero sovrastante. Si ha così quella che viene chiamata una \textit{chroot jail}, in quanto il processo non può più accedere a file al di fuori della sezione di albero in cui è stato @@ -2555,10 +2570,11 @@ cambia la directory di lavoro, che potrebbe restare fuori dalla \textit{chroot Questo è il motivo per cui la funzione è efficace solo se dopo averla eseguita si cedono i privilegi di root. Infatti se per un qualche motivo il processo resta con la directory di lavoro fuori dalla \textit{chroot jail}, potrà -comunque accedere a tutto il resto del filesystem usando pathname relativi, i -quali, partendo dalla directory di lavoro che è fuori della \textit{chroot - jail}, potranno (con l'uso di \texttt{..}) risalire fino alla radice -effettiva del filesystem. +comunque accedere a tutto il resto del filesystem usando +\index{\textit{pathname}!relativo}\textit{pathname} relativi, i quali, +partendo dalla directory di lavoro che è fuori della \textit{chroot jail}, +potranno (con l'uso di \texttt{..}) risalire fino alla radice effettiva del +filesystem. Ma se ad un processo restano i privilegi di amministratore esso potrà comunque portare la sua directory di lavoro fuori dalla \textit{chroot jail} in cui si diff --git a/fileintro.tex b/fileintro.tex index 0d9de52..f2b6336 100644 --- a/fileintro.tex +++ b/fileintro.tex @@ -19,7 +19,7 @@ file di dati. Questo significa che si può accedere a qualunque periferica del computer, dalla seriale, alla parallela, alla console, e agli stessi dischi attraverso i -cosiddetti file di dispositivo\index{file!di dispositivo} (i \textit{device +cosiddetti file di dispositivo\index{file!di~dispositivo} (i \textit{device file}). Questi sono dei file speciali agendo sui quali i programmi possono leggere, scrivere e compiere operazioni direttamente sulle periferiche, usando le stesse funzioni che si usano per i normali file di dati. @@ -53,20 +53,21 @@ file ed introducendo le interfacce disponibili e le loro caratteristiche. \subsection{L'organizzazione di file e directory} \label{sec:file_organization} +\index{\textit{pathname}|(} In Unix, a differenza di quanto avviene in altri sistemi operativi, tutti i file vengono tenuti all'interno di un unico albero la cui radice (quella che viene chiamata \textit{root directory}) viene montata all'avvio. Un file viene identificato dall'utente usando quello che viene chiamato -\textit{pathname}\index{pathname}\footnote{il manuale della \acr{glibc} - depreca questa nomenclatura, che genererebbe confusione poiché \textit{path} - indica anche un insieme di directory su cui effettuare una ricerca (come - quello in cui si cercano i comandi). Al suo posto viene proposto l'uso di - \textit{filename} e di componente per il nome del file all'interno della - directory. Non seguiremo questa scelta dato che l'uso della parola - \textit{pathname} è ormai così comune che mantenerne l'uso è senz'altro più - chiaro dell'alternativa proposta.}, cioè il percorso che si deve fare per -accedere al file a partire dalla \textit{root directory}, che è composto da -una serie di nomi separati da una \file{/}. +\textit{pathname}\footnote{il manuale della \acr{glibc} depreca questa + nomenclatura, che genererebbe confusione poiché \textit{path} indica anche + un insieme di directory su cui effettuare una ricerca (come quello in cui si + cercano i comandi). Al suo posto viene proposto l'uso di \textit{filename} e + di componente per il nome del file all'interno della directory. Non + seguiremo questa scelta dato che l'uso della parola \textit{pathname} è + ormai così comune che mantenerne l'uso è senz'altro più chiaro + dell'alternativa proposta.}, cioè il percorso che si deve fare per accedere +al file a partire dalla \textit{root directory}, che è composto da una serie +di nomi separati da una \file{/}. All'avvio del sistema, completata la fase di inizializzazione, il kernel riceve dal bootloader l'indicazione di quale dispositivo contiene il @@ -95,7 +96,7 @@ specificandone il nome\footnote{Il manuale delle \acr{glibc} chiama i nomi contenuto. All'interno dello stesso albero si potranno poi inserire anche tutti gli altri oggetti visti attraverso l'interfaccia che manipola i file come le fifo, i link, i socket\index{socket} e gli stessi file di dispositivo -\index{file!di dispositivo} (questi +\index{file!di~dispositivo} (questi ultimi, per convenzione, sono inseriti nella directory \file{/dev}). Il nome completo di un file viene chiamato \textit{pathname} ed il @@ -110,14 +111,14 @@ esistano e siano effettivamente directory, inoltre i permessi (si veda sez.~\ref{sec:file_access_control}) devono consentire l'accesso all'intero \textit{pathname}. -Se il \textit{pathname}\index{pathname} comincia per \file{/} la ricerca parte -dalla directory radice del processo; questa, a meno di un \func{chroot} (su -cui torneremo in sez.~\ref{sec:file_chroot}) è la stessa per tutti i processi -ed equivale alla directory radice dell'albero dei file: in questo caso si -parla di un \textsl{pathname assoluto}\index{pathname!assoluto}. Altrimenti la +Se il \textit{pathname} comincia per \file{/} la ricerca parte dalla directory +radice del processo; questa, a meno di un \func{chroot} (su cui torneremo in +sez.~\ref{sec:file_chroot}) è la stessa per tutti i processi ed equivale alla +directory radice dell'albero dei file: in questo caso si parla di un +\textsl{pathname assoluto}\index{\textit{pathname}!assoluto}. Altrimenti la ricerca parte dalla directory corrente (su cui torneremo in sez.~\ref{sec:file_work_dir}) ed il pathname è detto \textsl{pathname - relativo}\index{pathname!relativo}. + relativo}\index{\textit{pathname}!relativo}. I nomi \file{.} e \file{..} hanno un significato speciale e vengono inseriti in ogni directory: il primo fa riferimento alla directory corrente e il @@ -134,7 +135,7 @@ Come detto in precedenza, in Unix esistono vari tipi di file; in Linux questi sono implementati come oggetti del \textit{Virtual File System} (vedi sez.~\ref{sec:file_vfs_work}) e sono presenti in tutti i filesystem unix-like utilizzabili con Linux. L'elenco dei vari tipi di file definiti dal -\textit{Virtual File System}\index{Virtual File System} è riportato in +\textit{Virtual File System}\index{\textit{Virtual~File~System}} è riportato in tab.~\ref{tab:file_file_types}. Si tenga ben presente che questa classificazione non ha nulla a che fare con @@ -145,7 +146,7 @@ Alcuni di essi, come le \textit{fifo} (che tratteremo in sez.~\ref{sec:ipc_named_pipe}) ed i \textit{socket}\index{socket} (che tratteremo in cap.~\ref{cha:socket_intro}) non sono altro che dei riferimenti per utilizzare delle funzionalità di comunicazione fornite dal kernel. Gli -altri sono i \textsl{file di dispositivo}\index{file!di dispositivo} (o +altri sono i \textsl{file di dispositivo}\index{file!di~dispositivo} (o \textit{device file}) che costituiscono una interfaccia diretta per leggere e scrivere sui dispositivi fisici; essi vengono suddivisi in due grandi categorie, \textsl{a blocchi} e \textsl{a caratteri} a seconda delle modalità @@ -198,7 +199,7 @@ VMS.\footnote{questo vale anche per i dispositivi a blocchi: la strutturazione ed è completamente trasparente all'utente. Inoltre talvolta si parla di \textsl{accesso diretto} riferendosi alla capacità, che non ha niente a che fare con tutto ciò, di effettuare, attraverso degli appositi file di - dispositivo\index{file!di dispositivo}, operazioni di I/O direttamente sui + dispositivo\index{file!di~dispositivo}, operazioni di I/O direttamente sui dischi senza passare attraverso un filesystem (il cosiddetto \textit{raw access}, introdotto coi kernel della serie 2.4.x).} @@ -376,14 +377,14 @@ Linux, l'\acr{ext2}. % \textit{inode}, \textit{dentry}, \textit{dcache}. In Linux il concetto di \textit{everything is a file} è stato implementato -attraverso il \textit{Virtual File System} (da qui in avanti VFS) che è uno -strato intermedio che il kernel usa per accedere ai più svariati filesystem -mantenendo la stessa interfaccia per i programmi in user space. Esso fornisce -un livello di indirezione che permette di collegare le operazioni di -manipolazione sui file alle operazioni di I/O, e gestisce l'organizzazione di -queste ultime nei vari modi in cui i diversi filesystem le effettuano, -permettendo la coesistenza di filesystem differenti all'interno dello stesso -albero delle directory. +attraverso il \textit{Virtual File System}\index{\textit{Virtual~File~System}} +(da qui in avanti VFS) che è uno strato intermedio che il kernel usa per +accedere ai più svariati filesystem mantenendo la stessa interfaccia per i +programmi in user space. Esso fornisce un livello di indirezione che permette +di collegare le operazioni di manipolazione sui file alle operazioni di I/O, e +gestisce l'organizzazione di queste ultime nei vari modi in cui i diversi +filesystem le effettuano, permettendo la coesistenza di filesystem differenti +all'interno dello stesso albero delle directory. Quando un processo esegue una system call che opera su un file, il kernel chiama sempre una funzione implementata nel VFS; la funzione eseguirà le @@ -439,21 +440,22 @@ il descrittore di file contiene i puntatori alle funzioni che vengono usate sui file già aperti. -\subsection{Il funzionamento del VFS} +\subsection{Il funzionamento del \textit{Virtual File System}} \label{sec:file_vfs_work} -La funzione più importante implementata dal VFS è la system call \func{open} -che permette di aprire un file. Dato un pathname viene eseguita una ricerca -dentro la \textit{directory entry cache} (in breve \textit{dcache}), una -tabella che contiene tutte le \textit{directory entry} (in breve -\textit{dentry}) che permette di associare in maniera rapida ed efficiente il -pathname a una specifica \textit{dentry}. +La funzione più importante implementata dal +VFS\index{\textit{Virtual~File~System}} è la system call \func{open} che +permette di aprire un file. Dato un \index{\textit{pathname}}\textit{pathname} +viene eseguita una ricerca dentro la \textit{directory entry cache} (in breve +\textit{dcache}), una tabella che contiene tutte le \textit{directory entry} +(in breve \textit{dentry}) che permette di associare in maniera rapida ed +efficiente il \textit{pathname} a una specifica \textit{dentry}. Una singola \textit{dentry} contiene in genere il puntatore ad un \textit{inode}\index{inode}; quest'ultimo è la struttura base che sta sul disco e che identifica un singolo oggetto del VFS sia esso un file ordinario, una directory, un link simbolico, una FIFO, un file di -dispositivo\index{file!di dispositivo}, o una qualsiasi altra cosa che possa +dispositivo\index{file!di~dispositivo}, o una qualsiasi altra cosa che possa essere rappresentata dal VFS (i tipi di file riportati in tab.~\ref{tab:file_file_types}). A ciascuno di essi è associata pure una struttura che sta in memoria, e che, oltre alle informazioni sullo specifico @@ -471,8 +473,8 @@ La \textit{dcache} costituisce perci l'albero dei file, ovviamente per non riempire tutta la memoria questa vista è parziale (la \textit{dcache} cioè contiene solo le \textit{dentry} per i file per i quali è stato richiesto l'accesso), quando si vuole risolvere un nuovo -pathname il VFS deve creare una nuova \textit{dentry} e caricare -l'inode\index{inode} corrispondente in memoria. +\index{\textit{pathname}}\textit{pathname} il VFS deve creare una nuova +\textit{dentry} e caricare l'inode\index{inode} corrispondente in memoria. Questo procedimento viene eseguito dal metodo \code{lookup()} dell'inode\index{inode} della directory che contiene il file; questo viene diff --git a/filestd.tex b/filestd.tex index 8a8ed6f..0b4e88b 100644 --- a/filestd.tex +++ b/filestd.tex @@ -747,9 +747,10 @@ viene restituito un \val{NULL}, ed il buffer \param{buf} non viene toccato. L'uso di \func{gets} è deprecato e deve essere assolutamente evitato; la funzione infatti non controlla il numero di byte letti, per cui nel caso la stringa letta superi le dimensioni del buffer, si avrà un \textit{buffer - overflow}\index{buffer overflow}, con sovrascrittura della memoria del -processo adiacente al buffer.\footnote{questa tecnica è spiegata in dettaglio - e con molta efficacia nell'ormai famoso articolo di Aleph1 \cite{StS}.} + overflow}\index{\textit{buffer~overflow}}, con sovrascrittura della memoria +del processo adiacente al buffer.\footnote{questa tecnica è spiegata in + dettaglio e con molta efficacia nell'ormai famoso articolo di Aleph1 + \cite{StS}.} Questa è una delle vulnerabilità più sfruttate per guadagnare accessi non autorizzati al sistema (i cosiddetti \textit{exploit}), basta @@ -870,14 +871,14 @@ come per entrambi i parametri si siano usati dei dei puntatori anziché i valori delle variabili, secondo la tecnica spiegata in sez.~\ref{sec:proc_var_passing}). -Se si passa alla funzione l'indirizzo di un puntatore impostato a \val{NULL} -e \var{*n} è zero, la funzione provvede da sola all'allocazione della memoria +Se si passa alla funzione l'indirizzo di un puntatore impostato a \val{NULL} e +\var{*n} è zero, la funzione provvede da sola all'allocazione della memoria necessaria a contenere la linea. In tutti i casi si ottiene dalla funzione un puntatore all'inizio del testo della linea letta. Un esempio di codice può -essere il seguente: -\includecodesnip{listati/getline.c} -e per evitare memory leak\index{memory leak} occorre ricordarsi di liberare -\var{ptr} con una \func{free}. +essere il seguente: +\includecodesnip{listati/getline.c} +e per evitare memory leak\index{\textit{memory~leak}} occorre ricordarsi di +liberare \var{ptr} con una \func{free}. Il valore di ritorno della funzione indica il numero di caratteri letti dallo stream (quindi compreso il newline, ma non lo zero di @@ -926,13 +927,14 @@ L'output formattato viene eseguito con una delle 13 funzioni della famiglia \bodydesc{Le funzioni ritornano il numero di caratteri stampati.} \end{functions} -\noindent le prime due servono per stampare su file (lo standard output -o quello specificato) la terza permette di stampare su una stringa, in genere +\noindent le prime due servono per stampare su file (lo standard output o +quello specificato) la terza permette di stampare su una stringa, in genere l'uso di \func{sprintf} è sconsigliato in quanto è possibile, se non si ha la sicurezza assoluta sulle dimensioni del risultato della stampa, eccedere le dimensioni di \param{str}, con conseguente sovrascrittura di altre variabili e -possibili \textit{buffer overflow}\index{buffer overflow}; per questo motivo -si consiglia l'uso dell'alternativa \funcd{snprintf}, il cui prototipo è: +possibili \textit{buffer overflow}\index{\textit{buffer~overflow}}; per questo +motivo si consiglia l'uso dell'alternativa \funcd{snprintf}, il cui prototipo +è: \begin{prototype}{stdio.h} {snprintf(char *str, size\_t size, const char *format, ...)} Identica a \func{sprintf}, ma non scrive su \param{str} più di @@ -1116,7 +1118,8 @@ scritti sulla stringa di destinazione: Identica a \func{vsprintf}, ma non scrive su \param{str} più di \param{size} caratteri. \end{prototype} -\noindent in modo da evitare possibili buffer overflow\index{buffer overflow}. +\noindent in modo da evitare possibili buffer +overflow\index{\textit{buffer~overflow}}. Per eliminare alla radice questi problemi, le \acr{glibc} supportano una @@ -1145,7 +1148,7 @@ proposito dei \index{\textit{value~result~argument}}\textit{value result argument}) l'indirizzo della stringa allocata automaticamente dalle funzioni. Occorre inoltre ricordarsi di invocare \func{free} per liberare detto puntatore quando la stringa non serve più, onde evitare memory -leak\index{memory leak}. +leak\index{\textit{memory~leak}}. Infine una ulteriore estensione GNU definisce le due funzioni \func{dprintf} e \func{vdprintf}, che prendono un file descriptor al posto dello stream. Altre @@ -1228,7 +1231,7 @@ punto prestabilito; sempre che l'operazione di riposizionamento sia supportata dal file sottostante lo stream, quando cioè si ha a che fare con quello che viene detto un file ad \textsl{accesso casuale}.\footnote{dato che in un sistema Unix esistono vari tipi di file, come le fifo ed i file di - dispositivo\index{file!di dispositivo}, non è scontato che questo sia sempre + dispositivo\index{file!di~dispositivo}, non è scontato che questo sia sempre vero.} In GNU/Linux ed in generale in ogni sistema unix-like la posizione nel file è diff --git a/fileunix.tex b/fileunix.tex index b3190f1..cf9c10a 100644 --- a/fileunix.tex +++ b/fileunix.tex @@ -187,7 +187,8 @@ system call del kernel. \label{sec:file_open} La funzione \funcd{open} è la funzione fondamentale per accedere ai file, ed è -quella che crea l'associazione fra un pathname ed un file descriptor, il suo +quella che crea l'associazione fra un +\index{\textit{pathname}}\textit{pathname} ed un file descriptor, il suo prototipo è: \begin{functions} \headdecl{sys/types.h} @@ -217,9 +218,9 @@ prototipo dispositivo che non esiste. \item[\errcode{ETXTBSY}] si è cercato di accedere in scrittura all'immagine di un programma in esecuzione. - \item[\errcode{ELOOP}] si sono incontrati troppi link simbolici nel risolvere - pathname o si è indicato \const{O\_NOFOLLOW} e \param{pathname} è un link - simbolico. + \item[\errcode{ELOOP}] si sono incontrati troppi link simbolici nel + risolvere il \textit{pathname} o si è indicato \const{O\_NOFOLLOW} e + \param{pathname} è un link simbolico. \end{errlist} ed inoltre \errval{EACCES}, \errval{ENAMETOOLONG}, \errval{ENOENT}, \errval{EROFS}, \errval{EFAULT}, \errval{ENOSPC}, \errval{ENOMEM}, @@ -244,66 +245,79 @@ usato sempre il file descriptor con il valore pi \hline % modalità di apertura del file \hline \const{O\_CREAT} & se il file non esiste verrà creato, con le regole di - titolarità del file viste in sez.~\ref{sec:file_ownership}. L'argomento - \param{mode} deve essere specificato. \\ - \const{O\_EXCL} & usato in congiunzione con \const{O\_CREAT} fa sì che - l'esistenza del file diventi un errore\protect\footnotemark\ che fa fallire - \func{open} con \errcode{EEXIST}. \\ - \const{O\_NONBLOCK} & apre il file in modalità non bloccante. Questo - valore specifica anche una modalità di operazione (vedi sotto), e - comporta che \func{open} ritorni immediatamente (l'opzione ha senso - solo per le fifo, torneremo questo in sez.~\ref{sec:ipc_named_pipe}). \\ - \const{O\_NOCTTY} & se \param{pathname} si riferisce ad un dispositivo di - terminale, questo non diventerà il terminale di controllo, anche se il - processo non ne ha ancora uno (si veda sez.~\ref{sec:sess_ctrl_term}). \\ + titolarità del file viste in + sez.~\ref{sec:file_ownership}. L'argomento + \param{mode} deve essere specificato. \\ + \const{O\_EXCL} & usato in congiunzione con \const{O\_CREAT} fa sì che + l'esistenza del file diventi un + errore\protect\footnotemark\ che fa fallire + \func{open} con \errcode{EEXIST}. \\ + \const{O\_NONBLOCK}& apre il file in modalità non bloccante. Questo + valore specifica anche una modalità di operazione (vedi + sotto), e comporta che \func{open} ritorni + immediatamente (l'opzione ha senso solo per le fifo, + torneremo questo in sez.~\ref{sec:ipc_named_pipe}). \\ + \const{O\_NOCTTY}& se \param{pathname} si riferisce ad un dispositivo di + terminale, questo non diventerà il terminale di + controllo, anche se il processo non ne ha ancora uno + (si veda sez.~\ref{sec:sess_ctrl_term}). \\ \const{O\_SHLOCK} & opzione di BSD, acquisisce uno shared lock (vedi - sez.~\ref{sec:file_locking}) sul file. Non è disponibile in Linux. \\ + sez.~\ref{sec:file_locking}) sul file. Non è + disponibile in Linux. \\ \const{O\_EXLOCK} & opzione di BSD, acquisisce uno lock esclusivo (vedi - sez.~\ref{sec:file_locking}) sul file. Non è disponibile in Linux. \\ - \const{O\_TRUNC} & se il file esiste ed è un file di dati e la modalità di - apertura consente la scrittura, allora la sua lunghezza verrà troncata a - zero. Se il file è un terminale o una fifo il flag verrà ignorato, negli - altri casi il comportamento non è specificato. \\ - \const{O\_NOFOLLOW} & se \param{pathname} è un link simbolico la chiamata - fallisce. Questa è un'estensione BSD aggiunta in Linux dal kernel 2.1.126. - Nelle versioni precedenti i link simbolici sono sempre seguiti, e questa - opzione è ignorata. \\ - \const{O\_DIRECTORY} & se \param{pathname} non è una directory la chiamata - fallisce. Questo flag è specifico di Linux ed è stato introdotto con il - kernel 2.1.126 per evitare dei - \textit{DoS}\index{DoS}\protect\footnotemark\ quando - \func{opendir} viene chiamata su una - fifo o su un device di unità a nastri, non deve essere utilizzato al di - fuori dell'implementazione di \func{opendir}. \\ - \const{O\_LARGEFILE} & nel caso di sistemi a 32 bit che supportano file di - grandi dimensioni consente di aprire file le cui dimensioni non possono - essere rappresentate da numeri a 31 bit. \\ + sez.~\ref{sec:file_locking}) sul file. Non è + disponibile in Linux. \\ + \const{O\_TRUNC} & se il file esiste ed è un file di dati e la modalità di + apertura consente la scrittura, allora la sua + lunghezza verrà troncata a zero. Se il file è un + terminale o una fifo il flag verrà ignorato, negli + altri casi il comportamento non è specificato. \\ + \const{O\_NOFOLLOW}&se \param{pathname} è un link simbolico la chiamata + fallisce. Questa è un'estensione BSD aggiunta in Linux + dal kernel 2.1.126. Nelle versioni precedenti i link + simbolici sono sempre seguiti, e questa opzione è + ignorata. \\ + \const{O\_DIRECTORY}& se \param{pathname} non è una directory la chiamata + fallisce. Questo flag è specifico di Linux ed è stato + introdotto con il kernel 2.1.126 per evitare dei + \textit{DoS}\index{DoS}\protect\footnotemark\ quando + \func{opendir} viene chiamata su una fifo o su un + device di unità a nastri, non deve essere utilizzato + al di fuori dell'implementazione di \func{opendir}. \\ + \const{O\_LARGEFILE}& nel caso di sistemi a 32 bit che supportano file di + grandi dimensioni consente di aprire file le cui + dimensioni non possono essere rappresentate da numeri + a 31 bit. \\ \hline \hline % modalità di operazione col file \const{O\_APPEND} & il file viene aperto in append mode. Prima di ciascuna - scrittura la posizione corrente viene sempre impostata alla fine del - file. Può causare corruzione del file con NFS se più di un processo scrive - allo stesso tempo.\footnotemark\\ - \const{O\_NONBLOCK} & il file viene aperto in modalità non bloccante per - le operazioni di I/O (che tratteremo in sez.~\ref{sec:file_noblocking}): - questo significa il fallimento di \func{read} in assenza di dati da - leggere e quello di \func{write} in caso di impossibilità di scrivere - immediatamente. Questa modalità ha senso solo per le fifo e per alcuni - file di dispositivo. \\ + scrittura la posizione corrente viene sempre impostata + alla fine del file. Può causare corruzione del file + con NFS se più di un processo scrive allo stesso + tempo.\footnotemark\\ + \const{O\_NONBLOCK}&il file viene aperto in modalità non bloccante per + le operazioni di I/O (che tratteremo in + sez.~\ref{sec:file_noblocking}): questo significa il + fallimento di \func{read} in assenza di dati da + leggere e quello di \func{write} in caso di + impossibilità di scrivere immediatamente. Questa + modalità ha senso solo per le fifo e per alcuni file + di dispositivo. \\ \const{O\_NDELAY} & in Linux\footnotemark\ è sinonimo di - \const{O\_NONBLOCK}.\\ - \const{O\_ASYNC} & apre il file per l'I/O in modalità - asincrona (vedi sez.~\ref{sec:file_asyncronous_io}). Quando è impostato - viene generato il segnale \const{SIGIO} tutte le volte che sono disponibili - dati in input sul file. \\ - \const{O\_SYNC} & apre il file per l'input/output sincrono: ogni - \func{write} bloccherà fino al completamento della scrittura di tutti i - dati sull'hardware sottostante.\\ - \const{O\_FSYNC} & sinonimo di \const{O\_SYNC}. \\ - \const{O\_NOATIME} & blocca l'aggiornamento dei tempi di accesso dei - file (vedi sez.~\ref{sec:file_file_times}). Per molti filesystem questa - funzionalità non è disponibile per il singolo file ma come opzione in fase - di montaggio.\\ + \const{O\_NONBLOCK}.\\ + \const{O\_ASYNC} & apre il file per l'I/O in modalità asincrona (vedi + sez.~\ref{sec:file_asyncronous_io}). Quando è + impostato viene generato il segnale \const{SIGIO} + tutte le volte che sono disponibili dati in input + sul file. \\ + \const{O\_SYNC} & apre il file per l'input/output sincrono: ogni + \func{write} bloccherà fino al completamento della + scrittura di tutti i dati sull'hardware sottostante.\\ + \const{O\_FSYNC} & sinonimo di \const{O\_SYNC}. \\ + \const{O\_NOATIME}& blocca l'aggiornamento dei tempi di accesso dei + file (vedi sez.~\ref{sec:file_file_times}). Per molti + filesystem questa funzionalità non è disponibile per + il singolo file ma come opzione in fase di montaggio.\\ \hline \end{tabular} \caption{Valori e significato dei vari bit del \textit{file status flag}.} @@ -313,8 +327,8 @@ usato sempre il file descriptor con il valore pi \footnotetext[2]{la pagina di manuale di \func{open} segnala che questa opzione è difettosa su NFS, e che i programmi che la usano per stabilire un \textsl{file di lock}\index{file!di lock} possono incorrere in una race - condition\index{race condition}. Si consiglia come alternativa di usare un - file con un nome univoco e la funzione \func{link} per verificarne + condition\index{\textit{race~condition}}. Si consiglia come alternativa di + usare un file con un nome univoco e la funzione \func{link} per verificarne l'esistenza (vedi sez.~\ref{sec:ipc_file_lock}).} \footnotetext[3]{\textit{Denial of Service}\index{DoS}, si chiamano così @@ -501,7 +515,7 @@ la successiva scrittura avvenga alla fine del file, infatti se questo aperto anche da un altro processo che vi ha scritto, la fine del file può essersi spostata, ma noi scriveremo alla posizione impostata in precedenza (questa è una potenziale sorgente di \textit{race condition} -\index{race condition}, vedi sez.~\ref{sec:file_atomic}). +\index{\textit{race~condition}}, vedi sez.~\ref{sec:file_atomic}). Non tutti i file supportano la capacità di eseguire una \func{lseek}, in questo caso la funzione ritorna l'errore \errcode{EPIPE}. Questo, oltre che per @@ -789,12 +803,12 @@ Un caso tipico di necessit vari processi devono scrivere alla fine di un file (ad esempio un file di log). Come accennato in sez.~\ref{sec:file_lseek} impostare la posizione alla fine del file e poi scrivere può condurre ad una \textit{race - condition}\index{race condition}: infatti può succedere che un secondo -processo scriva alla fine del file fra la \func{lseek} e la \func{write}; in -questo caso, come abbiamo appena visto, il file sarà esteso, ma il nostro -primo processo avrà ancora la posizione corrente impostata con la \func{lseek} -che non corrisponde più alla fine del file, e la successiva \func{write} -sovrascriverà i dati del secondo processo. + condition}\index{\textit{race~condition}}: infatti può succedere che un +secondo processo scriva alla fine del file fra la \func{lseek} e la +\func{write}; in questo caso, come abbiamo appena visto, il file sarà esteso, +ma il nostro primo processo avrà ancora la posizione corrente impostata con la +\func{lseek} che non corrisponde più alla fine del file, e la successiva +\func{write} sovrascriverà i dati del secondo processo. Il problema è che usare due system call in successione non è un'operazione atomica; il problema è stato risolto introducendo la modalità @@ -808,9 +822,9 @@ Un altro caso tipico in cui creare un \textsl{file di lock}\index{file!di lock}, bloccandosi se il file esiste. In questo caso la sequenza logica porterebbe a verificare prima l'esistenza del file con una \func{stat} per poi crearlo con una \func{creat}; -di nuovo avremmo la possibilità di una race condition\index{race condition} da -parte di un altro processo che crea lo stesso file fra il controllo e la -creazione. +di nuovo avremmo la possibilità di una race +condition\index{\textit{race~condition}} da parte di un altro processo che +crea lo stesso file fra il controllo e la creazione. Per questo motivo sono stati introdotti per \func{open} i due flag \const{O\_CREAT} e \const{O\_EXCL}. In questo modo l'operazione di controllo @@ -936,9 +950,9 @@ sull'altro (dato che quello che viene modificato della \textit{file table} a cui entrambi fanno riferimento). L'unica differenza fra due file descriptor duplicati è che ciascuno avrà il suo \textit{file descriptor flag}; a questo proposito va specificato che nel caso -di \func{dup} il flag di \textit{close-on-exec}\index{close-on-exec} (vedi -sez.~\ref{sec:proc_exec} e sez.~\ref{sec:file_fcntl}) viene sempre cancellato -nella copia. +di \func{dup} il flag di \textit{close-on-exec}\index{\textit{close-on-exec}} +(vedi sez.~\ref{sec:proc_exec} e sez.~\ref{sec:file_fcntl}) viene sempre +cancellato nella copia. L'uso principale di questa funzione è per la redirezione dell'input e dell'output fra l'esecuzione di una \func{fork} e la successiva \func{exec}; @@ -1036,10 +1050,10 @@ per \var{cmd} massimo numero di descrittori consentito. \item[\const{F\_SETFD}] imposta il valore del \textit{file descriptor flag} al valore specificato con \param{arg}. Al momento l'unico bit usato è quello di - \textit{close-on-exec}\index{close-on-exec}, identificato dalla costante - \const{FD\_CLOEXEC}, che serve a richiedere che il file venga chiuso nella - esecuzione di una \func{exec} (vedi sez.~\ref{sec:proc_exec}). Ritorna un - valore nullo in caso di successo e -1 in caso di errore. + \textit{close-on-exec}\index{\textit{close-on-exec}}, identificato dalla + costante \const{FD\_CLOEXEC}, che serve a richiedere che il file venga + chiuso nella esecuzione di una \func{exec} (vedi sez.~\ref{sec:proc_exec}). + Ritorna un valore nullo in caso di successo e -1 in caso di errore. \item[\const{F\_GETFD}] ritorna il valore del \textit{file descriptor flag} di \param{fd} o -1 in caso di errore; se \const{FD\_CLOEXEC} è impostato i file descriptor aperti vengono chiusi attraverso una \func{exec} altrimenti (il @@ -1139,7 +1153,6 @@ sez.~\ref{sec:file_asyncronous_operation} mentre quelle relative al \textit{file locking}\index{file!locking} saranno esaminate in sez.~\ref{sec:file_locking}). - Si tenga presente infine che quando si usa la funzione per determinare le modalità di accesso con cui è stato aperto il file (attraverso l'uso del comando \const{F\_GETFL}) è necessario estrarre i bit corrispondenti nel diff --git a/intro.tex b/intro.tex index d981ad5..39e27d9 100644 --- a/intro.tex +++ b/intro.tex @@ -62,16 +62,17 @@ all'hardware, mentre i programmi normali vengono eseguiti in modalit (e non possono accedere direttamente alle zone di memoria riservate o alle porte di input/output). -Una parte del kernel, lo \textit{scheduler}\index{scheduler}, si occupa di -stabilire, ad intervalli fissi e sulla base di un opportuno calcolo delle -priorità, quale ``\textsl{processo}'' deve essere posto in esecuzione (il -cosiddetto \textit{preemptive scheduling}\index{preemptive scheduling}). -Questo verrà comunque eseguito in modalità protetta; quando necessario il -processo potrà accedere alle risorse hardware soltanto attraverso delle -opportune chiamate al sistema che restituiranno il controllo al kernel. +Una parte del kernel, lo \textit{scheduler}\index{\textit{scheduler}}, si +occupa di stabilire, ad intervalli fissi e sulla base di un opportuno calcolo +delle priorità, quale ``\textsl{processo}'' deve essere posto in esecuzione +(il cosiddetto \textit{preemptive + scheduling}\index{\textit{preemptive~scheduling}}). Questo verrà comunque +eseguito in modalità protetta; quando necessario il processo potrà accedere +alle risorse hardware soltanto attraverso delle opportune chiamate al sistema +che restituiranno il controllo al kernel. La memoria viene sempre gestita dal kernel attraverso il meccanismo della -\textsl{memoria virtuale}\index{memoria virtuale}, che consente di assegnare a +\textsl{memoria virtuale}\index{memoria~virtuale}, che consente di assegnare a ciascun processo uno spazio di indirizzi ``\textsl{virtuale}'' (vedi sez.~\ref{sec:proc_memory}) che il kernel stesso, con l'ausilio della unità di gestione della memoria, si incaricherà di rimappare automaticamente sulla diff --git a/ipc.tex b/ipc.tex index 0215ace..c241c77 100644 --- a/ipc.tex +++ b/ipc.tex @@ -169,13 +169,14 @@ direzione del flusso dei dati Si potrebbe obiettare che sarebbe molto più semplice salvare il risultato intermedio su un file temporaneo. Questo però non tiene conto del fatto che un \textit{CGI} deve poter gestire più richieste in concorrenza, e si avrebbe una -evidente race condition\index{race condition} in caso di accesso simultaneo a -detto file.\footnote{il problema potrebbe essere superato determinando in - anticipo un nome appropriato per il file temporaneo, che verrebbe utilizzato - dai vari sotto-processi, e cancellato alla fine della loro esecuzione; ma a - questo le cose non sarebbero più tanto semplici.} L'uso di una pipe invece -permette di risolvere il problema in maniera semplice ed elegante, oltre ad -essere molto più efficiente, dato che non si deve scrivere su disco. +evidente \textit{race condition}\index{\textit{race~condition}} in caso di +accesso simultaneo a detto file.\footnote{il problema potrebbe essere superato + determinando in anticipo un nome appropriato per il file temporaneo, che + verrebbe utilizzato dai vari sotto-processi, e cancellato alla fine della + loro esecuzione; ma a questo le cose non sarebbero più tanto semplici.} +L'uso di una pipe invece permette di risolvere il problema in maniera semplice +ed elegante, oltre ad essere molto più efficiente, dato che non si deve +scrivere su disco. Il programma ci servirà anche come esempio dell'uso delle funzioni di duplicazione dei file descriptor che abbiamo trattato in @@ -452,8 +453,8 @@ comunque una fifo in scrittura anche se non ci sono ancora processi il lettura; è possibile anche usare la fifo all'interno di un solo processo, nel qual caso però occorre stare molto attenti alla possibili situazioni di stallo.\footnote{se si cerca di leggere da una fifo che non contiene dati si - avrà un deadlock\index{deadlock} immediato, dato che il processo si blocca e - non potrà quindi mai eseguire le funzioni di scrittura.} + avrà un deadlock\index{\textit{deadlock}} immediato, dato che il processo si + blocca e non potrà quindi mai eseguire le funzioni di scrittura.} Per la loro caratteristica di essere accessibili attraverso il filesystem, è piuttosto frequente l'utilizzo di una fifo come canale di comunicazione nelle @@ -646,7 +647,8 @@ state raccolte nella libreria \file{libgapil.so}, per poter usare quest'ultima occorrerà definire la speciale variabile di ambiente \code{LD\_LIBRARY\_PATH} in modo che il linker dinamico possa accedervi. -In generale questa variabile indica il pathname della directory contenente la +In generale questa variabile indica il +\index{\textit{pathname}}\textit{pathname} della directory contenente la libreria. Nell'ipotesi (che daremo sempre per verificata) che si facciano le prove direttamente nella directory dei sorgenti (dove di norma vengono creati sia i programmi che la libreria), il comando da dare sarà \code{export @@ -877,13 +879,13 @@ nome di un file ed un numero di versione; il suo prototipo \end{functions} La funzione determina un valore della chiave sulla base di \param{pathname}, -che deve specificare il pathname di un file effettivamente esistente e di un -numero di progetto \param{proj\_id)}, che di norma viene specificato come -carattere, dato che ne vengono utilizzati solo gli 8 bit meno -significativi.\footnote{nelle libc4 e libc5, come avviene in SunOS, - l'argomento \param{proj\_id} è dichiarato tipo \ctyp{char}, le \acr{glibc} - usano il prototipo specificato da XPG4, ma vengono lo stesso utilizzati gli - 8 bit meno significativi.} +che deve specificare il \index{\textit{pathname}}\textit{pathname} di un file +effettivamente esistente e di un numero di progetto \param{proj\_id)}, che di +norma viene specificato come carattere, dato che ne vengono utilizzati solo +gli 8 bit meno significativi.\footnote{nelle libc4 e libc5, come avviene in + SunOS, l'argomento \param{proj\_id} è dichiarato tipo \ctyp{char}, le + \acr{glibc} usano il prototipo specificato da XPG4, ma vengono lo stesso + utilizzati gli 8 bit meno significativi.} Il problema è che anche così non c'è la sicurezza che il valore della chiave sia univoco, infatti esso è costruito combinando il byte di \param{proj\_id)} @@ -1514,8 +1516,8 @@ possono essere utilizzate, e non si ha a disposizione niente di analogo alle funzioni \func{select} e \func{poll}. Questo rende molto scomodo usare più di una di queste strutture alla volta; ad esempio non si può scrivere un server che aspetti un messaggio su più di una coda senza fare ricorso ad una tecnica -di \textit{polling}\index{polling} che esegua un ciclo di attesa su ciascuna -di esse. +di \textit{polling}\index{\textit{polling}} che esegua un ciclo di attesa su +ciascuna di esse. Come esempio dell'uso delle code di messaggi possiamo riscrivere il nostro server di \textit{fortunes} usando queste al posto delle fifo. In questo caso @@ -1690,7 +1692,7 @@ indirizzato a lui. I semafori non sono meccanismi di intercomunicazione diretta come quelli (pipe, fifo e code di messaggi) visti finora, e non consentono di scambiare dati fra processi, ma servono piuttosto come meccanismi di sincronizzazione o -di protezione per le \textsl{sezioni critiche}\index{sezioni critiche} del +di protezione per le \textsl{sezioni critiche}\index{sezioni~critiche} del codice (si ricordi quanto detto in sez.~\ref{sec:proc_race_cond}). Un semaforo è uno speciale contatore, mantenuto nel kernel, che permette, a @@ -2191,9 +2193,10 @@ coda di attesa associata a ciascun insieme di semafori\footnote{che viene referenziata tramite i campi \var{sem\_pending} e \var{sem\_pending\_last} di \struct{semid\_ds}.}. Nella struttura viene memorizzato il riferimento alle operazioni richieste (nel campo \var{sops}, che è un puntatore ad una -struttura \struct{sembuf}) e al processo corrente (nel campo \var{sleeper}) poi -quest'ultimo viene messo stato di attesa e viene invocato lo -scheduler\index{scheduler} per passare all'esecuzione di un altro processo. +struttura \struct{sembuf}) e al processo corrente (nel campo \var{sleeper}) +poi quest'ultimo viene messo stato di attesa e viene invocato lo +scheduler\index{\textit{scheduler}} per passare all'esecuzione di un altro +processo. Se invece tutte le operazioni possono avere successo queste vengono eseguite immediatamente, dopo di che il kernel esegue una scansione della coda di @@ -2500,19 +2503,20 @@ corrispondente comportamento della funzione, sono i seguenti: \var{shm\_perm.uid} e \var{shm\_perm.gid} occorre essere il proprietario o il creatore del segmento, oppure l'amministratore. Compiuta l'operazione aggiorna anche il valore del campo \var{shm\_ctime}. -\item[\const{SHM\_LOCK}] Abilita il - \textit{memory locking}\index{memory locking}\footnote{impedisce cioè che la +\item[\const{SHM\_LOCK}] Abilita il \textit{memory + locking}\index{\textit{memory~locking}}\footnote{impedisce cioè che la memoria usata per il segmento venga salvata su disco dal meccanismo della - memoria virtuale\index{memoria virtuale}; si ricordi quanto trattato in + memoria virtuale\index{memoria~virtuale}; si ricordi quanto trattato in sez.~\ref{sec:proc_mem_lock}.} sul segmento di memoria condivisa. Solo l'amministratore può utilizzare questo comando. -\item[\const{SHM\_UNLOCK}] Disabilita il \textit{memory locking} sul segmento - di memoria condivisa. Solo l'amministratore può utilizzare questo comando. +\item[\const{SHM\_UNLOCK}] Disabilita il \textit{memory + locking}\index{\textit{memory~locking}} sul segmento di memoria condivisa. + Solo l'amministratore può utilizzare questo comando. \end{basedescript} i primi tre comandi sono gli stessi già visti anche per le code di messaggi e gli insiemi di semafori, gli ultimi due sono delle estensioni specifiche previste da Linux, che permettono di abilitare e disabilitare il meccanismo -della memoria virtuale\index{memoria virtuale} per il segmento. +della memoria virtuale\index{memoria~virtuale} per il segmento. L'argomento \param{buf} viene utilizzato solo con i comandi \const{IPC\_STAT} e \const{IPC\_SET} nel qual caso esso dovrà puntare ad una struttura @@ -3030,13 +3034,13 @@ caratteristica della funzione \func{open} (illustrata in sez.~\ref{sec:file_open}) che prevede\footnote{questo è quanto dettato dallo standard POSIX.1, ciò non toglie che in alcune implementazioni questa tecnica possa non funzionare; in particolare per Linux, nel caso di NFS, si - è comunque soggetti alla possibilità di una race - condition\index{race condition}.} che essa ritorni un errore quando usata -con i flag di \const{O\_CREAT} e \const{O\_EXCL}. In tal modo la creazione di -un \textsl{file di lock} può essere eseguita atomicamente, il processo che -crea il file con successo si può considerare come titolare del lock (e della -risorsa ad esso associata) mentre il rilascio si può eseguire con una chiamata -ad \func{unlink}. + è comunque soggetti alla possibilità di una race + condition\index{\textit{race~condition}}.} che essa ritorni un errore quando +usata con i flag di \const{O\_CREAT} e \const{O\_EXCL}. In tal modo la +creazione di un \textsl{file di lock} può essere eseguita atomicamente, il +processo che crea il file con successo si può considerare come titolare del +lock (e della risorsa ad esso associata) mentre il rilascio si può eseguire +con una chiamata ad \func{unlink}. Un esempio dell'uso di questa funzione è mostrato dalle funzioni \func{LockFile} ed \func{UnlockFile} riportate in fig.~\ref{fig:ipc_file_lock} @@ -3076,8 +3080,8 @@ problemi, che non lo rendono una alternativa praticabile per la sincronizzazione: anzitutto in caso di terminazione imprevista del processo, si lascia allocata la risorsa (il \textsl{file di lock}) e questa deve essere sempre cancellata esplicitamente. Inoltre il controllo della disponibilità -può essere eseguito solo con una tecnica di \textit{polling}\index{polling}, -ed è quindi molto inefficiente. +può essere eseguito solo con una tecnica di +\textit{polling}\index{\textit{polling}}, ed è quindi molto inefficiente. La tecnica dei file di lock ha comunque una sua utilità, e può essere usata con successo quando l'esigenza è solo quella di segnalare l'occupazione di una @@ -3094,14 +3098,15 @@ disponibile.\index{file!di lock|)} Dato che i file di lock\index{file!di lock} presentano gli inconvenienti illustrati in precedenza, la tecnica alternativa di sincronizzazione più comune è quella di fare ricorso al \textit{file locking}\index{file!locking} -(trattato in sez.~\ref{sec:file_locking}) usando \func{fcntl} su un file creato -per l'occasione per ottenere un write lock. In questo modo potremo usare il -lock come un \textit{mutex}: per bloccare la risorsa basterà acquisire il -lock, per sbloccarla basterà rilasciare il lock. Una richiesta fatta con un -write lock metterà automaticamente il processo in stato di attesa, senza -necessità di ricorrere al \textit{polling}\index{polling} per determinare la -disponibilità della risorsa, e al rilascio della stessa da parte del processo -che la occupava si otterrà il nuovo lock atomicamente. +(trattato in sez.~\ref{sec:file_locking}) usando \func{fcntl} su un file +creato per l'occasione per ottenere un write lock. In questo modo potremo +usare il lock come un \textit{mutex}: per bloccare la risorsa basterà +acquisire il lock, per sbloccarla basterà rilasciare il lock. Una richiesta +fatta con un write lock metterà automaticamente il processo in stato di +attesa, senza necessità di ricorrere al +\textit{polling}\index{\textit{polling}} per determinare la disponibilità +della risorsa, e al rilascio della stessa da parte del processo che la +occupava si otterrà il nuovo lock atomicamente. Questo approccio presenta il notevole vantaggio che alla terminazione di un processo tutti i lock acquisiti vengono rilasciati automaticamente (alla @@ -3248,16 +3253,16 @@ tuttavia dei patch e una libreria aggiuntiva. La caratteristica fondamentale dell'interfaccia POSIX è l'abbandono dell'uso degli identificatori e delle chiavi visti nel SysV IPC, per passare ai -\textit{Posix IPC names}\index{Posix IPC names}, che sono sostanzialmente -equivalenti ai nomi dei file. Tutte le funzioni che creano un oggetto di IPC -Posix prendono come primo argomento una stringa che indica uno di questi nomi; -lo standard è molto generico riguardo l'implementazione, ed i nomi stessi -possono avere o meno una corrispondenza sul filesystem; tutto quello che è -richiesto è che: +\textit{Posix IPC names}\index{\textit{Posix~IPC~names}}, che sono +sostanzialmente equivalenti ai nomi dei file. Tutte le funzioni che creano un +oggetto di IPC Posix prendono come primo argomento una stringa che indica uno +di questi nomi; lo standard è molto generico riguardo l'implementazione, ed i +nomi stessi possono avere o meno una corrispondenza sul filesystem; tutto +quello che è richiesto è che: \begin{itemize} \item i nomi devono essere conformi alle regole che caratterizzano i - \textit{pathname}, in particolare non essere più lunghi di \const{PATH\_MAX} - byte e terminati da un carattere nullo. + \index{\textit{pathname}}\textit{pathname}, in particolare non essere più + lunghi di \const{PATH\_MAX} byte e terminati da un carattere nullo. \item se il nome inizia per una \texttt{/} chiamate differenti allo stesso nome fanno riferimento allo stesso oggetto, altrimenti l'interpretazione del nome dipende dall'implementazione. @@ -3275,8 +3280,8 @@ messaggi, tutto viene creato usando come radici delle opportune directory (rispettivamente \file{/dev/shm} e \file{/dev/mqueue}, per i dettagli si faccia riferimento a sez.~\ref{sec:ipc_posix_shm} e sez.~\ref{sec:ipc_posix_mq}) ed i nomi specificati nelle relative funzioni -sono considerati come un pathname assoluto (comprendente eventuali -sottodirectory) rispetto a queste radici. +sono considerati come un \index{\textit{pathname}!assoluto}\textit{pathname} +assoluto (comprendente eventuali sottodirectory) rispetto a queste radici. Il vantaggio degli oggetti di IPC POSIX è comunque che essi vengono inseriti nell'albero dei file, e possono essere maneggiati con le usuali funzioni e @@ -3779,7 +3784,7 @@ tutti i suoi contenuti in memoria,\footnote{il filesystem \texttt{tmpfs} utilizzabile anche per la memoria condivisa; esso infatti non ha dimensione fissa, ed usa direttamente la cache interna del kernel (che viene usata anche per la shared memory in stile SysV). In più i suoi contenuti, essendo - trattati direttamente dalla memoria virtuale\index{memoria virtuale} possono + trattati direttamente dalla memoria virtuale\index{memoria~virtuale} possono essere salvati sullo swap automaticamente.} che viene attivato abilitando l'opzione \texttt{CONFIG\_TMPFS} in fase di compilazione del kernel. diff --git a/process.tex b/process.tex index 006947b..0dbe225 100644 --- a/process.tex +++ b/process.tex @@ -14,7 +14,7 @@ Come accennato nell'introduzione il \textsl{processo} è l'unità di base con cui un sistema unix-like alloca ed utilizza le risorse. Questo capitolo tratterà l'interfaccia base fra il sistema e i processi, come vengono passati -i parametri, come viene gestita e allocata la memoria, come un processo può +gli argomenti, come viene gestita e allocata la memoria, come un processo può richiedere servizi al sistema e cosa deve fare quando ha finito la sua esecuzione. Nella sezione finale accenneremo ad alcune problematiche generiche di programmazione. @@ -200,7 +200,7 @@ definita su altri sistemi; il suo prototipo fallimento, \var{errno} non viene modificata.} \end{prototype} -In questo caso la funzione da chiamare all'uscita prende i due parametri +In questo caso la funzione da chiamare all'uscita prende i due argomenti specificati nel prototipo, dovrà cioè essere definita come \code{void function(int status, void *argp)}. Il primo argomento sarà inizializzato allo stato di uscita con cui è stata chiamata \func{exit} ed il secondo al @@ -260,7 +260,7 @@ esecuzione, e le varie funzioni utilizzabili per la sua gestione. Ci sono vari modi in cui i vari sistemi organizzano la memoria (ed i dettagli di basso livello dipendono spesso in maniera diretta dall'architettura dell'hardware), ma quello più tipico, usato dai sistemi unix-like come Linux è -la cosiddetta \textsl{memoria virtuale}\index{memoria virtuale} che consiste +la cosiddetta \textsl{memoria virtuale}\index{memoria~virtuale} che consiste nell'assegnare ad ogni processo uno spazio virtuale di indirizzamento lineare, in cui gli indirizzi vanno da zero ad un qualche valore massimo.\footnote{nel caso di Linux fino al kernel 2.2 detto massimo era, per macchine a 32bit, di @@ -291,22 +291,23 @@ condivise). Ad esempio il codice della funzione \func{printf} star sola pagina di memoria reale che farà da supporto a tutte le pagine di memoria virtuale di tutti i processi che hanno detta funzione nel loro codice. -La corrispondenza fra le pagine della memoria virtuale e quelle della memoria -fisica della macchina viene gestita in maniera trasparente dall'hardware di -gestione della memoria (la \textit{Memory Management Unit} del processore). -Poiché in genere la memoria fisica è solo una piccola frazione della memoria -virtuale, è necessario un meccanismo che permetta di trasferire le pagine che -servono dal supporto su cui si trovano in memoria, eliminando quelle che non -servono. Questo meccanismo è detto \textsl{paginazione}\index{paginazione} (o -\textit{paging}), ed è uno dei compiti principali del kernel. +La corrispondenza fra le pagine della \index{memoria~virtuale}memoria virtuale +e quelle della memoria fisica della macchina viene gestita in maniera +trasparente dall'hardware di gestione della memoria (la \textit{Memory + Management Unit} del processore). Poiché in genere la memoria fisica è solo +una piccola frazione della memoria virtuale, è necessario un meccanismo che +permetta di trasferire le pagine che servono dal supporto su cui si trovano in +memoria, eliminando quelle che non servono. Questo meccanismo è detto +\textsl{paginazione}\index{paginazione} (o \textit{paging}), ed è uno dei +compiti principali del kernel. Quando un processo cerca di accedere ad una pagina che non è nella memoria -reale, avviene quello che viene chiamato un -\textit{page fault}\index{page fault}; -l'hardware di gestione della memoria genera un'interruzione e passa -il controllo al kernel il quale sospende il processo e si incarica di mettere -in RAM la pagina richiesta (effettuando tutte le operazioni necessarie per -reperire lo spazio necessario), per poi restituire il controllo al processo. +reale, avviene quello che viene chiamato un \textit{page + fault}\index{\textit{page~fault}}; l'hardware di gestione della memoria +genera un'interruzione e passa il controllo al kernel il quale sospende il +processo e si incarica di mettere in RAM la pagina richiesta (effettuando +tutte le operazioni necessarie per reperire lo spazio necessario), per poi +restituire il controllo al processo. Dal punto di vista di un processo questo meccanismo è completamente trasparente, e tutto avviene come se tutte le pagine fossero sempre @@ -330,12 +331,12 @@ tentativo di accedere ad un indirizzo non allocato commette quando si è manipolato male un puntatore e genera quello che viene chiamato un \textit{segmentation fault}. Se si tenta cioè di leggere o scrivere da un indirizzo per il quale non esiste un'associazione della pagina -virtuale, il kernel risponde al relativo \textit{page fault}\index{page fault} -mandando un segnale \const{SIGSEGV} al processo, che normalmente ne causa la -terminazione immediata. +virtuale, il kernel risponde al relativo \textit{page + fault}\index{\textit{page~fault}} mandando un segnale \const{SIGSEGV} al +processo, che normalmente ne causa la terminazione immediata. È pertanto importante capire come viene strutturata \textsl{la memoria - virtuale}\index{page fault} di un processo. Essa viene divisa in + virtuale}\index{\textit{page~fault}} di un processo. Essa viene divisa in \textsl{segmenti}, cioè un insieme contiguo di indirizzi virtuali ai quali il processo può accedere. Solitamente un programma C viene suddiviso nei seguenti segmenti: @@ -553,7 +554,7 @@ tollerante nei confronti di piccoli errori come quello di chiamate doppie a Il problema più comune e più difficile da risolvere che si incontra con le routine di allocazione è quando non viene opportunamente liberata la memoria non più utilizzata, quello che in inglese viene chiamato \textit{memory - leak}\index{memory leak}, cioè una \textsl{perdita di memoria}. + leak}\index{\textit{memory~leak}}, cioè una \textsl{perdita di memoria}. Un caso tipico che illustra il problema è quello in cui in una subroutine si alloca della memoria per uso locale senza liberarla prima di uscire. La @@ -566,7 +567,7 @@ Il problema momento, in corrispondenza ad una qualunque chiamata di \func{malloc}, che può essere in una sezione del codice che non ha alcuna relazione con la subroutine che contiene l'errore. Per questo motivo è sempre molto difficile trovare un -\textit{memory leak}\index{memory leak}. +\textit{memory leak}\index{\textit{memory~leak}}. In C e C++ il problema è particolarmente sentito. In C++, per mezzo della programmazione ad oggetti, il problema dei \textit{memory leak} è notevolmente @@ -612,10 +613,10 @@ molto complesse riguardo l'allocazione della memoria. \label{sec:proc_mem_alloca} Una possibile alternativa all'uso di \func{malloc}, che non soffre dei -problemi di \textit{memory leak}\index{memory leak} descritti in precedenza, è -la funzione \funcd{alloca}, che invece di allocare la memoria nello heap usa -il segmento di stack della funzione corrente. La sintassi è identica a quella -di \func{malloc}, il suo prototipo è: +problemi di \textit{memory leak}\index{\textit{memory~leak}} descritti in +precedenza, è la funzione \funcd{alloca}, che invece di allocare la memoria +nello heap usa il segmento di stack della funzione corrente. La sintassi è +identica a quella di \func{malloc}, il suo prototipo è: \begin{prototype}{stdlib.h}{void *alloca(size\_t size)} Alloca \param{size} byte nello stack. @@ -631,10 +632,11 @@ quindi non esiste un analogo della \func{free}) in quanto essa viene rilasciata automaticamente al ritorno della funzione. Come è evidente questa funzione ha molti vantaggi, anzitutto permette di -evitare alla radice i problemi di memory leak\index{memory leak}, dato che non -serve più la deallocazione esplicita; inoltre la deallocazione automatica -funziona anche quando si usa \func{longjmp} per uscire da una subroutine con -un salto non locale da una funzione (vedi sez.~\ref{sec:proc_longjmp}). +evitare alla radice i problemi di memory leak\index{\textit{memory~leak}}, +dato che non serve più la deallocazione esplicita; inoltre la deallocazione +automatica funziona anche quando si usa \func{longjmp} per uscire da una +subroutine con un salto non locale da una funzione (vedi +sez.~\ref{sec:proc_longjmp}). Un altro vantaggio è che in Linux la funzione è molto più veloce di \func{malloc} e non viene sprecato spazio, infatti non è necessario gestire un @@ -710,9 +712,10 @@ standard descritte in precedenza, che sono costruite su di esse. % \label{sec:proc_mem_malloc_custom} -\subsection{Il controllo della memoria virtuale\index{memoria virtuale}} +\subsection{Il controllo della memoria virtuale} \label{sec:proc_mem_lock} +\index{memoria~virtuale|(} Come spiegato in sez.~\ref{sec:proc_mem_gen} il kernel gestisce la memoria virtuale in maniera trasparente ai processi, decidendo quando rimuovere pagine dalla memoria per metterle nello swap, sulla base dell'utilizzo corrente da @@ -749,6 +752,7 @@ motivi per cui si possono avere di queste necessit crittografia richiedono il blocco di alcune pagine di memoria. \end{itemize} +\index{\textit{memory~locking}|(} Il meccanismo che previene la paginazione\index{paginazione} di parte della memoria virtuale di un processo è chiamato \textit{memory locking} (o \textsl{blocco della memoria}). Il blocco è sempre associato alle pagine della @@ -766,10 +770,10 @@ memoria bloccata non la sblocca. Chiaramente la terminazione del processo comporta anche la fine dell'uso della sua memoria virtuale, e quindi anche di tutti i suoi \textit{memory lock}. Infine \textit{memory lock} non sono ereditati dai processi figli.\footnote{ma siccome Linux usa il \textit{copy on - write}\index{copy on write} (vedi sez.~\ref{sec:proc_fork}) gli indirizzi - virtuali del figlio sono mantenuti sullo stesso segmento di RAM del padre, - quindi fintanto che un figlio non scrive su un segmento, può usufruire del - memory lock del padre.} + write} (vedi sez.~\ref{sec:proc_fork}) gli indirizzi virtuali del figlio + sono mantenuti sullo stesso segmento di RAM del padre, quindi fintanto che + un figlio non scrive su un segmento, può usufruire del \textit{memory lock} + del padre.} Siccome la richiesta di un \textit{memory lock} da parte di un processo riduce la memoria fisica disponibile nel sistema, questo ha un evidente impatto su @@ -852,44 +856,46 @@ esempio limitandosi a tutte le pagine allocate a partire da un certo momento. In ogni caso un processo real-time che deve entrare in una sezione critica deve provvedere a riservare memoria sufficiente prima dell'ingresso, per -scongiurare l'occorrenza di un eventuale \textit{page fault}\index{page fault} -causato dal meccanismo di \textit{copy on write}\index{copy on write}. -Infatti se nella sezione critica si va ad utilizzare memoria che non è ancora -stata riportata in RAM si potrebbe avere un page fault durante l'esecuzione -della stessa, con conseguente rallentamento (probabilmente inaccettabile) dei -tempi di esecuzione. +scongiurare l'occorrenza di un eventuale \textit{page + fault}\index{\textit{page~fault}} causato dal meccanismo di \textit{copy on + write}\index{\textit{copy~on~write}}. Infatti se nella sezione critica si +va ad utilizzare memoria che non è ancora stata riportata in RAM si potrebbe +avere un page fault durante l'esecuzione della stessa, con conseguente +rallentamento (probabilmente inaccettabile) dei tempi di esecuzione. In genere si ovvia a questa problematica chiamando una funzione che ha allocato una quantità sufficientemente ampia di variabili automatiche, in modo che esse vengano mappate in RAM dallo stack, dopo di che, per essere sicuri che esse siano state effettivamente portate in memoria, ci si scrive sopra. +\index{memoria~virtuale|)} +\index{\textit{memory~locking}|)} -\section{Parametri, opzioni ed ambiente di un processo} +\section{Argomenti, opzioni ed ambiente di un processo} \label{sec:proc_options} -Tutti i programmi hanno la possibilità di ricevere parametri e opzioni quando -vengono lanciati. Il passaggio dei parametri è effettuato attraverso gli +Tutti i programmi hanno la possibilità di ricevere argomenti e opzioni quando +vengono lanciati. Il passaggio degli argomenti è effettuato attraverso gli argomenti \param{argc} e \param{argv} della funzione \func{main}, che vengono passati al programma dalla shell (o dal processo che esegue la \func{exec}, secondo le modalità che vedremo in sez.~\ref{sec:proc_exec}) quando questo viene messo in esecuzione. -Oltre al passaggio dei parametri, un'altra modalità che permette di passare +Oltre al passaggio degli argomenti, un'altra modalità che permette di passare delle informazioni che modifichino il comportamento di un programma è quello dell'uso del cosiddetto \textit{environment} (cioè l'uso delle \textsl{variabili di ambiente}). In questa sezione esamineremo le funzioni che -permettono di gestire parametri ed opzioni, e quelle che consentono di +permettono di gestire argomenti ed opzioni, e quelle che consentono di manipolare ed utilizzare le variabili di ambiente. -\subsection{Il formato dei parametri} +\subsection{Il formato degli argomenti} \label{sec:proc_par_format} -In genere passaggio dei parametri al programma viene effettuato dalla shell, +In genere passaggio degli argomenti al programma viene effettuato dalla shell, che si incarica di leggere la linea di comando e di effettuarne la scansione (il cosiddetto \textit{parsing}) per individuare le parole che la compongono, -ciascuna delle quali viene considerata un parametro. Di norma per individuare +ciascuna delle quali viene considerata un argomento. Di norma per individuare le parole viene usato come carattere di separazione lo spazio o il tabulatore, ma il comportamento è modificabile attraverso l'impostazione della variabile di ambiente \cmd{IFS}. @@ -904,7 +910,7 @@ di ambiente \cmd{IFS}. Nella scansione viene costruito il vettore di puntatori \param{argv} inserendo in successione il puntatore alla stringa costituente l'$n$-simo parametro; la -variabile \param{argc} viene inizializzata al numero di parametri trovati, in +variabile \param{argc} viene inizializzata al numero di argomenti trovati, in questo modo il primo parametro è sempre il nome del programma; un esempio di questo meccanismo è mostrato in fig.~\ref{fig:proc_argv_argc}. @@ -1029,8 +1035,8 @@ sistema un \textsl{ambiente}, nella forma di una lista di variabili (detta \textit{environment list}) messa a disposizione dal processo, e costruita nella chiamata alla funzione \func{exec} quando questo viene lanciato. -Come per la lista dei parametri anche questa lista è un vettore di puntatori a -caratteri, ciascuno dei quali punta ad una stringa, terminata da un +Come per la lista degli argomenti anche questa lista è un vettore di puntatori +a caratteri, ciascuno dei quali punta ad una stringa, terminata da un \val{NULL}. A differenza di \code{argv[]} in questo caso non si ha una lunghezza del vettore data da un equivalente di \param{argc}, ma la lista è terminata da un puntatore nullo. @@ -1279,13 +1285,13 @@ chiamante. Nella maggior parte delle funzioni di libreria e delle system call i puntatori vengono usati per scambiare dati (attraverso buffer o strutture) e le -variabili semplici vengono usate per specificare parametri; in genere le +variabili semplici vengono usate per specificare argomenti; in genere le informazioni a riguardo dei risultati vengono passate alla routine chiamante attraverso il valore di ritorno. È buona norma seguire questa pratica anche nella programmazione normale. Talvolta però è necessario che la funzione possa restituire indietro alla -funzione chiamante un valore relativo ad uno dei suoi parametri. Per far +funzione chiamante un valore relativo ad uno dei suoi argomenti. Per far questo si usa il cosiddetto \index{\textit{value~result~argument}}\textit{value result argument}, si passa cioè, invece di una normale variabile, un puntatore alla stessa; vedremo @@ -1299,7 +1305,7 @@ viene usato questo meccanismo. \label{sec:proc_variadic} Come vedremo nei capitoli successivi, non sempre è possibile specificare un -numero fisso di parametri per una funzione. Lo standard ISO C prevede nella +numero fisso di argomenti per una funzione. Lo standard ISO C prevede nella sua sintassi la possibilità di definire delle \textit{variadic function}\index{variadic} che abbiano un numero variabile di argomenti, attraverso l'uso della \textit{ellipsis} \code{...} nella dichiarazione della @@ -1324,8 +1330,8 @@ deve essere incluso l'apposito header file \file{stdarg.h}; un esempio di dichiarazione è il prototipo della funzione \func{execl} che vedremo in sez.~\ref{sec:proc_exec}: \includecodesnip{listati/exec_sample.c} -in questo caso la funzione prende due parametri fissi ed un numero variabile -di altri parametri (che verranno a costituire gli elementi successivi al primo +in questo caso la funzione prende due argomenti fissi ed un numero variabile +di altri argomenti (che verranno a costituire gli elementi successivi al primo del vettore \param{argv} passato al nuovo processo). Lo standard ISO C richiede inoltre che l'ultimo degli argomenti fissi sia di tipo \textit{self-promoting}\footnote{il linguaggio C prevede che quando si @@ -1338,9 +1344,9 @@ inoltre che l'ultimo degli argomenti fissi sia di tipo alcuni compilatori è di non dichiarare l'ultimo parametro fisso come \direct{register}. -Una volta dichiarata la funzione il secondo passo è accedere ai vari parametri -quando la si va a definire. I parametri fissi infatti hanno un loro nome, ma -quelli variabili vengono indicati in maniera generica dalla ellipsis. +Una volta dichiarata la funzione il secondo passo è accedere ai vari argomenti +quando la si va a definire. Gli argomenti fissi infatti hanno un loro nome, ma +quelli variabili vengono indicati in maniera generica dalla \textit{ellipsis}. L'unica modalità in cui essi possono essere recuperati è pertanto quella sequenziale; essi verranno estratti dallo stack secondo l'ordine in cui sono @@ -1352,7 +1358,7 @@ macro; la procedura da seguire \item Accedere ai vari argomenti opzionali con chiamate successive alla macro \macro{va\_arg}, la prima chiamata restituirà il primo argomento, la seconda il secondo e così via. -\item Dichiarare la conclusione dell'estrazione dei parametri invocando la +\item Dichiarare la conclusione dell'estrazione degli argomenti invocando la macro \macro{va\_end}. \end{enumerate*} in generale è perfettamente legittimo richiedere meno argomenti di quelli che @@ -1369,7 +1375,7 @@ Le definizioni delle tre macro sono le seguenti: \funcdecl{void va\_start(va\_list ap, last)} Inizializza il puntatore alla lista di argomenti \param{ap}; il parametro \param{last} \emph{deve} essere - l'ultimo dei parametri fissi. + l'ultimo degli argomenti fissi. \funcdecl{type va\_arg(va\_list ap, type)} Restituisce il valore del successivo parametro opzionale, modificando opportunamente \param{ap}; la @@ -1396,12 +1402,12 @@ caso per usato (lo standard richiederebbe la chiamata esplicita di \macro{va\_end}), dato che il valore di \param{ap} risulterebbe indefinito. -Esistono dei casi in cui è necessario eseguire più volte la scansione dei -parametri e poter memorizzare una posizione durante la stessa. La cosa più +Esistono dei casi in cui è necessario eseguire più volte la scansione degli +argomenti e poter memorizzare una posizione durante la stessa. La cosa più naturale in questo caso sembrerebbe quella di copiarsi il puntatore alla lista degli argomenti con una semplice assegnazione. Dato che una delle realizzazioni più comuni di \macro{va\_list} è quella di un puntatore nello -stack all'indirizzo dove sono stati salvati i parametri, è assolutamente +stack all'indirizzo dove sono stati salvati gli argomenti, è assolutamente normale pensare di poter effettuare questa operazione. In generale però possono esistere anche realizzazioni diverse, per questo @@ -1422,9 +1428,9 @@ alla lista degli argomenti. La chiamata di una funzione con un numero variabile di argomenti, posto che la si sia dichiarata e definita come tale, non prevede nulla di particolare; -l'invocazione è identica alle altre, con i parametri, sia quelli fissi che +l'invocazione è identica alle altre, con gli argomenti, sia quelli fissi che quelli opzionali, separati da virgole. Quello che però è necessario tenere -presente è come verranno convertiti gli argomenti variabili. +presente è come verranno convertiti gli argomenti variabili. In Linux gli argomenti dello stesso tipo sono passati allo stesso modo, sia che siano fissi sia che siano opzionali (alcuni sistemi trattano diversamente @@ -1435,7 +1441,7 @@ dei medesimi occorrer Uno dei problemi che si devono affrontare con le funzioni con un numero variabile di argomenti è che non esiste un modo generico che permetta di -stabilire quanti sono i parametri passati effettivamente in una chiamata. +stabilire quanti sono gli argomenti passati effettivamente in una chiamata. Esistono varie modalità per affrontare questo problema; una delle più immediate è quella di specificare il numero degli argomenti opzionali come uno @@ -1443,8 +1449,8 @@ degli argomenti fissi. Una variazione di questo metodo per specificare anche il tipo degli argomenti (come fa la stringa di formato per \func{printf}). -Una modalità diversa, che può essere applicata solo quando il tipo dei -parametri lo rende possibile, è quella che prevede di usare un valore speciale +Una modalità diversa, che può essere applicata solo quando il tipo degli +argomenti lo rende possibile, è quella che prevede di usare un valore speciale come ultimo argomento (come fa ad esempio \func{execl} che usa un puntatore \val{NULL} per indicare la fine della lista degli argomenti). @@ -1478,10 +1484,12 @@ caso in cui l'uso di questa istruzione porta all'implementazione pi efficiente e più chiara anche dal punto di vista della struttura del programma: quello dell'uscita in caso di errore. -Il C però non consente di effettuare un salto ad una etichetta definita in -un'altra funzione, per cui se l'errore avviene in una funzione, e la sua -gestione ordinaria è in un'altra, occorre usare quello che viene chiamato un -\textsl{salto non-locale}\index{salto non-locale}. Il caso classico in cui si +\index{salto~non-locale|(} + +Il C però non consente di effettuare un salto ad +una etichetta definita in un'altra funzione, per cui se l'errore avviene in +una funzione, e la sua gestione ordinaria è in un'altra, occorre usare quello +che viene chiamato un \textsl{salto non-locale}. Il caso classico in cui si ha questa necessità, citato sia da \cite{APUE} che da \cite{glibc}, è quello di un programma nel cui corpo principale vengono letti dei dati in ingresso sui quali viene eseguita, tramite una serie di funzioni di analisi, una @@ -1498,7 +1506,7 @@ molto pi scartando l'input come errato.\footnote{a meno che, come precisa \cite{glibc}, alla chiusura di ciascuna fase non siano associate operazioni di pulizia specifiche (come deallocazioni, chiusure di file, ecc.), che non potrebbero - essere eseguite con un salto non-locale\index{salto non-locale}.} + essere eseguite con un salto non-locale.} Tutto ciò può essere realizzato proprio con un salto non-locale; questo di norma viene realizzato salvando il contesto dello stack nel punto in cui si @@ -1530,13 +1538,12 @@ essere viste in tutte le funzioni del programma. Quando viene eseguita direttamente la funzione ritorna sempre zero, un valore diverso da zero viene restituito solo quando il ritorno è dovuto ad una chiamata di \func{longjmp} in un'altra parte del programma che ripristina lo -stack effettuando il salto non-locale\index{salto non-locale}. Si tenga conto -che il contesto salvato in \param{env} viene invalidato se la routine che ha -chiamato \func{setjmp} ritorna, nel qual caso un successivo uso di -\func{longjmp} può comportare conseguenze imprevedibili (e di norma fatali) -per il processo. +stack effettuando il salto non-locale. Si tenga conto che il contesto salvato +in \param{env} viene invalidato se la routine che ha chiamato \func{setjmp} +ritorna, nel qual caso un successivo uso di \func{longjmp} può comportare +conseguenze imprevedibili (e di norma fatali) per il processo. -Come accennato per effettuare un salto non-locale\index{salto non-locale} ad +Come accennato per effettuare un salto non-locale ad un punto precedentemente stabilito con \func{setjmp} si usa la funzione \funcd{longjmp}; il suo prototipo è: \begin{functions} @@ -1581,11 +1588,11 @@ In generale, dato che l'unica differenza fra la chiamata diretta e quella ottenuta da un \func{longjmp}, è il valore di ritorno di \func{setjmp}, essa è usualmente chiamata all'interno di un comando \code{if}. -Uno dei punti critici dei salti non-locali\index{salto non-locale} è quello -del valore delle variabili, ed in particolare quello delle variabili -automatiche della funzione a cui si ritorna. In generale le variabili globali -e statiche mantengono i valori che avevano al momento della chiamata di -\func{longjmp}, ma quelli delle variabili automatiche (o di quelle dichiarate +Uno dei punti critici dei salti non-locali è quello del valore delle +variabili, ed in particolare quello delle variabili automatiche della funzione +a cui si ritorna. In generale le variabili globali e statiche mantengono i +valori che avevano al momento della chiamata di \func{longjmp}, ma quelli +delle variabili automatiche (o di quelle dichiarate \direct{register}\footnote{la direttiva \direct{register} del compilatore chiede che la variabile dichiarata tale sia mantenuta, nei limiti del possibile, all'interno di un registro del processore. Questa direttiva è @@ -1611,7 +1618,7 @@ l'ottimizzazione che porta le variabili nei registri dichiarandole tutte come si perderebbero le eventuali modifiche fatte dagli altri programmi (che avvengono solo in una copia posta in memoria).}. - +\index{salto~non-locale|)} %%% Local Variables: %%% mode: latex diff --git a/prochand.tex b/prochand.tex index 84bec32..fefa94a 100644 --- a/prochand.tex +++ b/prochand.tex @@ -144,8 +144,8 @@ fig.~\ref{fig:proc_task_struct}. \end{figure} Come accennato in sez.~\ref{sec:intro_unix_struct} è lo -\textit{scheduler}\index{scheduler} che decide quale processo mettere in -esecuzione; esso viene eseguito ad ogni system call ed ad ogni +\textit{scheduler}\index{\textit{scheduler}} che decide quale processo mettere +in esecuzione; esso viene eseguito ad ogni system call ed ad ogni interrupt,\footnote{più in una serie di altre occasioni. NDT completare questa parte.} (ma può essere anche attivato esplicitamente). Il timer di sistema provvede comunque a che esso sia invocato periodicamente, generando un @@ -157,10 +157,10 @@ Hertz.\footnote{Il valore usuale di questa costante sez.~\ref{sec:sys_unix_time}).} %Si ha cioè un interrupt dal timer ogni centesimo di secondo. -Ogni volta che viene eseguito, lo \textit{scheduler}\index{scheduler} effettua -il calcolo delle priorità dei vari processi attivi (torneremo su questo in -sez.~\ref{sec:proc_priority}) e stabilisce quale di essi debba essere posto in -esecuzione fino alla successiva invocazione. +Ogni volta che viene eseguito, lo \textit{scheduler}\index{\textit{scheduler}} +effettua il calcolo delle priorità dei vari processi attivi (torneremo su +questo in sez.~\ref{sec:proc_priority}) e stabilisce quale di essi debba +essere posto in esecuzione fino alla successiva invocazione. \subsection{Una panoramica sulle funzioni fondamentali} @@ -268,8 +268,9 @@ Il fatto che il \acr{pid} sia un numero univoco per il sistema lo rende un candidato per generare ulteriori indicatori associati al processo di cui diventa possibile garantire l'unicità: ad esempio in alcune implementazioni la funzione \func{tmpname} (si veda sez.~\ref{sec:file_temp_file}) usa il -\acr{pid} per generare un pathname univoco, che non potrà essere replicato da -un altro processo che usi la stessa funzione. +\acr{pid} per generare un \index{\textit{pathname}}\textit{pathname} univoco, +che non potrà essere replicato da un altro processo che usi la stessa +funzione. Tutti i processi figli dello stesso processo padre sono detti \textit{sibling}, questa è una delle relazioni usate nel \textsl{controllo di @@ -325,14 +326,14 @@ pertanto padre e figlio vedono variabili diverse. Per quanto riguarda la gestione della memoria, in generale il segmento di testo, che è identico per i due processi, è condiviso e tenuto in read-only per il padre e per i figli. Per gli altri segmenti Linux utilizza la tecnica -del \textit{copy on write}\index{copy on write}; questa tecnica comporta che -una pagina di memoria viene effettivamente copiata per il nuovo processo solo -quando ci viene effettuata sopra una scrittura (e si ha quindi una reale -differenza fra padre e figlio). In questo modo si rende molto più efficiente -il meccanismo della creazione di un nuovo processo, non essendo più necessaria -la copia di tutto lo spazio degli indirizzi virtuali del padre, ma solo delle -pagine di memoria che sono state modificate, e solo al momento della modifica -stessa. +del \textit{copy on write}\index{\textit{copy~on~write}}; questa tecnica +comporta che una pagina di memoria viene effettivamente copiata per il nuovo +processo solo quando ci viene effettuata sopra una scrittura (e si ha quindi +una reale differenza fra padre e figlio). In questo modo si rende molto più +efficiente il meccanismo della creazione di un nuovo processo, non essendo più +necessaria la copia di tutto lo spazio degli indirizzi virtuali del padre, ma +solo delle pagine di memoria che sono state modificate, e solo al momento +della modifica stessa. La differenza che si ha nei due processi è che nel processo padre il valore di ritorno della funzione \func{fork} è il \acr{pid} del processo figlio, mentre @@ -441,8 +442,8 @@ Go to next child Esaminiamo questo risultato: una prima conclusione che si può trarre è che non si può dire quale processo fra il padre ed il figlio venga eseguito per primo\footnote{a partire dal kernel 2.5.2-pre10 è stato introdotto il nuovo - scheduler\index{scheduler} di Ingo Molnar che esegue sempre per primo il - figlio; per mantenere la portabilità è opportuno non fare comunque + scheduler\index{\textit{scheduler}} di Ingo Molnar che esegue sempre per + primo il figlio; per mantenere la portabilità è opportuno non fare comunque affidamento su questo comportamento.} dopo la chiamata a \func{fork}; dall'esempio si può notare infatti come nei primi due cicli sia stato eseguito per primo il padre (con la stampa del \acr{pid} del nuovo processo) per poi @@ -464,7 +465,7 @@ istruzioni del codice fra padre e figli, n essere messi in esecuzione. Se è necessaria una qualche forma di precedenza occorrerà provvedere ad espliciti meccanismi di sincronizzazione, pena il rischio di incorrere nelle cosiddette -\textit{race condition}\index{race condition} +\textit{race condition}\index{\textit{race~condition}} (vedi sez.~\ref{sec:proc_race_cond}). Si noti inoltre che essendo i segmenti di memoria utilizzati dai singoli @@ -585,7 +586,7 @@ propriet comune dopo l'esecuzione di una \func{fork} è la seguente: \begin{itemize*} \item i file aperti e gli eventuali flag di - \textit{close-on-exec}\index{close-on-exec} impostati (vedi + \textit{close-on-exec}\index{\textit{close-on-exec}} impostati (vedi sez.~\ref{sec:proc_exec} e sez.~\ref{sec:file_fcntl}). \item gli identificatori per il controllo di accesso: l'\textsl{user-ID reale}, il \textsl{group-ID reale}, l'\textsl{user-ID effettivo}, il @@ -636,10 +637,11 @@ padre, che costituiva un inutile appesantimento in tutti quei casi in cui la \func{fork} veniva fatta solo per poi eseguire una \func{exec}. La funzione venne introdotta in BSD per migliorare le prestazioni. -Dato che Linux supporta il \textit{copy on write}\index{copy on write} la -perdita di prestazioni è assolutamente trascurabile, e l'uso di questa -funzione (che resta un caso speciale della system call \func{\_\_clone}), è -deprecato; per questo eviteremo di trattarla ulteriormente. +Dato che Linux supporta il \textit{copy on + write}\index{\textit{copy~on~write}} la perdita di prestazioni è +assolutamente trascurabile, e l'uso di questa funzione (che resta un caso +speciale della system call \func{\_\_clone}), è deprecato; per questo +eviteremo di trattarla ulteriormente. \subsection{La conclusione di un processo.} @@ -1179,7 +1181,7 @@ non viene trovato nessun altro file viene finalmente restituito Le altre quattro funzioni si limitano invece a cercare di eseguire il file indicato dall'argomento \param{path}, che viene interpretato come il -\textit{pathname} del programma. +\index{\textit{pathname}}\textit{pathname} del programma. \begin{figure}[htb] \centering @@ -1227,7 +1229,7 @@ speciale sez.~\ref{sec:sig_gen_beha}). La gestione dei file aperti dipende dal valore che ha il flag di -\textit{close-on-exec}\index{close-on-exec} (vedi anche +\textit{close-on-exec}\index{\textit{close-on-exec}} (vedi anche sez.~\ref{sec:file_fcntl}) per ciascun file descriptor. I file per cui è impostato vengono chiusi, tutti gli altri file restano aperti. Questo significa che il comportamento predefinito è che i file restano aperti @@ -1237,8 +1239,9 @@ che imposti il suddetto flag. Per le directory, lo standard POSIX.1 richiede che esse vengano chiuse attraverso una \func{exec}, in genere questo è fatto dalla funzione \func{opendir} (vedi sez.~\ref{sec:file_dir_read}) che effettua da sola -l'impostazione del flag di \textit{close-on-exec}\index{close-on-exec} sulle -directory che apre, in maniera trasparente all'utente. +l'impostazione del flag di +\textit{close-on-exec}\index{\textit{close-on-exec}} sulle directory che apre, +in maniera trasparente all'utente. Abbiamo detto che l'\textsl{user-ID reale} ed il \textsl{group-ID reale} restano gli stessi all'esecuzione di \func{exec}; lo stesso vale per @@ -1865,10 +1868,10 @@ scrivere codice portabile. \label{sec:proc_priority} In questa sezione tratteremo più approfonditamente i meccanismi con il quale -lo \textit{scheduler}\index{scheduler} assegna la CPU ai vari processi attivi. -In particolare prenderemo in esame i vari meccanismi con cui viene gestita -l'assegnazione del tempo di CPU, ed illustreremo le varie funzioni di -gestione. +lo \textit{scheduler}\index{\textit{scheduler}} assegna la CPU ai vari +processi attivi. In particolare prenderemo in esame i vari meccanismi con cui +viene gestita l'assegnazione del tempo di CPU, ed illustreremo le varie +funzioni di gestione. \subsection{I meccanismi di \textit{scheduling}} @@ -1886,8 +1889,8 @@ contrario di altri sistemi (che usano invece il cosiddetto \textit{cooperative multitasking}) non sono i singoli processi, ma il kernel stesso a decidere quando la CPU deve essere passata ad un altro processo. Come accennato in sez.~\ref{sec:proc_hierarchy} questa scelta viene eseguita da una sezione -apposita del kernel, lo \textit{scheduler}\index{scheduler}, il cui scopo è -quello di distribuire al meglio il tempo di CPU fra i vari processi. +apposita del kernel, lo \textit{scheduler}\index{\textit{scheduler}}, il cui +scopo è quello di distribuire al meglio il tempo di CPU fra i vari processi. La cosa è resa ancora più complicata dal fatto che con le architetture multi-processore si deve anche scegliere quale sia la CPU più opportuna da @@ -2018,8 +2021,8 @@ che viene assegnato ad un altro campo della struttura (\var{counter}) quando il processo viene eseguito per la prima volta e diminuito progressivamente ad ogni interruzione del timer. -Durante la sua esecuzione lo scheduler\index{scheduler} scandisce la coda dei -processi in stato \textit{runnable} associando, in base al valore di +Durante la sua esecuzione lo scheduler\index{\textit{scheduler}} scandisce la +coda dei processi in stato \textit{runnable} associando, in base al valore di \var{counter}, un peso ad ogni processo in attesa di esecuzione,\footnote{il calcolo del peso in realtà è un po' più complicato, ad esempio nei sistemi multiprocessore viene favorito un processo eseguito sulla stessa CPU, e a @@ -2157,8 +2160,8 @@ processo qualsiasi sia la sua priorit Adeos gestiti dalle code del nano-kernel), in modo da poterli controllare direttamente qualora ci sia la necessità di avere un processo con priorità più elevata di un \textit{interrupt handler}.} mentre con l'incorrere in un -page fault\index{page fault} si possono avere ritardi non previsti. Se -l'ultimo problema può essere aggirato attraverso l'uso delle funzioni di +page fault\index{\textit{page~fault}} si possono avere ritardi non previsti. +Se l'ultimo problema può essere aggirato attraverso l'uso delle funzioni di controllo della memoria virtuale (vedi sez.~\ref{sec:proc_mem_lock}), il primo non è superabile e può comportare ritardi non prevedibili riguardo ai tempi di esecuzione di qualunque processo. @@ -2172,13 +2175,14 @@ si lavora con processi che usano priorit cui si sia assegnata la massima priorità assoluta, in modo da poter essere comunque in grado di rientrare nel sistema. -Quando c'è un processo con priorità assoluta lo scheduler\index{scheduler} lo -metterà in esecuzione prima di ogni processo normale. In caso di più processi -sarà eseguito per primo quello con priorità assoluta più alta. Quando ci sono -più processi con la stessa priorità assoluta questi vengono tenuti in una coda -e tocca al kernel decidere quale deve essere eseguito. -Il meccanismo con cui vengono gestiti questi processi dipende dalla politica -di scheduling che si è scelto; lo standard ne prevede due: +Quando c'è un processo con priorità assoluta lo +scheduler\index{\textit{scheduler}} lo metterà in esecuzione prima di ogni +processo normale. In caso di più processi sarà eseguito per primo quello con +priorità assoluta più alta. Quando ci sono più processi con la stessa priorità +assoluta questi vengono tenuti in una coda e tocca al kernel decidere quale +deve essere eseguito. Il meccanismo con cui vengono gestiti questi processi +dipende dalla politica di scheduling che si è scelto; lo standard ne prevede +due: \begin{basedescript}{\desclabelwidth{1.2cm}\desclabelstyle{\nextlinelabel}} \item[\textit{FIFO}] \textit{First In First Out}. Il processo viene eseguito fintanto che non cede volontariamente la CPU, si blocca, finisce o viene @@ -2404,7 +2408,7 @@ In un ambiente multitasking il concetto essere interrotto in qualunque momento dal kernel che mette in esecuzione un altro processo o dalla ricezione di un segnale; occorre pertanto essere accorti nei confronti delle possibili -\textit{race condition}\index{race condition} (vedi +\textit{race condition}\index{\textit{race~condition}} (vedi sez.~\ref{sec:proc_race_cond}) derivanti da operazioni interrotte in una fase in cui non erano ancora state completate. @@ -2438,17 +2442,17 @@ condiviso, onde evitare problemi con le ottimizzazioni del codice. -\subsection{Le \textit{race condition}\index{race condition} e i - \textit{deadlock}\index{deadlock}} +\subsection{Le \textit{race condition} ed i \textit{deadlock}} \label{sec:proc_race_cond} -Si definiscono \textit{race condition}\index{race condition} tutte quelle -situazioni in cui processi diversi operano su una risorsa comune, ed in cui il -risultato viene a dipendere dall'ordine in cui essi effettuano le loro -operazioni. Il caso tipico è quello di un'operazione che viene eseguita da un -processo in più passi, e può essere compromessa dall'intervento di un altro -processo che accede alla stessa risorsa quando ancora non tutti i passi sono -stati completati. +\index{\textit{race~condition}|(} +Si definiscono \textit{race condition} tutte quelle situazioni in cui processi +diversi operano su una risorsa comune, ed in cui il risultato viene a +dipendere dall'ordine in cui essi effettuano le loro operazioni. Il caso +tipico è quello di un'operazione che viene eseguita da un processo in più +passi, e può essere compromessa dall'intervento di un altro processo che +accede alla stessa risorsa quando ancora non tutti i passi sono stati +completati. Dato che in un sistema multitasking ogni processo può essere interrotto in qualunque momento per farne subentrare un altro in esecuzione, niente può @@ -2461,37 +2465,39 @@ funzioner Per questo occorre essere ben consapevoli di queste problematiche, e del fatto che l'unico modo per evitarle è quello di riconoscerle come tali e prendere gli adeguati provvedimenti per far sì che non si verifichino. Casi tipici di -\textit{race condition}\index{race condition} si hanno quando diversi processi -accedono allo stesso file, o nell'accesso a meccanismi di intercomunicazione -come la memoria condivisa. In questi casi, se non si dispone della possibilità -di eseguire atomicamente le operazioni necessarie, occorre che quelle parti di -codice in cui si compiono le operazioni sulle risorse condivise (le cosiddette -\textsl{sezioni critiche}\index{sezioni critiche}) del programma, siano +\textit{race condition} si hanno quando diversi processi accedono allo stesso +file, o nell'accesso a meccanismi di intercomunicazione come la memoria +condivisa. In questi casi, se non si dispone della possibilità di eseguire +atomicamente le operazioni necessarie, occorre che quelle parti di codice in +cui si compiono le operazioni sulle risorse condivise (le cosiddette +\textsl{sezioni critiche}\index{sezioni~critiche}) del programma, siano opportunamente protette da meccanismi di sincronizzazione (torneremo su queste problematiche di questo tipo in cap.~\ref{cha:IPC}). -Un caso particolare di \textit{race condition}\index{race condition} sono poi -i cosiddetti \textit{deadlock}\index{deadlock}, particolarmente gravi in -quanto comportano spesso il blocco completo di un servizio, e non il -fallimento di una singola operazione. Per definizione un -\textit{deadlock}\index{deadlock} è una situazione in cui due o più processi +\index{\textit{deadlock}|(} +Un caso particolare di \textit{race condition} sono poi i cosiddetti +\textit{deadlock}, particolarmente gravi in quanto comportano spesso il blocco +completo di un servizio, e non il fallimento di una singola operazione. Per +definizione un \textit{deadlock} è una situazione in cui due o più processi non sono più in grado di proseguire perché ciascuno aspetta il risultato di una operazione che dovrebbe essere eseguita dall'altro. L'esempio tipico di una situazione che può condurre ad un -\textit{deadlock}\index{deadlock} è quello in cui un flag di +\textit{deadlock} è quello in cui un flag di ``\textsl{occupazione}'' viene rilasciato da un evento asincrono (come un segnale o un altro processo) fra il momento in cui lo si è controllato (trovandolo occupato) e la successiva operazione di attesa per lo sblocco. In questo caso, dato che l'evento di sblocco del flag è avvenuto senza che ce ne accorgessimo proprio fra il controllo e la messa in attesa, quest'ultima -diventerà perpetua (da cui il nome di \textit{deadlock}\index{deadlock}). +diventerà perpetua (da cui il nome di \textit{deadlock}). In tutti questi casi è di fondamentale importanza il concetto di atomicità visto in sez.~\ref{sec:proc_atom_oper}; questi problemi infatti possono essere risolti soltanto assicurandosi, quando essa sia richiesta, che sia possibile eseguire in maniera atomica le operazioni necessarie. +\index{\textit{race~condition}|)} +\index{\textit{deadlock}|)} \subsection{Le funzioni rientranti} diff --git a/session.tex b/session.tex index d6438ed..b6ee946 100644 --- a/session.tex +++ b/session.tex @@ -235,7 +235,7 @@ s per entrambi; una delle due chiamate sarà ridondante, ma non potendo determinare quale dei due processi viene eseguito per primo, occorre eseguirle comunque entrambe per evitare di esporsi ad una race -condition\index{race condition}. +condition\index{\textit{race~condition}}. Si noti come nessuna delle funzioni esaminate finora permetta di spostare un processo da una sessione ad un altra; infatti l'unico modo di far cambiare @@ -1035,13 +1035,13 @@ prototipo Restituisce il nome del terminale di controllo del processo. \bodydesc{La funzione restituisce il puntatore alla stringa contenente il - pathname del terminale.} + \textit{pathname} del terminale.} \end{prototype} -La funzione scrive il pathname del terminale di controllo del processo -chiamante nella stringa posta all'indirizzo specificato dall'argomento -\param{s}. La memoria per contenere la stringa deve essere stata allocata in -precedenza ed essere lunga almeno +La funzione scrive il \index{\textit{pathname}}\textit{pathname} del terminale +di controllo del processo chiamante nella stringa posta all'indirizzo +specificato dall'argomento \param{s}. La memoria per contenere la stringa +deve essere stata allocata in precedenza ed essere lunga almeno \const{L\_ctermid}\footnote{\const{L\_ctermid} è una delle varie costanti del sistema, non trattata esplicitamente in sez.~\ref{sec:sys_characteristics} che indica la dimensione che deve avere una stringa per poter contenere il @@ -1070,11 +1070,12 @@ ovviamente essere stata allocata in precedenza), e la relativa dimensione, \param{len}; se la stringa che deve essere restituita eccede questa dimensione si avrà una condizione di errore. -Se si passa come argomento \val{NULL} la funzione restituisce il puntatore -ad una stringa statica che può essere sovrascritta da chiamate successive. Si -tenga presente che il pathname restituito potrebbe non identificare -univocamente il terminale (ad esempio potrebbe essere \file{/dev/tty}), -inoltre non è detto che il processo possa effettivamente aprire il terminale. +Se si passa come argomento \val{NULL} la funzione restituisce il puntatore ad +una stringa statica che può essere sovrascritta da chiamate successive. Si +tenga presente che il \index{\textit{pathname}}\textit{pathname} restituito +potrebbe non identificare univocamente il terminale (ad esempio potrebbe +essere \file{/dev/tty}), inoltre non è detto che il processo possa +effettivamente aprire il terminale. I vari attributi vengono mantenuti per ciascun terminale in una struttura \struct{termios}, (la cui definizione è riportata in diff --git a/signal.tex b/signal.tex index e8efc45..13c8d77 100644 --- a/signal.tex +++ b/signal.tex @@ -115,8 +115,8 @@ verr Questa è la ragione per cui l'implementazione dei segnali secondo questa semantica viene chiamata \textsl{inaffidabile}; infatti la ricezione del -segnale e la reinstallazione del suo gestore non sono operazioni -atomiche, e sono sempre possibili delle race condition\index{race condition} +segnale e la reinstallazione del suo gestore non sono operazioni atomiche, e +sono sempre possibili delle race condition\index{\textit{race~condition}} (sull'argomento vedi quanto detto in sez.~\ref{sec:proc_multi_prog}). Un'altro problema è che in questa semantica non esiste un modo per bloccare i @@ -136,7 +136,7 @@ Si dice che il segnale viene \textsl{consegnato} al processo (dall'inglese \textit{delivered}) quando viene eseguita l'azione per esso prevista, mentre per tutto il tempo che passa fra la generazione del segnale e la sua consegna esso è detto \textsl{pendente} (o \textit{pending}). In genere questa -procedura viene effettuata dallo scheduler\index{scheduler} quando, +procedura viene effettuata dallo scheduler\index{\textit{scheduler}} quando, riprendendo l'esecuzione del processo in questione, verifica la presenza del segnale nella \struct{task\_struct} e mette in esecuzione il gestore. @@ -208,9 +208,9 @@ ignorarlo). Normalmente l'invio al processo che deve ricevere il segnale è immediato ed avviene non appena questo viene rimesso in esecuzione dallo -scheduler\index{scheduler} che esegue l'azione specificata. Questo a meno che -il segnale in questione non sia stato bloccato prima della notifica, nel qual -caso l'invio non avviene ed il segnale resta \textsl{pendente} +scheduler\index{\textit{scheduler}} che esegue l'azione specificata. Questo a +meno che il segnale in questione non sia stato bloccato prima della notifica, +nel qual caso l'invio non avviene ed il segnale resta \textsl{pendente} indefinitamente. Quando lo si sblocca il segnale \textsl{pendente} sarà subito notificato. Si tenga presente però che i segnali \textsl{pendenti} non si accodano, alla generazione infatti il kernel marca un flag nella @@ -244,7 +244,7 @@ sez.~\ref{sec:sig_sigaction}). Se si quest'ultimo ad essere eseguito alla notifica del segnale. Inoltre il sistema farà si che mentre viene eseguito il gestore di un segnale, quest'ultimo venga automaticamente bloccato (così si possono evitare race -condition\index{race condition}). +condition\index{\textit{race~condition}}). Nel caso non sia stata specificata un'azione, viene utilizzata l'azione standard che (come vedremo in sez.~\ref{sec:sig_standard}) è propria di ciascun @@ -786,7 +786,7 @@ programmi eseguiti in background, che altrimenti sarebbero interrotti da una successiva pressione di \texttt{C-c} o \texttt{C-y}. Per quanto riguarda il comportamento di tutte le altre system call si danno -sostanzialmente due casi, a seconda che esse siano\index{system call lente} +sostanzialmente due casi, a seconda che esse siano\index{system~call~lente} \textsl{lente} (\textit{slow}) o \textsl{veloci} (\textit{fast}). La gran parte di esse appartiene a quest'ultima categoria, che non è influenzata dall'arrivo di un segnale. Esse sono dette \textsl{veloci} in quanto la loro @@ -802,7 +802,7 @@ eseguito prima che la system call sia ritornata. Un elenco dei casi in cui si presenta questa situazione è il seguente: \begin{itemize*} \item la lettura da file che possono bloccarsi in attesa di dati non ancora - presenti (come per certi file di dispositivo\index{file!di dispositivo}, i + presenti (come per certi file di dispositivo\index{file!di~dispositivo}, i socket\index{socket} o le pipe). \item la scrittura sugli stessi file, nel caso in cui dati non possano essere accettati immediatamente. @@ -1355,11 +1355,12 @@ Chiaramente, anche se il tempo pu nanosecondo, la precisione di \func{nanosleep} è determinata dalla risoluzione temporale del timer di sistema. Perciò la funzione attenderà comunque il tempo specificato, ma prima che il processo possa tornare ad essere eseguito -occorrerà almeno attendere il successivo giro di scheduler\index{scheduler} e -cioè un tempo che a seconda dei casi può arrivare fino a 1/\const{HZ}, (sempre -che il sistema sia scarico ed il processa venga immediatamente rimesso in -esecuzione); per questo motivo il valore restituito in \param{rem} è sempre -arrotondato al multiplo successivo di 1/\const{HZ}. +occorrerà almeno attendere il successivo giro di +scheduler\index{\textit{scheduler}} e cioè un tempo che a seconda dei casi può +arrivare fino a 1/\const{HZ}, (sempre che il sistema sia scarico ed il +processa venga immediatamente rimesso in esecuzione); per questo motivo il +valore restituito in \param{rem} è sempre arrotondato al multiplo successivo +di 1/\const{HZ}. In realtà è possibile ottenere anche pause più precise del centesimo di secondo usando politiche di scheduling real time come \const{SCHED\_FIFO} o @@ -1459,8 +1460,8 @@ tutti gli stati di terminazione sono stati ricevuti. Le funzioni esaminate finora fanno riferimento ad alle modalità più elementari della gestione dei segnali; non si sono pertanto ancora prese in considerazione le tematiche più complesse, collegate alle varie race -condition\index{race condition} che i segnali possono generare e alla natura -asincrona degli stessi. +condition\index{\textit{race~condition}} che i segnali possono generare e alla +natura asincrona degli stessi. Affronteremo queste problematiche in questa sezione, partendo da un esempio che le evidenzi, per poi prendere in esame le varie funzioni che permettono di @@ -1501,13 +1502,14 @@ l'interruzione di \func{pause} venisse causata da un altro segnale. Questo codice però, a parte il non gestire il caso in cui si è avuta una precedente chiamata a \func{alarm} (che si è tralasciato per brevità), -presenta una pericolosa race condition\index{race condition}. Infatti se il -processo viene interrotto fra la chiamata di \func{alarm} e \func{pause} può -capitare (ad esempio se il sistema è molto carico) che il tempo di attesa -scada prima dell'esecuzione quest'ultima, cosicché essa sarebbe eseguita dopo -l'arrivo di \const{SIGALRM}. In questo caso ci si troverebbe di fronte ad un -deadlock\index{deadlock}, in quanto \func{pause} non verrebbe mai più -interrotta (se non in caso di un altro segnale). +presenta una pericolosa race condition\index{\textit{race~condition}}. +Infatti se il processo viene interrotto fra la chiamata di \func{alarm} e +\func{pause} può capitare (ad esempio se il sistema è molto carico) che il +tempo di attesa scada prima dell'esecuzione quest'ultima, cosicché essa +sarebbe eseguita dopo l'arrivo di \const{SIGALRM}. In questo caso ci si +troverebbe di fronte ad un deadlock\index{\textit{deadlock}}, in quanto +\func{pause} non verrebbe mai più interrotta (se non in caso di un altro +segnale). Questo problema può essere risolto (ed è la modalità con cui veniva fatto in SVr2) usando la funzione \func{longjmp} (vedi sez.~\ref{sec:proc_longjmp}) per @@ -1563,10 +1565,10 @@ quale potr segnale, e prendere le relative azioni conseguenti (\texttt{\small 6-11}). Questo è il tipico esempio di caso, già citato in -sez.~\ref{sec:proc_race_cond}, in cui si genera una race condition -\index{race condition}; se infatti il segnale arriva immediatamente dopo -l'esecuzione del controllo (\texttt{\small 6}) ma prima della cancellazione -del flag (\texttt{\small 7}), la sua occorrenza sarà perduta. +sez.~\ref{sec:proc_race_cond}, in cui si genera una race condition +\index{\textit{race~condition}}; se infatti il segnale arriva immediatamente +dopo l'esecuzione del controllo (\texttt{\small 6}) ma prima della +cancellazione del flag (\texttt{\small 7}), la sua occorrenza sarà perduta. Questi esempi ci mostrano che per una gestione effettiva dei segnali occorrono funzioni più sofisticate di quelle illustrate finora, che hanno origine dalla @@ -1579,6 +1581,7 @@ reagire alla ricezione di un segnale. \subsection{Gli \textsl{insiemi di segnali} o \textit{signal set}} \label{sec:sig_sigset} +\index{\textit{signal~set}|(} Come evidenziato nel paragrafo precedente, le funzioni di gestione dei segnali originarie, nate con la semantica inaffidabile, hanno dei limiti non superabili; in particolare non è prevista nessuna funzione che permetta di @@ -1587,10 +1590,9 @@ pendenti. Per questo motivo lo standard POSIX.1, insieme alla nuova semantica dei segnali ha introdotto una interfaccia di gestione completamente nuova, che permette di ottenete un controllo molto più dettagliato. In particolare lo standard ha introdotto un nuovo tipo di dato \type{sigset\_t}, che permette di -rappresentare un \textsl{insieme di segnali} (un -\index{\textit{signal set}}\textit{signal set}, come viene usualmente -chiamato), che è il tipo di dato che viene usato per gestire il blocco dei -segnali. +rappresentare un \textsl{insieme di segnali} (un \textit{signal set}, come +viene usualmente chiamato), che è il tipo di dato che viene usato per gestire +il blocco dei segnali. In genere un \textsl{insieme di segnali} è rappresentato da un intero di dimensione opportuna, di solito si pari al numero di bit dell'architettura @@ -1642,6 +1644,8 @@ ottenuto con \func{sigemptyset} o togliendo quelli che non servono da un insieme completo ottenuto con \func{sigfillset}. Infine \func{sigismember} permette di verificare la presenza di uno specifico segnale in un insieme. +\index{\textit{signal~set}|)} + \subsection{La funzione \func{sigaction}} @@ -1744,7 +1748,7 @@ in tab.~\ref{tab:sig_sa_flag}. \const{SA\_RESTART} & Riavvia automaticamente le \textit{slow system call} quando vengono interrotte dal suddetto segnale; riproduce cioè il comportamento standard - di BSD.\index{system call lente}\\ + di BSD.\index{system~call~lente}\\ \const{SA\_NOMASK} & Evita che il segnale corrente sia bloccato durante l'esecuzione del gestore.\\ \const{SA\_NODEFER} & Sinonimo di \const{SA\_NOMASK}.\\ @@ -1875,6 +1879,7 @@ estremamente semplice, \textit{signal mask}} \label{sec:sig_sigmask} +\index{\textit{signal mask}|(} Come spiegato in sez.~\ref{sec:sig_semantics} tutti i moderni sistemi unix-like permettono si bloccare temporaneamente (o di eliminare completamente, impostando \const{SIG\_IGN} come azione) la consegna dei segnali ad un @@ -1952,10 +1957,10 @@ occorre ricordare che qualunque modifica alla maschera dei segnali viene perduta alla conclusione del terminatore. Benché con l'uso di \func{sigprocmask} si possano risolvere la maggior parte -dei casi di race condition\index{race condition} restano aperte alcune -possibilità legate all'uso di \func{pause}; il caso è simile a quello del -problema illustrato nell'esempio di fig.~\ref{fig:sig_sleep_incomplete}, e cioè -la possibilità che il processo riceva il segnale che si intende usare per +dei casi di race condition\index{\textit{race~condition}} restano aperte +alcune possibilità legate all'uso di \func{pause}; il caso è simile a quello +del problema illustrato nell'esempio di fig.~\ref{fig:sig_sleep_incomplete}, e +cioè la possibilità che il processo riceva il segnale che si intende usare per uscire dallo stato di attesa invocato con \func{pause} immediatamente prima dell'esecuzione di quest'ultima. Per poter effettuare atomicamente la modifica della maschera dei segnali (di solito attivandone uno specifico) insieme alla @@ -2011,11 +2016,12 @@ fine (\texttt{\small 27}), e al contempo si prepara la maschera dei segnali \var{sleep\_mask} per riattivare \const{SIGALRM} all'esecuzione di \func{sigsuspend}. -In questo modo non sono più possibili race condition\index{race condition} -dato che \const{SIGALRM} viene disabilitato con \func{sigprocmask} fino alla -chiamata di \func{sigsuspend}. Questo metodo è assolutamente generale e può -essere applicato a qualunque altra situazione in cui si deve attendere per un -segnale, i passi sono sempre i seguenti: +In questo modo non sono più possibili race +condition\index{\textit{race~condition}} dato che \const{SIGALRM} viene +disabilitato con \func{sigprocmask} fino alla chiamata di \func{sigsuspend}. +Questo metodo è assolutamente generale e può essere applicato a qualunque +altra situazione in cui si deve attendere per un segnale, i passi sono sempre +i seguenti: \begin{enumerate*} \item Leggere la maschera dei segnali corrente e bloccare il segnale voluto con \func{sigprocmask}. @@ -2025,8 +2031,9 @@ segnale, i passi sono sempre i seguenti: \end{enumerate*} Per quanto possa sembrare strano bloccare la ricezione di un segnale per poi riabilitarla immediatamente dopo, in questo modo si evita il -deadlock\index{deadlock} dovuto all'arrivo del segnale prima dell'esecuzione -di \func{sigsuspend}. +deadlock\index{\textit{deadlock}} dovuto all'arrivo del segnale prima +dell'esecuzione di \func{sigsuspend}. +\index{\textit{signal mask}|)} \subsection{Ulteriori funzioni di gestione} @@ -2175,7 +2182,7 @@ due comportamenti il programma deve assumere; i loro prototipi sono: \headdecl{setjmp.h} \funcdecl{int sigsetjmp(sigjmp\_buf env, int savesigs)} Salva il contesto - dello stack per un salto non-locale\index{salto non-locale}. + dello stack per un salto non-locale\index{salto~non-locale}. \funcdecl{void siglongjmp(sigjmp\_buf env, int val)} Esegue un salto non-locale su un precedente contesto. @@ -2187,7 +2194,7 @@ due comportamenti il programma deve assumere; i loro prototipi sono: Le due funzioni prendono come primo argomento la variabile su cui viene salvato il contesto dello stack per permettere il salto non-locale -\index{salto non-locale}; nel caso specifico essa è di tipo +\index{salto~non-locale}; nel caso specifico essa è di tipo \type{sigjmp\_buf}, e non \type{jmp\_buf} come per le analoghe di sez.~\ref{sec:proc_longjmp} in quanto in questo caso viene salvata anche la maschera dei segnali. diff --git a/sockctrl.tex b/sockctrl.tex index af35bca..9e91f2d 100644 --- a/sockctrl.tex +++ b/sockctrl.tex @@ -34,6 +34,7 @@ porte o altre propriet \subsection{La struttura del \textit{resolver}} \label{sec:sock_resolver} +\index{\textit{resolver}|(} La risoluzione dei nomi è associata tradizionalmente al servizio del \textit{Domain Name Service} che permette di identificare le macchine su internet invece che per numero IP attraverso il relativo \textsl{nome a @@ -607,6 +608,7 @@ Restituisce una stringa corrispondente ad un errore di risoluzione. \noindent che, come l'analoga \func{strerror}, restituisce una stringa con un messaggio di errore già formattato, corrispondente al codice passato come argomento (che si presume sia dato da \var{h\_errno}). +\index{\textit{resolver}|)} @@ -614,11 +616,12 @@ argomento (che si presume sia dato da \var{h\_errno}). \subsection{La risoluzione dei nomi a dominio} \label{sec:sock_name_services} -La principale funzionalità del \textit{resolver} resta quella di risolvere i -nomi a dominio in indirizzi IP, per cui non ci dedicheremo oltre alle funzioni -di richiesta generica ed esamineremo invece le funzioni a questo dedicate. La -prima funzione è \funcd{gethostbyname} il cui scopo è ottenere l'indirizzo di -una stazione noto il suo nome a dominio, il suo prototipo è: +La principale funzionalità del \index{\textit{resolver}}\textit{resolver} +resta quella di risolvere i nomi a dominio in indirizzi IP, per cui non ci +dedicheremo oltre alle funzioni di richiesta generica ed esamineremo invece le +funzioni a questo dedicate. La prima funzione è \funcd{gethostbyname} il cui +scopo è ottenere l'indirizzo di una stazione noto il suo nome a dominio, il +suo prototipo è: \begin{prototype}{netdb.h} {struct hostent *gethostbyname(const char *name)} @@ -678,10 +681,10 @@ Con l'uso di \func{gethostbyname} normalmente si ottengono solo gli indirizzi IPv4, se si vogliono ottenere degli indirizzi IPv6 occorrerà prima impostare l'opzione \const{RES\_USE\_INET6} nel campo \texttt{\_res.options} e poi chiamare \func{res\_init} (vedi sez.~\ref{sec:sock_resolver_functions}) per -modificare le opzioni del resolver; dato che questo non è molto comodo è stata -definita\footnote{questa è una estensione fornita dalle \acr{glibc}, - disponibile anche in altri sistemi unix-like.} un'altra funzione, -\funcd{gethostbyname2}, il cui prototipo è: +modificare le opzioni del \index{\textit{resolver}}\textit{resolver}; dato che +questo non è molto comodo è stata definita\footnote{questa è una estensione + fornita dalle \acr{glibc}, disponibile anche in altri sistemi unix-like.} +un'altra funzione, \funcd{gethostbyname2}, il cui prototipo è: \begin{functions} \headdecl{netdb.h} \headdecl{sys/socket.h} @@ -714,11 +717,11 @@ suoi risultati. Vediamo allora un primo esempio dell'uso delle funzioni di risoluzione, in fig.~\ref{fig:mygethost_example} è riportato un estratto del codice di un -programma che esegue una semplice interrogazione al \textit{resolver} usando -\func{gethostbyname} e poi ne stampa a video i risultati. Al solito il -sorgente completo, che comprende il trattamento delle opzioni ed una funzione -per stampare un messaggio di aiuto, è nel file \texttt{mygethost.c} dei -sorgenti allegati alla guida. +programma che esegue una semplice interrogazione al +\index{\textit{resolver}}\textit{resolver} usando \func{gethostbyname} e poi +ne stampa a video i risultati. Al solito il sorgente completo, che comprende +il trattamento delle opzioni ed una funzione per stampare un messaggio di +aiuto, è nel file \texttt{mygethost.c} dei sorgenti allegati alla guida. Il programma richiede un solo argomento che specifichi il nome da cercare, senza il quale (\texttt{\small 12--15}) esce con un errore. Dopo di che @@ -1462,12 +1465,13 @@ lista illustrata in fig.~\ref{fig:sock_addrinfo_list}. \end{figure} Come primo esempio di uso di \func{getaddrinfo} vediamo un programma -elementare di interrogazione del resolver basato questa funzione, il cui corpo -principale è riportato in fig.~\ref{fig:mygetaddr_example}. Il codice completo -del programma, compresa la gestione delle opzioni in cui è gestita l'eventuale -inizializzazione dell'argomento \var{hints} per restringere le ricerche su -protocolli, tipi di socket o famiglie di indirizzi, è disponibile nel file -\texttt{mygetaddr.c} dei sorgenti allegati alla guida. +elementare di interrogazione del \index{\textit{resolver}}\textit{resolver} +basato questa funzione, il cui corpo principale è riportato in +fig.~\ref{fig:mygetaddr_example}. Il codice completo del programma, compresa +la gestione delle opzioni in cui è gestita l'eventuale inizializzazione +dell'argomento \var{hints} per restringere le ricerche su protocolli, tipi di +socket o famiglie di indirizzi, è disponibile nel file \texttt{mygetaddr.c} +dei sorgenti allegati alla guida. \begin{figure}[!htb] \footnotesize \centering diff --git a/socket.tex b/socket.tex index 61815e0..6358905 100644 --- a/socket.tex +++ b/socket.tex @@ -541,8 +541,9 @@ il campo \var{sun\_path} deve specificare un indirizzo. Questo ha due forme; può essere un file (di tipo socket) nel filesystem o una stringa univoca (mantenuta in uno spazio di nomi astratto). Nel primo caso l'indirizzo viene specificato come una stringa (terminata da uno zero) corrispondente al -pathname del file; nel secondo invece \var{sun\_path} inizia con uno zero e -vengono usati come nome i restanti byte come stringa, senza terminazione. +\index{\textit{pathname}}\textit{pathname} del file; nel secondo invece +\var{sun\_path} inizia con uno zero e vengono usati come nome i restanti byte +come stringa, senza terminazione. \subsection{La struttura degli indirizzi AppleTalk} @@ -739,9 +740,10 @@ ci seguito. -\subsection{La \textit{endianess}\index{endianess}} +\subsection{La \textit{endianess}} \label{sec:sock_endianess} +\index{\textit{endianess}|(} La rappresentazione di un numero binario in un computer può essere fatta in due modi, chiamati rispettivamente \textit{big endian} e \textit{little endian} a seconda di come i singoli bit vengono aggregati per formare le @@ -763,15 +765,15 @@ parte dal bit meno significativo \centering \includegraphics[height=3cm]{img/endianess} \caption{Schema della disposizione dei dati in memoria a seconda della - \textit{endianess}\index{endianess}.} + \textit{endianess}.} \label{fig:sock_endianess} \end{figure} -Si può allora verificare quale tipo di endianess usa il proprio computer con -un programma elementare che si limita ad assegnare un valore ad una variabile -per poi ristamparne il contenuto leggendolo un byte alla volta. Il codice di -detto programma, \file{endtest.c}, è nei sorgenti allegati, allora se lo -eseguiamo su un PC otterremo: +Si può allora verificare quale tipo di \textit{endianess} usa il proprio +computer con un programma elementare che si limita ad assegnare un valore ad +una variabile per poi ristamparne il contenuto leggendolo un byte alla volta. +Il codice di detto programma, \file{endtest.c}, è nei sorgenti allegati, +allora se lo eseguiamo su un PC otterremo: \begin{verbatim} [piccardi@gont sources]$ ./endtest Using value ABCDEF01 @@ -791,13 +793,13 @@ val[3]= 1 \end{verbatim}%$ -La \textit{endianess}\index{endianess} di un computer dipende essenzialmente -dalla architettura hardware usata; Intel e Digital usano il \textit{little - endian}, Motorola, IBM, Sun (sostanzialmente tutti gli altri) usano il -\textit{big endian}. Il formato dei dati contenuti nelle intestazioni dei -protocolli di rete è anch'esso \textit{big endian}; altri esempi di uso di -questi due diversi formati sono quello del bus PCI, che è \textit{little - endian}, o quello del bus VME che è \textit{big endian}. +La \textit{endianess} di un computer dipende essenzialmente dalla architettura +hardware usata; Intel e Digital usano il \textit{little endian}, Motorola, +IBM, Sun (sostanzialmente tutti gli altri) usano il \textit{big endian}. Il +formato dei dati contenuti nelle intestazioni dei protocolli di rete è +anch'esso \textit{big endian}; altri esempi di uso di questi due diversi +formati sono quello del bus PCI, che è \textit{little endian}, o quello del +bus VME che è \textit{big endian}. Esistono poi anche dei processori che possono scegliere il tipo di formato all'avvio e alcuni che, come il PowerPC o l'Intel i860, possono pure passare @@ -833,20 +835,22 @@ significativo (cio \textit{little endian}). Infine la funzione restituisce (\texttt{\small 12}) il valore del confonto delle due variabili. +\index{\textit{endianess}|)} \subsection{Le funzioni per il riordinamento} \label{sec:sock_func_ord} -Il problema connesso all'endianess\index{endianess} è che quando si passano -dei dati da un tipo di architettura all'altra i dati vengono interpretati in -maniera diversa, e ad esempio nel caso dell'intero a 16 bit ci si ritroverà -con i due byte in cui è suddiviso scambiati di posto. Per questo motivo si -usano delle funzioni di conversione che servono a tener conto automaticamente -della possibile differenza fra l'ordinamento usato sul computer e quello che -viene usato nelle trasmissione sulla rete; queste funzioni sono \funcd{htonl}, -\funcd{htons}, \funcd{ntohl} e \funcd{ntohs} ed i rispettivi prototipi sono: +Il problema connesso all'endianess\index{\textit{endianess}} è che quando si +passano dei dati da un tipo di architettura all'altra i dati vengono +interpretati in maniera diversa, e ad esempio nel caso dell'intero a 16 bit ci +si ritroverà con i due byte in cui è suddiviso scambiati di posto. Per questo +motivo si usano delle funzioni di conversione che servono a tener conto +automaticamente della possibile differenza fra l'ordinamento usato sul +computer e quello che viene usato nelle trasmissione sulla rete; queste +funzioni sono \funcd{htonl}, \funcd{htons}, \funcd{ntohl} e \funcd{ntohs} ed i +rispettivi prototipi sono: \begin{functions} \headdecl{netinet/in.h} \funcdecl{unsigned long int htonl(unsigned long int hostlong)} diff --git a/system.tex b/system.tex index 4ae5eb0..fcc7947 100644 --- a/system.tex +++ b/system.tex @@ -390,7 +390,8 @@ riportate in tab.~\ref{tab:sys_file_macro}. \hline \const{LINK\_MAX} &8 & numero massimo di link a un file\\ \const{NAME\_MAX}& 14 & lunghezza in byte di un nome di file. \\ - \const{PATH\_MAX}& 256 & lunghezza in byte di un pathname.\\ + \const{PATH\_MAX}& 256 & lunghezza in byte di un + \index{\textit{pathname}}\textit{pathname}.\\ \const{PIPE\_BUF}&4096 & byte scrivibili atomicamente in una pipe (vedi sez.~\ref{sec:ipc_pipes}).\\ \const{MAX\_CANON}&255 & dimensione di una riga di terminale in modo @@ -420,13 +421,14 @@ le analoghe di tab.~\ref{tab:sys_posix1_general}. \hline \const{\_POSIX\_LINK\_MAX} &8 & numero massimo di link a un file.\\ \const{\_POSIX\_NAME\_MAX}& 14 & lunghezza in byte di un nome di file. \\ - \const{\_POSIX\_PATH\_MAX}& 256 & lunghezza in byte di un pathname.\\ + \const{\_POSIX\_PATH\_MAX}& 256 & lunghezza in byte di un + \index{\textit{pathname}}\textit{pathname}.\\ \const{\_POSIX\_PIPE\_BUF}& 512 & byte scrivibili atomicamente in una - pipe.\\ + pipe.\\ \const{\_POSIX\_MAX\_CANON}&255 & dimensione di una riga di - terminale in modo canonico.\\ + terminale in modo canonico.\\ \const{\_POSIX\_MAX\_INPUT}&255 & spazio disponibile nella coda di input - del terminale.\\ + del terminale.\\ % \const{\_POSIX\_MQ\_OPEN\_MAX}& 8& \\ % \const{\_POSIX\_MQ\_PRIO\_MAX}& 32& \\ % \const{\_POSIX\_FD\_SETSIZE}& 16 & \\ @@ -462,14 +464,14 @@ con la funzione \funcd{pathconf}, il cui prototipo E si noti come la funzione in questo caso richieda un parametro che specifichi a quale file si fa riferimento, dato che il valore del limite cercato può variare a seconda del filesystem. Una seconda versione della funzione, -\funcd{fpathconf}, opera su un file descriptor invece che su un pathname. Il -suo prototipo è: +\funcd{fpathconf}, opera su un file descriptor invece che su un +\index{\textit{pathname}}\textit{pathname}. Il suo prototipo è: \begin{prototype}{unistd.h}{long fpathconf(int fd, int name)} Restituisce il valore del parametro \param{name} per il file \param{fd}. \bodydesc{È identica a \func{pathconf} solo che utilizza un file descriptor - invece di un pathname; pertanto gli errori restituiti cambiano di - conseguenza.} + invece di un \index{\textit{pathname}}\textit{pathname}; pertanto gli + errori restituiti cambiano di conseguenza.} \end{prototype} \noindent ed il suo comportamento è identico a quello di \func{pathconf}. @@ -587,8 +589,8 @@ maniera gerarchica all'interno di un albero;\footnote{si tenga presente che occorrerà includere anche i file \file{linux/unistd.h} e \file{linux/sysctl.h}.} per accedere ad uno di essi occorre specificare un cammino attraverso i vari nodi dell'albero, in maniera analoga a come avviene -per la risoluzione di un pathname (da cui l'uso alternativo del filesystem -\file{/proc}, che vedremo dopo). +per la risoluzione di un \index{\textit{pathname}}\textit{pathname} (da cui +l'uso alternativo del filesystem \file{/proc}, che vedremo dopo). Ciascun nodo dell'albero è identificato da un valore intero, ed il cammino che arriva ad identificare un parametro specifico è passato alla funzione @@ -631,11 +633,11 @@ forma di file alcune delle strutture interne del kernel stesso. In particolare l'albero dei valori di \func{sysctl} viene presentato in forma di file nella directory \file{/proc/sys}, cosicché è possibile accedervi -specificando un pathname e leggendo e scrivendo sul file corrispondente al -parametro scelto. Il kernel si occupa di generare al volo il contenuto ed i -nomi dei file corrispondenti, e questo ha il grande vantaggio di rendere -accessibili i vari parametri a qualunque comando di shell e di permettere la -navigazione dell'albero dei valori. +specificando un \index{\textit{pathname}}\textit{pathname} e leggendo e +scrivendo sul file corrispondente al parametro scelto. Il kernel si occupa di +generare al volo il contenuto ed i nomi dei file corrispondenti, e questo ha +il grande vantaggio di rendere accessibili i vari parametri a qualunque +comando di shell e di permettere la navigazione dell'albero dei valori. Alcune delle corrispondenze dei file presenti in \file{/proc/sys} con i valori di \func{sysctl} sono riportate nei commenti del codice che può essere trovato @@ -687,9 +689,10 @@ sulla directory \param{target}. \textit{mount point} o di spostarlo quando \param{target} non è un \textit{mount point} o è \file{/}. \item[\errcode{EACCES}] non si ha il permesso di accesso su uno dei - componenti del pathname, o si è cercato di montare un filesystem - disponibile in sola lettura senza averlo specificato o il device - \param{source} è su un filesystem montato con l'opzione \const{MS\_NODEV}. + componenti del \index{\textit{pathname}}\textit{pathname}, o si è cercato + di montare un filesystem disponibile in sola lettura senza averlo + specificato o il device \param{source} è su un filesystem montato con + l'opzione \const{MS\_NODEV}. \item[\errcode{ENXIO}] il \textit{major number} del device \param{source} è sbagliato. \item[\errcode{EMFILE}] la tabella dei device \textit{dummy} è piena. @@ -1360,12 +1363,13 @@ processo nell'eseguire le istruzioni in user space, e quello impiegato dal kernel nelle system call eseguite per conto del processo. Gli altri tre campi servono a quantificare l'uso della memoria -virtuale\index{memoria virtuale} e corrispondono rispettivamente al numero di -\textit{page fault}\index{page fault} (vedi sez.~\ref{sec:proc_mem_gen}) -avvenuti senza richiedere I/O su disco (i cosiddetti \textit{minor page - fault}), a quelli che invece han richiesto I/O su disco (detti invece -\textit{major page fault}) ed al numero di volte che il processo è stato -completamente tolto dalla memoria per essere inserito nello swap. +virtuale\index{memoria~virtuale} e corrispondono rispettivamente al numero di +\textit{page fault}\index{\textit{page~fault}} (vedi +sez.~\ref{sec:proc_mem_gen}) avvenuti senza richiedere I/O su disco (i +cosiddetti \textit{minor page fault}), a quelli che invece han richiesto I/O +su disco (detti invece \textit{major page fault}) ed al numero di volte che il +processo è stato completamente tolto dalla memoria per essere inserito nello +swap. In genere includere esplicitamente \file{} non è più strettamente necessario, ma aumenta la portabilità, e serve comunque quando, come nella @@ -1540,7 +1544,7 @@ sez.~\ref{sec:proc_exec}). La gestione della memoria è già stata affrontata in dettaglio in sez.~\ref{sec:proc_memory}; abbiamo visto allora che il kernel provvede il -meccanismo della memoria virtuale\index{memoria virtuale} attraverso la +meccanismo della memoria virtuale\index{memoria~virtuale} attraverso la divisione della memoria fisica in pagine. In genere tutto ciò è del tutto trasparente al singolo processo, ma in certi @@ -1618,11 +1622,12 @@ Il suo prototipo \end{prototype} La funzione restituisce in ciascun elemento di \param{loadavg} il numero medio -di processi attivi sulla coda dello scheduler\index{scheduler}, calcolato su -un diverso intervalli di tempo. Il numero di intervalli che si vogliono -leggere è specificato da \param{nelem}, dato che nel caso di Linux il carico -viene valutato solo su tre intervalli (corrispondenti a 1, 5 e 15 minuti), -questo è anche il massimo valore che può essere assegnato a questo argomento. +di processi attivi sulla coda dello scheduler\index{\textit{scheduler}}, +calcolato su un diverso intervalli di tempo. Il numero di intervalli che si +vogliono leggere è specificato da \param{nelem}, dato che nel caso di Linux il +carico viene valutato solo su tre intervalli (corrispondenti a 1, 5 e 15 +minuti), questo è anche il massimo valore che può essere assegnato a questo +argomento. diff --git a/tcpsock.tex b/tcpsock.tex index b13c16d..eced3f8 100644 --- a/tcpsock.tex +++ b/tcpsock.tex @@ -34,9 +34,11 @@ questa sezione ci concentreremo sulle modalit inizio e conclude una connessione e faremo inoltre un breve accenno al significato di alcuni dei vari \textsl{stati} ad essa associati. + \subsection{La creazione della connessione: il \textit{three way handshake}} \label{sec:TCP_conn_cre} +\index{\textit{three~way~handshake}|(} Il processo che porta a creare una connessione TCP è chiamato \textit{three way handshake}; la successione tipica degli eventi (e dei \textsl{segmenti}\footnote{Si ricordi che il segmento è l'unità elementare di @@ -116,6 +118,8 @@ aspetta di ricevere con il pacchetto successivo; dato che il primo pacchetto SYN consuma un byte, nel \textit{three way handshake} il numero di acknowledge è sempre pari al numero di sequenza iniziale incrementato di uno; lo stesso varrà anche (vedi fig.~\ref{fig:TCP_close}) per l'acknowledgement di un FIN. +\index{\textit{three~way~handshake}|)} + \subsection{Le opzioni TCP.} \label{sec:TCP_TCP_opt} @@ -705,9 +709,9 @@ Si noti che si \const{INADDR\_ANY}, anche se, essendo questo nullo, il riordinamento è inutile. Si tenga presente comunque che tutte le costanti \val{INADDR\_} (riportate in tab.~\ref{tab:TCP_ipv4_addr}) sono definite secondo -l'\textit{endianess} della macchina, ed anche se esse possono essere -invarianti rispetto all'ordinamento dei bit, è comunque buona norma usare -sempre la funzione \func{htonl}. +l'\textit{endianess}\index{\textit{endianess}} della macchina, ed anche se +esse possono essere invarianti rispetto all'ordinamento dei bit, è comunque +buona norma usare sempre la funzione \func{htonl}. \begin{table}[htb] \centering @@ -754,8 +758,8 @@ connessione con un server TCP,\footnote{di nuovo la funzione limiterà ad impostare l'indirizzo dal quale e verso il quale saranno inviati e ricevuti i pacchetti, mentre per socket di tipo \texttt{SOCK\_STREAM} o \texttt{SOCK\_SEQPACKET}, essa attiverà la procedura di avvio (nel caso del - TCP il \textit{three-way-handsjake}) della connessione.} il prototipo della -funzione è il seguente: + TCP il \index{\textit{three~way~handshake}}\textit{three way handshake}) + della connessione.} il prototipo della funzione è il seguente: \begin{prototype}{sys/socket.h} {int connect(int sockfd, const struct sockaddr *servaddr, socklen\_t addrlen)} @@ -797,12 +801,12 @@ numero di porta del server a cui ci si vuole connettere, come mostrato nell'esempio sez.~\ref{sec:TCP_daytime_client}, usando le funzioni illustrate in sez.~\ref{sec:sock_addr_func}. -Nel caso di socket TCP la funzione \func{connect} avvia il \textit{three way - handshake}, e ritorna solo quando la connessione è stabilita o si è -verificato un errore. Le possibili cause di errore sono molteplici (ed i -relativi codici riportati sopra), quelle che però dipendono dalla situazione -della rete e non da errori o problemi nella chiamata della funzione sono le -seguenti: +Nel caso di socket TCP la funzione \func{connect} avvia il +\index{\textit{three~way~handshake}}\textit{three way handshake}, e ritorna +solo quando la connessione è stabilita o si è verificato un errore. Le +possibili cause di errore sono molteplici (ed i relativi codici riportati +sopra), quelle che però dipendono dalla situazione della rete e non da errori +o problemi nella chiamata della funzione sono le seguenti: \begin{enumerate} \item Il client non riceve risposta al SYN: l'errore restituito è \errcode{ETIMEDOUT}. Stevens riporta che BSD invia un primo SYN alla chiamata @@ -897,11 +901,12 @@ infatti vengono mantenute due code: \begin{enumerate} \item La coda delle connessioni incomplete (\textit{incomplete connection queue} che contiene un riferimento per ciascun socket per il quale è - arrivato un SYN ma il \textit{three way handshake} non si è ancora concluso. - Questi socket sono tutti nello stato \texttt{SYN\_RECV}. + arrivato un SYN ma il \index{\textit{three~way~handshake}}\textit{three way + handshake} non si è ancora concluso. Questi socket sono tutti nello stato + \texttt{SYN\_RECV}. \item La coda delle connessioni complete (\textit{complete connection queue} - che contiene un ingresso per ciascun socket per il quale il three way - handshake è stato completato ma ancora \func{accept} non è ritornata. + che contiene un ingresso per ciascun socket per il quale il \textit{three + way handshake} è stato completato ma ancora \func{accept} non è ritornata. Questi socket sono tutti nello stato \texttt{ESTABLISHED}. \end{enumerate} @@ -909,12 +914,13 @@ Lo schema di funzionamento quando arriva un SYN da un client il server crea una nuova voce nella coda delle connessioni incomplete, e poi risponde con il SYN$+$ACK. La voce resterà nella coda delle connessioni incomplete fino al ricevimento dell'ACK dal -client o fino ad un timeout. Nel caso di completamento del three way handshake -la voce viene spostata nella coda delle connessioni complete. Quando il -processo chiama la funzione \func{accept} (vedi sez.~\ref{sec:TCP_func_accept}) -la prima voce nella coda delle connessioni complete è passata al programma, o, -se la coda è vuota, il processo viene posto in attesa e risvegliato all'arrivo -della prima connessione completa. +client o fino ad un timeout. Nel caso di completamento del +\index{\textit{three~way~handshake}}\textit{three way handshake} la voce viene +spostata nella coda delle connessioni complete. Quando il processo chiama la +funzione \func{accept} (vedi sez.~\ref{sec:TCP_func_accept}) la prima voce +nella coda delle connessioni complete è passata al programma, o, se la coda è +vuota, il processo viene posto in attesa e risvegliato all'arrivo della prima +connessione completa. \begin{figure}[htb] \centering @@ -966,7 +972,7 @@ che il compito principale della coda sia quello di gestire il caso in cui il server è occupato fra chiamate successive alla \func{accept} (per cui la coda più occupata sarebbe quella delle connessioni completate), ma piuttosto quello di gestire la presenza di un gran numero di SYN in attesa di concludere il -three way handshake. +\textit{three way handshake}\index{\textit{three~way~handshake}}. Infine va messo in evidenza che, nel caso di socket TCP, quando un SYN arriva con tutte le code piene, il pacchetto deve essere ignorato. Questo perché la @@ -1898,14 +1904,14 @@ connessioni da qualunque indirizzo e da qualunque porta e su qualunque interfaccia locale. A questo punto si può lanciare il client, esso chiamerà \func{socket} e -\func{connect}; una volta completato il three way handshake la connessione è -stabilita; la \func{connect} ritornerà nel client\footnote{si noti che è - sempre la \func{connect} del client a ritornare per prima, in quanto - questo avviene alla ricezione del secondo segmento (l'ACK del server) del - three way handshake, la \func{accept} del server ritorna solo dopo - un altro mezzo RTT quando il terzo segmento (l'ACK del client) viene - ricevuto.} e la \func{accept} nel server, ed usando di nuovo -\cmd{netstat} otterremmo che: +\func{connect}; una volta completato il \textit{three way handshake} la +connessione è stabilita; la \func{connect} ritornerà nel client\footnote{si + noti che è sempre la \func{connect} del client a ritornare per prima, in + quanto questo avviene alla ricezione del secondo segmento (l'ACK del server) + del \textit{three way handshake}, la \func{accept} del server ritorna solo + dopo un altro mezzo RTT quando il terzo segmento (l'ACK del client) viene + ricevuto.} e la \func{accept} nel server, ed usando di nuovo \cmd{netstat} +otterremmo che: \begin{verbatim} Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State @@ -2152,7 +2158,7 @@ perch interrotta dall'arrivo di \const{SIGCHLD}, è quella ad \func{accept}, che è l'unica funzione che può mettere il processo padre in stato di sleep nel periodo in cui un figlio può terminare; si noti infatti come le altre -\index{system call lente} \textit{slow system call}\footnote{si ricordi la +\index{system~call~lente} \textit{slow system call}\footnote{si ricordi la distinzione fatta in sez.~\ref{sec:sig_gen_beha}.} o sono chiamate prima di entrare nel ciclo principale, quando ancora non esistono processi figli, o sono chiamate dai figli stessi e non risentono di \const{SIGCHLD}. @@ -2248,13 +2254,14 @@ funzione \func{accept}. Benché questo non sia un fatto comune, un evento simile può essere osservato con dei server molto occupati. In tal caso, con una struttura del server simile a quella del nostro esempio, in cui la gestione delle singole -connessioni è demandata a processi figli, può accadere che il three way -handshake venga completato e la relativa connessione abortita subito dopo, -prima che il padre, per via del carico della macchina, abbia fatto in tempo ad -eseguire la chiamata ad \func{accept}. Di nuovo si ha una situazione analoga -a quella illustrata in fig.~\ref{fig:TCP_early_abort}, in cui la connessione -viene stabilita, ma subito dopo si ha una condizione di errore che la chiude -prima che essa sia stata accettata dal programma. +connessioni è demandata a processi figli, può accadere che il \textit{three + way handshake}\index{\textit{three~way~handshake}} venga completato e la +relativa connessione abortita subito dopo, prima che il padre, per via del +carico della macchina, abbia fatto in tempo ad eseguire la chiamata ad +\func{accept}. Di nuovo si ha una situazione analoga a quella illustrata in +fig.~\ref{fig:TCP_early_abort}, in cui la connessione viene stabilita, ma +subito dopo si ha una condizione di errore che la chiude prima che essa sia +stata accettata dal programma. Questo significa che, oltre alla interruzione da parte di un segnale, che abbiamo trattato in sez.~\ref{sec:TCP_child_hand} nel caso particolare di @@ -2357,14 +2364,15 @@ anarres.echo > gont.34559: R 511689732:511689732(0) win 0 \end{verbatim} Le prime tre righe vengono prodotte al momento in cui lanciamo il nostro -client, e corrispondono ai tre pacchetti del three way handshake. L'output del -comando riporta anche i numeri di sequenza iniziali, mentre la lettera -\texttt{S} indica che per quel pacchetto si aveva il SYN flag attivo. Si noti +client, e corrispondono ai tre pacchetti del +\index{\textit{three~way~handshake}}\textit{three way handshake}. L'output +del comando riporta anche i numeri di sequenza iniziali, mentre la lettera +\texttt{S} indica che per quel pacchetto si aveva il SYN flag attivo. Si noti come a partire dal secondo pacchetto sia sempre attivo il campo \texttt{ack}, seguito dal numero di sequenza per il quale si da il ricevuto; quest'ultimo, a partire dal terzo pacchetto, viene espresso in forma relativa per maggiore compattezza. Il campo \texttt{win} in ogni riga indica la \textit{advertising - window} di cui parlavamo in sez.~\ref{sec:TCP_TCP_opt}. Allora si può + window} di cui parlavamo in sez.~\ref{sec:TCP_TCP_opt}. Allora si può verificare dall'output del comando come venga appunto realizzata la sequenza di pacchetti descritta in sez.~\ref{sec:TCP_conn_cre}: prima viene inviato dal client un primo pacchetto con il SYN che inizia la connessione, a cui il @@ -2372,16 +2380,17 @@ server risponde dando il ricevuto con un secondo pacchetto, che a sua volta porta un SYN, cui il client risponde con un il terzo pacchetto di ricevuto. Ritorniamo allora alla nostra sessione con il servizio echo: dopo le tre righe -del three way handshake non avremo nulla fin tanto che non scriveremo una -prima riga sul client; al momento in cui facciamo questo si genera una -sequenza di altri quattro pacchetti. Il primo, dal client al server, -contraddistinto da una lettera \texttt{P} che significa che il flag PSH è -impostato, contiene la nostra riga (che è appunto di 11 caratteri), e ad esso -il server risponde immediatamente con un pacchetto vuoto di ricevuto. Poi -tocca al server riscrivere indietro quanto gli è stato inviato, per cui sarà -lui a mandare indietro un terzo pacchetto con lo stesso contenuto appena -ricevuto, e a sua volta riceverà dal client un ACK nel quarto pacchetto. -Questo causerà la ricezione dell'eco nel client che lo stamperà a video. +del \textit{three way handshake}\index{\textit{three~way~handshake}} non +avremo nulla fin tanto che non scriveremo una prima riga sul client; al +momento in cui facciamo questo si genera una sequenza di altri quattro +pacchetti. Il primo, dal client al server, contraddistinto da una lettera +\texttt{P} che significa che il flag PSH è impostato, contiene la nostra riga +(che è appunto di 11 caratteri), e ad esso il server risponde immediatamente +con un pacchetto vuoto di ricevuto. Poi tocca al server riscrivere indietro +quanto gli è stato inviato, per cui sarà lui a mandare indietro un terzo +pacchetto con lo stesso contenuto appena ricevuto, e a sua volta riceverà dal +client un ACK nel quarto pacchetto. Questo causerà la ricezione dell'eco nel +client che lo stamperà a video. A questo punto noi procediamo ad interrompere l'esecuzione del server con un \texttt{C-c} (cioè con l'invio di \const{SIGTERM}): nel momento in cui -- 2.30.2