indicizzazioni.
%% errors.tex
%%
-%% Copyright (C) 2000-2006 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2007 Simone Piccardi. Permission is granted to
%% copy, distribute and/or modify this document under the terms of the GNU Free
%% Documentation License, Version 1.1 or any later version published by the
%% Free Software Foundation; with the Invariant Sections being "Un preambolo",
%% license is included in the section entitled "GNU Free Documentation
%% License".
%%
+
\chapter{I codici di errore}
\label{cha:errors}
accessibili attraverso l'inclusione del file di header \file{errno.h}, che
definisce anche la variabile globale \var{errno}. Per ogni errore definito
riporteremo la stringa stampata da \func{perror} ed una breve spiegazione. Si
-tenga presente che spiegazioni più particolareggiate, qualora necessarie per
-il caso specifico, possono essere trovate nella descrizione del prototipo
-della funzione.
+tenga presente che spiegazioni più particolareggiate del significato
+dell'errore, qualora necessarie per casi specifici, possono essere trovate
+nella descrizione del prototipo della funzione per cui detto errore si è
+verificato.
I codici di errore sono riportati come costanti di tipo \ctyp{int}, i valori
delle costanti sono definiti da macro di preprocessore nel file citato, e
-
-
% \section{Errori del kernel}
% \label{sec:err_kernel_err}
% \end{description}
-
-%%% Local Variables:
-%%% mode: latex
-%%% TeX-master: "gapil"
-%%% End:
-
% LocalWords: header errno perror int strerror sez EPERM Operation not ENOENT
% LocalWords: permitted such pathname EIO error ENXIO device address kernel Is
% LocalWords: ENOEXEC Invalid executable format exec EBADF Bad descriptor Too
% LocalWords: SysV EMULTIHOP Multihop attempted ENODATA ENOLINK been severed
% LocalWords: ENOMSG desired ENOSR streams resources ENOSTR stream EOVERFLOW
% LocalWords: Value large defined STAT EPROTO ETIME Timer expired
+
+
+%%% Local Variables:
+%%% mode: latex
+%%% TeX-master: "gapil"
+%%% End:
%% fileadv.tex
%%
-%% Copyright (C) 2000-2006 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2007 Simone Piccardi. Permission is granted to
%% copy, distribute and/or modify this document under the terms of the GNU Free
%% Documentation License, Version 1.1 or any later version published by the
%% Free Software Foundation; with the Invariant Sections being "Un preambolo",
possibile prevedere quando questo può avvenire (il caso più classico è quello
di un server in attesa di dati in ingresso da vari client). Quello che può
accadere è di restare bloccati nell'eseguire una operazione su un file
-descriptor che non è ``\textsl{pronto}'', quando ce ne potrebbe essere
-un altro disponibile. Questo comporta nel migliore dei casi una operazione
+descriptor che non è ``\textsl{pronto}'', quando ce ne potrebbe essere 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}\itindex{deadlock}.
+potrebbe addirittura arrivare ad un \itindex{deadlock} \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
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}\itindex{polling}, è
+Ovviamente questa tecnica, detta \itindex{polling} \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.
grafica) sono state successivamente introdotte delle estensioni che
permettessero la creazione di meccanismi di notifica più efficienti dell'unica
soluzione disponibile con l'interfaccia tradizionale, che è quella del
-\itindex{polling}\textit{polling}.
+\itindex{polling} \textit{polling}.
Queste nuove funzionalità sono delle estensioni specifiche, non
standardizzate, che sono disponibili soltanto su Linux (anche se altri kernel
Benché la modalità di apertura asincrona di un file possa risultare utile in
varie occasioni (in particolar modo con i socket e gli altri file per i quali
-le funzioni di I/O sono \index{system~call~lente}system call lente), essa è
+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 asincrono vero
Una modalità alternativa di I/O, che usa una interfaccia completamente diversa
rispetto a quella classica vista in cap.~\ref{cha:file_unix_interface}, è il
cosiddetto \textit{memory-mapped I/O}, che, attraverso il meccanismo della
-\textsl{paginazione}\index{paginazione} usato dalla memoria virtuale (vedi
+\textsl{paginazione} \index{paginazione} usato dalla memoria virtuale (vedi
sez.~\ref{sec:proc_mem_gen}), permette di \textsl{mappare} il contenuto di un
file in una sezione dello spazio di indirizzi del processo.
file viene \textsl{mappata} direttamente nello spazio degli indirizzi del
programma. Tutte le operazioni di lettura e scrittura su variabili contenute
in questa zona di memoria verranno eseguite leggendo e scrivendo dal contenuto
-del file attraverso il sistema della memoria virtuale\index{memoria~virtuale}
+del file attraverso il sistema della memoria virtuale \index{memoria~virtuale}
che in maniera analoga a quanto avviene per le pagine che vengono salvate e
rilette nella swap, si incaricherà di sincronizzare il contenuto di quel
segmento di memoria con quello del file mappato su di esso. Per questo motivo
di caricare in 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
-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
+Infatti, dato che l'accesso è fatto direttamente attraverso la
+\index{memoria~virtuale} 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à
allo stesso modo con cui vengono caricate in memoria le pagine che sono state
salvate sullo swap.
privata cui solo il processo chiamante ha
accesso. Le modifiche sono mantenute attraverso
il meccanismo del \textit{copy on
- write}\itindex{copy~on~write} e
+ write} \itindex{copy~on~write} e
salvate su swap in caso di necessità. Non è
specificato se i cambiamenti sul file originale
vengano riportati sulla regione
mappata. Incompatibile con \const{MAP\_SHARED}. \\
\const{MAP\_DENYWRITE} & In Linux viene ignorato per evitare
- \textit{DoS}\itindex{Denial~of~Service~(DoS)}
+ \textit{DoS} \itindex{Denial~of~Service~(DoS)}
(veniva usato per segnalare che tentativi di
scrittura sul file 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 del
- \textit{copy on write}\itindex{copy~on~write}
+ \textit{copy on write} \itindex{copy~on~write}
per mantenere le
modifiche fatte alla regione mappata, in
questo caso dopo una scrittura, se non c'è più
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 meccanismo della memoria
-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
-consentono questo tipo di accesso.
+tutto quanto è comunque basato sul meccanismo della \index{memoria~virtuale}
+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 consentono questo
+tipo di accesso.
È invece assai diversa la questione relativa agli accessi al di fuori della
regione di cui si è richiesta la mappatura. A prima vista infatti si potrebbe
ritenere che anch'essi debbano generare un segnale di violazione di accesso;
questo però non tiene conto del fatto che, essendo basata sul meccanismo della
-paginazione\index{paginazione}, la mappatura in memoria non può che essere
+paginazione \index{paginazione}, la mappatura in memoria non può che essere
eseguita su un segmento di dimensioni rigorosamente multiple di quelle di una
pagina, ed in generale queste potranno non corrispondere alle dimensioni
-effettive del file o della sezione che si vuole mappare.
+effettive del file o della sezione che si vuole mappare.
\footnotetext[20]{Dato che tutti faranno riferimento alle stesse pagine di
memoria.}
output sul file.
In tutti questi casi il \textit{file locking} è la tecnica che permette di
-evitare le \textit{race condition}\itindex{race~condition}, attraverso una
+evitare le \textit{race condition} \itindex{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.
\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}\itindex{deadlock}. Non è garantito che il sistema
+ \itindex{deadlock} \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.
\begin{figure}[htb]
\centering \includegraphics[width=9cm]{img/file_lock_dead}
- \caption{Schema di una situazione di \textit{deadlock}\itindex{deadlock}.}
+ \caption{Schema di una situazione di \itindex{deadlock} \textit{deadlock}.}
\label{fig:file_flock_dead}
\end{figure}
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}\itindex{deadlock}, dato che a quel punto anche
+porta ad un \itindex{deadlock} \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}.
+cerca di acquisire un lock che porterebbe ad un \itindex{deadlock}
+\textit{deadlock}.
\begin{figure}[!bht]
\centering \includegraphics[width=13cm]{img/file_posix_lock}
bloccata grazie ai campi \var{fl\_start} e \var{fl\_end}. La struttura è
comunque la stessa, solo che in questo caso nel campo \var{fl\_flags} è
impostato il bit \const{FL\_POSIX} ed il campo \var{fl\_file} non viene
- usato.} il lock è sempre associato all'inode\index{inode}, solo che in
+ usato.} il lock è sempre associato \index{inode} all'inode, solo che in
questo caso la titolarità non viene identificata con il riferimento ad una
voce nella \itindex{file~table} \textit{file table}, ma con il valore del
\acr{pid} del processo.
soltanto quando si chiama \func{mmap} con l'opzione \const{MAP\_SHARED} (nel
qual caso la funzione fallisce con il solito \errcode{EAGAIN}) che comporta la
possibilità di modificare il file.
-\index{file!locking|)}
-\itindend{mandatory~locking|(}
+\index{file!locking|)}
+\itindend{mandatory~locking|(}
-%%% Local Variables:
-%%% mode: latex
-%%% TeX-master: "gapil"
-%%% End:
-
% LocalWords: dell'I locking multiplexing cap dell' sez system call socket BSD
% LocalWords: descriptor client deadlock NONBLOCK EAGAIN polling select kernel
% LocalWords: pselect like sys unistd int fd readfds writefds exceptfds struct
% LocalWords: EDEADLK whence SEEK CUR type pid GETLK SETLK SETLKW all'inode HP
% LocalWords: switch bsd lockf mandatory SVr sgid group root mount mand TRUNC
% LocalWords: SVID UX Documentation sendfile
+
+
+%%% Local Variables:
+%%% mode: latex
+%%% TeX-master: "gapil"
+%%% End:
%% filedir.tex
%%
-%% Copyright (C) 2000-2006 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2007 Simone Piccardi. Permission is granted to
%% copy, distribute and/or modify this document under the terms of the GNU Free
%% Documentation License, Version 1.1 or any later version published by the
%% Free Software Foundation; with the Invariant Sections being "Un preambolo",
fare questa operazione.
Come spiegato in sez.~\ref{sec:file_filesystem} l'accesso al contenuto di un
-file su disco avviene passando attraverso il suo inode\index{inode}, che è la
+file su disco avviene passando attraverso il suo \index{inode} inode, che è la
struttura usata dal kernel che lo identifica univocamente all'interno di un
singolo filesystem. Il nome del file che si trova nella voce di una directory
è solo un'etichetta, mantenuta all'interno della directory, che viene
Questo significa che, fintanto che si resta sullo stesso filesystem, la
realizzazione di un link è immediata, ed uno stesso file può avere tanti nomi
-diversi, dati da altrettante diverse associazioni allo stesso
-inode\index{inode} di etichette diverse in directory diverse. Si noti anche
-che nessuno di questi nomi viene ad assumere una particolare preferenza o
-originalità rispetto agli altri, in quanto tutti fanno comunque riferimento
-allo stesso inode\index{inode}.
+diversi, dati da altrettante diverse associazioni allo stesso \index{inode}
+inode di etichette diverse in directory diverse. Si noti anche che nessuno di
+questi nomi viene ad assumere una particolare preferenza o originalità
+rispetto agli altri, in quanto tutti fanno comunque riferimento allo stesso
+\index{inode} inode.
Per aggiungere ad una directory una voce che faccia riferimento ad un
-inode\index{inode} già esistente si utilizza la funzione \func{link}; si suole
-chiamare questo tipo di associazione un collegamento diretto (o \textit{hard
- link}). Il prototipo della funzione è:
+\index{inode} inode già esistente si utilizza la funzione \func{link}; si
+suole chiamare questo tipo di associazione un collegamento diretto (o
+\textit{hard link}). Il prototipo della funzione è:
\begin{prototype}{unistd.h}
{int link(const char *oldpath, const char *newpath)}
Crea un nuovo collegamento diretto.
\errval{ENOSPC}, \errval{EIO}.}
\end{prototype}
-La funzione crea sul \itindex{pathname}\textit{pathname} \param{newpath} un
+La funzione crea sul \itindex{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
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
-\itindex{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).
+collegamento diretto è possibile solo se entrambi i \itindex{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
abbia privilegi sufficienti.}
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, 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
+directory e decrementa il numero di riferimenti nel relativo \index{inode}
+inode. Nel caso di link simbolico cancella il link simbolico; nel caso di
+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
Una delle caratteristiche di queste funzioni è che la creazione/rimozione del
nome dalla directory e l'incremento/decremento del numero di riferimenti
-nell'inode\index{inode} devono essere effettuati in maniera atomica (si veda
+\index{inode} nell'inode devono essere effettuati in maniera atomica (si veda
sez.~\ref{sec:proc_atom_oper}) senza possibili interruzioni fra le due
operazioni. Per questo entrambe queste funzioni sono realizzate tramite una
singola system call.
Si ricordi infine che un 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\index{inode} diventa zero lo spazio occupato su
+ count} mantenuto \index{inode} nell'inode diventa zero lo spazio occupato su
disco viene rimosso (si ricordi comunque che a questo si aggiunge sempre
un'ulteriore condizione,\footnote{come vedremo in
cap.~\ref{cha:file_unix_interface} il kernel mantiene anche una tabella dei
\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
- \itindex{pathname}\textit{pathname} non è una directory o \param{oldpath}
- è una directory e \param{newpath} esiste e non è una directory.
+ \item[\errcode{ENOTDIR}] Uno dei componenti dei \itindex{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},
\errval{ENOENT}, \errval{ENOMEM}, \errval{EROFS}, \errval{ELOOP} e
\label{sec:file_symlink}
Come abbiamo visto in sez.~\ref{sec:file_link} la funzione \func{link} crea
-riferimenti agli \index{inode}inode, pertanto può funzionare soltanto per file
+riferimenti agli \index{inode} inode, pertanto può funzionare soltanto per file
che risiedono sullo stesso filesystem e solo per un filesystem di tipo Unix.
Inoltre abbiamo visto che in Linux non è consentito eseguire un link diretto
ad una directory.
\file{/boot/boot/boot} e così via.
Per questo motivo il kernel e le librerie prevedono che nella risoluzione di
-un \itindex{pathname}\textit{pathname} possano essere seguiti un numero
+un \itindex{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}.
\label{sec:file_dir_creat_rem}
Benché in sostanza le directory non siano altro che dei file contenenti
-elenchi di nomi ed \index{inode}inode, non è possibile trattarle come file
+elenchi di nomi ed \index{inode} inode, non è possibile trattarle come file
ordinari e devono essere create direttamente dal kernel attraverso una
opportuna system call.\footnote{questo permette anche, attraverso l'uso del
VFS, l'utilizzo di diversi formati per la gestione dei suddetti elenchi.}
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
-\itindex{pathname}\textit{pathname} assoluto che relativo.
+\param{dirname}. Il nome può essere indicato sia come \itindex{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
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
-\itindex{pathname}\textit{pathname} assoluto o relativo.
+\file{..}). Il nome può essere indicato con il \itindex{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
+\func{unlink}: fintanto che il numero di link \index{inode} all'inode della
directory non diventa nullo e nessun processo ha la directory aperta lo spazio
occupato su disco non viene rilasciato. Se un processo ha la directory aperta
-la funzione rimuove il link all'inode\index{inode} e nel caso sia l'ultimo,
+la funzione rimuove il link \index{inode} all'inode e nel caso sia l'ultimo,
pure le voci standard \file{.} e \file{..}, a questo punto il kernel non
consentirà di creare più nuovi file nella directory.
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 sono un caso a parte, che
-tratteremo in cap.~\ref{cha:socket_intro}).
+degli altri tipi di file speciali, come i \index{file!di~dispositivo} file di
+dispositivo e le fifo (i socket sono un caso a parte, che tratteremo 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
codici di errore.} l'uso per la creazione di una fifo è consentito anche
agli utenti normali.
-I nuovi inode\index{inode} creati con \func{mknod} apparterranno al
+I nuovi \index{inode} inode creati con \func{mknod} apparterranno al
proprietario e al gruppo del processo che li ha creati, a meno che non si sia
attivato il bit \acr{sgid} per la directory o sia stata attivata la semantica
BSD per il filesystem (si veda sez.~\ref{sec:file_ownership_management}) in
-cui si va a creare l'inode\index{inode}.
+cui si va a creare \index{inode} l'inode.
Per creare una fifo (un file speciale, su cui torneremo in dettaglio in
sez.~\ref{sec:ipc_named_pipe}) lo standard POSIX specifica l'uso della funzione
\label{sec:file_dir_read}
Benché le directory alla fine non siano altro che dei file che contengono
-delle liste di nomi ed \index{inode}inode, per il ruolo che rivestono nella
+delle liste di nomi ed \index{inode} inode, per il ruolo che rivestono nella
struttura del sistema, non possono essere trattate come dei normali file di
dati. Ad esempio, onde evitare inconsistenze all'interno del filesystem, solo
il kernel può scrivere il contenuto di una directory, e non può essere un
La funzione apre un \textit{directory stream} per la directory
\param{dirname}, ritornando il puntatore ad un oggetto di tipo \type{DIR} (che
-è il tipo opaco\index{tipo!opaco} usato dalle librerie per gestire i
+è il \index{tipo!opaco} tipo opaco usato dalle librerie per gestire i
\textit{directory stream}) da usare per tutte le operazioni successive, la
funzione inoltre posiziona lo stream sulla prima voce contenuta nella
directory.
\end{functions}
La funzione restituisce in \param{result} (come
-\itindex{value~result~argument}\textit{value result argument}) l'indirizzo
+\itindex{value~result~argument} \textit{value result argument}) l'indirizzo
dove sono stati salvati i dati, che di norma corrisponde a quello della
struttura precedentemente allocata e specificata dall'argomento \param{entry}
(anche se non è assicurato che la funzione usi lo spazio fornito dall'utente).
ma solo un limite \const{NAME\_MAX}; in SVr4 la lunghezza del campo è
definita come \code{NAME\_MAX+1} che di norma porta al valore di 256 byte
usato anche in Linux.} ed il campo \var{d\_ino}, che contiene il numero di
-\index{inode}inode cui il file è associato (di solito corrisponde al campo
+\index{inode} inode cui il file è associato (di solito corrisponde al campo
\var{st\_ino} di \struct{stat}).
\begin{figure}[!htb]
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 \textit{pathname}
+In genere il kernel tiene traccia per ciascun processo \index{inode}
+dell'inode della directory di lavoro, per ottenere il \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)}
sembri semplice, in realtà il problema è più sottile di quanto non appaia a
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}\itindex{race~condition} (si ricordi quanto visto in
+controllo e la creazione si ha giusto lo spazio per una possibile
+\itindex{race~condition} \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,
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}\itindex{race~condition}.
+funzione è rientrante e non soffre di problemi di \itindex{race~condition}
+\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
\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}\itindex{race~condition} date per
+alle possibili \itindex{race~condition} \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à
\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}\itindex{race~condition} non si pongono.
+della directory è sempre esclusiva i precedenti problemi di
+\itindex{race~condition} \textit{race condition} non si pongono.
\section{La manipolazione delle caratteristiche dei file}
Come spiegato in sez.~\ref{sec:file_filesystem} tutte le informazioni generali
relative alle caratteristiche di ciascun file, a partire dalle informazioni
-relative al controllo di accesso, sono mantenute nell'inode\index{inode}.
+relative al controllo di accesso, sono mantenute \index{inode} nell'inode.
Vedremo in questa sezione come sia possibile leggere tutte queste informazioni
usando la funzione \func{stat}, che permette l'accesso a tutti i dati
-memorizzati nell'inode\index{inode}; esamineremo poi le varie funzioni usate
+memorizzati \index{inode} nell'inode; esamineremo poi le varie funzioni usate
per manipolare tutte queste informazioni (eccetto quelle che riguardano la
gestione del controllo di accesso, trattate in in
sez.~\ref{sec:file_access_control}).
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
- \itindex{pathname}\textit{pathname}.
+ permesso di esecuzione una delle directory del \itindex{pathname}
+ \textit{pathname}.
\item[\errcode{ETXTBSY}] Il file è un programma in esecuzione.
\end{errlist}
ed anche \errval{ENOTDIR}, \errval{ENAMETOOLONG}, \errval{ENOENT},
\label{sec:file_file_times}
Il sistema mantiene per ciascun file tre tempi. Questi sono registrati
-nell'inode\index{inode} insieme agli altri attributi del file e possono essere
-letti tramite la funzione \func{stat}, che li restituisce attraverso tre campi
-della struttura \struct{stat} di fig.~\ref{fig:file_stat_struct}. Il
+\index{inode} nell'inode insieme agli altri attributi del file e possono
+essere letti tramite la funzione \func{stat}, che li restituisce attraverso
+tre campi della struttura \struct{stat} di fig.~\ref{fig:file_stat_struct}. Il
significato di detti tempi e dei relativi campi è riportato nello schema in
tab.~\ref{tab:file_file_times}, dove è anche riportato un esempio delle
funzioni che effettuano cambiamenti su di essi.
modifica (il \textit{modification time} \var{st\_mtime}) e il tempo di
cambiamento di stato (il \textit{change time} \var{st\_ctime}). Il primo
infatti fa riferimento ad una modifica del contenuto di un file, mentre il
-secondo ad una modifica dell'inode\index{inode}; siccome esistono molte
+secondo ad una modifica \index{inode} dell'inode; siccome esistono molte
operazioni (come la funzione \func{link} e molte altre che vedremo in seguito)
-che modificano solo le informazioni contenute nell'inode\index{inode} senza
+che modificano solo le informazioni contenute \index{inode} nell'inode senza
toccare il contenuto del file, diventa necessario l'utilizzo di un altro
tempo.
\begin{prototype}{utime.h}
{int utime(const char *filename, struct utimbuf *times)}
-Cambia i tempi di ultimo accesso e modifica dell'inode\index{inode}
+Cambia i tempi di ultimo accesso e modifica \index{inode} dell'inode
specificato da \param{filename} secondo i campi \var{actime} e \var{modtime}
di \param{times}. Se questa è \val{NULL} allora viene usato il tempo corrente.
Si tenga presente che non è comunque possibile specificare il tempo di
cambiamento di stato del file, che viene comunque cambiato dal kernel tutte le
-volte che si modifica l'inode\index{inode} (quindi anche alla chiamata di
+volte che si modifica \index{inode} l'inode (quindi anche alla chiamata di
\func{utime}). Questo serve anche come misura di sicurezza per evitare che si
possa modificare un file nascondendo completamente le proprie tracce. In
realtà la cosa resta possibile, se si è in grado di accedere al file di
riportato in fig.~\ref{fig:file_perm_bit}.
Anche i permessi, come tutte le altre informazioni pertinenti al file, sono
-memorizzati nell'inode\index{inode}; in particolare essi sono contenuti in
+memorizzati \index{inode} nell'inode; in particolare essi sono contenuti in
alcuni bit del campo \var{st\_mode} della struttura \struct{stat} (si veda di
nuovo fig.~\ref{fig:file_stat_struct}).
avanti.
La prima regola è che per poter accedere ad un file attraverso il suo
-\itindex{pathname}\textit{pathname} occorre il permesso di esecuzione in
+\itindex{pathname} \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 \itindex{pathname}\textit{pathname},
-ed è distinto dal permesso di lettura che invece implica che si può leggere il
-contenuto della directory.
+essere attraversata nella risoluzione del \itindex{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
%% fileintro.tex
%%
-%% Copyright (C) 2000-2004 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2007 Simone Piccardi. Permission is granted to
%% copy, distribute and/or modify this document under the terms of the GNU Free
%% Documentation License, Version 1.1 or any later version published by the
%% Free Software Foundation; with the Invariant Sections being "Prefazione",
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
- 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.
+cosiddetti \index{file!di~dispositivo} file di dispositivo (i cosiddetti
+\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.
In questo capitolo forniremo una descrizione dell'architettura dei file in
Linux, iniziando da una panoramica sulle caratteristiche principali delle
\textsl{voci}.} da essa 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 e gli stessi
-file di dispositivo \index{file!di~dispositivo} (questi ultimi, per
+\index{file!di~dispositivo} 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
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}\itindex{Virtual~File~System} è riportato in
+\itindex{Virtual~File~System} \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
sez.~\ref{sec:ipc_named_pipe}) ed i \textit{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 \textit{device
+\index{file!di~dispositivo} \textsl{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à in cui il
un file che contiene dei dati (l'accezione normale di file) \\
\textit{directory} & \textsl{cartella o direttorio} &
un file che contiene una lista di nomi associati a degli
- \textit{inode}\index{inode} (vedi sez.~\ref{sec:file_vfs}). \\
+ \index{inode} \textit{inode} (vedi sez.~\ref{sec:file_vfs}). \\
\textit{symbolic link} & \textsl{collegamento simbolico} &
un file che contiene un riferimento ad un altro file/directory \\
\textit{char device} & \textsl{dispositivo a caratteri} &
dell'I/O in blocchi di dimensione fissa avviene solo all'interno del kernel,
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
- dischi senza passare attraverso un filesystem (il cosiddetto \textit{raw
- access}, introdotto coi kernel della serie 2.4.x).}
+ fare con tutto ciò, di effettuare, attraverso degli appositi
+ \index{file!di~dispositivo} 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).}
Una seconda differenza è nel formato dei file ASCII: in Unix la fine riga è
codificata in maniera diversa da Windows o Mac, in particolare il fine riga è
bufferizzato in quanto la lettura e la scrittura vengono eseguite chiamando
direttamente le system call del kernel (in realtà il kernel effettua al suo
interno alcune bufferizzazioni per aumentare l'efficienza nell'accesso ai
-dispositivi); i \textit{file descriptor}\index{file!descriptor} sono
+dispositivi); i \index{file!descriptor} \textit{file descriptor} sono
rappresentati da numeri interi (cioè semplici variabili di tipo \ctyp{int}).
L'interfaccia è definita nell'header \file{unistd.h}.
La seconda interfaccia è quella che il manuale della \acr{glibc} chiama degli
-\textit{stream}\index{file!stream}. Essa fornisce funzioni più evolute e un
-accesso bufferizzato (controllato dalla implementazione fatta dalle
-\acr{glibc}), la tratteremo in dettaglio nel
+\index{file!stream} \textit{stream}.\footnote{in realtà una interfaccia con lo
+ stesso nome è stata introdotta a livello di kernel negli Unix derivati da
+ \textit{System V}, come strato di astrazione per file e socket; in Linux
+ questa interfaccia, che comunque ha avuto poco successo, non esiste, per cui
+ facendo riferimento agli \index{file!stream} \textit{stream} useremo il
+ significato adottato dal manuale delle \acr{glibc}.} Essa fornisce funzioni
+più evolute e un accesso bufferizzato (controllato dalla implementazione fatta
+dalle \acr{glibc}), la tratteremo in dettaglio nel
cap.~\ref{cha:files_std_interface}.
Questa è l'interfaccia standard specificata dall'ANSI C e perciò si trova
-anche su tutti i sistemi non Unix. Gli \textit{stream}\index{file!stream} sono
-oggetti complessi e sono rappresentati da puntatori ad un opportuna struttura
-definita dalle librerie del C; si accede ad essi sempre in maniera indiretta
-utilizzando il tipo \ctyp{FILE *}. L'interfaccia è definita nell'header
-\file{stdio.h}.
+anche su tutti i sistemi non Unix. Gli \index{file!stream} \textit{stream}
+sono oggetti complessi e sono rappresentati da puntatori ad un opportuna
+struttura definita dalle librerie del C; si accede ad essi sempre in maniera
+indiretta utilizzando il tipo \ctyp{FILE *}. L'interfaccia è definita
+nell'header \file{stdio.h}.
Entrambe le interfacce possono essere usate per l'accesso ai file come agli
altri oggetti del VFS (fifo, socket, dispositivi, sui quali torneremo in
controllo (descritte in sez.~\ref{sec:file_fcntl} e sez.~\ref{sec:file_ioctl})
su un qualunque tipo di oggetto del VFS occorre usare l'interfaccia standard
di Unix con i \textit{file descriptor}. Allo stesso modo devono essere usati i
-\textit{file descriptor} \index{file!descriptor} se si vuole ricorrere a
-modalità speciali di I/O come il \textit{file locking}\index{file!locking} o
+\index{file!descriptor} \textit{file descriptor} se si vuole ricorrere a
+modalità speciali di I/O come il \index{file!locking} \textit{file locking} o
l'I/O non-bloccante (vedi cap.~\ref{cha:file_advanced}).
Gli \textit{stream} forniscono un'interfaccia di alto livello costruita sopra
è che l'interfaccia per le operazioni di input/output è enormemente più ricca
di quella dei \textit{file descriptor}, che forniscono solo funzioni
elementari per la lettura/scrittura diretta di blocchi di byte. In
-particolare gli \textit{stream}\index{file!stream} dispongono di tutte le
+particolare gli \index{file!stream} \textit{stream} dispongono di tutte le
funzioni di formattazione per l'input e l'output adatte per manipolare anche i
dati in forma di linee o singoli caratteri.
In ogni caso, dato che gli stream sono implementati sopra l'interfaccia
standard di Unix, è sempre possibile estrarre il \textit{file descriptor} da
uno stream ed eseguirvi operazioni di basso livello, o associare in un secondo
-tempo uno \textit{stream}\index{file!stream} ad un \textit{file
- descriptor}\index{file!descriptor}.
+tempo uno \index{file!stream} \textit{stream} ad un \index{file!descriptor}
+\textit{file descriptor}.
In generale, se non necessitano specificatamente le funzionalità di basso
-livello, è opportuno usare sempre gli \textit{stream}\index{file!stream} per
+livello, è opportuno usare sempre gli \index{file!stream} \textit{stream} per
la loro maggiore portabilità, essendo questi ultimi definiti nello standard
-ANSI C; l'interfaccia con i \textit{file descriptor}\index{file!descriptor}
+ANSI C; l'interfaccia con i \index{file!descriptor} \textit{file descriptor}
infatti segue solo lo standard POSIX.1 dei sistemi Unix, ed è pertanto di
portabilità più limitata.
\section{L'architettura della gestione dei file}
\label{sec:file_arch_func}
-
In questa sezione esamineremo come viene implementato l'accesso ai file in
Linux, come il kernel può gestire diversi tipi di filesystem, descrivendo
prima le caratteristiche generali di un filesystem di un sistema unix-like,
per poi trattare in maniera un po' più dettagliata il filesystem più usato con
-Linux, l'\acr{ext2}.
+Linux, l'\acr{ext2} (e derivati).
\subsection{Il \textit{Virtual File System} di Linux}
\label{sec:file_vfs}
\itindbeg{Virtual~File~System}
+
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
Il VFS definisce un insieme di funzioni che tutti i filesystem devono
implementare. L'interfaccia comprende tutte le funzioni che riguardano i file;
le operazioni sono suddivise su tre tipi di oggetti: \textit{filesystem},
-\textit{inode}\index{inode} e \textit{file}, corrispondenti a tre apposite
+\index{inode} \textit{inode} e \textit{file}, corrispondenti a tre apposite
strutture definite nel kernel.
Il VFS usa una tabella mantenuta dal kernel che contiene il nome di ciascun
su cui è strutturata l'interfaccia. Ciascuno di essi contiene le informazioni
relative al file in uso, insieme ai puntatori alle funzioni dello specifico
filesystem usate per l'accesso dal VFS; in particolare il descrittore
-dell'inode\index{inode} contiene i puntatori alle funzioni che possono essere
+\index{inode} dell'inode contiene i puntatori alle funzioni che possono essere
usate su qualunque file (come \func{link}, \func{stat} e \func{open}), mentre
il descrittore di file contiene i puntatori alle funzioni che vengono usate
sui file già aperti.
\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 \itindex{pathname}\textit{pathname}
+che permette di aprire un file. Dato un \itindex{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
+\index{inode} \textit{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
+\index{file!di~dispositivo} 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
da usare per poterlo manipolare.
Le \textit{dentry} ``vivono'' in memoria e non vengono mai salvate su disco,
-vengono usate per motivi di velocità, gli \textit{inode}\index{inode} invece
+vengono usate per motivi di velocità, gli \index{inode} \textit{inode} invece
stanno su disco e vengono copiati in memoria quando serve, ed ogni cambiamento
-viene copiato all'indietro sul disco, gli inode\index{inode} che stanno in
-memoria sono inode\index{inode} del VFS ed è ad essi che puntano le singole
+viene copiato all'indietro sul disco, gli \index{inode} inode che stanno in
+memoria sono \index{inode} inode del VFS ed è ad essi che puntano le singole
\textit{dentry}.
La \textit{dcache} costituisce perciò una sorta di vista completa di tutto
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
-\itindex{pathname}\textit{pathname} il VFS deve creare una nuova
-\textit{dentry} e caricare l'inode\index{inode} corrispondente in memoria.
+\itindex{pathname} \textit{pathname} il VFS deve creare una nuova
+\textit{dentry} e caricare \index{inode} l'inode corrispondente in memoria.
-Questo procedimento viene eseguito dal metodo \code{lookup()}
-dell'inode\index{inode} della directory che contiene il file; questo viene
-installato nelle relative strutture in memoria quando si effettua il montaggio
-lo specifico filesystem su cui l'inode va a vivere.
+Questo procedimento viene eseguito dal metodo \code{lookup()} \index{inode}
+dell'inode della directory che contiene il file; questo viene installato nelle
+relative strutture in memoria quando si effettua il montaggio lo specifico
+filesystem su cui l'inode va a vivere.
Una volta che il VFS ha a disposizione la \textit{dentry} (ed il relativo
\textit{inode}) diventa possibile accedere alle varie operazioni sul file come
la \func{open} per aprire il file o la \func{stat} per leggere i dati
-dell'inode\index{inode} e passarli in user space.
+\index{inode} dell'inode e passarli in user space.
L'apertura di un file richiede comunque un'altra operazione, l'allocazione di
una struttura di tipo \struct{file} in cui viene inserito un puntatore alla
sez.~\ref{sec:file_ext2}). È comunque caratteristica comune di tutti i
filesystem per Unix, indipendentemente da come poi viene strutturata nei
dettagli questa informazione, prevedere una divisione fra la lista degli
-inode\index{inode} e lo spazio a disposizione per i dati e le directory.
+\index{inode} inode e lo spazio a disposizione per i dati e le directory.
\begin{figure}[htb]
\centering
\begin{enumerate}
-\item L'\textit{inode}\index{inode} contiene tutte le informazioni riguardanti
- il file: il tipo di file, i permessi di accesso, le dimensioni, i puntatori
- ai blocchi fisici che contengono i dati e così via; le informazioni che la
- funzione \func{stat} fornisce provengono dall'\textit{inode}; dentro una
- directory si troverà solo il nome del file e il numero
- dell'\textit{inode}\index{inode} ad esso associato, cioè quella che da qui
- in poi chiameremo una \textsl{voce} (come traduzione dell'inglese
+\item L'\textit{inode} \index{inode} contiene tutte le informazioni
+ riguardanti il file: il tipo di file, i permessi di accesso, le dimensioni,
+ i puntatori ai blocchi fisici che contengono i dati e così via; le
+ informazioni che la funzione \func{stat} fornisce provengono
+ dall'\textit{inode}; dentro una directory si troverà solo il nome del file e
+ il numero \index{inode} dell'\textit{inode} ad esso associato, cioè quella
+ che da qui in poi chiameremo una \textsl{voce} (come traduzione dell'inglese
\textit{directory entry}, che non useremo anche per evitare confusione con
le \textit{dentry} del kernel di cui si parlava in sez.~\ref{sec:file_vfs}).
file vengono effettivamente rimossi dal disco. Per questo la funzione per
cancellare un file si chiama \func{unlink}, ed in realtà non cancella
affatto i dati del file, ma si limita ad eliminare la relativa voce da una
- directory e decrementare il numero di riferimenti
- nell'\textit{inode}\index{inode}.
+ directory e decrementare il numero di riferimenti \index{inode}
+ nell'\textit{inode}.
\item Il numero di \textit{inode} nella voce si riferisce ad un \textit{inode}
nello stesso filesystem e non ci può essere una directory che contiene
- riferimenti ad \textit{inode}\index{inode} relativi ad altri filesystem.
+ riferimenti ad \index{inode} \textit{inode} relativi ad altri filesystem.
Questo limita l'uso del comando \cmd{ln} (che crea una nuova voce per un
file esistente, con la funzione \func{link}) al filesystem corrente.
\item Quando si cambia nome ad un file senza cambiare filesystem, il contenuto
del file non viene spostato fisicamente, viene semplicemente creata una
- nuova voce per l'\textit{inode}\index{inode} in questione e rimossa la
+ nuova voce per \index{inode} l'\textit{inode} in questione e rimossa la
vecchia (questa è la modalità in cui opera normalmente il comando \cmd{mv}
attraverso la funzione \func{rename}).
mostrata in fig.~\ref{fig:file_filesys_detail} creiamo una nuova directory
\file{img} nella directory \file{gapil}, avremo una situazione come quella in
fig.~\ref{fig:file_dirs_link}, dove per chiarezza abbiamo aggiunto dei numeri
-di inode\index{inode}.
+di \index{inode} inode.
\begin{figure}[htb]
\centering
in fase di creazione, a seconda delle sue esigenze (blocchi più grandi
permettono un accesso più veloce, ma sprecano più spazio disco).
\item il filesystem implementa link simbolici veloci, in cui il nome del file
- non è salvato su un blocco, ma tenuto all'interno dell'inode\index{inode}
+ non è salvato su un blocco, ma tenuto all'interno \index{inode} dell'inode
(evitando letture multiple e spreco di spazio), non tutti i nomi però
possono essere gestiti così per limiti di spazio (il limite è 60 caratteri).
\item vengono supportati i file immutabili (che possono solo essere letti) per
\label{fig:file_ext2_dirs}
\end{figure}
-L'utilizzo di raggruppamenti di blocchi ha inoltre degli effetti positivi nelle
-prestazioni dato che viene ridotta la distanza fra i dati e la tabella degli
-inode\index{inode}.
+L'utilizzo di raggruppamenti di blocchi ha inoltre degli effetti positivi
+nelle prestazioni dato che viene ridotta la distanza fra i dati e la tabella
+degli \index{inode} inode.
-Le directory sono implementate come una \itindex{linked~list}\textit{linked
+Le directory sono implementate come una \itindex{linked~list} \textit{linked
list} con voci di dimensione variabile. Ciascuna voce della lista contiene
-il numero di inode\index{inode}, la sua lunghezza, il nome del file e la sua
+il numero di inode \index{inode}, la sua lunghezza, il nome del file e la sua
lunghezza, secondo lo schema in fig.~\ref{fig:file_ext2_dirs}; in questo modo
è possibile implementare nomi per i file anche molto lunghi (fino a 1024
caratteri) senza sprecare spazio disco.
-%%% Local Variables:
-%%% mode: latex
-%%% TeX-master: "gapil"
-%%% End:
-
% LocalWords: everything is device kernel filesystem sez pathname root glibc
% LocalWords: path filename bootloader proc name components fifo socket dev LF
% LocalWords: resolution chroot parent Virtual System like tab cap l'I regular
% LocalWords: multiplexing mmap fsync fasync seek MacOs group dall' dell' img
% LocalWords: count unlink nell' rename gapil second Tb attributes BSD SVr gid
% LocalWords: sgid append only log fs linux extented linked list
+
+
+%%% Local Variables:
+%%% mode: latex
+%%% TeX-master: "gapil"
+%%% End:
%% filestd.tex
%%
-%% Copyright (C) 2000-2006 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2007 Simone Piccardi. Permission is granted to
%% copy, distribute and/or modify this document under the terms of the GNU Free
%% Documentation License, Version 1.1 or any later version published by the
%% Free Software Foundation; with the Invariant Sections being "Un preambolo",
%% license is included in the section entitled "GNU Free Documentation
%% License".
%%
+
\chapter{I file: l'interfaccia standard ANSI C}
\label{cha:files_std_interface}
\label{sec:file_stream}
\index{file!stream|(}
+
Come più volte ribadito, l'interfaccia dei file descriptor è un'interfaccia di
basso livello, che non provvede nessuna forma di formattazione dei dati e
nessuna forma di bufferizzazione per ottimizzare le operazioni di I/O.
(sui quali sono basati), ed in particolare continua a valere quanto visto in
sez.~\ref{sec:file_sharing} a proposito dell'accesso condiviso ed in
sez.~\ref{sec:file_access_control} per il controllo di accesso.
+
\index{file!stream|)}
stato e di fine del file.
Per questo motivo gli utenti non devono mai utilizzare direttamente o allocare
-queste strutture (che sono dei \textsl{tipi opachi}\index{tipo!opaco}) ma
+queste strutture (che sono dei \index{tipo!opaco} \textsl{tipi opachi}) ma
usare sempre puntatori del tipo \texttt{FILE *} ottenuti dalla libreria stessa
(tanto che in certi casi il termine di puntatore a file è diventato sinonimo
di stream). Tutte le funzioni della libreria che operano sui file accettano
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}\itindex{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}.}
+stringa letta superi le dimensioni del buffer, si avrà un
+\itindex{buffer~overflow} \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 infatti inviare
subito, altrimenti il buffer viene allargato usando \func{realloc} e la nuova
dimensione ed il nuovo puntatore vengono restituiti indietro (si noti infatti
come per entrambi gli argomenti si siano usati dei
-\itindex{value~result~argument}\textit{value result argument}, passando dei
+\itindex{value~result~argument} \textit{value result argument}, passando dei
puntatori anziché i valori delle variabili, secondo la tecnica spiegata in
sez.~\ref{sec:proc_var_passing}).
puntatore all'inizio del testo della linea letta. Un esempio di codice può
essere il seguente:
\includecodesnip{listati/getline.c}
-e per evitare \textit{memory leak}\itindex{memory~leak} occorre ricordarsi di
+e per evitare \itindex{memory~leak} \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
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}\itindex{buffer~overflow}; per questo motivo
-si consiglia l'uso dell'alternativa \funcd{snprintf}, il cui prototipo è:
+possibili \itindex{buffer~overflow} \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
La parte più complessa delle funzioni di scrittura formattata è il formato
della stringa \param{format} che indica le conversioni da fare, e da cui
deriva anche il numero degli argomenti che dovranno essere passati a seguire
-(si noti come tutte queste funzioni siano \textit{variadic}\index{variadic},
+(si noti come tutte queste funzioni siano \index{variadic} \textit{variadic},
prendendo un numero di argomenti variabile che dipende appunto da quello che
si è specificato in \param{format}).
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\itindex{buffer~overflow}.
+\noindent in modo da evitare possibili \itindex{buffer~overflow} buffer
+overflow.
Per eliminare alla radice questi problemi, le \acr{glibc} supportano una
Entrambe le funzioni prendono come argomento \param{strptr} che deve essere
l'indirizzo di un puntatore ad una stringa di caratteri, in cui verrà
restituito (si ricordi quanto detto in sez.~\ref{sec:proc_var_passing} a
-proposito dei \itindex{value~result~argument}\textit{value result argument})
+proposito dei \itindex{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 \textit{memory
- leak}\itindex{memory~leak}.
+la stringa non serve più, onde evitare \itindex{memory~leak} \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
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
- vero.}
+ sistema Unix esistono vari tipi di file, come le fifo ed i
+ \index{file!di~dispositivo} 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 è
espressa da un intero positivo, rappresentato dal tipo \type{off\_t}, il
%% fileunix.tex
%%
-%% Copyright (C) 2000-2006 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2007 Simone Piccardi. Permission is granted to
%% copy, distribute and/or modify this document under the terms of the GNU Free
%% Documentation License, Version 1.1 or any later version published by the
%% Free Software Foundation; with the Invariant Sections being "Un preambolo",
Esamineremo in questo capitolo la prima delle due interfacce di programmazione
-per i file, quella dei \textit{file descriptor}\index{file!descriptor},
+per i file, quella dei \index{file!descriptor} \textit{file descriptor},
nativa di Unix. Questa è l'interfaccia di basso livello provvista direttamente
dalle system call, che non prevede funzionalità evolute come la
bufferizzazione o funzioni di lettura o scrittura formattata, e sulla quale è
\index{file!descriptor|(}
-Per poter accedere al contenuto di un file occorre
-creare un canale di comunicazione con il kernel che renda possibile operare su
-di esso (si ricordi quanto visto in sez.~\ref{sec:file_vfs_work}). Questo si
-fa aprendo il file con la funzione \func{open} che provvederà a localizzare
-l'inode\index{inode} del file e inizializzare i puntatori che rendono
-disponibili le funzioni che il VFS mette a disposizione (riportate in
+Per poter accedere al contenuto di un file occorre creare un canale di
+comunicazione con il kernel che renda possibile operare su di esso (si ricordi
+quanto visto in sez.~\ref{sec:file_vfs_work}). Questo si fa aprendo il file
+con la funzione \func{open} che provvederà a localizzare \index{inode} l'inode
+del file e inizializzare i puntatori che rendono disponibili le funzioni che
+il VFS mette a disposizione (riportate in
tab.~\ref{tab:file_file_operations}). Una volta terminate le operazioni, il
file dovrà essere chiuso, e questo chiuderà il canale di comunicazione
impedendo ogni ulteriore operazione.
\item il valore della posizione corrente (l'\textit{offset}) nel file (nel
campo \var{f\_pos}).
\item un puntatore \index{inode} all'inode\footnote{nel kernel 2.4.x si è in
- realtà passati ad un puntatore ad una struttura \struct{dentry} che punta a
- sua volta all'inode\index{inode} passando per la nuova struttura del VFS.}
- del file.
+ realtà passati ad un puntatore ad una struttura \struct{dentry} che punta
+ a sua volta \index{inode} 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 sez.~\ref{sec:file_vfs_work}} che si possono usare
% sul file.
Ritorneremo su questo schema più volte, dato che esso è fondamentale per
capire i dettagli del funzionamento dell'interfaccia dei \textit{file
descriptor}.
+
\index{file!descriptor|)}
\begin{figure}[htb]
facendo riferimento ad un programma in cui lo \textit{standard input} è
associato ad un file mentre lo \textit{standard output} e lo \textit{standard
error} sono entrambi associati ad un altro file (e quindi utilizzano lo
-stesso inode\index{inode}).
+stesso \index{inode} inode).
Nelle vecchie versioni di Unix (ed anche in Linux fino al kernel 2.0.x) il
numero di file aperti era anche soggetto ad un limite massimo dato dalle
\label{sec:file_open}
La funzione \funcd{open} è la funzione fondamentale per accedere ai file, ed è
-quella che crea l'associazione fra un \itindex{pathname}\textit{pathname} ed
-un file descriptor, il suo prototipo è:
+quella che crea l'associazione fra un \itindex{pathname} \textit{pathname} ed
+un \index{file!descriptor} file descriptor, il suo prototipo è:
\begin{functions}
\headdecl{sys/types.h}
\headdecl{sys/stat.h}
\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
- \textit{race condition}\itindex{race~condition}. Si consiglia come
+ \index{file!di lock} \textsl{file di lock} possono incorrere in una
+ \itindex{race~condition} \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]{acronimo di \textit{Denial of
- Service}\itindex{Denial~of~Service~(DoS)}, si chiamano così attacchi
- miranti ad impedire un servizio causando una qualche forma di carico
- eccessivo per il sistema, che resta bloccato nelle risposte all'attacco.}
+\footnotetext[3]{acronimo di \itindex{Denial~of~Service~(DoS)} \textit{Denial
+ of Service}, si chiamano così attacchi miranti ad impedire un servizio
+ causando una qualche forma di carico eccessivo per il sistema, che resta
+ bloccato nelle risposte all'attacco.}
\begin{table}[!htb]
\centering
la successiva scrittura avvenga alla fine del file, infatti se questo è stato
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 \itindex{race~condition}\textit{race
+(questa è una potenziale sorgente di \itindex{race~condition} \textit{race
condition}, vedi sez.~\ref{sec:file_atomic}).
Non tutti i file supportano la capacità di eseguire una \func{lseek}, in
\label{fig:file_mult_acc}
\end{figure}
-Il primo caso è quello in cui due processi diversi aprono lo stesso file
-su disco; sulla base di quanto visto in sez.~\ref{sec:file_fd} avremo una
+Il primo caso è quello in cui due processi diversi aprono lo stesso file su
+disco; sulla base di quanto visto in sez.~\ref{sec:file_fd} avremo una
situazione come quella illustrata in fig.~\ref{fig:file_mult_acc}: ciascun
processo avrà una sua voce nella \textit{file table} referenziata da un
diverso file descriptor nella sua \struct{file\_struct}. Entrambe le voci
-nella \textit{file table} faranno però riferimento allo stesso
-inode\index{inode} su disco.
+nella \itindex{file~table} \textit{file table} faranno però riferimento allo
+stesso \index{inode} inode su disco.
Questo significa che ciascun processo avrà la sua posizione corrente sul file,
la sua modalità di accesso e versioni proprie di tutte le proprietà che
-vengono mantenute nella sua voce della \textit{file table}. Questo ha
-conseguenze specifiche sugli effetti della possibile azione simultanea sullo
-stesso file, in particolare occorre tenere presente che:
+vengono mantenute nella sua voce della \itindex{file~table} \textit{file
+ table}. Questo ha conseguenze specifiche sugli effetti della possibile
+azione simultanea sullo stesso file, in particolare occorre tenere presente
+che:
\begin{itemize}
\item ciascun processo può scrivere indipendentemente; dopo ciascuna
\func{write} la posizione corrente sarà cambiata solo nel processo. Se la
scrittura eccede la dimensione corrente del file questo verrà esteso
- automaticamente con l'aggiornamento del campo \var{i\_size}
- nell'inode\index{inode}.
+ automaticamente con l'aggiornamento del campo \var{i\_size} \index{inode}
+ nell'inode.
\item se un file è in modalità \itindex{append~mode} \const{O\_APPEND} tutte
le volte che viene effettuata una scrittura la posizione corrente viene
- prima impostata alla dimensione corrente del file letta
- dall'inode\index{inode}. Dopo la scrittura il file viene automaticamente
- esteso.
+ prima impostata alla dimensione corrente del file letta \index{inode}
+ dall'inode. Dopo la scrittura il file viene automaticamente esteso.
\item l'effetto di \func{lseek} è solo quello di cambiare il campo
- \var{f\_pos} nella struttura \struct{file} della \textit{file table}, non
- c'è nessuna operazione sul file su disco. Quando la si usa per porsi alla
- fine del file la posizione viene impostata leggendo la dimensione corrente
- dall'inode\index{inode}.
+ \var{f\_pos} nella struttura \struct{file} della \itindex{file~table}
+ \textit{file table}, non c'è nessuna operazione sul file su disco. Quando la
+ si usa per porsi alla fine del file la posizione viene impostata leggendo la
+ dimensione corrente \index{inode} dall'inode.
\end{itemize}
\begin{figure}[htb]
\end{figure}
Il secondo caso è quello in cui due file descriptor di due processi diversi
-puntino alla stessa voce nella \textit{file table}; questo è ad esempio il
-caso dei file aperti che vengono ereditati dal processo figlio all'esecuzione
-di una \func{fork} (si ricordi quanto detto in sez.~\ref{sec:proc_fork}). La
-situazione è illustrata in fig.~\ref{fig:file_acc_child}; dato che il processo
-figlio riceve una copia dello spazio di indirizzi del padre, riceverà anche
-una copia di \struct{file\_struct} e relativa tabella dei file aperti.
+puntino alla stessa voce nella \itindex{file~table} \textit{file table};
+questo è ad esempio il caso dei file aperti che vengono ereditati dal processo
+figlio all'esecuzione di una \func{fork} (si ricordi quanto detto in
+sez.~\ref{sec:proc_fork}). La situazione è illustrata in
+fig.~\ref{fig:file_acc_child}; dato che il processo figlio riceve una copia
+dello spazio di indirizzi del padre, riceverà anche una copia di
+\struct{file\_struct} e relativa tabella dei file aperti.
In questo modo padre e figlio avranno gli stessi file descriptor che faranno
riferimento alla stessa voce nella \textit{file table}, condividendo così la
Un caso tipico di necessità di accesso condiviso in scrittura è quello in cui
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
-\itindex{race~condition}\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.
+fine del file e poi scrivere può condurre ad una \itindex{race~condition}
+\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à
atomica.
Un altro caso tipico in cui è necessaria l'atomicità è quello in cui si vuole
-creare un \textsl{file di lock}\index{file!di lock}, bloccandosi se il file
+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 \textit{race
- condition}\itindex{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 \itindex{race~condition} \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
file specificato, ed attendono fino alla conclusione delle operazioni;
\func{fsync} forza anche la sincronizzazione dei metadati del file (che
riguardano sia le modifiche alle tabelle di allocazione dei settori, che gli
-altri dati contenuti nell'inode\index{inode} che si leggono con \func{fstat},
+altri dati contenuti \index{inode} nell'inode che si leggono con \func{fstat},
come i tempi del file).
Si tenga presente che questo non comporta la sincronizzazione della
gestione sia delle loro proprietà, che di tutta una serie di ulteriori
funzionalità che il kernel può mettere a disposizione.\footnote{ad esempio si
gestiscono con questa funzione varie modalità di I/O asincrono (vedi
- sez.~\ref{sec:file_asyncronous_operation}) e il \textit{file locking}
- \index{file!locking} (vedi sez.~\ref{sec:file_locking}).}
+ sez.~\ref{sec:file_asyncronous_operation}) e il \index{file!locking}
+ \textit{file locking} (vedi sez.~\ref{sec:file_locking}).}
Per queste operazioni di manipolazione e di controllo delle varie proprietà e
caratteristiche di un file descriptor, viene usata la funzione \funcd{fcntl},
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}\itindex{close-on-exec}, identificato dalla costante
+ \itindex{close-on-exec} \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.
dei segnali \const{SIGIO} e \const{SIGURG} per gli eventi associati al file
descriptor \param{fd}. Nel caso di un \textit{process group} viene
restituito un valore negativo il cui valore assoluto corrisponde
- all'identificatore del \itindex{process~group}\textit{process group}. In
+ all'identificatore del \itindex{process~group} \textit{process group}. In
caso di errore viene restituito $-1$.
\item[\const{F\_SETOWN}] imposta, con il valore dell'argomento \param{arg},
l'identificatore del processo o del \itindex{process~group} \textit{process
valore nullo in caso di successo o $-1$ in caso di errore. Questa
funzionalità avanzata è trattata in dettaglio in
sez.~\ref{sec:file_asyncronous_lease}.
-\item[\const{F\_GETLEASE}] restituisce il tipo di \textit{file lease}
- \index{file!lease} che il processo detiene nei confronti del file descriptor
- \var{fd} o $-1$ in caso di errore. Con questo comando il terzo argomento può
- essere omesso. Questa funzionalità avanzata è trattata in dettaglio in
- sez.~\ref{sec:file_asyncronous_lease}.
+\item[\const{F\_GETLEASE}] restituisce il tipo di \index{file!lease}
+ \textit{file lease} che il processo detiene nei confronti del file
+ descriptor \var{fd} o $-1$ in caso di errore. Con questo comando il terzo
+ argomento può essere omesso. Questa funzionalità avanzata è trattata in
+ dettaglio in sez.~\ref{sec:file_asyncronous_lease}.
\item[\const{F\_NOTIFY}] attiva un meccanismo di notifica per cui viene
riportata al processo chiamante, tramite il segnale \const{SIGIO} (o altro
segnale specificato con \const{F\_SETSIG}) ogni modifica eseguita o
pertanto riprese più avanti quando affronteremo le problematiche ad esse
relative. In particolare le tematiche relative all'I/O asincrono e ai vari
meccanismi di notifica saranno trattate in maniera esaustiva in
-sez.~\ref{sec:file_asyncronous_access} mentre quelle relative al \textit{file
- locking}\index{file!locking} saranno esaminate in
+sez.~\ref{sec:file_asyncronous_access} mentre quelle relative al
+\index{file!locking} \textit{file locking} saranno esaminate in
sez.~\ref{sec:file_locking}). L'uso di questa funzione con i socket verrà
trattato in sez.~\ref{sec:sock_ctrl_func}.
Data la assoluta specificità della funzione, il cui comportamento varia da
dispositivo a dispositivo, non è possibile fare altro che dare una descrizione
sommaria delle sue caratteristiche; torneremo ad esaminare in
-seguito\footnote{per l'uso con i socket si veda
- sez.~\ref{sec:sock_ctrl_func}.} quelle relative ad alcuni casi specifici
-(ad esempio la gestione dei terminali è effettuata attraverso \func{ioctl} in
+seguito\footnote{per l'uso di \func{ioctl} con i socket si veda
+ sez.~\ref{sec:sock_ctrl_func}.} quelle relative ad alcuni casi specifici (ad
+esempio la gestione dei terminali è effettuata attraverso \func{ioctl} in
quasi tutte le implementazioni di Unix), qui riportiamo solo i valori di
alcuni comandi che sono definiti per ogni file:
\begin{basedescript}{\desclabelwidth{2.0cm}}
-\item[\const{FIOCLEX}] Imposta il flag di
- \textit{close-on-exec}\itindex{close-on-exec}.
-\item[\const{FIONCLEX}] Cancella il flag di
- \textit{close-on-exec}\itindex{close-on-exec}.
+\item[\const{FIOCLEX}] Imposta il flag di \itindex{close-on-exec}
+ \textit{close-on-exec}.
+\item[\const{FIONCLEX}] Cancella il flag di \itindex{close-on-exec}
+ \textit{close-on-exec}.
\item[\const{FIOASYNC}] Abilita l'I/O asincrono.
\item[\const{FIONBIO}] Abilita l'I/O in modalità non bloccante.
\end{basedescript}
-% TODO estendere la lista delle ioctl
+% TODO estendere la lista delle ioctl sui file
%%% Local Variables:
%% gapil.tex
%%
-%% Copyright (C) 2000-2006 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2007 Simone Piccardi. Permission is granted to
%% copy, distribute and/or modify this document under the terms of the GNU Free
%% Documentation License, Version 1.1 or any later version published by the
%% Free Software Foundation; with the Invariant Sections being "Un preambolo",
\begin{quote}
- Copyright \copyright\ 2000-2004 Simone Piccardi. Permission is granted to
+ Copyright \copyright\ 2000-2007 Simone Piccardi. Permission is granted to
copy, distribute and/or modify this document under the terms of the GNU Free
Documentation License, Version 1.1 or any later version published by the
Free Software Foundation; with the Invariant Sections being ``Un preambolo''
%% macro.tex
%%
-%% Copyright (C) 2000-2006 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2007 Simone Piccardi. Permission is granted to
%% copy, distribute and/or modify this document under the terms of the GNU Free
%% Documentation License, Version 1.1 or any later version published by the
%% Free Software Foundation; with the Invariant Sections being "Un preambolo",
%% netlayer.tex
%%
-%% Copyright (C) 2000-2006 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2007 Simone Piccardi. Permission is granted to
%% copy, distribute and/or modify this document under the terms of the GNU Free
%% Documentation License, Version 1.1 or any later version published by the
%% Free Software Foundation; with the Invariant Sections being "Un preambolo",
%% License".
%%
-
-
\chapter{Il livello di rete}
\label{cha:network_layer}
realtà i valori esatti sarebbero 254 e 65536, una rete con a disposizione
$N$ bit dell'indirizzo IP, ha disponibili per le singole macchine soltanto
$@^N-2$ numeri, dato che uno deve essere utilizzato come indirizzo di rete e
- uno per l'indirizzo di \itindex{broadcast}\textit{broadcast}.} con un
+ uno per l'indirizzo di \itindex{broadcast} \textit{broadcast}.} con un
conseguente spreco di numeri.
Inoltre, in particolare per le reti di classe C, la presenza di tanti
%% network.tex
%%
-%% Copyright (C) 2000-2006 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2007 Simone Piccardi. Permission is granted to
%% copy, distribute and/or modify this document under the terms of the GNU Free
%% Documentation License, Version 1.1 or any later version published by the
%% Free Software Foundation; with the Invariant Sections being "Un preambolo",
%% license is included in the section entitled "GNU Free Documentation
%% License".
%%
+
\chapter{Introduzione alla programmazione di rete}
\label{cha:network}
presta bene per le applicazioni in cui la connessione non è necessaria, e
costituirebbe solo un peso in termini di prestazioni, mentre una perdita di
pacchetti può essere tollerata: ad esempio le applicazioni di streaming e
-quelle che usano il \textit{multicast}. \itindex{multicast}
+quelle che usano il \itindex{multicast} \textit{multicast}.
\subsection{Transport Control Protocol (TCP)}
\label{sec:net_tcp}
impostato alla dimensione della MTU dell'interfaccia meno la lunghezza delle
intestazioni di IP e TCP, in Linux il default, mantenuto nella costante
\const{TCP\_MSS} è 512.
+
\itindend{Maximum~Transfer~Unit}
%% othersock.tex
%%
-%% Copyright (C) 2004-2006 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2004-2007 Simone Piccardi. Permission is granted to
%% copy, distribute and/or modify this document under the terms of the GNU Free
%% Documentation License, Version 1.1 or any later version published by the
%% Free Software Foundation; with the Invariant Sections being "Un preambolo",
%% license is included in the section entitled "GNU Free Documentation
%% License".
%%
+
\chapter{Gli altri tipi di socket}
\label{cha:other_socket}
-Dopo aver trattato in cap.~\ref{cha:TCP_socket} i socket TCP, che costituiscono
-l'esempio più comune dell'interfaccia dei socket, esamineremo in questo
-capitolo gli altri tipi di socket, a partire dai socket UDP, e i socket
+Dopo aver trattato in cap.~\ref{cha:TCP_socket} i socket TCP, che
+costituiscono l'esempio più comune dell'interfaccia dei socket, esamineremo in
+questo capitolo gli altri tipi di socket, a partire dai socket UDP, e i socket
\textit{Unix domain} già incontrati in sez.~\ref{sec:ipc_socketpair}.
Questa differenza comporta ovviamente che anche le modalità con cui si usano i
socket UDP sono completamente diverse rispetto ai socket TCP, ed in
particolare non esistendo il concetto di connessione non esiste il meccanismo
-del \itindex{three~way~handshake}\textit{three way handshake} né quello degli
+del \itindex{three~way~handshake} \textit{three way handshake} né quello degli
stati del protocollo. In realtà tutto quello che avviene nella comunicazione
attraverso dei socket UDP è la trasmissione di un pacchetto da un client ad un
server o viceversa, secondo lo schema illustrato in
opportunamente inizializzati con i puntatori alle variabili dove la struttura
contenente quest'ultimo e la relativa lunghezza saranno scritti (si noti che
\param{fromlen} è un valore intero ottenuto come
-\itindex{value~result~argument}\textit{value result argument}). Se non si è
+\itindex{value~result~argument} \textit{value result argument}). Se non si è
interessati a questa informazione, entrambi gli argomenti devono essere
inizializzati al valore \const{NULL}.
%% preambolo.tex
%%
-%% Copyright (C) 2000-2006 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2007 Simone Piccardi. Permission is granted to
%% copy, distribute and/or modify this document under the terms of the GNU Free
%% Documentation License, Version 1.1 or any later version published by the
%% Free Software Foundation; with the Invariant Sections being "Un preambolo",
%% pref.tex
%%
-%% Copyright (C) 2000-2006 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2007 Simone Piccardi. Permission is granted to
%% copy, distribute and/or modify this document under the terms of the GNU Free
%% Documentation License, Version 1.1 or any later version published by the
%% Free Software Foundation; with the Invariant Sections being "Un preambolo",
%% process.tex
%%
-%% Copyright (C) 2000-2006 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2007 Simone Piccardi. Permission is granted to
%% copy, distribute and/or modify this document under the terms of the GNU Free
%% Documentation License, Version 1.1 or any later version published by the
%% Free Software Foundation; with the Invariant Sections being "Un preambolo",
%% license is included in the section entitled "GNU Free Documentation
%% License".
%%
+
\chapter{L'interfaccia base con i processi}
\label{cha:process_interface}
Ci sono vari modi in cui i sistemi operativi 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 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 2Gb. Con il kernel
- 2.4 ed il supporto per la \textit{high-memory} il limite è stato esteso
- anche per macchine a 32 bit.}
+unix-like come Linux è la cosiddetta \index{memoria~virtuale} \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 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 anche per macchine a 32 bit.}
Come accennato in cap.~\ref{cha:intro_unix} questo spazio di indirizzi è
virtuale e non corrisponde all'effettiva posizione dei dati nella RAM del
memoria reale o ad un dispositivo di stoccaggio secondario (come lo spazio
disco riservato alla swap, o i file che contengono il codice). Per ciascun
processo il kernel si cura di mantenere un mappa di queste corrispondenze
-nella cosiddetta \itindex{page~table}\textit{page table}.\footnote{questa è
+nella cosiddetta \itindex{page~table} \textit{page table}.\footnote{questa è
una semplificazione brutale, il meccanismo è molto più complesso; una buona
trattazione di come Linux gestisce la memoria virtuale si trova su
\cite{LinVM}.}
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}
+servono. Questo meccanismo è detto \index{paginazione} \textsl{paginazione}
(o \textit{paging}), ed è uno dei compiti principali del kernel.
Quando un processo cerca di accedere ad una pagina che non è nella memoria
Normalmente questo è il prezzo da pagare per avere un multitasking reale, ed
in genere il sistema è molto efficiente in questo lavoro; quando però ci siano
esigenze specifiche di prestazioni è possibile usare delle funzioni che
-permettono di bloccare il meccanismo della paginazione\index{paginazione} e
-mantenere fisse delle pagine in memoria (vedi
-sez.~\ref{sec:proc_mem_lock}). Inoltre per certe applicazioni gli algoritmi di
-gestione della memoria
+permettono di bloccare il meccanismo della \index{paginazione} paginazione e
+mantenere fisse delle pagine in memoria (vedi sez.~\ref{sec:proc_mem_lock}).
+Inoltre per certe applicazioni gli algoritmi di gestione della memoria
\subsection{La struttura della memoria di un processo}
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{memoria~virtuale} di un processo. Essa viene divisa in
+È pertanto importante capire come viene strutturata \index{memoria~virtuale}
+\textsl{la memoria virtuale} 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:
Storicamente questa seconda parte del segmento dati viene chiamata BSS (da
\textit{Block Started by Symbol}). La sua dimensione è fissa.
-\item Lo \itindex{heap}\textit{heap}. Tecnicamente lo si può considerare
+\item Lo \itindex{heap} \textit{heap}. Tecnicamente lo si può considerare
l'estensione del segmento dati, a cui di solito è posto giusto di seguito. È
qui che avviene l'allocazione dinamica della memoria; può essere
ridimensionato allocando e disallocando la memoria dinamica con le apposite
L'\textsl{allocazione automatica} è quella che avviene per gli argomenti di
una funzione e per le sue variabili locali (le cosiddette \textsl{variabili
automatiche}), che esistono solo per la durata della funzione. Lo spazio
-per queste variabili viene allocato nello \itindex{stack}\textit{stack} quando
+per queste variabili viene allocato nello \itindex{stack} \textit{stack} quando
viene eseguita la funzione e liberato quando si esce dalla medesima.
Esiste però un terzo tipo di allocazione, l'\textsl{allocazione dinamica}
cioè definire in fase di programmazione una variabile le cui dimensioni
possano essere modificate durante l'esecuzione del programma. Per questo le
librerie del C forniscono una serie opportuna di funzioni per eseguire
-l'allocazione dinamica di memoria (in genere nello \itindex{heap} heap).
+l'allocazione dinamica di memoria (in genere nello \itindex{heap}
+\textit{heap}).
Le variabili il cui contenuto è allocato in questo modo non potranno essere
usate direttamente come le altre (quelle nello \itindex{stack}
\begin{functions}
\headdecl{stdlib.h}
\funcdecl{void *calloc(size\_t nmemb, size\_t size)}
- Alloca nello heap un'area di memoria per un vettore di \param{nmemb} membri
- di \param{size} byte di dimensione. La memoria viene inizializzata a 0.
+ Alloca nello \textit{heap} un'area di memoria per un vettore di
+ \param{nmemb} membri di \param{size} byte di dimensione. La memoria viene
+ inizializzata a 0.
La funzione restituisce il puntatore alla zona di memoria allocata in caso
di successo e \val{NULL} in caso di fallimento, nel qual caso
\var{errno} assumerà il valore \errval{ENOMEM}.
\funcdecl{void *malloc(size\_t size)}
- Alloca \param{size} byte nello heap. La memoria non viene inizializzata.
+ Alloca \param{size} byte nello \textit{heap}. La memoria non viene
+ inizializzata.
La funzione restituisce il puntatore alla zona di memoria allocata in caso
di successo e \val{NULL} in caso di fallimento, nel qual caso
Il problema più comune e più difficile da risolvere che si incontra con le
funzioni di allocazione è quando non viene opportunamente liberata la memoria
-non più utilizzata, quello che in inglese viene chiamato \textit{memory
- leak}\itindex{memory~leak}, cioè una \textsl{perdita di memoria}.
+non più utilizzata, quello che in inglese viene chiamato \itindex{memory~leak}
+\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
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}\itindex{memory~leak}.
+\itindex{memory~leak} \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}\itindex{memory~leak} è notevolmente ridimensionato attraverso l'uso
-accurato di appositi oggetti come gli \textit{smartpointers}. Questo però in
-genere va a scapito delle prestazioni dell'applicazione in esecuzione.
+programmazione ad oggetti, il problema dei \itindex{memory~leak}
+\textit{memory leak} è notevolmente ridimensionato attraverso l'uso accurato
+di appositi oggetti come gli \textit{smartpointers}. Questo però in genere va
+a scapito delle prestazioni dell'applicazione in esecuzione.
% TODO decidere cosa fare di questo che segue
% In altri linguaggi come il java e recentemente il C\# il problema non si pone
% automatica, ovvero il programmatore non deve minimamente preoccuparsi di
% liberare la memoria allocata precedentemente quando non serve più, poiché
% l'infrastruttura del linguaggio gestisce automaticamente la cosiddetta
-% \index{\textit{garbage~collection}}\textit{garbage collection}. In tal caso,
+% \index{\textit{garbage~collection}} \textit{garbage collection}. In tal caso,
% attraverso meccanismi simili a quelli del \textit{reference counting}, quando
% una zona di memoria precedentemente allocata non è più riferita da nessuna
% parte del codice in esecuzione, può essere deallocata automaticamente in
Una possibile alternativa all'uso di \func{malloc}, che non soffre dei
-problemi di \textit{memory leak}\itindex{memory~leak} descritti in precedenza,
-è la funzione \funcd{alloca}, che invece di allocare la memoria nello
-\itindex{heap}\textit{heap} usa il segmento di \itindex{stack} \textit{stack}
-della funzione corrente. La sintassi è identica a quella di \func{malloc}, il
-suo prototipo è:
+problemi di \itindex{memory~leak} \textit{memory leak} descritti in
+precedenza, è la funzione \funcd{alloca}, che invece di allocare la memoria
+nello \itindex{heap} \textit{heap} usa il segmento di \itindex{stack}
+\textit{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.
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 \textit{memory leak}\itindex{memory~leak},
+evitare alla radice i problemi di \itindex{memory~leak} \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
\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
parte dei vari processi.
Nell'uso comune un processo non deve preoccuparsi di tutto ciò, in quanto il
-meccanismo della paginazione\index{paginazione} riporta in RAM, ed in maniera
+meccanismo della \index{paginazione} paginazione riporta in RAM, ed in maniera
trasparente, tutte le pagine che gli occorrono; esistono però esigenze
particolari in cui non si vuole che questo meccanismo si attivi. In generale i
motivi per cui si possono avere di queste necessità sono due:
\begin{itemize}
-\item \textsl{La velocità}. Il processo della paginazione\index{paginazione} è
- trasparente solo se il programma in esecuzione non è sensibile al tempo che
- occorre a riportare la pagina in memoria; per questo motivo processi critici
- che hanno esigenze di tempo reale o tolleranze critiche nelle risposte (ad
- esempio processi che trattano campionamenti sonori) possono non essere in
- grado di sopportare le variazioni della velocità di accesso dovuta alla
- paginazione.
+\item \textsl{La velocità}. Il processo della \index{paginazione} paginazione
+ è trasparente solo se il programma in esecuzione non è sensibile al tempo
+ che occorre a riportare la pagina in memoria; per questo motivo processi
+ critici che hanno esigenze di tempo reale o tolleranze critiche nelle
+ risposte (ad esempio processi che trattano campionamenti sonori) possono non
+ essere in grado di sopportare le variazioni della velocità di accesso dovuta
+ alla paginazione.
In certi casi poi un programmatore può conoscere meglio dell'algoritmo di
allocazione delle pagine le esigenze specifiche del suo programma e decidere
\item \textsl{La sicurezza}. Se si hanno password o chiavi segrete in chiaro
in memoria queste possono essere portate su disco dal meccanismo della
- paginazione\index{paginazione}. Questo rende più lungo il periodo di tempo
+ \index{paginazione} paginazione. Questo rende più lungo il periodo di tempo
in cui detti segreti sono presenti in chiaro e più complessa la loro
cancellazione (un processo può cancellare la memoria su cui scrive le sue
variabili, ma non può toccare lo spazio disco su cui una pagina di memoria
\itindbeg{memory~locking}
-Il meccanismo che previene la paginazione\index{paginazione} di parte della
+Il meccanismo che previene la \index{paginazione} 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
memoria virtuale del processo, e non al segmento reale di RAM su cui essa
viene mantenuta. La regola è che se un segmento di RAM fa da supporto ad
almeno una pagina bloccata allora esso viene escluso dal meccanismo della
-paginazione\index{paginazione}. I blocchi non si accumulano, se si blocca due
+\index{paginazione} paginazione. I blocchi non si accumulano, se si blocca due
volte la stessa pagina non è necessario sbloccarla due volte, una pagina o è
-bloccata oppure no.
+bloccata oppure no.
Il \textit{memory lock} persiste fintanto che il processo che detiene la
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 i \textit{memory lock} non sono
ereditati dai processi figli,\footnote{ma siccome Linux usa il
- \itindex{copy~on~write}\textit{copy on write} (vedi
+ \itindex{copy~on~write} \textit{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 \textit{memory lock} del padre.} e
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
tutti gli altri processi, per cui fino al kernel 2.6.9 solo un processo con i
-privilegi opportuni (la \itindex{capabilities}\textit{capability}
+privilegi opportuni (la \itindex{capabilities} \textit{capability}
\const{CAP\_IPC\_LOCK}, vedi sez.~\ref{sec:proc_capabilities}) aveva la
-capacità di bloccare una pagina.
+capacità di bloccare una pagina.
Il sistema pone dei limiti all'ammontare di memoria di un processo che può
essere bloccata e al totale di memoria fisica che si può dedicare a questo, lo
però diversi processi bloccano la stessa pagina questa resterà bloccata
fintanto che ci sarà almeno un processo che la blocca.
-Le funzioni per bloccare e sbloccare la paginazione \index{paginazione} di
+Le funzioni per bloccare e sbloccare la \index{paginazione} paginazione di
singole sezioni di memoria sono \funcd{mlock} e \funcd{munlock}; i loro
prototipi sono:
\begin{functions}
\end{functions}
Le due funzioni permettono rispettivamente di bloccare e sbloccare la
-paginazione\index{paginazione} per l'intervallo di memoria specificato dagli
+\index{paginazione} paginazione per l'intervallo di memoria specificato dagli
argomenti, che ne indicano nell'ordine l'indirizzo iniziale e la lunghezza.
Tutte le pagine che contengono una parte dell'intervallo bloccato sono
mantenute in RAM per tutta la durata del blocco.\footnote{con altri kernel si
della dimensione delle pagine di memoria.}
Altre due funzioni, \funcd{mlockall} e \funcd{munlockall}, consentono di
-bloccare genericamente la paginazione\index{paginazione} per l'intero spazio
+bloccare genericamente la \index{paginazione} paginazione per l'intero spazio
di indirizzi di un processo. I prototipi di queste funzioni sono:
\begin{functions}
\headdecl{sys/mman.h}
\bodydesc{Codici di ritorno ed errori sono gli stessi di \func{mlock} e
\func{munlock}, con un kernel successivo al 2.6.9 l'uso di
- \func{munlockall} senza la \itindex{capabilities}\textit{capability}
+ \func{munlockall} senza la \itindex{capabilities} \textit{capability}
\const{CAP\_IPC\_LOCK} genera un errore di \errcode{EPERM}.}
\end{functions}
Con \func{mlockall} si possono bloccare tutte le pagine mappate nello spazio
di indirizzi del processo, sia che comprendano il \index{segmento!dati}
-\index{segmento!testo} segmento di testo, di dati, lo \itindex{stack} stack,
-lo \itindex{heap} heap e pure le funzioni di libreria chiamate, i file mappati
-in memoria, i dati del kernel mappati in user space, la memoria condivisa.
-L'uso dei flag permette di selezionare con maggior finezza le pagine da
-bloccare, ad esempio limitandosi a tutte le pagine allocate a partire da un
-certo momento.
+\index{segmento!testo} segmento di testo, di dati, lo \itindex{stack}
+\textit{stack}, lo \itindex{heap} \textit{heap} e pure le funzioni di libreria
+chiamate, i file mappati in memoria, i dati del kernel mappati in user space,
+la memoria condivisa. L'uso dei flag permette di selezionare con maggior
+finezza le pagine da bloccare, ad 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
\index{sezione~critica} sezione critica deve provvedere a riservare memoria
sufficiente prima dell'ingresso, per scongiurare l'occorrenza di un eventuale
-\textit{page fault}\itindex{page~fault} causato dal meccanismo di \textit{copy
- on write}\itindex{copy~on~write}. Infatti se nella \index{sezione~critica}
-sezione critica si va ad utilizzare memoria che non è ancora stata riportata
-in RAM si potrebbe avere un \itindex{page~fault}\textit{page fault} durante
-l'esecuzione della stessa, con conseguente rallentamento (probabilmente
-inaccettabile) dei tempi di esecuzione.
+\itindex{page~fault} \textit{page fault} causato dal meccanismo di
+\itindex{copy~on~write} \textit{copy on write}. Infatti se nella
+\index{sezione~critica} sezione critica si va ad utilizzare memoria che non è
+ancora stata riportata in RAM si potrebbe avere un \itindex{page~fault}
+\textit{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 \itindex{stack} stack, dopo di che, per
-essere sicuri che esse siano state effettivamente portate in memoria, ci si
-scrive sopra.
+che esse vengano mappate in RAM dallo \itindex{stack} \textit{stack}, dopo di
+che, per essere sicuri che esse siano state effettivamente portate in memoria,
+ci si scrive sopra.
\itindend{memory~locking}
fatta in precedenza da un'altra \func{putenv}. Questo perché il vettore delle
variabili di ambiente iniziale, creato dalla chiamata ad \func{exec} (vedi
sez.~\ref{sec:proc_exec}) è piazzato al di sopra dello \itindex{stack} stack,
-(vedi fig.~\ref{fig:proc_mem_layout}) e non nello \itindex{heap} heap e non
-può essere deallocato. Inoltre la memoria associata alle variabili di
+(vedi fig.~\ref{fig:proc_mem_layout}) e non nello \itindex{heap} \textit{heap}
+e non può essere deallocato. Inoltre la memoria associata alle variabili di
ambiente eliminate non viene liberata.
L'ultima funzione è \funcd{clearenv}, che viene usata per cancellare
Talvolta però è necessario che la funzione possa restituire indietro alla
funzione chiamante un valore relativo ad uno dei suoi argomenti. Per far
-questo si usa il cosiddetto \itindex{value~result~argument}\textit{value
+questo si usa il cosiddetto \itindex{value~result~argument} \textit{value
result argument}, si passa cioè, invece di una normale variabile, un
puntatore alla stessa; vedremo alcuni esempi di questa modalità nelle funzioni
che gestiscono i socket (in sez.~\ref{sec:TCP_functions}), in cui, per
Come vedremo nei capitoli successivi, non sempre è possibile specificare un
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,
+sua sintassi la possibilità di definire delle \index{variadic}
+\textit{variadic function} che abbiano un numero variabile di argomenti,
attraverso l'uso nella dichiarazione della funzione dello speciale costrutto
-``\texttt{\textellipsis}'', che viene chiamato \textit{ellipsis}.
+``\texttt{\textellipsis}'', che viene chiamato \textit{ellipsis}.
Lo standard però non provvede a livello di linguaggio alcun meccanismo con cui
dette funzioni possono accedere ai loro argomenti. L'accesso viene pertanto
a seguire quelli addizionali.
\end{itemize}
-Lo standard ISO C prevede che una \textit{variadic function}\index{variadic}
+Lo standard ISO C prevede che una \index{variadic} \textit{variadic function}
abbia sempre almeno un argomento fisso; prima di effettuare la dichiarazione
deve essere incluso l'apposito header file \file{stdarg.h}; un esempio di
dichiarazione è il prototipo della funzione \func{execl} che vedremo in
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 \itindex{stack} stack secondo
-l'ordine in cui sono stati scritti. Per fare questo in \file{stdarg.h} sono
-definite delle apposite macro; la procedura da seguire è la seguente:
+sequenziale; essi verranno estratti dallo \itindex{stack} \textit{stack}
+secondo l'ordine in cui sono stati scritti. Per fare questo in \file{stdarg.h}
+sono definite delle apposite macro; la procedura da seguire è la seguente:
\begin{enumerate}
\item Inizializzare un puntatore alla lista degli argomenti di tipo
\macro{va\_list} attraverso la macro \macro{va\_start}.
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
-\itindex{stack} stack all'indirizzo dove sono stati salvati gli argomenti, è
-assolutamente normale pensare di poter effettuare questa operazione.
+\itindex{stack} \textit{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
-motivo \macro{va\_list} è definito come \textsl{tipo opaco}\index{tipo!opaco}
+motivo \macro{va\_list} è definito come \index{tipo!opaco} \textsl{tipo opaco}
e non può essere assegnato 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
Uno dei possibili problemi che si possono avere con le subroutine è quello di
restituire alla funzione chiamante dei dati che sono contenuti in una
variabile automatica. Ovviamente quando la subroutine ritorna la sezione
-dello \itindex{stack} stack che conteneva la variabile automatica potrà essere
-riutilizzata da una nuova funzione, con le immaginabili conseguenze di
-sovrapposizione e sovrascrittura dei dati.
+dello \itindex{stack} \textit{stack} che conteneva la variabile automatica
+potrà essere riutilizzata da una nuova funzione, con le immaginabili
+conseguenze di sovrapposizione e sovrascrittura dei dati.
Per questo una delle regole fondamentali della programmazione in C è che
all'uscita di una funzione non deve restare nessun riferimento alle variabili
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 \itindex{stack} stack nel
-punto in cui si vuole tornare in caso di errore, e ripristinandolo, in modo da
-tornare nella funzione da cui si era partiti, quando serve. La funzione che
-permette di salvare il contesto dello \itindex{stack} stack è \funcd{setjmp},
-il cui prototipo è:
+norma viene realizzato salvando il contesto dello \itindex{stack}
+\textit{stack} nel punto in cui si vuole tornare in caso di errore, e
+ripristinandolo, in modo da tornare nella funzione da cui si era partiti,
+quando serve. La funzione che permette di salvare il contesto dello
+\itindex{stack} \textit{stack} è \funcd{setjmp}, il cui prototipo è:
\begin{functions}
\headdecl{setjmp.h}
\funcdecl{int setjmp(jmp\_buf env)}
che usa il contesto salvato in precedenza.}
\end{functions}
-Quando si esegue la funzione il contesto corrente dello \itindex{stack} stack
-viene salvato nell'argomento \param{env}, una variabile di tipo
+Quando si esegue la funzione il contesto corrente dello \itindex{stack}
+\textit{stack} viene salvato nell'argomento \param{env}, una variabile di tipo
\type{jmp\_buf}\footnote{questo è un classico esempio di variabile di
- \textsl{tipo opaco}\index{tipo!opaco}. Si definiscono così strutture ed
+ \index{tipo!opaco} \textsl{tipo opaco}. Si definiscono così strutture ed
altri oggetti usati da una libreria, la cui struttura interna non deve
essere vista dal programma chiamante (da cui il nome) che li devono
utilizzare solo attraverso dalle opportune funzioni di gestione.} che deve
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
-\itindex{stack} stack effettuando il salto non-locale. Si tenga conto che il
-contesto salvato in \param{env} viene invalidato se la funzione che ha
+\itindex{stack} \textit{stack} effettuando il salto non-locale. Si tenga conto
+che il contesto salvato in \param{env} viene invalidato se la funzione 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.
\bodydesc{La funzione non ritorna.}
\end{functions}
-La funzione ripristina il contesto dello \itindex{stack} stack salvato da una
-chiamata a \func{setjmp} nell'argomento \param{env}. Dopo l'esecuzione della
-funzione il programma prosegue nel codice successivo al ritorno della
-\func{setjmp} con cui si era salvato \param{env}, che restituirà il valore
+La funzione ripristina il contesto dello \itindex{stack} \textit{stack}
+salvato da una chiamata a \func{setjmp} nell'argomento \param{env}. Dopo
+l'esecuzione della funzione il programma prosegue nel codice successivo al
+ritorno della \func{setjmp} con cui si era salvato \param{env}, che restituirà
+il valore
\param{val} invece di zero. Il valore di \param{val} specificato nella
chiamata deve essere diverso da zero, se si è specificato 0 sarà comunque
restituito 1 al suo posto.
annidate.
L'implementazione di queste funzioni comporta alcune restrizioni dato che esse
-interagiscono direttamente con la gestione dello \itindex{stack} stack ed il
-funzionamento del compilatore stesso. In particolare \func{setjmp} è
-implementata con una macro, pertanto non si può cercare di ottenerne
-l'indirizzo, ed inoltre delle chiamate a questa funzione sono sicure solo in
-uno dei seguenti casi:
+interagiscono direttamente con la gestione dello \itindex{stack}
+\textit{stack} ed il funzionamento del compilatore stesso. In particolare
+\func{setjmp} è implementata con una macro, pertanto non si può cercare di
+ottenerne l'indirizzo, ed inoltre delle chiamate a questa funzione sono sicure
+solo in uno dei seguenti casi:
\begin{itemize}
\item come espressione di controllo in un comando condizionale, di selezione
o di iterazione (come \code{if}, \code{switch} o \code{while});
memoria manterranno il valore avuto al momento della chiamata di
\func{longjmp}, mentre quelli tenuti nei registri del processore (che nella
chiamata ad un'altra funzione vengono salvati nel contesto nello
-\itindex{stack} stack) torneranno al valore avuto al momento della chiamata di
-\func{setjmp}; per questo quando si vuole avere un comportamento coerente si
-può bloccare l'ottimizzazione che porta le variabili nei registri
-dichiarandole tutte come \direct{volatile}\footnote{la direttiva
+\itindex{stack} \textit{stack}) torneranno al valore avuto al momento della
+chiamata di \func{setjmp}; per questo quando si vuole avere un comportamento
+coerente si può bloccare l'ottimizzazione che porta le variabili nei registri
+dichiarandole tutte come \direct{volatile}.\footnote{la direttiva
\direct{volatile} informa il compilatore che la variabile che è dichiarata
può essere modificata, durante l'esecuzione del nostro, da altri programmi.
Per questo motivo occorre dire al compilatore che non deve essere mai
utilizzata l'ottimizzazione per cui quanto opportuno essa viene mantenuta in
un registro, poiché in questo modo si perderebbero le eventuali modifiche
fatte dagli altri programmi (che avvengono solo in una copia posta in
- memoria).}.
+ memoria).}
\index{salto~non-locale|)}
-%%% Local Variables:
-%%% mode: latex
-%%% TeX-master: "gapil"
-%%% End:
+
% LocalWords: like exec kernel thread main ld linux static linker char envp Gb
% LocalWords: sez POSIX exit system call cap abort shell diff errno stdlib int
% LocalWords: socket variadic ellipsis header stdarg execl self promoting last
% LocalWords: float double short register type dest src extern setjmp jmp buf
% LocalWords: env return if while sottoprocesso Di
+
+%%% Local Variables:
+%%% mode: latex
+%%% TeX-master: "gapil"
+%%% End:
%% prochand.tex
%%
-%% Copyright (C) 2000-2006 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2007 Simone Piccardi. Permission is granted to
%% copy, distribute and/or modify this document under the terms of the GNU Free
%% Documentation License, Version 1.1 or any later version published by the
%% Free Software Foundation; with the Invariant Sections being "Un preambolo",
%% license is included in the section entitled "GNU Free Documentation
%% License".
%%
+
\chapter{La gestione dei processi}
\label{cha:process_handling}
\label{fig:proc_task_struct}
\end{figure}
-Come accennato in sez.~\ref{sec:intro_unix_struct} è lo \textit{scheduler}
-\itindex{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.}
-% TODO completare questa parte.
+Come accennato in sez.~\ref{sec:intro_unix_struct} è lo \itindex{scheduler}
+\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.}
+% TODO completare questa parte su quando viene chiamato lo scheduler.
(ma può essere anche attivato esplicitamente). Il timer di sistema provvede
comunque a che esso sia invocato periodicamente, generando un interrupt
periodico secondo la frequenza specificata dalla costante \const{HZ}, definita
% TODO verificare gli ultimi cambiamenti del 2.6
% Si ha cioè un interrupt dal timer ogni centesimo di secondo.
-Ogni volta che viene eseguito, lo \textit{scheduler} \itindex{scheduler}
+Ogni volta che viene eseguito, lo \itindex{scheduler} \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.
candidato per generare ulteriori indicatori associati al processo di cui
diventa possibile garantire l'unicità: ad esempio in alcune implementazioni la
funzione \func{tempnam} (si veda sez.~\ref{sec:file_temp_file}) usa il
-\acr{pid} per generare un \itindex{pathname}\textit{pathname} univoco, che non
-potrà essere replicato da un altro processo che usi la stessa funzione.
+\acr{pid} per generare un \itindex{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
Dopo il successo dell'esecuzione di una \func{fork} sia il processo padre che
il processo figlio continuano ad essere eseguiti normalmente a partire
dall'istruzione successiva alla \func{fork}; il processo figlio è però una
-copia del padre, e riceve una copia dei segmenti di testo, \itindex{stack}
-stack e dati (vedi sez.~\ref{sec:proc_mem_layout}), ed esegue esattamente lo
-stesso codice del padre. Si tenga presente però che la memoria è copiata, non
-condivisa, pertanto padre e figlio vedono variabili diverse.
-
-Per quanto riguarda la gestione della memoria, in generale
-il\index{segmento!testo} 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}
-\itindex{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.
+copia del padre, e riceve una copia dei \index{segmento!testo} segmenti di
+testo, \itindex{stack} stack e \index{segmento!dati} dati (vedi
+sez.~\ref{sec:proc_mem_layout}), ed esegue esattamente lo stesso codice del
+padre. Si tenga presente però che la memoria è copiata, non condivisa,
+pertanto padre e figlio vedono variabili diverse.
+
+Per quanto riguarda la gestione della memoria, in generale il
+\index{segmento!testo} 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 \itindex{copy~on~write} \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
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\itindex{scheduler} di Ingo Molnar che esegue sempre per primo il
- figlio; per mantenere la portabilità è opportuno non fare comunque
+ \itindex{scheduler} \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
istruzioni del codice fra padre e figli, né sull'ordine in cui questi potranno
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}
-\itindex{race~condition} (vedi sez.~\ref{sec:proc_race_cond}).
+rischio di incorrere nelle cosiddette \itindex{race~condition} \textit{race
+ condition} (vedi sez.~\ref{sec:proc_race_cond}).
Si noti inoltre che essendo i segmenti di memoria utilizzati dai singoli
processi completamente separati, le modifiche delle variabili nei processi
proprietà; la lista dettagliata delle proprietà che padre e figlio hanno in
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}\itindex{close-on-exec} impostati (vedi
- sez.~\ref{sec:proc_exec} e sez.~\ref{sec:file_fcntl});
+\item i file aperti e gli eventuali flag di \itindex{close-on-exec}
+ \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
\textsl{group-ID effettivo} ed i \textit{group-ID supplementari} (vedi
sez.~\ref{sec:proc_access_id});
-\item gli identificatori per il controllo di sessione: il \textit{process
- group-ID} e il \textit{session id} ed il terminale di controllo (vedi
- sez.~\ref{sec:sess_proc_group});
+\item gli identificatori per il controllo di sessione: il
+ \itindex{process~group} \textit{process group-ID} e il \textit{session id}
+ ed il terminale di controllo (vedi sez.~\ref{sec:sess_proc_group});
\item la directory di lavoro e la directory radice (vedi
sez.~\ref{sec:file_work_dir} e sez.~\ref{sec:file_chroot});
\item la maschera dei permessi di creazione (vedi
- sez.~\ref{sec:file_perm_managemen});
+ sez.~\ref{sec:file_perm_managemen});
\item la maschera dei segnali bloccati (vedi sez.~\ref{sec:sig_sigmask}) e le
azioni installate (vedi sez.~\ref{sec:sig_gen_beha});
\item i segmenti di memoria condivisa agganciati al processo (vedi
\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} \itindex{copy~on~write} la
+Dato che Linux supporta il \itindex{copy~on~write} \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.
dal processo (vedi sez.~\ref{sec:sys_unix_time}) e lo stato di terminazione,
mentre la memoria in uso ed i file aperti vengono rilasciati immediatamente. I
processi che sono terminati, ma il cui stato di terminazione non è stato
-ancora ricevuto dal padre sono chiamati \textit{zombie}\index{zombie}, essi
+ancora ricevuto dal padre sono chiamati \index{zombie} \textit{zombie}, essi
restano presenti nella tabella dei processi ed in genere possono essere
identificati dall'output di \cmd{ps} per la presenza di una \texttt{Z} nella
colonna che ne indica lo stato (vedi tab.~\ref{tab:proc_proc_states}). Quando
\end{verbatim} %$
\normalsize e come si vede, dato che non si è fatto nulla per riceverne lo
stato di terminazione, i tre processi figli sono ancora presenti pur essendosi
-conclusi, con lo stato di zombie \index{zombie} e l'indicazione che sono stati
-terminati.
-
-La possibilità di avere degli zombie \index{zombie} deve essere tenuta sempre
-presente quando 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 sez.~\ref{sec:sig_sigchld} e sez.~\ref{sec:proc_wait}).
-Questa operazione è necessaria perché anche se gli \textit{zombie}
-\index{zombie} non consumano risorse di memoria o processore, occupano
-comunque una voce nella tabella dei processi, che a lungo andare potrebbe
-esaurirsi.
+conclusi, con lo stato di \index{zombie} \textit{zombie} e l'indicazione che
+sono stati terminati.
+
+La possibilità di avere degli \index{zombie} \textit{zombie} deve essere
+tenuta sempre presente quando 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 sez.~\ref{sec:sig_sigchld} e
+sez.~\ref{sec:proc_wait}). Questa operazione è necessaria perché anche se gli
+\index{zombie} \textit{zombie} non consumano risorse di memoria o processore,
+occupano comunque una voce nella tabella dei processi, che a lungo andare
+potrebbe esaurirsi.
Si noti che quando un processo adottato da \cmd{init} termina, esso non
-diviene uno \textit{zombie}\index{zombie}; questo perché una delle funzioni di
-\cmd{init} è appunto quella di chiamare la funzione \func{wait} per i processi
-cui fa da padre, completandone la terminazione. Questo è quanto avviene anche
-quando, come nel caso del precedente esempio con \cmd{forktest}, il padre
-termina con dei figli in stato di zombie\index{zombie}: alla sua terminazione
-infatti tutti i suoi figli (compresi gli zombie\index{zombie}) verranno
-adottati da \cmd{init}, il quale provvederà a completarne la terminazione.
-
-Si tenga presente infine che siccome gli zombie\index{zombie} sono processi
-già usciti, non c'è modo di eliminarli con il comando \cmd{kill}; l'unica
-possibilità di cancellarli dalla tabella dei processi è quella di terminare il
-processo che li ha generati, in modo che \cmd{init} possa adottarli e
-provvedere a concluderne la terminazione.
+diviene uno \index{zombie} \textit{zombie}; questo perché una delle funzioni
+di \cmd{init} è appunto quella di chiamare la funzione \func{wait} per i
+processi cui fa da padre, completandone la terminazione. Questo è quanto
+avviene anche quando, come nel caso del precedente esempio con \cmd{forktest},
+il padre termina con dei figli in stato di \index{zombie} \textit{zombie}:
+alla sua terminazione infatti tutti i suoi figli (compresi gli \index{zombie}
+\textit{zombie}) verranno adottati da \cmd{init}, il quale provvederà a
+completarne la terminazione.
+
+Si tenga presente infine che siccome gli \index{zombie} \textit{zombie} sono
+processi già usciti, non c'è modo di eliminarli con il comando \cmd{kill};
+l'unica possibilità di cancellarli dalla tabella dei processi è quella di
+terminare il processo che li ha generati, in modo che \cmd{init} possa
+adottarli e provvedere a concluderne la terminazione.
\subsection{Le funzioni \func{wait} e \func{waitpid}}
principale attende le richieste che vengono poi soddisfatte da una serie di
processi figli. Si è già sottolineato al paragrafo precedente come in questo
caso diventi necessario gestire esplicitamente la conclusione dei figli onde
-evitare di riempire di \textit{zombie}\index{zombie} la tabella dei processi;
+evitare di riempire di \index{zombie} \textit{zombie} la tabella dei processi;
le funzioni deputate a questo compito sono sostanzialmente due, \funcd{wait} e
\func{waitpid}. La prima, il cui prototipo è:
\begin{functions}
In genere in un programma non si vuole essere forzati ad attendere la
conclusione di un processo per proseguire, specie se tutto questo serve solo
-per leggerne lo stato di chiusura (ed evitare la presenza di
-\textit{zombie}\index{zombie}), per questo la modalità più usata per chiamare
-queste funzioni è quella di utilizzarle all'interno di un \textit{signal
- handler} (vedremo un esempio di come gestire \const{SIGCHLD} con i segnali
-in sez.~\ref{sec:sig_example}). In questo caso infatti, dato che il segnale è
+per leggerne lo stato di chiusura (ed evitare la presenza di \index{zombie}
+\textit{zombie}), per questo la modalità più usata per chiamare queste
+funzioni è quella di utilizzarle all'interno di un \textit{signal handler}
+(vedremo un esempio di come gestire \const{SIGCHLD} con i segnali in
+sez.~\ref{sec:sig_example}). In questo caso infatti, dato che il segnale è
generato dalla terminazione di un figlio, avremo la certezza che la chiamata a
\func{wait} non si bloccherà.
valutata solo se \val{WIFSIGNALED} ha restituito
un valore non nullo.\\
\macro{WCOREDUMP(s)} & Vera se il processo terminato ha generato un
- file di \itindex{core~dump}\textit{core
+ file di \itindex{core~dump} \textit{core
dump}. Può essere valutata solo se
\val{WIFSIGNALED} ha restituito un valore non
nullo.\footnotemark \\
bit (in genere 8) sono riservati per memorizzare lo stato di uscita, e altri
per indicare il segnale che ha causato la terminazione (in caso di
conclusione anomala), uno per indicare se è stato generato un
-\itindex{core~dump}\textit{core dump}, ecc.\footnote{le definizioni esatte
+\itindex{core~dump} \textit{core dump}, ecc.\footnote{le definizioni esatte
si possono trovare in \file{<bits/waitstatus.h>} ma questo file non deve
mai essere usato direttamente, esso viene incluso attraverso
\file{<sys/wait.h>}.}
processo chiama una di queste funzioni esso viene completamente sostituito dal
nuovo programma; il \acr{pid} del processo non cambia, dato che non viene
creato un nuovo processo, la funzione semplicemente rimpiazza lo
-\itindex{stack} stack, lo \itindex{heap} heap, i dati ed il testo del processo
+\itindex{stack} \textit{stack}, lo \itindex{heap} \textit{heap}, i
+\index{segmento!dati} dati ed il \index{segmento!testo} testo del processo
corrente con un nuovo programma letto da disco.
Ci sono sei diverse versioni di \func{exec} (per questo la si è chiamata
Le altre quattro funzioni si limitano invece a cercare di eseguire il file
indicato dall'argomento \param{path}, che viene interpretato come il
-\itindex{pathname}\textit{pathname} del programma.
+\itindex{pathname} \textit{pathname} del programma.
\begin{figure}[htb]
\centering
sez.~\ref{sec:sig_gen_beha}).
La gestione dei file aperti dipende dal valore che ha il flag di
-\textit{close-on-exec}\itindex{close-on-exec} (vedi anche
+\itindex{close-on-exec} \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
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}\itindex{close-on-exec} sulle
-directory che apre, in maniera trasparente all'utente.
+l'impostazione del flag di \itindex{close-on-exec} \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
l'\textsl{user-ID effettivo} ed il \textsl{group-ID effettivo} (il significato
di questi identificatori è trattato in sez.~\ref{sec:proc_access_id}), tranne
-quando il file che si va ad eseguire abbia o il \itindex{suid~bit}\acr{suid}
+quando il file che si va ad eseguire abbia o il \itindex{suid~bit} \acr{suid}
bit o lo \itindex{sgid~bit} \acr{sgid} bit impostato, in questo caso
l'\textsl{user-ID effettivo} ed il \textsl{group-ID effettivo} vengono
impostati rispettivamente all'utente o al gruppo cui il file appartiene (per i
realtà già esistono estensioni di questo modello base, che lo rendono più
flessibile e controllabile, come le \itindex{capabilities}
\textit{capabilities} illustrate in sez.~\ref{sec:proc_capabilities}, le ACL
- per i file o il \textit{Mandatory Access Control}
- \itindex{Mandatory~Access~Control~(MAC)} di SELinux; inoltre basandosi sul
- lavoro effettuato con SELinux, a partire dal kernel 2.5.x, è iniziato lo
- sviluppo di una infrastruttura di sicurezza, il \textit{Linux Security
- Modules}, o LSM, in grado di fornire diversi agganci a livello del kernel
- per modularizzare tutti i possibili controlli di accesso.} 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
-utenti, per i quali invece vengono effettuati i vari controlli di accesso.
+ per i file o il \itindex{Mandatory~Access~Control~(MAC)} \textit{Mandatory
+ Access Control} di SELinux; inoltre basandosi sul lavoro effettuato con
+ SELinux, a partire dal kernel 2.5.x, è iniziato lo sviluppo di una
+ infrastruttura di sicurezza, il \textit{Linux Security Modules}, o LSM, in
+ grado di fornire diversi agganci a livello del kernel per modularizzare
+ tutti i possibili controlli di accesso.} 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 utenti, per i quali invece
+vengono effettuati i vari controlli di accesso.
Abbiamo già accennato come il sistema associ ad ogni utente e gruppo due
identificatori univoci, lo user-ID ed il group-ID; questi servono al kernel per
padre, e vengono impostati dalla funzione \func{exec} all'avvio del processo,
come copie dell'\textsl{user-ID effettivo} e del \textsl{group-ID effettivo}
dopo che questi sono stati impostati tenendo conto di eventuali
-\itindex{suid~bit}\acr{suid} o \itindex{sgid~bit} \acr{sgid}. Essi quindi
+\itindex{suid~bit} \acr{suid} o \itindex{sgid~bit} \acr{sgid}. Essi quindi
consentono di tenere traccia di quale fossero utente e gruppo effettivi
all'inizio dell'esecuzione di un nuovo programma.
Anche queste funzioni sono un'estensione specifica di Linux, e non richiedono
nessun privilegio. I valori sono restituiti negli argomenti, che vanno
specificati come puntatori (è un altro esempio di
-\itindex{value~result~argument}\textit{value result argument}). Si noti che
+\itindex{value~result~argument} \textit{value result argument}). Si noti che
queste funzioni sono le uniche in grado di leggere gli identificatori del
gruppo \textit{saved}.
\label{sec:proc_priority}
In questa sezione tratteremo più approfonditamente i meccanismi con il quale
-lo \textit{scheduler}\itindex{scheduler} assegna la CPU ai vari processi
+lo \itindex{scheduler} \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.
\label{sec:proc_sched}
\itindbeg{scheduler}
+
La scelta di un meccanismo che sia in grado di distribuire in maniera efficace
il tempo di CPU per l'esecuzione dei processi è sempre una questione delicata,
ed oggetto di numerose ricerche; in generale essa dipende in maniera
cui non esiste un meccanismo che sia valido per tutti gli usi.
La caratteristica specifica di un sistema multitasking come Linux è quella del
-cosiddetto \itindex{prehemptive~multitasking}\textit{prehemptive
+cosiddetto \itindex{prehemptive~multitasking} \textit{prehemptive
multitasking}: questo significa che al contrario di altri sistemi (che usano
-invece il cosiddetto \itindex{cooperative~multitasking}\textit{cooperative
+invece il cosiddetto \itindex{cooperative~multitasking} \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
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
-\textit{page fault}\itindex{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.
+\itindex{page~fault} \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.
Occorre usare le priorità assolute con molta attenzione: se si dà ad un
processo una priorità assoluta e questo finisce in un loop infinito, nessun
funzioni che permettono di controllare in maniera più dettagliata la scelta di
quale processore utilizzare per eseguire un certo programma. Uno dei problemi
che si pongono nei sistemi multiprocessore è infatti quello
-dell'\textsl{effetto ping-pong}.\index{effetto~ping-pong} Può accadere cioè
+\index{effetto~ping-pong} dell'\textsl{effetto ping-pong}. Può accadere cioè
che lo scheduler, quando riavvia un processo precedentemente interrotto,
scegliendo il primo processore disponibile lo faccia eseguire da un processore
diverso rispetto a quello su cui era stato eseguito in precedenza. Se il
disponibile.
\itindbeg{CPU~affinity}
+
Per ovviare a questo tipo di problemi è nato il concetto di \textsl{affinità
di processore} (o \textit{CPU affinity}); la
possibilità cioè di far sì che un processo possa essere assegnato per
soltanto su un sistema multiprocessore, esse possono comunque essere
utilizzate anche in un sistema con un processore singolo, nel qual caso però
non avranno alcun risultato effettivo.
+
\itindend{scheduler}
\itindend{CPU~affinity}
In un ambiente multitasking il concetto è essenziale, dato che un processo può
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}\itindex{race~condition} (vedi sez.~\ref{sec:proc_race_cond})
-derivanti da operazioni interrotte in una fase in cui non erano ancora state
-completate.
+accorti nei confronti delle possibili \itindex{race~condition} \textit{race
+ condition} (vedi sez.~\ref{sec:proc_race_cond}) derivanti da operazioni
+interrotte in una fase in cui non erano ancora state completate.
Nel caso dell'interazione fra processi la situazione è molto più semplice, ed
occorre preoccuparsi della atomicità delle operazioni solo quando si ha a che
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{sezione~critica}) del programma, siano
+\index{sezione~critica} \textsl{sezioni critiche}) del programma, siano
opportunamente protette da meccanismi di sincronizzazione (torneremo su queste
problematiche di questo tipo in cap.~\ref{cha:IPC}).
%% ringraziamenti.tex
%%
-%% Copyright (C) 2000-2006 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2007 Simone Piccardi. Permission is granted to
%% copy, distribute and/or modify this document under the terms of the GNU Free
%% Documentation License, Version 1.1 or any later version published by the
%% Free Software Foundation; with the Invariant Sections being "Un preambolo",
aiutato ed han contribuito a migliorare in molteplici aspetti la qualità di
GaPiL. In ordine rigorosamente alfabetico desidero citare:
\begin{description}
-\item[\textbf{Alessio Frusciante}] per l'apprezzamento, le molteplici
+\item[\textbf{Alessio Frusciante}] per l'apprezzamento, le innumerevoli
correzioni ed i suggerimenti per rendere più chiara l'esposizione.
\item[\textbf{Daniele Masini}] per la rilettura puntuale, le innumerevoli
correzioni, i consigli sull'esposizione ed i contributi relativi alle
{\texttt{http://gapil.truelite.it/sources}}.
+% LocalWords: GaPiL Masini calling convention Maischberger HTML Group FLUG CVS
+% LocalWords: repository Truelite Srl SVN
+
+
%%% Local Variables:
%%% mode: latex
%%% TeX-master: "gapil"
%%% End:
-% LocalWords: GaPiL Masini calling convention Maischberger HTML Group FLUG CVS
-% LocalWords: repository Truelite Srl SVN
%% session.tex
%%
-%% Copyright (C) 2000-2006 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2007 Simone Piccardi. Permission is granted to
%% copy, distribute and/or modify this document under the terms of the GNU Free
%% Documentation License, Version 1.1 or any later version published by the
%% Free Software Foundation; with the Invariant Sections being "Un preambolo",
%% license is included in the section entitled "GNU Free Documentation
%% License".
%%
+
\chapter{Terminali e sessioni di lavoro}
\label{cha:session}
In generale allora all'interno di una sessione avremo un eventuale (può non
esserci) \itindex{process~group} \textit{process group} in
\textit{foreground}, che riunisce i processi che possono accedere al
-terminale, e più \textit{process group} in \textit{background}, che non
-possono accedervi. Il job control prevede che quando un processo appartenente
-ad un raggruppamento in \textit{background} cerca di accedere al terminale,
-venga inviato un segnale a tutti i processi del raggruppamento, in modo da
-bloccarli (vedi sez.~\ref{sec:sess_ctrl_term}).
+terminale, e più \itindex{process~group} \textit{process group} in
+\textit{background}, che non possono accedervi. Il job control prevede che
+quando un processo appartenente ad un raggruppamento in \textit{background}
+cerca di accedere al terminale, venga inviato un segnale a tutti i processi
+del raggruppamento, in modo da bloccarli (vedi sez.~\ref{sec:sess_ctrl_term}).
Un comportamento analogo si ha anche per i segnali generati dai comandi di
tastiera inviati dal terminale che vengono inviati a tutti i processi del
processi dall'uno all'altro, ma sempre all'interno di una stessa sessione.
Ciascun raggruppamento di processi ha sempre un processo principale, il
-cosiddetto \itindex{process~group~leader}\textit{process group leader}, che è
+cosiddetto \itindex{process~group~leader} \textit{process group leader}, che è
identificato dall'avere un \acr{pgid} uguale al suo \acr{pid}, in genere
questo è il primo processo del raggruppamento, che si incarica di lanciare
tutti gli altri. Un nuovo raggruppamento si crea con la funzione
quest'ultimo, per sé stesso, in modo che il cambiamento di \textit{process
group} sia immediato 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 \textit{race
- condition}\itindex{race~condition}.
+occorre eseguirle comunque entrambe per evitare di esporsi ad una
+\itindex{race~condition} \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
controllo. Consideriamo allora cosa avviene di norma nel \textit{job
control}: una sessione viene creata con \func{setsid} che crea anche un
nuovo \itindex{process~group} \textit{process group}: per definizione
-quest'ultimo è sempre \textsl{orfano}, dato che il padre del leader di
-sessione è fuori dalla stessa e il nuovo \textit{process group}
-\itindex{process~group} contiene solo il leader di sessione. Questo è un caso
-limite, e non viene emesso nessun segnale perché quanto previsto dallo
-standard riguarda solo i raggruppamenti che diventano orfani in seguito alla
-terminazione di un processo.\footnote{l'emissione dei segnali infatti avviene
- solo nella fase di uscita del processo, come una delle operazioni legate
- all'esecuzione di \func{\_exit}, secondo quanto illustrato in
- sez.~\ref{sec:proc_termination}.}
+quest'ultimo è sempre \itindex{process~group~orphaned} \textsl{orfano}, dato
+che il padre del leader di sessione è fuori dalla stessa e il nuovo
+\textit{process group} \itindex{process~group} contiene solo il leader di
+sessione. Questo è un caso limite, e non viene emesso nessun segnale perché
+quanto previsto dallo standard riguarda solo i raggruppamenti che diventano
+orfani in seguito alla terminazione di un processo.\footnote{l'emissione dei
+ segnali infatti avviene solo nella fase di uscita del processo, come una
+ delle operazioni legate all'esecuzione di \func{\_exit}, secondo quanto
+ illustrato in sez.~\ref{sec:proc_termination}.}
Il leader di sessione provvederà a creare nuovi raggruppamenti che a questo
punto non sono orfani in quanto esso resta padre per almeno uno dei processi
\textit{pathname} del terminale.}
\end{prototype}
-La funzione scrive il \itindex{pathname}\textit{pathname} del terminale di
+La funzione scrive il \itindex{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
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 \itindex{pathname}\textit{pathname} restituito
+tenga presente che il \itindex{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.
Qui vanno le cose su \func{openpty} e compagnia.
-%%% Local Variables:
-%%% mode: latex
-%%% TeX-master: "gapil"
-%%% End:
% LocalWords: kernel multitasking dell'I job control BSD POSIX shell sez group
% LocalWords: foreground process bg fg Di waitpid WUNTRACED pgrp session sched
% LocalWords: cfgetospeed quest'ultime tcsendbreak duration break tcdrain
% LocalWords: tcflush queue TCIFLUSH TCOFLUSH TCIOFLUSH tcflow action TCOOFF
% LocalWords: TCOON TCIOFF TCION timer openpty Window nochdir
+
+
+%%% Local Variables:
+%%% mode: latex
+%%% TeX-master: "gapil"
+%%% End:
\ No newline at end of file
%% signal.tex
%%
-%% Copyright (C) 2000-2006 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2007 Simone Piccardi. Permission is granted to
%% copy, distribute and/or modify this document under the terms of the GNU Free
%% Documentation License, Version 1.1 or any later version published by the
%% Free Software Foundation; with the Invariant Sections being "Un preambolo",
%% license is included in the section entitled "GNU Free Documentation
%% License".
%%
+
\chapter{I segnali}
\label{cha:signals}
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 \textit{race condition}\itindex{race~condition}
+sono sempre possibili delle \itindex{race~condition} \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
\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 \itindex{scheduler} quando,
+procedura viene effettuata dallo \itindex{scheduler} scheduler quando,
riprendendo l'esecuzione del processo in questione, verifica la presenza del
segnale nella \struct{task\_struct} e mette in esecuzione il gestore.
Normalmente l'invio al processo che deve ricevere il segnale è immediato ed
avviene non appena questo viene rimesso in esecuzione dallo
-scheduler \itindex{scheduler} che esegue l'azione specificata. Questo a meno
+\itindex{scheduler} 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
sez.~\ref{sec:sig_sigaction}). Se si è installato un gestore sarà 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 \textit{race
- condition}\itindex{race~condition}).
+automaticamente bloccato (così si possono evitare \itindex{race~condition}
+\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
I segnali che rappresentano errori del programma (divisione per zero o
violazioni di accesso) hanno anche la caratteristica di scrivere un file di
-\itindex{core~dump}\textit{core dump} che registra lo stato del processo (ed
+\itindex{core~dump} \textit{core dump} che registra lo stato del processo (ed
in particolare della memoria e dello \itindex{stack} stack) prima della
terminazione. Questo può essere esaminato in seguito con un debugger per
investigare sulla causa dell'errore. Lo stesso avviene se i suddetti segnali
In alcuni casi alla terminazione del processo è associata la creazione di un
file (posto nella directory corrente del processo e chiamato \file{core}) su
cui viene salvata un'immagine della memoria del processo (il cosiddetto
-\itindex{core~dump}\textit{core dump}), che può essere usata da un debugger
+\itindex{core~dump} \textit{core dump}), che può essere usata da un debugger
per esaminare lo stato dello \itindex{stack} stack e delle variabili al
momento della ricezione del segnale.
\label{sec:sig_prog_error}
Questi segnali sono generati quando il sistema, o in certi casi direttamente
-l'hardware (come per i \itindex{page~fault}\textit{page fault} non validi)
+l'hardware (come per i \itindex{page~fault} \textit{page fault} non validi)
rileva un qualche errore insanabile nel programma in esecuzione. In generale
la generazione di questi segnali significa che il programma ha dei gravi
problemi (ad esempio ha dereferenziato un puntatore non valido o ha eseguito
In genere si intercettano questi segnali per permettere al programma di
terminare in maniera pulita, ad esempio per ripristinare le impostazioni della
-console o eliminare i file di lock\index{file!di lock} prima dell'uscita. In
+console o eliminare i \index{file!di lock} file di lock prima dell'uscita. In
questo caso il gestore deve concludersi ripristinando l'azione predefinita e
rialzando il segnale, in questo modo il programma si concluderà senza effetti
spiacevoli, ma riportando lo stesso stato di uscita che avrebbe avuto se il
L'azione predefinita per tutti questi segnali è causare la terminazione del
processo che li ha causati. In genere oltre a questo il segnale provoca pure
-la registrazione su disco di un file di \itindex{core~dump}\textit{core dump}
+la registrazione su disco di un file di \itindex{core~dump} \textit{core dump}
che viene scritto in un file \file{core} nella directory corrente del processo
al momento dell'errore, che il debugger può usare per ricostruire lo stato del
programma al momento della terminazione. Questi segnali sono:
comando \cmd{kill} o dall'invio sul terminale del carattere di controllo
INTR (interrupt, generato dalla sequenza \cmd{C-c}).
-\item[\const{SIGQUIT}] È analogo a \const{SIGINT} con la differenza
- che è controllato da un altro carattere di controllo, QUIT,
- corrispondente alla sequenza \texttt{C-\bslash}. A differenza del
- precedente l'azione predefinita, oltre alla terminazione del
- processo, comporta anche la creazione di un
- \itindex{core~dump}\textit{core dump}.
+\item[\const{SIGQUIT}] È analogo a \const{SIGINT} con la differenza che è
+ controllato da un altro carattere di controllo, QUIT, corrispondente alla
+ sequenza \texttt{C-\bslash}. A differenza del precedente l'azione
+ predefinita, oltre alla terminazione del processo, comporta anche la
+ creazione di un \itindex{core~dump} \textit{core dump}.
In genere lo si può pensare come corrispondente ad una condizione di errore
del programma rilevata dall'utente. Per questo motivo non è opportuno fare
eseguire al gestore di questo segnale le operazioni di pulizia normalmente
previste (tipo la cancellazione di file temporanei), dato che in certi casi
- esse possono eliminare informazioni utili nell'esame dei \textit{core dump}.
- \itindex{core~dump}
+ esse possono eliminare informazioni utili nell'esame dei \itindex{core~dump}
+ \textit{core dump}.
+
\item[\const{SIGKILL}] Il nome è utilizzato per terminare in maniera immediata
qualunque programma. Questo segnale non può essere né intercettato, né
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
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 \index{file!di~dispositivo} file di dispositivo, i
socket o le pipe);
\item la scrittura sugli stessi file, nel caso in cui dati non possano essere
accettati immediatamente (di nuovo comune per i socket);
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 \itindex{scheduler}
+occorrerà almeno attendere il successivo giro di \itindex{scheduler} 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
padre.\footnote{in realtà in SVr4 eredita la semantica di System V, in cui il
segnale si chiama \const{SIGCLD} e viene trattato in maniera speciale; in
System V infatti se si imposta esplicitamente l'azione a \const{SIG\_IGN} il
- segnale non viene generato ed il sistema non genera zombie\index{zombie} (lo
- stato di terminazione viene scartato senza dover chiamare una \func{wait}).
- L'azione predefinita è sempre quella di ignorare il segnale, ma non attiva
- questo comportamento. Linux, come BSD e POSIX, non supporta questa semantica
- ed usa il nome di \const{SIGCLD} come sinonimo di \const{SIGCHLD}.} In
-generale dunque, quando non interessa elaborare lo stato di uscita di un
-processo, si può completare la gestione della terminazione installando un
-gestore per \const{SIGCHLD} il cui unico compito sia quello di chiamare
-\func{waitpid} per completare la procedura di terminazione in modo da evitare
-la formazione di zombie\index{zombie}.
+ segnale non viene generato ed il sistema non genera \index{zombie} zombie
+ (lo stato di terminazione viene scartato senza dover chiamare una
+ \func{wait}). L'azione predefinita è sempre quella di ignorare il segnale,
+ ma non attiva questo comportamento. Linux, come BSD e POSIX, non supporta
+ questa semantica ed usa il nome di \const{SIGCLD} come sinonimo di
+ \const{SIGCHLD}.} In generale dunque, quando non interessa elaborare lo
+stato di uscita di un processo, si può completare la gestione della
+terminazione installando un gestore per \const{SIGCHLD} il cui unico compito
+sia quello di chiamare \func{waitpid} per completare la procedura di
+terminazione in modo da evitare la formazione di \index{zombie} zombie.
In fig.~\ref{fig:sig_sigchld_handl} è mostrato il codice contenente una
implementazione generica di una funzione di gestione per \const{SIGCHLD}, (che
di sez.~\ref{sec:proc_termination}, invocando \cmd{forktest} con l'opzione
\cmd{-s} (che si limita ad effettuare l'installazione di questa funzione come
gestore di \const{SIGCHLD}) potremo verificare che non si ha più la creazione
-di zombie\index{zombie}.
+di \index{zombie} zombie.
\begin{figure}[!htb]
\footnotesize \centering
Allora, nel caso della terminazione dei processi figli, se si chiamasse
\func{waitpid} una sola volta, essa leggerebbe lo stato di terminazione per un
solo processo, anche se i processi terminati sono più di uno, e gli altri
-resterebbero in stato di zombie\index{zombie} per un tempo indefinito.
+resterebbero in stato di \index{zombie} zombie per un tempo indefinito.
Per questo occorre ripetere la chiamata di \func{waitpid} fino a che essa non
ritorni un valore nullo, segno che non resta nessun processo di cui si debba
Le funzioni esaminate finora fanno riferimento alle modalità più elementari
della gestione dei segnali; non si sono pertanto ancora prese in
-considerazione le tematiche più complesse, collegate alle varie \textit{race
- condition}\itindex{race~condition} che i segnali possono generare e alla
-natura asincrona degli stessi.
+considerazione le tematiche più complesse, collegate alle varie
+\itindex{race~condition} \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
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 \textit{race condition}\itindex{race~condition}.
+presenta una pericolosa \itindex{race~condition} \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 di quest'ultima, cosicché essa
sarebbe eseguita dopo l'arrivo di \const{SIGALRM}. In questo caso ci si
-troverebbe di fronte ad un deadlock\itindex{deadlock}, in quanto \func{pause}
+troverebbe di fronte ad un \itindex{deadlock} 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
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
-\itindex{race~condition}\textit{race condition}; infatti, in una situazione in
-cui un segnale è già arrivato (e \var{flag} è già ad 1) se un altro segnale
-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 \itindex{race~condition}
+\textit{race condition}; infatti, in una situazione in cui un segnale è già
+arrivato (e \var{flag} è già ad 1) se un altro segnale 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
delle funzioni più sofisticate di quelle finora illustrate, queste hanno la
perduta alla conclusione del terminatore.
Benché con l'uso di \func{sigprocmask} si possano risolvere la maggior parte
-dei casi di \textit{race condition}\itindex{race~condition} restano aperte
+dei casi di \itindex{race~condition} \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
\var{sleep\_mask} per riattivare \const{SIGALRM} all'esecuzione di
\func{sigsuspend}.
-In questo modo non sono più possibili \textit{race
- condition}\itindex{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 \itindex{race~condition} \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};
\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\itindex{deadlock} dovuto all'arrivo del segnale prima dell'esecuzione
-di \func{sigsuspend}.
+\itindex{deadlock} deadlock dovuto all'arrivo del segnale prima
+dell'esecuzione di \func{sigsuspend}.
\itindend{signal~mask}
\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 \index{salto~non-locale} salto non-locale.
\funcdecl{void siglongjmp(sigjmp\_buf env, int val)} Esegue un salto
non-locale su un precedente contesto.
Le due funzioni prendono come primo argomento la variabile su cui viene
salvato il contesto dello \itindex{stack} stack per permettere il
-\index{salto~non-locale}salto non-locale; nel caso specifico essa è di tipo
+\index{salto~non-locale} 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.
%% sockadv.tex
%%
-%% Copyright (C) 2004-2006 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2004-2007 Simone Piccardi. Permission is granted to
%% copy, distribute and/or modify this document under the terms of the GNU Free
%% Documentation License, Version 1.1 or any later version published by the
%% Free Software Foundation; with the Invariant Sections being "Un preambolo",
%% license is included in the section entitled "GNU Free Documentation
%% License".
%%
+
\chapter{Socket avanzati}
\label{cha:advanced_socket}
%% sockctrl.tex
%%
-%% Copyright (C) 2004-2006 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2004-2007 Simone Piccardi. Permission is granted to
%% copy, distribute and/or modify this document under the terms of the GNU Free
%% Documentation License, Version 1.1 or any later version published by the
%% Free Software Foundation; with the Invariant Sections being "Prefazione",
%% license is included in the section entitled "GNU Free Documentation
%% License".
%%
+
\chapter{La gestione dei socket}
\label{cha:sock_generic_management}
\subsection{La risoluzione dei nomi a dominio}
\label{sec:sock_name_services}
-La principale funzionalità del \itindex{resolver}\textit{resolver} resta
+La principale funzionalità del \itindex{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
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 \itindex{resolver}\textit{resolver}; dato che
+modificare le opzioni del \itindex{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 è:
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
-\itindex{resolver}\textit{resolver} usando \func{gethostbyname} e poi ne
+\itindex{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.
copiare il contenuto della sola struttura non è sufficiente per salvare tutti
i dati, in quanto questa contiene puntatori ad altri dati, che pure possono
essere sovrascritti; per questo motivo, se si vuole salvare il risultato di
-una chiamata, occorrerà eseguire quella che si chiama una
-\itindex{deep~copy}\textit{deep copy}.\footnote{si chiama così quella tecnica
- per cui, quando si deve copiare il contenuto di una struttura complessa (con
- puntatori che puntano ad altri dati, che a loro volta possono essere
- puntatori ad altri dati) si deve copiare non solo il contenuto della
- struttura, ma eseguire una scansione per risolvere anche tutti i puntatori
- contenuti in essa (e così via se vi sono altre sottostrutture con altri
- puntatori) e copiare anche i dati da questi referenziati.}
+una chiamata, occorrerà eseguire quella che si chiama una \itindex{deep~copy}
+\textit{deep copy}.\footnote{si chiama così quella tecnica per cui, quando si
+ deve copiare il contenuto di una struttura complessa (con puntatori che
+ puntano ad altri dati, che a loro volta possono essere puntatori ad altri
+ dati) si deve copiare non solo il contenuto della struttura, ma eseguire una
+ scansione per risolvere anche tutti i puntatori contenuti in essa (e così
+ via se vi sono altre sottostrutture con altri puntatori) e copiare anche i
+ dati da questi referenziati.}
Per ovviare a questi problemi nelle \acr{glibc} sono definite anche delle
versioni rientranti delle precedenti funzioni, al solito queste sono
\param{buf} e \param{buflen}.
Gli ultimi due argomenti vengono utilizzati per avere indietro i risultati
-come \itindex{value~result~argument}\textit{value result argument}, si deve
+come \itindex{value~result~argument} \textit{value result argument}, si deve
specificare l'indirizzo della variabile su cui la funzione dovrà salvare il
codice di errore con \param{h\_errnop} e quello su cui dovrà salvare il
puntatore che si userà per accedere i dati con \param{result}.
rientrante, ed alloca autonomamente tutta la memoria necessaria in cui
verranno riportati i risultati della risoluzione. La funzione scriverà
all'indirizzo puntato da \param{res} il puntatore iniziale ad una
-\itindex{linked~list}\textit{linked list} di strutture di tipo
+\itindex{linked~list} \textit{linked list} di strutture di tipo
\struct{addrinfo} contenenti tutte le informazioni ottenute.
\begin{figure}[!htb]
\begin{figure}[!htb]
\centering
\includegraphics[width=10cm]{img/addrinfo_list}
- \caption{La \itindex{linked~list}\textit{linked list} delle strutture
+ \caption{La \itindex{linked~list} \textit{linked list} delle strutture
\struct{addrinfo} restituite da \func{getaddrinfo}.}
\label{fig:sock_addrinfo_list}
\end{figure}
Come primo esempio di uso di \func{getaddrinfo} vediamo un programma
-elementare di interrogazione del \itindex{resolver}\textit{resolver} basato
+elementare di interrogazione del \itindex{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
\end{Verbatim}
%$
-Una volta estratti i risultati dalla \itindex{linked~list}\textit{linked list}
+Una volta estratti i risultati dalla \itindex{linked~list} \textit{linked list}
puntata da \param{res} se questa non viene più utilizzata si dovrà avere cura
di disallocare opportunamente tutta la memoria, per questo viene fornita
l'apposita funzione \funcd{freeaddrinfo}, il cui prototipo è:
Si tenga presente infine che se si copiano i risultati da una delle strutture
\struct{addrinfo} restituite nella lista indicizzata da \param{res}, occorre
-avere cura di eseguire una \itindex{deep~copy}\textit{deep copy} in cui
+avere cura di eseguire una \itindex{deep~copy} \textit{deep copy} in cui
si copiano anche tutti i dati presenti agli indirizzi contenuti nella
struttura \struct{addrinfo}, perché una volta disallocati i dati con
\func{freeaddrinfo} questi non sarebbero più disponibili.
per entrambe le funzioni. In questo caso \param{optval} viene usato per
ricevere le informazioni ed indica l'indirizzo a cui andranno scritti i dati
letti dal socket, infine \param{optlen} diventa un puntatore ad una variabile
-che viene usata come \itindex{value~result~argument}\textit{value result
+che viene usata come \itindex{value~result~argument} \textit{value result
argument} per indicare, prima della chiamata della funzione, la lunghezza
del buffer allocato per \param{optval} e per ricevere indietro, dopo la
chiamata della funzione, la dimensione effettiva dei dati scritti su di esso.
%% socket.tex
%%
-%% Copyright (C) 2000-2006 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2007 Simone Piccardi. Permission is granted to
%% copy, distribute and/or modify this document under the terms of the GNU Free
%% Documentation License, Version 1.1 or any later version published by the
%% Free Software Foundation; with the Invariant Sections being "Un preambolo",
%% license is included in the section entitled "GNU Free Documentation
%% License".
%%
+
\chapter{Introduzione ai socket}
\label{cha:socket_intro}
dall'utente generico, ad esempio in generale tutti i socket di tipo
\const{SOCK\_RAW} possono essere creati solo da processi che hanno i privilegi
di amministratore (cioè con user-ID effettivo uguale a zero) o dotati della
-\itindex{capabilities}\textit{capability} \const{CAP\_NET\_RAW}.
+\itindex{capabilities} \textit{capability} \const{CAP\_NET\_RAW}.
\subsection{Il tipo di socket}
specifica il \textsl{numero di porta}. I numeri di porta sotto il 1024 sono
chiamati \textsl{riservati} in quanto utilizzati da servizi standard e
soltanto processi con i privilegi di amministratore (con user-ID effettivo
-uguale a zero) o con la \itindex{capabilities}\textit{capability}
+uguale a zero) o con la \itindex{capabilities} \textit{capability}
\const{CAP\_NET\_BIND\_SERVICE} possono usare la funzione \func{bind} (che
vedremo in sez.~\ref{sec:TCP_func_bind}) su queste porte.
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
-\itindex{pathname}\textit{pathname} del file; nel secondo invece
+\itindex{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.
pacchetti, qualunque sia il loro protocollo di collegamento. Ovviamente l'uso
di questi socket è una operazione privilegiata e può essere effettuati solo da
un processo con i privilegi di amministratore (user-ID effettivo nullo) o con
-la \itindex{capabilities}\textit{capability} \const{CAP\_NET\_RAW}.
+la \itindex{capabilities} \textit{capability} \const{CAP\_NET\_RAW}.
Una volta aperto un \textit{packet socket}, tutti i pacchetti del protocollo
specificato passeranno attraverso di esso, qualunque sia l'interfaccia da cui
\subsection{Le funzioni per il riordinamento}
\label{sec:sock_func_ord}
-Il problema connesso all'endianess\itindex{endianess} è che quando si passano
+Il problema connesso \itindex{endianess} all'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
%% system.tex
%%
-%% Copyright (C) 2000-2006 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2007 Simone Piccardi. Permission is granted to
%% copy, distribute and/or modify this document under the terms of the GNU Free
%% Documentation License, Version 1.1 or any later version published by the
%% Free Software Foundation; with the Invariant Sections being "Un preambolo",
%% license is included in the section entitled "GNU Free Documentation
%% License".
%%
+
\chapter{La gestione del sistema, del tempo e degli errori}
\label{cha:system}
\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
- \itindex{pathname}\textit{pathname}.\\
+ \itindex{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
\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
- \itindex{pathname}\textit{pathname}.\\
+ \itindex{pathname} \textit{pathname}.\\
\const{\_POSIX\_PIPE\_BUF}& 512 & byte scrivibili atomicamente in una
pipe.\\
\const{\_POSIX\_MAX\_CANON}&255 & dimensione di una riga di
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
-\itindex{pathname}\textit{pathname}. Il suo prototipo è:
+\itindex{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 \itindex{pathname}\textit{pathname}; pertanto gli errori
+ invece di un \itindex{pathname} \textit{pathname}; pertanto gli errori
restituiti cambiano di conseguenza.}
\end{prototype}
\noindent ed il suo comportamento è identico a quello di \func{pathconf}.
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 \itindex{pathname}\textit{pathname} (da cui l'uso
+per la risoluzione di un \itindex{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
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 \itindex{pathname}\textit{pathname} e leggendo e scrivendo sul
+specificando un \itindex{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
\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 \itindex{pathname}\textit{pathname}, o si è cercato
+ componenti del \itindex{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}.
\hline
\const{MS\_RDONLY} & 1 & monta in sola lettura.\\
\const{MS\_NOSUID} & 2 & ignora i bit \itindex{suid~bit} \acr{suid} e
- \itindex{sgid~bit}\acr{sgid}.\\
+ \itindex{sgid~bit} \acr{sgid}.\\
\const{MS\_NODEV} & 4 & impedisce l'accesso ai file di dispositivo.\\
\const{MS\_NOEXEC} & 8 & impedisce di eseguire programmi.\\
\const{MS\_SYNCHRONOUS}& 16 & abilita la scrittura sincrona.\\
informazioni degli utenti e dei gruppi per insiemi di macchine, in modo da
mantenere coerenti i dati, ha portato anche alla necessità di poter recuperare
e memorizzare dette informazioni su supporti diversi, introducendo il sistema
-del \itindex{Name~Service~Switch}\textit{Name Service Switch} che tratteremo
+del \itindex{Name~Service~Switch} \textit{Name Service Switch} che tratteremo
brevemente più avanti (in sez.~\ref{sec:sock_resolver}) dato che la maggior
parte delle sua applicazioni sono relative alla risoluzioni di nomi di rete.
Le funzioni viste finora sono in grado di leggere le informazioni sia
direttamente dal file delle password in \file{/etc/passwd} che tramite il
-sistema del \itindex{Name~Service~Switch}\textit{Name Service Switch} e
+sistema del \itindex{Name~Service~Switch} \textit{Name Service Switch} e
sono completamente generiche. Si noti però che non c'è una funzione che
permetta di impostare direttamente una password.\footnote{in realtà questo può
essere fatto ricorrendo a PAM, ma questo è un altro discorso.} Dato che
Gli altri tre campi servono a quantificare l'uso della memoria
virtuale\index{memoria~virtuale} e corrispondono rispettivamente al numero di
-\textit{page fault}\itindex{page~fault} (vedi sez.~\ref{sec:proc_mem_gen})
+\itindex{page~fault} \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
stack il processo riceverà un segnale di
\const{SIGSEGV}. \\
\const{RLIMIT\_CORE} & La massima dimensione per di un file di
- \textit{core dump}\itindex{core~dump} (vedi
+ \itindex{core~dump} \textit{core dump} (vedi
sez.~\ref{sec:sig_prog_error}) creato nella
terminazione di un processo; file di dimensioni
maggiori verranno troncati a questo valore,
mentre con un valore si bloccherà la creazione
- dei \textit{core dump}\itindex{core~dump}.\\
+ dei \itindex{core~dump} \textit{core dump}.\\
\const{RLIMIT\_CPU} & Il massimo tempo di CPU (vedi
sez.~\ref{sec:sys_cpu_times}) che il processo può
usare. Il superamento del limite corrente
dei due limiti.} comporta o l'emissione di un segnale o il fallimento della
system call che lo ha provocato;\footnote{si nuovo c'è una eccezione per
\const{RLIMIT\_CORE} che influenza soltanto la dimensione (o l'eventuale
- creazione) dei file di \itindex{core~dump}\textit{core dump}.} per
+ creazione) dei file di \itindex{core~dump} \textit{core dump}.} per
permettere di leggere e di impostare i limiti di utilizzo delle risorse da
parte di un processo sono previste due funzioni, \funcd{getrlimit} e
\funcd{setrlimit}, i cui prototipi sono:
anche usare la costante \const{RLIM\_INFINITY} che permette di sbloccare l'uso
di una risorsa; ma si ricordi che solo un processo con i privilegi di
amministratore\footnote{per essere precisi in questo caso quello che serve è
- la \itindex{capabilities}\textit{capability} \const{CAP\_SYS\_RESOURCE}.}
+ la \itindex{capabilities} \textit{capability} \const{CAP\_SYS\_RESOURCE}.}
può innalzare un limite al di sopra del valore corrente del limite massimo ed
usare un valore qualsiasi per entrambi i limiti. Si tenga conto infine che
tutti i limiti vengono ereditati dal processo padre attraverso una \func{fork}
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 \index{memoria~virtuale} memoria virtuale attraverso la
divisione della memoria fisica in pagine.
In genere tutto ciò è del tutto trasparente al singolo processo, ma in certi
che usa lo stesso meccanismo per accedere ai file, è necessario conoscere le
dimensioni delle pagine usate dal kernel. Lo stesso vale quando si vuole
gestire in maniera ottimale l'interazione della memoria che si sta allocando
-con il meccanismo della paginazione\index{paginazione}.
+con il meccanismo della \index{paginazione} paginazione.
Di solito la dimensione delle pagine di memoria è fissata dall'architettura
hardware, per cui il suo valore di norma veniva mantenuto in una costante che
\end{prototype}
La funzione restituisce in ciascun elemento di \param{loadavg} il numero medio
-di processi attivi sulla coda dello scheduler\itindex{scheduler}, calcolato su
-diversi intervalli di tempo. Il numero di intervalli che si vogliono
+di processi attivi sulla coda dello \itindex{scheduler} scheduler, calcolato
+su diversi 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.
dall'orologio hardware del calcolatore.
Anche il \itindex{process~time} \textit{process time} di solito si esprime in
-secondi, ma provvede una precisione ovviamente superiore al \textit{calendar
+secondi, ma fornisce una precisione ovviamente superiore al \textit{calendar
time} (che è mantenuto dal sistema con una granularità di un secondo) e
viene usato per tenere conto dei tempi di esecuzione dei processi. Per ciascun
processo il kernel calcola tre tempi diversi:
%% tcpsock.tex
%%
-%% Copyright (C) 2000-2006 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2007 Simone Piccardi. Permission is granted to
%% copy, distribute and/or modify this document under the terms of the GNU Free
%% Documentation License, Version 1.1 or any later version published by the
%% Free Software Foundation; with the Invariant Sections being "Un preambolo",
%% license is included in the section entitled "GNU Free Documentation
%% License".
%%
+
\chapter{I socket TCP}
\label{cha:TCP_socket}
\label{fig:TCP_conn_example}
\end{figure}
-La connessione viene iniziata dal client che annuncia una MSS
-\itindex{Maximum~Segment~Size} di 1460, un valore tipico con Linux per IPv4 su
-Ethernet, il server risponde con lo stesso valore (ma potrebbe essere anche un
-valore diverso).
+La connessione viene iniziata dal client che annuncia una
+\itindex{Maximum~Segment~Size} MSS di 1460, un valore tipico con Linux per
+IPv4 su Ethernet, il server risponde con lo stesso valore (ma potrebbe essere
+anche un valore diverso).
Una volta che la connessione è stabilita il client scrive al server una
richiesta (che assumiamo stare in un singolo segmento, cioè essere minore dei
\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}\itindex{endianess} della macchina, ed anche se
-esse possono essere invarianti rispetto all'ordinamento dei bit, è comunque
-buona norma usare sempre la funzione \func{htonl}.
+\itindex{endianess} 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}.
\begin{table}[htb]
\centering
limiterà ad impostare l'indirizzo dal quale e verso il quale saranno inviati
e ricevuti i pacchetti, mentre per socket di tipo \const{SOCK\_STREAM} o
\const{SOCK\_SEQPACKET}, essa attiverà la procedura di avvio (nel caso del
- TCP il \itindex{three~way~handshake}\textit{three way handshake}) della
+ TCP il \itindex{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
in sez.~\ref{sec:sock_addr_func}.
Nel caso di socket TCP la funzione \func{connect} avvia il
-\itindex{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:
+\itindex{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
del segnale \const{SIGCHLD} al padre, ma dato che non si è installato un
gestore e che l'azione predefinita per questo segnale è quella di essere
ignorato, non avendo predisposto la ricezione dello stato di terminazione,
-otterremo che il processo figlio entrerà nello stato di zombie\index{zombie}
+otterremo che il processo figlio entrerà nello stato di \index{zombie} zombie
(si riveda quanto illustrato in sez.~\ref{sec:sig_sigchld}), come risulterà
ripetendo il comando \cmd{ps}:
\begin{verbatim}
2359 pts/0 Z 0:00 [echod <defunct>]
\end{verbatim}
-Dato che non è il caso di lasciare processi zombie\index{zombie}, occorrerà
+Dato che non è il caso di lasciare processi \index{zombie} zombie, occorrerà
ricevere opportunamente lo stato di terminazione del processo (si veda
sez.~\ref{sec:proc_wait}), cosa che faremo utilizzando \const{SIGCHLD} secondo
quanto illustrato in sez.~\ref{sec:sig_sigchld}. Una prima modifica al nostro
il client risponde con un il terzo pacchetto di ricevuto.
Ritorniamo allora alla nostra sessione con il servizio echo: dopo le tre righe
-del \textit{three way handshake} \itindex{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
+del \itindex{three~way~handshake} \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
prima (\texttt{\small 19}) si imposta opportunamente \var{eof} ad un valore
non nullo, dopo di che (\texttt{\small 20}) si effettua la chiusura del lato
in scrittura del socket con \func{shutdown}. Infine (\texttt{\small 21}) si
-usa la macro \macro{FD\_CLR} per togliere lo standard input dal file
-descriptor set. \itindex{file~descriptor~set}
+usa la macro \macro{FD\_CLR} per togliere lo standard input dal
+\itindex{file~descriptor~set} \textit{file descriptor set}.
In questo modo anche se la lettura del file in ingresso è conclusa, la
funzione non esce dal ciclo principale (\texttt{\small 11--50}), ma continua
diverso da zero; in questo modo se l'unico socket con attività era quello
connesso, avendo opportunamente decrementato il contatore, il ciclo verrà
saltato, e si ritornerà immediatamente (ripetuta l'inizializzazione del
-\itindex{file~descriptor~set} file descriptor set con i nuovi valori nella
-tabella) alla chiamata di \func{accept}. Se il socket attivo non è quello in
-ascolto, o ce ne sono comunque anche altri, il valore di \var{n} non sarà
-nullo ed il controllo sarà eseguito. Prima di entrare nel ciclo comunque si
-inizializza (\texttt{\small 28}) il valore della variabile \var{i} che useremo
-come indice nella tabella \var{fd\_open} al valore minimo, corrispondente al
-file descriptor del socket in ascolto.
+\itindex{file~descriptor~set} \textit{file descriptor set} con i nuovi valori
+nella tabella) alla chiamata di \func{accept}. Se il socket attivo non è
+quello in ascolto, o ce ne sono comunque anche altri, il valore di \var{n} non
+sarà nullo ed il controllo sarà eseguito. Prima di entrare nel ciclo comunque
+si inizializza (\texttt{\small 28}) il valore della variabile \var{i} che
+useremo come indice nella tabella \var{fd\_open} al valore minimo,
+corrispondente al file descriptor del socket in ascolto.
Il primo passo (\texttt{\small 30}) nella verifica è incrementare il valore
dell'indice \var{i} per posizionarsi sul primo valore possibile per un file
Come si può notare la logica del programma è identica a quella vista in
fig.~\ref{fig:TCP_SelectEchod} per l'analogo server basato su \func{select};
la sola differenza significativa è che in questo caso non c'è bisogno di
-rigenerare i \itindex{file~descriptor~set} file descriptor set in quanto
-l'uscita è indipendente dai dati in ingresso. Si applicano comunque anche a
-questo server le considerazioni finali di sez.~\ref{sec:TCP_serv_select}.
+rigenerare i \itindex{file~descriptor~set} \textit{file descriptor set} in
+quanto l'uscita è indipendente dai dati in ingresso. Si applicano comunque
+anche a questo server le considerazioni finali di
+sez.~\ref{sec:TCP_serv_select}.
% LocalWords: socket TCP client dell'I multiplexing stream three way handshake
%% tcpprot.tex
%%
-%% Copyright (C) 2002-2006 Simone Piccardi. Permission is granted to
-%% copy, distribute and/or modify this document under the terms of the GNU Free
+%% Copyright (C) 2002-2007 Simone Piccardi. Permission is granted to copy,
+%% distribute and/or modify this document under the terms of the GNU Free
%% Documentation License, Version 1.1 or any later version published by the
%% Free Software Foundation; with the Invariant Sections being "Un preambolo",
%% with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the