From 7090500d79c488db306ed0c065b90bb0c0505430 Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Sun, 3 Mar 2002 23:05:11 +0000 Subject: [PATCH] Correzioni per le footnote e scritta altra roba sui segnali (finite kill e raise, iniziate alarm e setitimer). --- elemtcp.tex | 55 +++++++------- filedir.tex | 40 +++++----- filestd.tex | 16 ++-- fileunix.tex | 37 +++++---- intro.tex | 8 +- network.tex | 4 +- process.tex | 16 ++-- prochand.tex | 18 ++--- signal.tex | 206 +++++++++++++++++++++++++++++++++++++++++---------- simpltcp.tex | 12 +-- socket.tex | 12 +-- system.tex | 89 +++++++++++----------- 12 files changed, 321 insertions(+), 192 deletions(-) diff --git a/elemtcp.tex b/elemtcp.tex index ce44d1d..7e75f92 100644 --- a/elemtcp.tex +++ b/elemtcp.tex @@ -44,7 +44,7 @@ creazione di una connessione \func{connect}, attraverso un procedimento che viene chiamato \textsl{apertura attiva}, dall'inglese \textit{active open}. La chiamata di \func{connect} blocca il processo e causa l'invio da parte del client di un - segmento SYN\footnote{Si ricordi che il segmento è l'unità elementare di + segmento SYN,\footnote{Si ricordi che il segmento è l'unità elementare di dati trasmessa dal protocollo TCP al livello superiore; tutti i segmenti hanno un header che contiene le informazioni che servono allo \textit{stack TCP} (così viene di solito chiamata la parte del kernel che @@ -52,7 +52,7 @@ creazione di una connessione ci sono una serie di flag usati per gestire la connessione, come SYN, ACK, URG, FIN, alcuni di essi, come SYN (che sta per \textit{syncronize}) corrispondono a funzioni particolari del protocollo e danno il nome al - segmento, (per maggiori dettagli vedere \capref{cha:tcp_protocol})}, in + segmento, (per maggiori dettagli vedere \capref{cha:tcp_protocol}).} in sostanza viene inviato al server un pacchetto IP che contiene solo gli header IP e TCP (con il numero di sequenza iniziale e il flag SYN) e le opzioni di TCP. @@ -128,20 +128,20 @@ regolare la connessione. Normalmente vengono usate le seguenti opzioni: \textsl{finestra annunciata} (\textit{advertized window}) con la quale ciascun capo della comunicazione dichiara quanto spazio disponibile ha in memoria per i dati. Questo è un numero a 16 bit dell'header, che così può - indicare un massimo di 65535 byte (anche se Linux usa come massimo 32767 - per evitare problemi con alcuni stack bacati che usano l'aritmetica con - segno per implementare lo stack TCP); ma alcuni tipi di connessione come - quelle ad alta velocità (sopra i 45Mbits/sec) e quelle che hanno grandi - ritardi nel cammino dei pacchetti (come i satelliti) richiedono una finestra - più grande per poter ottenere il massimo dalla trasmissione, per questo - esiste questa opzione che indica un fattore di scala da applicare al valore - della finestra annunciata\footnote{essendo una nuova opzione per garantire - la compatibilità con delle vecchie implementazioni del protocollo la - procedura che la attiva prevede come negoziazione che l'altro capo della - connessione riconosca esplicitamente l'opzione inserendola anche lui nel - suo SYN di risposta dell'apertura della connessione} per la connessione - corrente (espresso come numero di bit cui shiftare a sinistra il valore - della finestra annunciata inserito nel pacchetto). + indicare un massimo di 65535 byte (anche se Linux usa come massimo 32767 per + evitare problemi con alcuni stack bacati che usano l'aritmetica con segno + per implementare lo stack TCP); ma alcuni tipi di connessione come quelle ad + alta velocità (sopra i 45Mbits/sec) e quelle che hanno grandi ritardi nel + cammino dei pacchetti (come i satelliti) richiedono una finestra più grande + per poter ottenere il massimo dalla trasmissione, per questo esiste questa + opzione che indica un fattore di scala da applicare al valore della finestra + annunciata\footnote{essendo una nuova opzione per garantire la compatibilità + con delle vecchie implementazioni del protocollo la procedura che la + attiva prevede come negoziazione che l'altro capo della connessione + riconosca esplicitamente l'opzione inserendola anche lui nel suo SYN di + risposta dell'apertura della connessione.} per la connessione corrente + (espresso come numero di bit cui shiftare a sinistra il valore della + finestra annunciata inserito nel pacchetto). \item \textit{timestamp option}, è anche questa una nuova opzione necessaria per le connessioni ad alta velocità per evitare possibili corruzioni di dati @@ -662,7 +662,7 @@ per il server\footnote{un'eccezione a tutto ci In questo caso viene fatta assegnare dal kernel una porta effimera che poi viene registrata presso il \textit{portmapper}; quest'ultimo è un altro demone che deve essere contattato dai client per ottenere la porta effimera - su cui si trova il server} che in genere viene identificato dalla porta su + su cui si trova il server.} che in genere viene identificato dalla porta su cui risponde. Con \func{bind} si può assegnare un IP specifico ad un socket, purché questo @@ -877,11 +877,11 @@ dette code. Stevens riporta che BSD ha sempre applicato un fattore di 1.5 al valore, e provvede una tabella con i risultati ottenuti con vari kernel, compreso Linux 2.0, che mostrano le differenze fra diverse implementazioni. -In Linux il significato di questo valore è cambiato a partire dal kernel -2.2 per prevenire l'attacco chiamato \textit{syn flood}. Questo si basa +In Linux il significato di questo valore è cambiato a partire dal kernel 2.2 +per prevenire l'attacco chiamato \textit{syn flood}. Questo si basa sull'emissione da parte dell'attaccante di un grande numero di pacchetti SYN indirizzati verso una porta forgiati con indirizzo IP fasullo\footnote{con la - tecnica che viene detta \textit{ip spoofing}} così che i SYN$+$ACK vanno + tecnica che viene detta \textit{ip spoofing}.} così che i SYN$+$ACK vanno perduti e la coda delle connessioni incomplete viene saturata, impedendo di fatto ulteriori connessioni. @@ -996,14 +996,13 @@ Se la funzione ha successo restituisce il descrittore di un nuovo socket creato dal kernel (detto \textit{connected socket}) a cui viene associata la prima connessione completa (estratta dalla relativa coda, vedi \secref{sec:TCPel_func_listen}) che il client TCP ha effettuato verso il -socket \var{sockfd}. Quest'ultimo (detto \textit{listening socket}) è -quello creato all'inizio e messo in ascolto con \func{listen}, e non viene -toccato dalla funzione. -Se non ci sono connessioni pendenti da accettare la funzione mette in attesa -il processo\footnote{a meno che non si sia settato il socket per essere - non-bloccante, nel qual caso ritorna con l'errore \macro{EAGAIN}, - torneremo su questa modalità di operazione in \secref{sec:xxx_sock_noblock}} -fintanto che non ne arriva una. +socket \var{sockfd}. Quest'ultimo (detto \textit{listening socket}) è quello +creato all'inizio e messo in ascolto con \func{listen}, e non viene toccato +dalla funzione. Se non ci sono connessioni pendenti da accettare la funzione +mette in attesa il processo\footnote{a meno che non si sia settato il socket + per essere non-bloccante, nel qual caso ritorna con l'errore \macro{EAGAIN}. + Torneremo su questa modalità di operazione in + \secref{sec:xxx_sock_noblock}.} fintanto che non ne arriva una. Il meccanismo di funzionamento di \func{accept} è essenziale per capire il funzionamento di un server: in generale infatti c'è sempre un solo socket in diff --git a/filedir.tex b/filedir.tex index efeb41c..d7cfa6f 100644 --- a/filedir.tex +++ b/filedir.tex @@ -151,7 +151,7 @@ singola system call. Si ricordi infine che il file non viene eliminato dal disco fintanto che tutti i riferimenti ad esso sono stati cancellati, solo quando il \textit{link count} mantenuto nell'inode diventa zero lo spazio occupato viene rimosso. A -questo però si aggiunge una altra condizione, e cioè che non ci siano processi +questo però si aggiunge un'altra condizione, e cioè che non ci siano processi che abbiano detto file aperto. Questa proprietà viene spesso usata per essere sicuri di non lasciare file @@ -185,9 +185,9 @@ directory \end{prototype} Per cambiare nome ad un file o a una directory (che devono comunque essere -nello stesso filesystem) si usa invece la funzione \func{rename}\footnote{la +nello stesso filesystem) si usa invece la funzione \func{rename},\footnote{la funzione è definita dallo standard ANSI C solo per i file, POSIX estende la - funzione anche alle directory}, il cui prototipo è: + funzione anche alle directory.} il cui prototipo è: \begin{prototype}{stdio.h} {int rename(const char *oldpath, const char *newpath)} @@ -248,7 +248,7 @@ eseguita. In ogni caso se \var{newpath} esiste e l'operazione fallisce per un qualche motivo (come un crash del kernel), \func{rename} garantisce di lasciare -presente una istanza di \var{newpath}. Tuttavia nella sovrascrittura potrà +presente un'istanza di \var{newpath}. Tuttavia nella sovrascrittura potrà esistere una finestra in cui sia \var{oldpath} che \var{newpath} fanno riferimento allo stesso file. @@ -387,13 +387,13 @@ stringa con un carattere nullo e la tronca alla dimensione specificata da Un caso comune che si può avere con i link simbolici è la creazione dei cosiddetti \textit{loop}. La situazione è illustrata in \curfig, che riporta la struttura della directory \file{/boot}. Come si vede si è creato al suo -interno un link simbolico che punta di nuovo a \file{/boot}\footnote{Questo +interno un link simbolico che punta di nuovo a \file{/boot}.\footnote{Questo tipo di loop è stato effettuato 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 in questa directory con lo stesso path con cui verrebbero visti dal sistema operativo, anche se essi si trovano, come è solito, su una partizione separata (e che \cmd{grub} - vedrebbe come radice).}. + vedrebbe 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 @@ -422,7 +422,7 @@ quanto aprendo in scrittura \file{temporaneo} verr $ cat temporaneo cat: temporaneo: No such file or directory \end{verbatim}%$ -con un errore che può sembrare sbagliato, dato che una ispezione con \cmd{ls} +con un errore che può sembrare sbagliato, dato che un'ispezione con \cmd{ls} ci mostrerebbe invece l'esistenza di \file{temporaneo}. @@ -597,7 +597,7 @@ Per accedere al contenuto delle directory si usano i cosiddetti \capref{cha:files_std_interface}); la funzione \func{opendir} apre uno di questi stream e la funzione \func{readdir} legge il contenuto della directory, i cui elementi sono le \textit{directory entry} (da distinguersi da quelle -della cache di cui parlavamo in \secref{sec:file_vfs}) in una opportuna +della cache di cui parlavamo in \secref{sec:file_vfs}) in un'opportuna struttura \var{struct dirent}. (NdA Il resto va scritto!!! É noioso e lo farò più avanti). @@ -644,8 +644,8 @@ apposita funzione di libreria, \func{getcwd}, il cui prototipo 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 \var{size} la funzione restituisce un errore. Si -può anche specificare un puntatore nullo come \var{buffer}\footnote{questa è - una estensione allo standard POSIX.1, supportata da Linux}, nel qual caso la +può anche specificare un puntatore nullo come \var{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 \var{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 @@ -998,7 +998,7 @@ Il primo valore dell'elenco di \secref{tab:file_mode_flags} binaria che permette di estrarre i bit nei quali viene memorizzato il tipo di file, i valori successivi sono le costanti corrispondenti ai singoli bit, e possono essere usati per effettuare la selezione sul tipo di file voluto, con -una opportuna combinazione. +un'opportuna combinazione. \begin{table}[htb] \centering @@ -1182,7 +1182,7 @@ essere capiti se si tiene conto di quanto gi directory sono file (che contengono una lista di nomi) che il sistema tratta in maniera del tutto analoga a tutti gli altri. -Per questo motivo tutte le volte che compiremo una operazione su un file che +Per questo motivo tutte le volte che compiremo un'operazione su un file che comporta una modifica del nome contenuto nella directory, andremo anche a scrivere sulla directory che lo contiene cambiandone il tempo di modifica. Un esempio di questo può essere la cancellazione di un file, invece leggere o @@ -1343,7 +1343,7 @@ Esistono varie estensioni a questo modello,\footnote{come le \textit{Access Control List} che possono essere aggiunte al filesystem standard con opportune patch, e sono presenti in filesystem non ancora inclusi nel kernel ufficiale come \textsl{xfs}, o meccanismi di controllo ancora più - sofisticati come il \textit{mandatory access control} di SE-Linux} ma nella + sofisticati come il \textit{mandatory access control} di SE-Linux.} ma nella maggior parte dei casi il meccanismo standard è più che sufficiente a soffisfare tutte le necessità più comuni. I tre permessi di base associati ad ogni file sono: @@ -1601,9 +1601,9 @@ Le attuali implementazioni di memoria virtuale e filesystem rendono sostanzialmente inutile questo procedimento. Benché ormai non venga più utilizzato per i file, lo \textsl{sticky bit} ha -invece assunto un uso importante per le directory\footnote{lo \textsl{sticky - bit} per le directory è una estensione non definita nello standard POSIX, - Linux però la supporta, così come BSD e SVR4.}; in questo caso se il bit è +invece assunto un uso importante per le directory;\footnote{lo \textsl{sticky + bit} per le directory è un'estensione non definita nello standard POSIX, + Linux però la supporta, così come BSD e SVR4.} in questo caso se il bit è settato un file potrà essere rimosso dalla directory soltanto se l'utente ha il permesso di scrittura su di essa ed inoltre è vera una delle seguenti condizioni: @@ -1818,7 +1818,7 @@ misura di sicurezza, volta ad scongiurare l'abuso dei bit \acr{suid} e \acr{sgid}; essa consiste nel cancellare automaticamente questi bit qualora un processo che non appartenga all'amministratore scriva su un file. In questo modo anche se un utente malizioso scopre un file \acr{suid} su cui può -scrivere, una eventuale modifica comporterà la perdita di ogni ulteriore +scrivere, un'eventuale modifica comporterà la perdita di ogni ulteriore privilegio. \subsection{La funzione \func{umask}} @@ -1839,7 +1839,7 @@ funzione \func{umask}, il cui prototipo Questa maschera è una caratteristica di ogni processo\footnote{è infatti contenuta nel campo \var{umask} di \var{fs\_struct}, vedi - \figref{fig:proc_task_struct}} e viene utilizzata per impedire che alcuni + \figref{fig:proc_task_struct}.} e viene utilizzata per impedire che alcuni permessi possano essere assegnati ai nuovi file in sede di creazione. I bit indicati nella maschera vengono infatti esclusi quando un nuovo file viene creato. @@ -1901,10 +1901,10 @@ in link simbolico si deve usare la funzione \func{lchown}.\footnote{fino alla versione 2.1.81 in Linux \func{chown} non seguiva i link simbolici, da allora questo comportamento è stato assegnato alla funzione \func{lchown}, introdotta per l'occasione, ed è stata creata una nuova system call per - \func{chown} che seguisse i link simbolici} La funzione \func{fchown} opera + \func{chown} che seguisse i link simbolici.} La funzione \func{fchown} opera su un file aperto, essa è mutuata da BSD, ma non è nello standard POSIX. Un'altra estensione rispetto allo standard POSIX è che specificando -1 come -valore per \var{owner} e \var{group} i valori restano immutati. +valore per \var{owner} e \var{group} i valori restano immutati. Quando queste funzioni sono chiamate con successo da un processo senza i privilegi di root entrambi i bit \acr{suid} e \acr{sgid} vengono diff --git a/filestd.tex b/filestd.tex index d46f965..5e6cdec 100644 --- a/filestd.tex +++ b/filestd.tex @@ -209,9 +209,9 @@ corrente in uno stream. \label{sec:file_fopen} Le funzioni che si possono usare per aprire uno stream sono solo tre: -\func{fopen}, \func{fdopen} e \func{freopen}\footnote{\func{fopen} e +\func{fopen}, \func{fdopen} e \func{freopen},\footnote{\func{fopen} e \func{freopen} fanno parte dello standard ANSI C, \func{fdopen} è parte - dello standard POSIX.1.}, i loro prototipi sono: + dello standard POSIX.1.} i loro prototipi sono: \begin{functions} \headdecl{stdio.h} \funcdecl{FILE *fopen(const char *path, const char *mode)} @@ -322,7 +322,7 @@ processo (si veda \secref{sec:file_umask}). In caso di file aperti in lettura e scrittura occorre ricordarsi che c'è di messo una bufferizzazione; per questo motivo lo standard ANSI C -richiede che ci sia una operazione di posizionamento fra una operazione +richiede che ci sia un'operazione di posizionamento fra un'operazione di output ed una di input o viceversa (eccetto il caso in cui l'input ha incontrato la fine del file), altrimenti una lettura può ritornare anche il risultato di scritture precedenti l'ultima effettuata. @@ -332,7 +332,7 @@ una scrittura una delle funzioni \func{fflush}, \func{fseek}, \func{fsetpos} o \func{rewind} prima di eseguire una rilettura; viceversa nel caso in cui si voglia fare una scrittura subito dopo aver eseguito una lettura occorre prima usare una delle funzioni \func{fseek}, \func{fsetpos} o \func{rewind}. Anche -una operazione nominalmente nulla come \code{fseek(file, 0, SEEK\_CUR)} è +un'operazione nominalmente nulla come \code{fseek(file, 0, SEEK\_CUR)} è sufficiente a garantire la sincronizzazione. Una volta aperto lo stream, si può cambiare la modalità di bufferizzazione @@ -1470,9 +1470,9 @@ e \func{setlinebuf}, i loro prototipi sono: \noindent tutte queste funzioni sono realizzate con opportune chiamate a \func{setvbuf} e sono definite solo per compatibilità con le vecchie librerie BSD. Infine le \acr{glibc} provvedono le funzioni non standard\footnote{anche - queste sono originarie di Solaris} \func{\_\_flbf} e \func{\_\_fbufsize} che -permettono di leggere le proprietà di bufferizzazione di uno stream; i cui -prototipi sono: + queste funzioni sono originarie di Solaris.} \func{\_\_flbf} e +\func{\_\_fbufsize} che permettono di leggere le proprietà di bufferizzazione +di uno stream; i cui prototipi sono: \begin{functions} \headdecl{stdio\_ext.h} @@ -1497,7 +1497,7 @@ scelta, si pu \end{prototype} \noindent anche di questa funzione esiste una analoga \func{fflush\_unlocked}\footnote{accessibile definendo \macro{\_BSD\_SOURCE} o - \macro{\_SVID\_SOURCE} o \macro{\_GNU\_SOURCE}} che non effettua il blocco + \macro{\_SVID\_SOURCE} o \macro{\_GNU\_SOURCE}.} che non effettua il blocco dello stream. Se \param{stream} è \macro{NULL} lo scarico dei dati è forzato per tutti gli diff --git a/fileunix.tex b/fileunix.tex index e99db64..cacce23 100644 --- a/fileunix.tex +++ b/fileunix.tex @@ -1,4 +1,4 @@ -\chapter{I file: l'interfaccia standard unix} +\chapter{I file: l'interfaccia standard Unix} \label{cha:file_unix_interface} Esamineremo in questo capitolo la prima delle due interfacce di programmazione @@ -68,7 +68,7 @@ file, fra cui: campo \var{f\_pos}). \item un puntatore all'inode\footnote{nel kernel 2.4.x si è in realtà passati ad un puntatore ad una struttura \var{dentry} che punta a sua volta - all'inode passando per la nuova struttura del VFS} del file. + all'inode passando per la nuova struttura del VFS.} del file. %\item un puntatore alla tabella delle funzioni \footnote{la struttura % \var{f\_op} descritta in \secref{sec:file_vfs_work}} che si possono usare % sul file. @@ -153,7 +153,7 @@ restano i limiti imposti dall'amministratore (vedi \secref{sec:sys_limits}). \section{Le funzioni base} \label{sec:file_base_func} -L'interfaccia standard unix per l'input/output sui file è basata su cinque +L'interfaccia standard Unix per l'input/output sui file è basata su cinque funzioni fondamentali: \func{open}, \func{read}, \func{write}, \func{lseek} e \func{close}, usate rispettivamente per aprire, leggere, scrivere, spostarsi e chiudere un file. @@ -245,7 +245,7 @@ sempre il file descriptor con il valore pi zero. Se il file è un terminale o una fifo il flag verrà ignorato, negli altri casi il comportamento non è specificato. \\ \macro{O\_NOFOLLOW} & se \var{pathname} è un link simbolico la chiamata - fallisce. Questa è una estensione BSD aggiunta in Linux dal kernel 2.1.126. + 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. \\ \macro{O\_DIRECTORY} & se \var{pathname} non è una directory la chiamata @@ -303,7 +303,7 @@ sempre il file descriptor con il valore pi \footnotetext[5]{l'opzione origina da SVr4, dove però causava il ritorno da una \func{read} con un valore nullo e non con un errore, questo introduce - una ambiguità, dato che come vedremo in \secref{sec:file_read} il ritorno di + un'ambiguità, dato che come vedremo in \secref{sec:file_read} il ritorno di zero da parte di \func{read} ha il significato di una end-of-file.} Questa caratteristica permette di prevedere qual'è il valore del file @@ -450,7 +450,7 @@ La nuova posizione sommato al riferimento dato da \param{whence}; quest'ultimo può assumere i seguenti valori\footnote{per compatibilità con alcune vecchie notazioni questi valori possono essere rimpiazzati rispettivamente con 0, 1 e 2 o con - \macro{L\_SET}, \macro{L\_INCR} e \macro{L\_XTND}}: + \macro{L\_SET}, \macro{L\_INCR} e \macro{L\_XTND}.}: \begin{basedescript}{\desclabelwidth{2.0cm}} \item[\macro{SEEK\_SET}] si fa riferimento all'inizio del file: il valore di \var{offset} è la nuova posizione. @@ -480,9 +480,9 @@ essersi spostata, ma noi scriveremo alla posizione settata in precedenza. Non tutti i file supportano la capacità di eseguire una \func{lseek}, in questo caso la funzione ritorna l'errore \macro{EPIPE}. Questo, oltre che per i tre casi citati nel prototipo, vale anche per tutti quei dispositivi che non -supportano questa funzione, come ad esempio per le \acr{tty}\footnote{altri +supportano questa funzione, come ad esempio per le \acr{tty}.\footnote{altri sistemi, usando \macro{SEEK\_SET}, in questo caso ritornano il numero di - caratteri che vi sono stati scritti}. Lo standard POSIX però non specifica + caratteri che vi sono stati scritti.} Lo standard POSIX però non specifica niente al proposito. Infine alcuni device, ad esempio \file{/dev/null}, non causano un errore ma restituiscono un valore indefinito. @@ -563,7 +563,7 @@ Nella seconda versione delle \textit{Single Unix Specification}\footnote{questa funzione, e l'analoga \func{pwrite} sono state aggiunte nel kernel 2.1.60, il supporto nelle \acr{glibc}, compresa l'emulazione per i vecchi kernel che non hanno la system call, è stato - aggiunto con la versione 2.1} (quello che viene chiamato normalmente Unix98, + aggiunto con la versione 2.1.} (quello che viene chiamato normalmente Unix98, vedi \secref{sec:intro_opengroup}) è stata introdotta la definizione di un'altra funzione di lettura, \func{pread}, che diventa accessibile con la definizione: @@ -636,7 +636,7 @@ i file ordinari il numero di byte scritti da \var{count}, a meno di un errore. Negli altri casi si ha lo stesso comportamento di \func{read}. -Anche per \func{write} lo standard Unix98 definisce una analoga \func{pwrite} +Anche per \func{write} lo standard Unix98 definisce un'analoga \func{pwrite} per scrivere alla posizione indicata senza modificare la posizione corrente nel file, il suo prototipo è: \begin{prototype}{unistd.h} @@ -731,7 +731,7 @@ corrente nel file varier Si noti inoltre che anche i flag di stato del file (quelli settati dall'argomento \param{flag} di \func{open}) essendo tenuti nella voce della \textit{file table}\footnote{per la precisione nel campo \var{f\_flags} di - \var{file}}, vengono in questo caso condivisi. Ai file però sono associati + \var{file}.}, vengono in questo caso condivisi. Ai file però sono associati anche altri flag, dei quali l'unico usato al momento è \macro{FD\_CLOEXEC}, detti \textit{file descriptor flags}. Questi ultimi sono tenuti invece in \var{file\_struct}, e perciò sono specifici di ciascun processo e non vengono @@ -765,14 +765,13 @@ file sar corrente settata 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 è una operazione +Il problema è che usare due system call in successione non è un'operazione atomica; il problema è stato risolto introducendo la modalità \macro{O\_APPEND}. In questo caso infatti, come abbiamo descritto in precedenza, è il kernel che aggiorna automaticamente la posizione alla fine del file prima di effettuare la scrittura, e poi estende il file. Tutto questo avviene all'interno di una singola system call (la \func{write}) che non -essendo interrompibile da un altro processo costituisce una operazione -atomica. +essendo interrompibile da un altro processo costituisce un'operazione atomica. Un altro caso tipico in cui è necessaria l'atomicità è quello in cui si vuole creare un file di lock, bloccandosi se il file esiste. In questo caso la @@ -798,10 +797,10 @@ secondo tempo rispetto al momento della esecuzione della \func{write}. Per questo motivo, quando è necessaria una sincronizzazione dei dati, il sistema mette a disposizione delle funzioni che provvedono a forzare lo -scarico dei dati dai buffer del kernel\footnote{come già accennato neanche +scarico dei dati dai buffer del kernel.\footnote{come già accennato neanche questo da la garanzia assoluta che i dati siano integri dopo la chiamata, l'hardware dei dischi è in genere dotato di un suo meccanismo interno che - può ritardare ulteriormente la scrittura effettiva.}. La prima di queste + può ritardare ulteriormente la scrittura effettiva.} La prima di queste funzioni è \func{sync} il cui prototipo è: \begin{prototype}{unistd.h}{int sync(void)} @@ -847,10 +846,10 @@ di \var{fstat} come i tempi del file). Si tenga presente che questo non comporta la sincronizzazione della directory che contiene il file (e scrittura della relativa voce su -disco) che deve essere effettuata esplicitamente\footnote{in realtà per +disco) che deve essere effettuata esplicitamente.\footnote{in realtà per il filesystem \acr{ext2}, quando lo si monta con l'opzione \cmd{sync}, il kernel provvede anche alla sincronizzazione automatica delle voci - delle directory.}. + delle directory.} \subsection{La funzioni \func{dup} e \func{dup2}} @@ -1026,7 +1025,7 @@ avanti quando affronteremo le problematiche ad esse relative. Per determinare le modalità di accesso inoltre è necessario estrarre i bit di accesso (ottenuti con il comando \macro{F\_GETFL}); infatti la definizione corrente non assegna bit separati a \macro{O\_RDONLY}, \macro{O\_WRONLY} e -\macro{O\_RDWR}\footnote{posti rispettivamente ai valori 0, 1 e 2}, per cui il +\macro{O\_RDWR},\footnote{posti rispettivamente ai valori 0, 1 e 2.} per cui il valore si ottiene eseguendo un AND binario del valore di ritorno di \func{fcntl} con la maschera \macro{O\_ACCMODE} anch'essa definita in \file{fcntl.h}. diff --git a/intro.tex b/intro.tex index b03d1e3..e8d8a1f 100644 --- a/intro.tex +++ b/intro.tex @@ -195,10 +195,10 @@ Ad ogni utente richiesto all'ingresso nel sistema dalla procedura di \textit{login}. Questa procedura si incarica di verificare l'identità dell'utente, in genere attraverso la richiesta di una parola d'ordine, anche se sono possibili -meccanismi diversi\footnote{Ad esempio usando la libreria PAM +meccanismi diversi.\footnote{Ad esempio usando la libreria PAM (\textit{Pluggable Autentication Methods}) è possibile astrarre completamente i meccanismi di autenticazione e sostituire ad esempio l'uso - delle password con meccanismi di identificazione biometrica}. + delle password con meccanismi di identificazione biometrica.} Eseguita la procedura di riconoscimento in genere il sistema manda in esecuzione un programma di interfaccia (che può essere la \textit{shell} su @@ -229,8 +229,8 @@ Infine in ogni unix \acr{uid} è zero. Esso identifica l'amministratore del sistema, che deve essere in grado di fare qualunque operazione; per l'utente \textit{root} infatti i meccanismi di controllo descritti in precedenza sono -disattivati\footnote{i controlli infatti vengono sempre eseguiti da un codice - del tipo \texttt{if (uid) \{ ... \}}}. +disattivati.\footnote{i controlli infatti vengono sempre eseguiti da un codice + del tipo \texttt{if (uid) \{ ... \}}} \section{Gli standard di unix e GNU/Linux} diff --git a/network.tex b/network.tex index 12d5c88..b1f825f 100644 --- a/network.tex +++ b/network.tex @@ -529,8 +529,8 @@ Quando un pacchetto IP viene inviato su una interfaccia di rete e le sue dimensioni eccedono la MTU viene eseguita la cosiddetta \textit{frammentazione}, i pacchetti cioè vengono spezzati (sia da IPv4 che da IPv6, anche se i pacchetti frammentati sono gestiti con modalità -diverse\footnote{il primo usa un flag nell'header, il secondo una opportuna - opzione, si veda \secref{cha:ip_protocol}}), in blocchi più piccoli che +diverse,\footnote{il primo usa un flag nell'header, il secondo una opportuna + opzione, si veda \secref{cha:ip_protocol}.}) in blocchi più piccoli che possono essere trasmessi attraverso l'interfaccia. \begin{table}[!htb] diff --git a/process.tex b/process.tex index 483fbb9..554f4d6 100644 --- a/process.tex +++ b/process.tex @@ -23,9 +23,9 @@ programma: si possono avere pi ciascun processo vedrà la sua copia del codice (in realtà il kernel fa sì che tutte le parti uguali siano condivise), avrà un suo spazio di indirizzi, variabili proprie e sarà eseguito in maniera completamente indipendente da -tutti gli altri\footnote{questo non è del tutto vero nel caso di un programma +tutti gli altri.\footnote{questo non è del tutto vero nel caso di un programma \textit{multi-thread}, ma sulla gestione dei \textit{thread} in Linux - torneremo più avanti}. + torneremo più avanti.} \subsection{La funzione \func{main}} @@ -255,9 +255,9 @@ 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} 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 +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 2Gb, con il kernel - 2.4 ed il supporto per la \textit{high-memory} il limite è stato esteso}. + 2.4 ed il supporto per la \textit{high-memory} il limite è stato esteso.} Come accennato in \capref{cha:intro_unix} questo spazio di indirizzi è virtuale e non corrisponde all'effettiva posizione dei dati nella RAM del @@ -495,13 +495,13 @@ La funzione \func{realloc} si usa invece per cambiare (in genere aumentare) la dimensione di un'area di memoria precedentemente allocata, la funzione vuole in ingresso il puntatore restituito dalla precedente chiamata ad una \func{malloc} (se è passato un valore \macro{NULL} allora la funzione si -comporta come \func{malloc}\footnote{questo è vero per Linux e +comporta come \func{malloc},\footnote{questo è vero per Linux e l'implementazione secondo lo standard ANSI C, ma non è vero per alcune vecchie implementazioni, inoltre alcune versioni delle librerie del C consentivano di usare \func{realloc} anche per un puntatore liberato con \func{free} purché non ci fossero state nel frattempo altre chiamate a funzioni di allocazione, questa funzionalità è totalmente deprecata e non è - consentita sotto Linux.}), ad esempio quando si deve far crescere la + consentita sotto Linux.}) ad esempio quando si deve far crescere la dimensione di un vettore. In questo caso se è disponibile dello spazio adiacente al precedente la funzione lo utilizza, altrimenti rialloca altrove un blocco della dimensione voluta, copiandoci automaticamente il contenuto; lo @@ -1340,8 +1340,8 @@ motivo \macro{va\_list} direttamente ad un altra variabile dello stesso tipo. Per risolvere questo problema lo standard ISO C99\footnote{alcuni sistemi che non hanno questa macro provvedono al suo posto \macro{\_\_va\_copy} che era il nome proposto - in una bozza dello standard} ha previsto una macro ulteriore che permette di -eseguire la copia di un puntatore alla lista degli argomenti: + in una bozza dello standard.} ha previsto una macro ulteriore che permette +di eseguire la copia di un puntatore alla lista degli argomenti: \begin{prototype}{stdarg.h}{void va\_copy(va\_list dest, va\_list src)} Copia l'attuale valore \param{src} del puntatore alla lista degli argomenti su \param{dest}. diff --git a/prochand.tex b/prochand.tex index 4f72ab5..baced8d 100644 --- a/prochand.tex +++ b/prochand.tex @@ -453,7 +453,7 @@ si pu primo\footnote{a partire dal kernel 2.5.2-pre10 è stato introdotto il nuovo 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 + 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 passare all'esecuzione del figlio (completata con i due avvisi di esecuzione ed uscita), e tornare @@ -682,7 +682,7 @@ eseguite alla chiusura di un processo \item ad ogni processo figlio viene assegnato un nuovo padre (in genere \cmd{init}). \item viene inviato il segnale \macro{SIGCHLD} al processo padre (vedi - \secref{sec:sig_xxx}). + \secref{sec:sig_sigchld}). \item se il processo è un leader di sessione viene mandato un segnale di \macro{SIGHUP} a tutti i processi in background e il terminale di controllo viene disconnesso (vedi \secref{sec:sess_xxx}). @@ -799,7 +799,7 @@ si scrive un programma che deve essere mantenuto in esecuzione a lungo e creare molti figli. In questo caso si deve sempre avere cura di far leggere l'eventuale stato di uscita di tutti i figli (in genere questo si fa attraverso un apposito \textit{signal handler}, che chiama la funzione -\func{wait}, vedi \secref{sec:sig_xxx} e \secref{sec:proc_wait}). Questa +\func{wait}, vedi \secref{sec:sig_sigchld} e \secref{sec:proc_wait}). Questa operazione è necessaria perché anche se gli \textit{zombie} non consumano risorse di memoria o processore, occupano comunque una voce nella tabella dei processi, che a lungo andare potrebbe esaurirsi. @@ -964,9 +964,9 @@ avremo la certezza che la chiamata a \func{wait} non si bloccher \macro{WIFSIGNALED} ha restituito un valore non nullo.\\ \macro{WCOREDUMP(s)} & Vera se il processo terminato ha generato un file si \textit{core dump}. Può essere valutata solo se - \macro{WIFSIGNALED} ha restituito un valore non nullo\footnote{questa + \macro{WIFSIGNALED} ha restituito un valore non nullo.\footnote{questa macro non è definita dallo standard POSIX.1, ma è presente come estensione - sia in Linux che in altri unix}.\\ + sia in Linux che in altri Unix.}\\ \macro{WIFSTOPPED(s)} & Vera se il processo che ha causato il ritorno di \func{waitpid} è bloccato. L'uso è possibile solo avendo specificato l'opzione \macro{WUNTRACED}. \\ @@ -1208,7 +1208,7 @@ la lista completa \item il \textit{session id} ed il \textit{process group id} (vedi \secref{sec:sess_xxx}). \item il terminale di controllo (vedi \secref{sec:sess_xxx}). -\item il tempo restante ad un allarme (vedi \secref{sec:sig_xxx}). +\item il tempo restante ad un allarme (vedi \secref{sec:sig_alarm_abort}). \item la directory radice e la directory di lavoro corrente (vedi \secref{sec:file_work_dir}). \item la maschera di creazione dei file (\var{umask}, vedi @@ -1286,7 +1286,7 @@ problematiche connesse ad una gestione accorta dei privilegi. Come accennato in \secref{sec:intro_multiuser} il modello base\footnote{in realtà già esistono estensioni di questo modello base, che lo rendono più flessibile e controllabile, come le \textit{capabilities}, le ACL per i file - o il \textit{Mandatory Access Control} di SELinux} di sicurezza di un + o il \textit{Mandatory Access Control} di SELinux.} di sicurezza di un sistema unix-like è fondato sui concetti di utente e gruppo, e sulla separazione fra l'amministratore (\textsl{root}, detto spesso anche \textit{superuser}) che non è sottoposto a restrizioni, ed il resto degli @@ -1881,11 +1881,11 @@ Il concetto di priorit l'esecuzione, vince sempre quello con la priorità assoluta più alta, anche quando l'altro è in esecuzione (grazie al \textit{prehemptive scheduling}). Ovviamente questo avviene solo per i processi che sono pronti per essere -eseguiti (cioè nello stato \textit{runnable}\footnote{lo stato di un processo +eseguiti (cioè nello stato \textit{runnable},\footnote{lo stato di un processo è riportato nel campo \texttt{STAT} dell'output del comando \cmd{ps}, abbiamo già visto che lo stato di \textit{zombie} è indicato con \texttt{Z}, gli stati \textit{runnable}, \textit{sleep} e di I/O (\textit{uninteruttible - sleep}) sono invece indicati con \texttt{R}, \texttt{S} e \texttt{D}.}), + sleep}) sono invece indicati con \texttt{R}, \texttt{S} e \texttt{D}.}) la priorità assoluta viene invece ignorata per quelli che sono bloccati su una richiesta di I/O o in stato di \textit{sleep}. La priorità assoluta viene in genere indicata con un numero intero, ed un valore più alto comporta una diff --git a/signal.tex b/signal.tex index aad92a9..90885ff 100644 --- a/signal.tex +++ b/signal.tex @@ -45,8 +45,8 @@ il seguente: \item una richiesta dell'utente di terminare o fermare il programma. In genere si realizza attraverso un segnale mandato dalla shell in corrispondenza della pressione di tasti del terminale come \code{C-c} o - \code{C-z}\footnote{indichiamo con \code{C-x} la pressione simultanea al - tasto \code{x} del tasto control (ctrl in molte tastiere)}. + \code{C-z}.\footnote{indichiamo con \code{C-x} la pressione simultanea al + tasto \code{x} del tasto control (ctrl in molte tastiere).} \item l'esecuzione di una \func{kill} o di una \func{raise} da parte del processo stesso o di un'altro (solo nel caso della \func{kill}). \end{itemize*} @@ -873,7 +873,7 @@ da essere del tutto inutile in un sistema Unix; ogni implementazione successiva ne ha modificato e ridefinito il comportamento, pur mantenendone immutato il prototipo\footnote{in realtà alcune vecchie implementazioni (SVR4 e 4.3+BSD) usano parametri aggiuntivi - per definire il comportamento della funzione} che è: + per definire il comportamento della funzione.} che è: \begin{prototype}{signal.h} {sighandler\_t signal(int signum, sighandler\_t handler)} @@ -898,10 +898,10 @@ con il precedente prototipo si pu typedef void (* sighandler_t)(int) \end{verbatim} e cioè un puntatore ad una funzione \type{void} (cioè senza valore di ritorno) -e che prende un argomento di tipo \type{int}\footnote{si devono usare le +e che prende un argomento di tipo \type{int}.\footnote{si devono usare le parentesi intorno al nome della funzione per via delle precedenze degli operatori del C, senza di esse si sarebbe definita una funzione che ritorna - un puntatore a \type{void} e non un puntatore ad una funzione \type{void}}. + un puntatore a \type{void} e non un puntatore ad una funzione \type{void}.} La funzione \func{signal} quindi restituisce e prende come secondo argomento un puntatore a una funzione di questo tipo, che è appunto il manipolatore del segnale. @@ -911,19 +911,30 @@ direttamente con una delle costanti definite in \secref{sec:sig_standard}. Il manipolatore \param{handler} invece, oltre all'indirizzo della funzione da chiamare all'occorrenza del segnale, può assumere anche i due valori costanti \macro{SIG\_IGN} con cui si dice ignorare il segnale e \macro{SIG\_DFL} per -installare l'azione di di default\footnote{si ricordi però che i due segnali +installare l'azione di di default.\footnote{si ricordi però che i due segnali \macro{SIGKILL} e \macro{SIGSTOP} non possono essere ignorati né - intercettati}. - -La funzione \func{signal} originale (e quella attuale in System V) era -conforme alla semantica inaffidabile e resettava l'azione di default a -\macro{SIG\_DEF}; Linux fino alle \acr{libc4} e le \acr{libc5} seguiva la -stessa semantica; al contrario con l'utilizzo delle \acr{glibc2}, Linux, come -BSD, non resetta il manipolatore e blocca il segnale durante la chiamata. La -versione originale della funzione, il cui uso è deprecato, può essere -utilizzata chiamando \func{sysv\_signal}. - -È da tenere presente che seguendo lo standard POSIX, il comportamento di un + intercettati.} + +La funzione restituisce l'indirizzo dell'azione precedente, che può essere +salvato per poterlo ripristinare (con un'altra chiamata a \func{signal}) in un +secondo tempo. Si ricordi che se si setta come azione \macro{SIG\_IGN} (o si +setta un \macro{SIG\_DFL} per un segnale il cui default è di essere ignorato), +tutti i segnali pendenti saranno scartati, e non verranno mai notificati. + +L'uso di \func{signal} è soggetto a problemi di compatibilità, dato che essa +si comporta in maniera diversa per sistemi derivati da BSD o da System V. In +questi ultimi infatti la funzione è conforme al comportamento originale dei +primi Unix in cui il manipolatore viene disinstallato alla sua chiamata +secondo la semantica inaffidabile; Linux seguiva questa convenzione fino alle +\acr{libc5}. Al contrario BSD segue la semantica affidabile, non resettando il +manipolatore e bloccando il segnale durante l'esecuzione dello stesso. Con +l'utilizzo delle \acr{glibc2} anche Linux è passato a questo comportamento; +quello della versione originale della funzione, il cui uso è deprecato per i +motivi visti in \secref{sec:sig_semantics}, può essere ottenuto chiamando +\func{sysv\_signal}. In generale, per evitare questi problemi, tutti i nuovi +programmi dovrebbero usare \func{sigaction}. + +È da tenere presente che, seguendo lo standard POSIX, il comportamento di un processo che ignora i segnali \macro{SIGFPE}, \macro{SIGILL}, o \macro{SIGSEGV} (qualora non originino da una \func{kill} o una \func{raise}) è indefinito. Un manipolatore che ritorna da questi segnali può dare luogo ad @@ -934,16 +945,33 @@ un ciclo infinito. \label{sec:sig_kill_raise} Come accennato in \secref{sec:sig_types}, un segnale può essere generato -``artificialmente'' attraverso l'uso delle funzioni \func{kill} e -\func{raise}, i cui prototipi sono: +direttamente da un processo. L'invio di un sengale generico può essere +effettuato attraverso delle funzioni \func{kill} e \func{raise}. La prima +serve per inviare un segnale al processo corrente, ed il suo prototipo è: +\begin{prototype}{signal.h}{int raise(int sig)} + Invia il segnale \param{sig} al processo corrente. + + \bodydesc{La funzione restituisce zero in caso di successo e -1 per un + errore, il solo errore restituito è \macro{EINVAL} qualora si sia + specificato un numero di segnale invalido.} +\end{prototype} + +Il valore di \param{sig} specifica il segnale che si vuole inviare e può +essere specificato con una delle macro definite in +\secref{sec:sig_classification}. In genere questa funzione viene usata per +riprodurre il comportamento di default di un segnale che sia stato +intercettato. In questo caso, una volta eseguite le operazioni volute, il +manipolatore potrà reinstallare l'azione di default, e attivarla con +\func{raise}. + +Se invece si vuole inviare un segnale ad un altro processo occorre utilizzare +la funzione \func{kill}; il suo prototipo è: \begin{functions} \headdecl{sys/types.h} \headdecl{signal.h} - \funcdecl{int kill(pid\_t pid, int sig)} invia il segnale \param{sig} al + \funcdecl{int kill(pid\_t pid, int sig)} Invia il segnale \param{sig} al processo specificato con \param{pid}. - \funcdecl{int raise(int sig)} invia il segnale \param{sig} al processo - corrente. - + \bodydesc{La funzione restituisce zero in caso di successo e -1 per un errore, nel qual caso \var{errno} assumerà i valori: \begin{errlist} @@ -957,26 +985,19 @@ Come accennato in \secref{sec:sig_types}, un segnale pu \end{functions} La funzione \code{raise(sig)} è sostanzialmente equivalente ad una -\code{kill(getpid(), sig)}. Il valore di \param{sig} specifica il segnale che -si vuole inviare e può essere specificato con una delle macro definite in -\ref{sec:sig_classification}. +\code{kill(getpid(), sig)}. Siccome \func{raise} è definita nello standard ISO +C non esiste in alcune vecchie versioni di Unix, per cui in generale l'uso di +\func{kill} è più portabile. Lo standard POSIX poi prevede che il valore 0 sia usato per specificare il segnale nullo. Se le funzioni vengono chiamate con questo valore non viene inviato nessun segnale, ma viene eseguito il controllo degli errori, in tal caso si otterrà un errore \macro{EPERM} se non si hanno i permessi necessari ed un errore \macro{ESRCH} se il processo specificato non esiste. Si tenga -conto però che il sistema ricicla i \acr{pid}, così come visto in -\secref{sec:proc_pid}, per cui l'esistenza di un processo non significa che +conto però che il sistema ricicla i \acr{pid} (come accennato in +\secref{sec:proc_pid}) per cui l'esistenza di un processo non significa che esso sia realmente quello a cui si intendeva mandare il segnale. -Per poter effettuare l'invio del segnale ad un altro processo, si devono -possedere i privilegi di amministratore, oppure il \textit{real user id} o -l'\textit{effective user id} del chiamante devono corrispondere al -\textit{real user id} o al \textit{aved user id} della destinazione. Nel caso -del segnale \macro{SIGCONT} entrambi i processi devono appartenere alla stessa -sessione. - Il valore dell'argomento \param{pid} specifica la destinazione a cui inviare il segnale e può assumere i seguenti significati: \begin{basedescript}{\desclabelwidth{2cm}\desclabelstyle{\nextlinelabel}} @@ -990,13 +1011,117 @@ il segnale e pu group $|\code{pid}|$. \end{basedescript} +Solo l'amministratore può inviare un segnale ad un processo qualunque, in +tutti gli altri casi il \textit{real user id} o l'\textit{effective user id} +del processo chiamante devono corrispondere al \textit{real user id} o al +\textit{saved user id} della destinazione. Fa eccezione il caso in cui il +segnale inviato sia \macro{SIGCONT}, nel quale occorre che entrambi i processi +appartengano alla stessa sessione. Inoltre, dato il ruolo fondamentale che +riveste nel sistema (si ricordi quanto visto in \secref{sec:sig_termination}), +non è possibile inviare al processo 1 (cioè a \cmd{init}) segnali per i quali +esso non abbia un manipolatore installato. + +Infine, seguendo le specifiche POSIX 1003.1-2001, l'uso della chiamata +\code{kill(-1, sig)} comporta che il segnale sia inviato (con la solita +eccezione di \cmd{init}) a tutti i processi per i quali i permessi lo +consentano. Lo standard permette comunque alle varie implementazione di +escludere alcuni processi specifici: nel caso in questione Linux non invia il +segnale al processo che ha effettuato la chiamata. + + +\subsection{Le funzioni \func{alarm} e \func{abort}} +\label{sec:sig_alarm_abort} + +Un caso particolare di segnali generati a richiesta è quello che riguarda i +segnali di temporizzazione e e \macro{SIGABORT}, per i quali sono previste +funzioni specifiche che ne effettuino l'invio. La prima di queste è +\func{alarm} il cui prototipo è: +\begin{prototype}{unistd.h}{unsigned int alarm(unsigned int seconds)} + Predispone l'invio di \macro{SIGALARM} dopo \param{seconds} secondi. + + \bodydesc{La funzione restituisce il numero di secondi rimanenti ad un + precedente allarme, o zero se non c'erano allarmi pendenti.} +\end{prototype} -\subsection{Le funzioni \func{alarm} e \func{pause}} -\label{sec:sig_alarm_pause} +La funzione provvede un meccanismo che consente ad un processo di predisporre +un'interruzione nel futuro, (ad esempio per effettuare una qualche operazione +dopo un certo periodo di tempo), programmando l'emissione si un segnale di +\macro{SIGALARM} dopo il numero di secondi specificato da \param{seconds}. +Chiaramente la precisione è determinata da quella dell'orologio di sistema, e +sono sempre possibili ritardi in caso di un sistema eccessivamente carico. + +Se si specifica per \param{seconds} un valore nullo non verrà inviato nessun +segnale; siccome alla chiamata viene cancellato ogni precedente allarme, +questo può essere usato per cancellare una programmazione precedente. La +funzione inoltre ritorna il numero di secondi rimanenti all'invio dell'allarme +precedentemente programmato, in modo che sia eventualmente possibile +effettuare delle scelte in caso di necessità di più interruzioni. + +In \secref{sec:sys_unix_time} abbiamo visto che ad ogni processo sono +associati tre tempi diversi: \textit{clock time}, \textit{user time} e +\textit{system time}. Per poterli calcolare il kernel mantiene tre diversi +timer per ciascun processo: +\begin{itemize} +\item un \textit{real-time timer} che calcola il tempo reale trascorso (che + corrisponde al \textit{clock time}). La scadenza di questo timer provoca + l'emissione di \macro{SIGALARM}. +\item un \textit{virtual timer} che calcola il tempo di processore usato dal + processo in user space (che corrisponde all'\textit{user time}). La scadenza + di questo timer provoca l'emissione di \macro{SIGVTALRM}. +\item un \textit{profiling timer} che calcola la somma dei tempi di processore + utilizzati direttamente dal processo in user space, e dal kernel nelle + system call ad esso relative (che corrisponde a quello che in + \secref{sec:sys_unix_time} abbiamo chiamato \textit{CPU time}). La scadenza + di questo timer provoca l'emissione di \macro{SIGPROF}. +\end{itemize} + +Il timer usato da \func{alarm} è il \textit{clock time}, e corrisponde cioè al +tempo reale. Dato che \func{alarm} non consente di usare gli altri timer, e +non può specificare intervalli con precisione maggiore al secondo le +\acr{glibc} provvedono la funzione \func{setitimer} che permette un controllo +completo, a scapito di un uso molto più complesso. Il suo prototipo è: +\begin{prototype}{sys/time.h}{int setitimer(int which, const struct + itimerval *value, struct itimerval *ovalue)} + + Predispone l'invio di un segnale di allarme alla scadenza dell'intervallo + \param{value} sul timer specificato da \func{which}. + + \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di + errore, nel qual caso \var{errno} può assumere i valori \macro{EINVAL} e + \macro{EFAULT}.} +\end{prototype} +Il valore di \param{which} permette di specificare quale dei tre timer usare; +i possibili valori sono riportati in \tabref{tab:sig_setitimer_values}. + +\begin{table}[htb] + \centering + \begin{tabular}[c]{|l|l|} + \hline + \textbf{Valore} & \textbf{Timer} \\ + \hline + \hline + \macro{ITIMER\_REAL} & \textit{real-time timer}\\ + \macro{ITIMER\_VIRTUAL} & \textit{virtual timer}\\ + \macro{ITIMER\_PROF} & \textit{profiling timer}\\ + \hline + \end{tabular} + \caption{Valori dell'argomento \param{which} per la funzione + \func{setitimer}.} + \label{tab:sig_setitimer_values} +\end{table} + + +\subsection{Le funzioni \func{pause} e \func{sleep}} +\label{sec:sig_pause_sleep} + + + + + +\subsection{Le semantiche di \macro{SIGCHLD}} +\label{sec:sig_sigchld} -\subsection{Funzioni rientranti e default dei segnali} -\label{sec:sig_reentrant} @@ -1016,6 +1141,9 @@ il segnale e pu +\subsection{Funzioni rientranti e default dei segnali} +\label{sec:sig_reentrant} + , affrontando inoltre le varie problematiche di programmazione che si devono tenere presenti quando si ha a che fare con essi. diff --git a/simpltcp.tex b/simpltcp.tex index c119df0..f210f21 100644 --- a/simpltcp.tex +++ b/simpltcp.tex @@ -8,13 +8,13 @@ comunicazione in entrambe le direzioni. Inoltre prenderemo in esame, oltre al comportamento in condizioni normali, anche tutti i possibili scenari particolari (errori, sconnessione della rete, crash del client o del server durante la connessione) che possono avere luogo -durante l'impiego di una applicazione di rete. +durante l'impiego di un'applicazione di rete. \section{Il servizio \texttt{echo}} \label{sec:TCPsimp_echo} -L'applicazione scelta come esempio sarà una implementazione elementare, ma +L'applicazione scelta come esempio sarà un'implementazione elementare, ma completa, del servizio \texttt{echo}. Il servizio \texttt{echo} è uno dei servizi standard solitamente provvisti direttamente dal superserver \cmd{inetd}, ed è definito dall'RFC~862. Come dice il nome il servizio deve @@ -35,10 +35,10 @@ risponde alle richieste di un client; tutto quello che cambia nel caso si una applicazione più complessa è la elaborazione dell'input del client da parte del server nel fornire le risposte in uscita. -Partiremo da una implementazione elementare che dovrà essere rimaneggiata di +Partiremo da un'implementazione elementare che dovrà essere rimaneggiata di volta in volta per poter tenere conto di tutte le evenienze che si possono -manifestare nella vita reale di una applicazione di rete, fino ad arrivare ad -una implementazione completa. +manifestare nella vita reale di un'applicazione di rete, fino ad arrivare ad +un'implementazione completa. \subsection{La struttura del server} \label{sec:TCPsimp_server_main} @@ -262,7 +262,7 @@ il client esce. Benché il codice dell'esempio precedente sia molto ridotto, esso ci permetterà di considerare in dettaglio tutte le problematiche che si possono incontrare -nello scrivere una applicazione di rete. Infatti attraverso l'esame delle sue +nello scrivere un'applicazione di rete. Infatti attraverso l'esame delle sue modalità di funzionamento normali, all'avvio e alla terminazione, e di quello che avviene nelle varie situazioni limite, da una parte potremo approfondire la comprensione del protocollo TCP/IP e dall'altra ricavare le indicazioni diff --git a/socket.tex b/socket.tex index 36f1f3e..619c1dd 100644 --- a/socket.tex +++ b/socket.tex @@ -8,7 +8,7 @@ operativi. Dopo una breve panoramica sulle caratteristiche di questa interfaccia vedremo come creare un socket e come collegarlo allo specifico protocollo di rete che -utilizzerà per la comunicazione. Per evitare una introduzione puramente teorica +utilizzerà per la comunicazione. Per evitare un'introduzione puramente teorica concluderemo il capitolo con un primo esempio di applicazione. \section{Una panoramica} @@ -22,9 +22,9 @@ con essi. \label{sec:sock_socket_def} Il \textit{socket}\footnote{una traduzione letterale potrebbe essere - \textsl{manicotto}, ma essendo universalmente noti come socket utilizzeremo - sempre la parola inglese} è uno dei principali meccanismi di comunicazione -fra programmi utilizzato in ambito unix. Il socket costituisce in sostanza un + \textsl{presa}, ma essendo universalmente noti come socket utilizzeremo + sempre la parola inglese.} è uno dei principali meccanismi di comunicazione +fra programmi utilizzato in ambito Unix. Il socket costituisce in sostanza un canale di comunicazione fra due processi su cui si possono leggere e scrivere dati analogo a quello di una pipe ma a differenza di questa e degli altri meccanismi esaminati nel capitolo \capref{cha:IPC} i socket non sono limitati @@ -430,7 +430,7 @@ problema e le relative soluzioni). \subsection{La struttura degli indirizzi IPv6} \label{sec:sock_sa_ipv6} -Essendo IPv6 una estensione di IPv4 i socket di tipo \macro{PF\_INET6} sono +Essendo IPv6 un'estensione di IPv4 i socket di tipo \macro{PF\_INET6} sono sostanzialmente identici ai precedenti; la parte in cui si trovano praticamente tutte le differenze è quella della struttura degli indirizzi. La struttura degli indirizzi è definita ancora in \file{netinet/in.h}. @@ -912,7 +912,7 @@ Il primo passo (\texttt{\small 14--18}) socket in tutte le chiamate successive. Nel caso la chiamata fallisca si stampa un errore con la relativa routine e si esce. -Il passo seguente (\texttt{\small 19--27}) è quello di costruire una apposita +Il passo seguente (\texttt{\small 19--27}) è quello di costruire un'apposita struttura \type{sockaddr\_in} in cui sarà inserito l'indirizzo del server ed il numero della porta del servizio. Il primo passo è inizializzare tutto a zero, per poi inserire il tipo di protocollo e la porta (usando per diff --git a/system.tex b/system.tex index 067dd59..062b90d 100644 --- a/system.tex +++ b/system.tex @@ -49,7 +49,7 @@ La prima funzionalit contengono le costanti necessarie definite come macro di preprocessore, per la seconda invece sono ovviamente necessarie delle funzioni. La situazione è complicata dal fatto che ci sono molti casi in cui alcuni di questi limiti -sono fissi in una implementazione mentre possono variare in un altra. Tutto +sono fissi in un'implementazione mentre possono variare in un altra. Tutto questo crea una ambiguità che non è sempre possibile risolvere in maniera chiara; in generale quello che succede è che quando i limiti del sistema sono fissi essi vengono definiti come macro di preprocessore nel file @@ -476,7 +476,7 @@ suo prototipo \subsection{La funzione \func{uname}} \label{sec:sys_uname} -Una altra funzione che si può utilizzare per raccogliere informazioni sia +Un'altra funzione che si può utilizzare per raccogliere informazioni sia riguardo al sistema che al computer su cui esso sta girando è \func{uname}, il suo prototipo è: \begin{prototype}{sys/utsname.h}{int uname(struct utsname *info)} @@ -636,7 +636,7 @@ Come accennato in \secref{sec:file_organization} per poter accedere ai file occorre prima rendere disponibile al sistema il filesystem su cui essi sono memorizzati; l'operazione di attivazione del filesystem è chiamata \textsl{montaggio}, per far questo in Linux\footnote{la funzione è specifica - di Linux e non è portabile} si usa la funzione \func{mount} il cui prototipo + di Linux e non è portabile.} si usa la funzione \func{mount} il cui prototipo è: \begin{prototype}{sys/mount.h} {mount(const char *source, const char *target, const char *filesystemtype, @@ -780,13 +780,13 @@ Una volta che non si voglia pi \macro{ENAMETOOLONG}, \macro{ENOENT} o \macro{ELOOP}.} \end{prototype} \noindent la funzione prende il nome della directory su cui il filesystem è -montato e non il file o il dispositivo che è stato montato\footnote{questo è +montato e non il file o il dispositivo che è stato montato,\footnote{questo è vero a partire dal kernel 2.3.99-pre7, prima esistevano due chiamate separate e la funzione poteva essere usata anche specificando il file di - dispositivo.}, in quanto con il kernel 2.4.x è possibile montare lo stesso + dispositivo.} in quanto con il kernel 2.4.x è possibile montare lo stesso dispositivo in più punti. Nel caso più di un filesystem sia stato montato sullo stesso \textit{mount point} viene smontato quello che è stato montato -per ultimo. +per ultimo. Si tenga presente che la funzione fallisce quando il filesystem è \textsl{occupato}, questo avviene quando ci sono ancora file aperti sul @@ -811,8 +811,8 @@ seconda del tipo di filesystem alcune (o tutte) possono essere superate, evitando l'errore di \macro{EBUSY}. In tutti i casi prima dello smontaggio viene eseguita una sincronizzazione dei dati. -Altre due funzioni specifiche di Linux\footnote{esse si trovano anche su BSD, - ma con una struttura diversa}, utili per ottenere in maniera diretta +Altre due funzioni specifiche di Linux,\footnote{esse si trovano anche su BSD, + ma con una struttura diversa.} utili per ottenere in maniera diretta informazioni riguardo al filesystem su cui si trova un certo file, sono \func{statfs} e \func{fstatfs}, i cui prototipi sono: \begin{functions} @@ -964,13 +964,13 @@ date e del tempo in un sistema unix-like, e quelle per convertire i vari tempi nelle differenti rappresentazioni che vengono utilizzate. -\subsection{La misura del tempo in unix} +\subsection{La misura del tempo in Unix} \label{sec:sys_unix_time} -Storicamente i sistemi unix-like hanno sempre mantenuto due distinti -valori per i tempi all'interno del sistema, essi sono rispettivamente -chiamati \textit{calendar time} e \textit{process time}, secondo le -definizioni: +Storicamente i sistemi unix-like hanno sempre mantenuto due distinti tipi di +dati per la misure dei tempi all'interno del sistema: essi sono +rispettivamente chiamati \textit{calendar time} e \textit{process time}, +secondo le definizioni: \begin{itemize} \item \textit{calendar time}: è il numero di secondi dalla mezzanotte del primo gennaio 1970, in tempo universale coordinato (o UTC), data che viene @@ -980,11 +980,11 @@ definizioni: viene mantenuto l'orologio del calcolatore, e viene usato ad esempio per indicare le date di modifica dei file o quelle di avvio dei processi. Per memorizzare questo tempo è stato riservato il tipo primitivo \type{time\_t}. -\item \textit{process time}: talvolta anche detto tempo di CPU. Viene misurato +\item \textit{process time}: detto anche tempo di processore. Viene misurato in \textit{clock tick}, corrispondenti al numero di interruzioni effettuate dal timer di sistema, e che per Linux avvengono ogni centesimo di - secondo\footnote{eccetto per la piattaforma alpha dove avvengono ogni - millesimo di secondo}. Il dato primitivo usato per questo tempo è + secondo.\footnote{eccetto per la piattaforma alpha dove avvengono ogni + millesimo di secondo.} Il dato primitivo usato per questo tempo è \type{clock\_t}, inoltre la costante \macro{HZ} restituisce la frequenza di operazione del timer, e corrisponde dunque al numero di tick al secondo. Lo standard POSIX definisce allo stesso modo la costante \macro{CLK\_TCK}); @@ -992,32 +992,35 @@ definizioni: \secref{sec:sys_limits}). \end{itemize} -In genere si usa il \textit{calendar time} per tenere le date dei file e le -informazioni analoghe che riguardano i tempi di ``orologio'', usati ad esempio -per i demoni che compiono lavori amministrativi ad ore definite, come -\cmd{cron}. Di solito questo vene convertito automaticamente dal valore in UTC -al tempo locale, utilizzando le opportune informazioni di localizzazione +In genere si usa il \textit{calendar time} per esprimere le date dei file e le +informazioni analoghe che riguardano i cosiddetti \textsl{tempi di orologio}, +che vengono usati ad esempio per i demoni che compiono lavori amministrativi +ad ore definite, come \cmd{cron}. + +Di solito questo tempo viene convertito automaticamente dal valore in UTC al +tempo locale, utilizzando le opportune informazioni di localizzazione (specificate in \file{/etc/timezone}). E da tenere presente che questo tempo è -mantenuto dal sistema e non corrisponde all'orologio hardware del calcolatore. +mantenuto dal sistema e non è detto che corrisponda al tempo tenuto +dall'orologio hardware del calcolatore. -Il \textit{process time} di solito si esprime in secondi e viene usato appunto -per tenere conto dei tempi di esecuzione dei processi. Per ciascun processo il -kernel tiene tre di questi tempi: -\begin{itemize*} -\item \textit{clock time} -\item \textit{user time} -\item \textit{system time} -\end{itemize*} -il primo è il tempo ``reale'' (viene anche chiamato \textit{wall clock time}) -dall'avvio del processo, e misura il tempo trascorso fino alla sua -conclusione; chiaramente un tale tempo dipende anche dal carico del sistema e -da quanti altri processi stavano girando nello stesso periodo. Il secondo -tempo è quello che la CPU ha speso nell'esecuzione delle istruzioni del -processo in user space. Il terzo è il tempo impiegato dal kernel per eseguire -delle system call per conto del processo medesimo (tipo quello usato per -eseguire una \func{write} su un file). In genere la somma di user e system -time viene chiamato \textit{CPU time}. +Anche il \textit{process time} di solito si esprime in secondi, ma provvede una +precisione ovviamente superiore al \textit{calendar time} (la cui granularità +minima è il secondo) e viene usato per tenere conto dei tempi di esecuzione +dei processi. Per ciascun processo il kernel calcola tre tempi diversi: +\begin{description*} +\item[\textit{clock time}]: il tempo \textsl{reale} (viene chiamato anche + \textit{wall clock time}) passato dall'avvio del processo. Chiaramente tale + tempo dipende anche dal carico del sistema e da quanti altri processi + stavano girando nello stesso periodo. +\item[\textit{user time}]: il tempo che la CPU ha impiegato nell'esecuzione + delle istruzioni del processo in user space. +\item[\textit{system time}]: il tempo che la CPU ha impiegato nel kernel per + eseguire delle system call per conto del processo. +\end{description*} +In genere la somma di \textit{user time} e \textit{system time} indica il +tempo di processore totale in cui il sistema è stato effettivamente impegnato +nell'eseguire un certo processo e viene chiamato \textit{CPU time}. @@ -1044,11 +1047,11 @@ costante \macro{EOF} (a seconda della funzione); ma questo valore segnala solo che c'è stato un errore, non il tipo di errore. Per riportare il tipo di errore il sistema usa la variabile globale -\var{errno}\footnote{L'uso di una variabile globale può comportare alcuni +\var{errno},\footnote{L'uso di una variabile globale può comportare alcuni problemi (ad esempio nel caso dei thread) ma lo standard ISO C consente anche di definire \var{errno} come un \textit{modifiable lvalue}, quindi si può anche usare una macro, e questo è infatti il modo usato da Linux per - renderla locale ai singoli thread.}, definita nell'header \file{errno.h}; la + renderla locale ai singoli thread.} definita nell'header \file{errno.h}; la variabile è in genere definita come \type{volatile} dato che può essere cambiata in modo asincrono da un segnale (per una descrizione dei segnali si veda \secref{cha:signals}), ma dato che un manipolatore di segnale scritto @@ -1095,7 +1098,7 @@ errore sconosciuto. La funzione utilizza una stringa statica che non deve essere modificata dal programma e che è utilizzabile solo fino ad una chiamata successiva a \func{strerror}; nel caso si usino i thread è provvista\footnote{questa funzione è una estensione GNU, non fa parte dello - standard POSIX} una versione apposita: + standard POSIX.} una versione apposita: \begin{prototype}{string.h} {char *strerror\_r(int errnum, char *buff, size\_t size)} Analoga a \func{strerror} ma ritorna il messaggio in un buffer @@ -1106,7 +1109,7 @@ provvista\footnote{questa funzione che utilizza un buffer che il singolo thread deve allocare, per evitare i problemi connessi alla condivisione del buffer statico. Infine, per completare la caratterizzazione dell'errore, si può usare anche la variabile -globale\footnote{anche questa è una estensione GNU} +globale\footnote{anche questa è un'estensione GNU.} \var{program\_invocation\_short\_name} che riporta il nome del programma attualmente in esecuzione. -- 2.30.2