delle costanti sono definiti da macro di preprocessore nel file citato, e
possono variare da architettura a architettura; è pertanto necessario
riferirsi ad essi tramite i nomi simbolici. Le funzioni \func{perror} e
-\func{strerror} (vedi \secref{sec:sys_strerror}) possono essere usate per
+\func{strerror} (vedi sez.~\ref{sec:sys_strerror}) possono essere usate per
ottenere dei messaggi di errore più espliciti.
filesystem read-only.
\item \errcode{EMLINK} \textit{Too many links}. Ci sono troppi link al file (il
numero massimo è specificato dalla variabile \const{LINK\_MAX}, vedi
- \secref{sec:sys_limits}).
+ sez.~\ref{sec:sys_limits}).
\item \errcode{EPIPE} \textit{Broken pipe}. Non c'è un processo che stia
leggendo l'altro capo della pipe. Ogni funzione che restituisce questo
errore genera anche un segnale \const{SIGPIPE}, la cui azione predefinita è
Uno dei problemi che si presentano quando si deve operare contemporaneamente
su molti file usando le funzioni illustrate in
-\capref{cha:file_unix_interface} e \capref{cha:files_std_interface} è che si
-può essere bloccati nelle operazioni su un file mentre un altro potrebbe
+cap.~\ref{cha:file_unix_interface} e cap.~\ref{cha:files_std_interface} è che
+si può essere bloccati nelle operazioni su un file mentre un altro potrebbe
essere disponibile. L'\textit{I/O multiplexing} nasce risposta a questo
problema. In questa sezione forniremo una introduzione a questa problematica
ed analizzeremo le varie funzioni usate per implementare questa modalità di
\subsection{La problematica dell'\textit{I/O multiplexing}}
\label{sec:file_noblocking}
-Abbiamo visto in \secref{sec:sig_gen_beha}, affrontando la suddivisione fra
+Abbiamo visto in sez.~\ref{sec:sig_gen_beha}, affrontando la suddivisione fra
\textit{fast} e \textit{slow} system call,\index{system call lente} che in
certi casi le funzioni di I/O possono bloccarsi indefinitamente.\footnote{si
ricordi però che questo può accadere solo per le pipe, i
da quanto si otterrebbe dal file descriptor ``\textsl{disponibile}'') si
potrebbe addirittura arrivare ad un \textit{deadlock}\index{deadlock}.
-Abbiamo già accennato in \secref{sec:file_open} che è possibile prevenire
+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 quella
che viene chiamata \textsl{modalità non-bloccante}, attraverso l'uso del flag
\const{O\_NONBLOCK} nella chiamata di \func{open}. In questo caso le funzioni
mai un accesso bloccante, l'uso più comune delle funzioni che esamineremo nei
prossimi paragrafi è per i server di rete, in cui esse vengono utilizzate per
tenere sotto controllo dei socket; pertanto ritorneremo su di esse con
-ulteriori dettagli e qualche esempio in \secref{sec:TCP_sock_multiplexing}.
+ulteriori dettagli e qualche esempio in sez.~\ref{sec:TCP_sock_multiplexing}.
\subsection{Le funzioni \func{select} e \func{pselect}}
\end{functions}
La funzione mette il processo in stato di \textit{sleep} (vedi
-\tabref{tab:proc_proc_states}) fintanto che almeno uno dei file descriptor
+tab.~\ref{tab:proc_proc_states}) fintanto che almeno uno dei file descriptor
degli insiemi specificati (\param{readfds}, \param{writefds} e
\param{exceptfds}), non diventa attivo, per un tempo massimo specificato da
\param{timeout}.
funzione usa un particolare oggetto, il \textit{file descriptor set},
identificato dal tipo \type{fd\_set}, che serve ad identificare un insieme di
file descriptor, in maniera analoga a come un \textit{signal set} (vedi
-\secref{sec:sig_sigset}) identifica un insieme di segnali. Per la
+sez.~\ref{sec:sig_sigset}) identifica un insieme di segnali. Per la
manipolazione di questi \textit{file descriptor set} si possono usare delle
opportune macro di preprocessore:
\begin{functions}
\param{writefds}, per verificare la possibilità effettuare una scrittura ed il
terzo, \param{exceptfds}, per verificare l'esistenza di eccezioni (come i
messaggi urgenti su un \textit{socket}\index{socket}, vedi
-\secref{sec:TCP_urgent_data}).
+sez.~\ref{sec:TCP_urgent_data}).
Dato che in genere non si tengono mai sotto controllo fino a
\const{FD\_SETSIZE} file contemporaneamente la funzione richiede di
\end{prototype}
La funzione è sostanzialmente identica a \func{select}, solo che usa una
-struttura \struct{timespec} (vedi \figref{fig:sys_timeval_struct}) per
+struttura \struct{timespec} (vedi fig.~\ref{fig:sys_timeval_struct}) per
indicare con maggiore precisione il timeout e non ne aggiorna il valore in
caso di interruzione. Inoltre prende un argomento aggiuntivo \param{sigmask}
che è il puntatore ad una maschera di segnali (si veda
-\secref{sec:sig_sigmask}). La maschera corrente viene sostituita da questa
+sez.~\ref{sec:sig_sigmask}). La maschera corrente viene sostituita da questa
immediatamente prima di eseguire l'attesa, e ripristinata al ritorno della
funzione.
\acr{glibc} attraverso \func{select} e la possibilità di race condition
permane.} La tecnica classica è quella di utilizzare il gestore per
impostare una variabile globale e controllare questa nel corpo principale del
-programma; abbiamo visto in \secref{sec:sig_example} come questo lasci spazio
+programma; abbiamo visto in sez.~\ref{sec:sig_example} come questo lasci spazio
a possibili race condition, per cui diventa essenziale utilizzare
\func{sigprocmask} per disabilitare la ricezione del segnale prima di eseguire
il controllo e riabilitarlo dopo l'esecuzione delle relative operazioni, onde
Per questo è stata introdotta \func{pselect}, che attraverso l'argomento
\param{sigmask} permette di riabilitare la ricezione il segnale
contestualmente all'esecuzione della funzione, e ribloccandolo non appena essa
-ritorna. In questo modo il precedente codice potrebbe essere essere modificato
+ritorna. In questo modo il precedente codice potrebbe essere modificato
nel seguente modo:
\includecodesnip{listati/pselect_norace.c}
in questo caso utilizzando \var{oldmask} durante l'esecuzione di
Per ciascun file da controllare deve essere inizializzata una struttura
\struct{pollfd} nel vettore indicato dall'argomento \param{ufds}. La
-struttura, la cui definizione è riportata in \figref{fig:file_pollfd}, prevede
-tre campi: in \var{fd} deve essere indicato il numero del file descriptor da
-controllare, in \var{events} deve essere specificata una maschera binaria di
-flag che indichino il tipo di evento che si vuole controllare, mentre in
-\var{revents} il kernel restituirà il relativo risultato. Usando un valore
-negativo per \param{fd} la corrispondente struttura sarà ignorata da
-\func{poll}. Dato che i dati in ingresso sono del tutto indipendenti da quelli
-in uscita (che vengono restituiti in \var{revents}) non è necessario
-reinizializzare tutte le volte il valore delle strutture \struct{pollfd} a
-meno di non voler cambiare qualche condizione.
+struttura, la cui definizione è riportata in fig.~\ref{fig:file_pollfd},
+prevede tre campi: in \var{fd} deve essere indicato il numero del file
+descriptor da controllare, in \var{events} deve essere specificata una
+maschera binaria di flag che indichino il tipo di evento che si vuole
+controllare, mentre in \var{revents} il kernel restituirà il relativo
+risultato. Usando un valore negativo per \param{fd} la corrispondente
+struttura sarà ignorata da \func{poll}. Dato che i dati in ingresso sono del
+tutto indipendenti da quelli in uscita (che vengono restituiti in
+\var{revents}) non è necessario reinizializzare tutte le volte il valore delle
+strutture \struct{pollfd} a meno di non voler cambiare qualche condizione.
Le costanti che definiscono i valori relativi ai bit usati nelle maschere
binarie dei campi \var{events} e \var{revents} sono riportati in
-\tabref{tab:file_pollfd_flags}, insieme al loro significato. Le si sono
+tab.~\ref{tab:file_pollfd_flags}, insieme al loro significato. Le si sono
suddivise in tre gruppi, nel primo gruppo si sono indicati i bit utilizzati
per controllare l'attività in ingresso, nel secondo quelli per l'attività in
uscita, mentre il terzo gruppo contiene dei valori che vengono utilizzati solo
costanti, in quanto per essi sono definite tre classi di dati:
\textsl{normali}, \textit{prioritari} ed \textit{urgenti}. In Linux la
distinzione ha senso solo per i dati \textit{out-of-band} dei socket (vedi
-\secref{sec:TCP_urgent_data}), ma su questo e su come \func{poll} reagisce
-alle varie condizioni dei socket torneremo in \secref{sec:TCP_serv_poll}, dove
-vedremo anche un esempio del suo utilizzo. Si tenga conto comunque che le
+sez.~\ref{sec:TCP_urgent_data}), ma su questo e su come \func{poll} reagisce
+alle varie condizioni dei socket torneremo in sez.~\ref{sec:TCP_serv_poll},
+dove vedremo anche un esempio del suo utilizzo. Si tenga conto comunque che le
costanti relative ai diversi tipi di dati (come \macro{POLLRDNORM} e
\macro{POLLRDBAND}) sono utilizzabili soltanto qualora si sia definita la
macro \macro{\_XOPEN\_SOURCE}.\footnote{e ci si ricordi di farlo sempre in
In caso di successo funzione ritorna restituendo il numero di file (un valore
positivo) per i quali si è verificata una delle condizioni di attesa richieste
o per i quali si è verificato un errore (nel qual caso vengono utilizzati i
-valori di \tabref{tab:file_pollfd_flags} esclusivi di \var{revents}). Un
+valori di tab.~\ref{tab:file_pollfd_flags} esclusivi di \var{revents}). Un
valore nullo indica che si è raggiunto il timeout, mentre un valore negativo
indica un errore nella chiamata, il cui codice viene riportato al solito
tramite \var{errno}.
\subsection{Operazioni asincrone sui file}
\label{sec:file_asyncronous_operation}
-Abbiamo accennato in \secref{sec:file_open} che è possibile, attraverso l'uso
+Abbiamo accennato in sez.~\ref{sec:file_open} che è possibile, attraverso l'uso
del flag \const{O\_ASYNC},\footnote{l'uso del flag di \const{O\_ASYNC} e dei
comandi \const{F\_SETOWN} e \const{F\_GETOWN} per \func{fcntl} è specifico
di Linux e BSD.} aprire un file in modalità asincrona, così come è possibile
attivare in un secondo tempo questa modalità impostando questo flag attraverso
l'uso di \func{fcntl} con il comando \const{F\_SETFL} (vedi
-\secref{sec:file_fcntl}).
+sez.~\ref{sec:file_fcntl}).
In realtà in questo caso non si tratta di eseguire delle operazioni di lettura
o scrittura del file in modo asincrono (tratteremo questo, che più
propriamente è detto \textsl{I/O asincrono} in
-\secref{sec:file_asyncronous_io}), quanto di un meccanismo asincrono di
+sez.~\ref{sec:file_asyncronous_io}), quanto di un meccanismo asincrono di
notifica delle variazione dello stato del file descriptor aperto in questo
modo.
riconoscere il file descriptor che li ha emessi. In questo caso infatti si può
fare ricorso alle informazioni aggiuntive restituite attraverso la struttura
\struct{siginfo\_t}, utilizzando la forma estesa \var{sa\_sigaction} del
-gestore (si riveda quanto illustrato in \secref{sec:sig_sigaction}).
+gestore (si riveda quanto illustrato in sez.~\ref{sec:sig_sigaction}).
Per far questo però occorre utilizzare le funzionalità dei segnali real-time
-(vedi \secref{sec:sig_real_time}) impostando esplicitamente con il comando
+(vedi sez.~\ref{sec:sig_real_time}) impostando esplicitamente con il comando
\const{F\_SETSIG} di \func{fcntl} un segnale real-time da inviare in caso di
I/O asincrono (il segnale predefinito è \const{SIGIO}). In questo caso il
gestore, tutte le volte che riceverà \const{SI\_SIGIO} come valore del
attraverso l'uso di una apposita struttura \struct{aiocb} (il cui nome sta per
\textit{asyncronous I/O control block}), che viene passata come argomento a
tutte le funzioni dell'interfaccia. La sua definizione, come effettuata in
-\file{aio.h}, è riportata in \figref{fig:file_aiocb}. Nello steso file è
+\file{aio.h}, è riportata in fig.~\ref{fig:file_aiocb}. Nello steso file è
definita la macro \macro{\_POSIX\_ASYNCHRONOUS\_IO}, che dichiara la
disponibilità dell'interfaccia per l'I/O asincrono.
piattaforma supporti questa caratteristica, questo viene indicato definendo
le macro \macro{\_POSIX\_PRIORITIZED\_IO}, e
\macro{\_POSIX\_PRIORITY\_SCHEDULING}.} La priorità viene impostata a
-partire da quella del processo chiamante (vedi \secref{sec:proc_priority}),
+partire da quella del processo chiamante (vedi sez.~\ref{sec:proc_priority}),
cui viene sottratto il valore di questo campo. Il campo
\var{aio\_lio\_opcode} è usato solo dalla funzione \func{lio\_listio}, che,
come vedremo, permette di eseguire con una sola chiamata una serie di
Infine il campo \var{aio\_sigevent} è una struttura di tipo \struct{sigevent}
che serve a specificare il modo in cui si vuole che venga effettuata la
notifica del completamento delle operazioni richieste. La struttura è
-riportata in \secref{fig:file_sigevent}; il campo \var{sigev\_notify} è quello
-che indica le modalità della notifica, esso può assumere i tre valori:
+riportata in fig.~\ref{fig:file_sigevent}; il campo \var{sigev\_notify} è
+quello che indica le modalità della notifica, esso può assumere i tre valori:
\begin{basedescript}{\desclabelwidth{2.6cm}}
\item[\const{SIGEV\_NONE}] Non viene inviata nessuna notifica.
\item[\const{SIGEV\_SIGNAL}] La notifica viene effettuata inviando al processo
chiamante il segnale specificato da \var{sigev\_signo}; se il gestore di
questo è stato installato con \const{SA\_SIGINFO} gli verrà restituito il
valore di \var{sigev\_value} (la cui definizione è in
- \figref{fig:sig_sigval}) come valore del campo \var{si\_value} di
+ fig.~\ref{fig:sig_sigval}) come valore del campo \var{si\_value} di
\struct{siginfo\_t}.
\item[\const{SIGEV\_THREAD}] La notifica viene effettuata creando un nuovo
thread che esegue la funzione specificata da \var{sigev\_notify\_function}
potrebbero anche emergere nelle fasi successive delle operazioni. Lettura e
scrittura avvengono alla posizione indicata da \var{aio\_offset}, a meno che
il file non sia stato aperto in \textit{append mode} (vedi
-\secref{sec:file_open}), nel qual caso le scritture vengono effettuate
+sez.~\ref{sec:file_open}), nel qual caso le scritture vengono effettuate
comunque alla fine de file, nell'ordine delle chiamate a \func{aio\_write}.
Si tenga inoltre presente che deallocare la memoria indirizzata da
modalità di esecuzione, se si specifica il valore \const{O\_DSYNC} le
operazioni saranno completate con una chiamata a \func{fdatasync}, se si
specifica \const{O\_SYNC} con una chiamata a \func{fsync} (per i dettagli vedi
-\secref{sec:file_sync}).
+sez.~\ref{sec:file_sync}).
Il successo della chiamata assicura la sincronizzazione delle operazioni fino
allora richieste, niente è garantito riguardo la sincronizzazione dei dati
Oltre alle precedenti modalità di \textit{I/O multiplexing} e \textsl{I/O
asincrono}, esistono altre funzioni che implementano delle modalità di
accesso ai file più evolute rispetto alle normali funzioni di lettura e
-scrittura che abbiamo esaminato in \secref{sec:file_base_func}. In questa
+scrittura che abbiamo esaminato in sez.~\ref{sec:file_base_func}. In questa
sezione allora prenderemo in esame le interfacce per l'\textsl{I/O
vettorizzato} e per l'\textsl{I/O mappato in memoria}.
\end{functions}
Entrambe le funzioni usano una struttura \struct{iovec}, definita in
-\figref{fig:file_iovec}, che definisce dove i dati devono essere letti o
+fig.~\ref{fig:file_iovec}, che definisce dove i dati devono essere letti o
scritti. Il primo campo, \var{iov\_base}, contiene l'indirizzo del buffer ed
il secondo, \var{iov\_len}, la dimensione dello stesso.
\label{sec:file_memory_map}
Una modalità alternativa di I/O, che usa una interfaccia completamente diversa
-rispetto a quella classica vista in \capref{cha:file_unix_interface}, è il
+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
-\secref{sec:proc_mem_gen}), permette di \textsl{mappare} il contenuto di un
+sez.~\ref{sec:proc_mem_gen}), permette di \textsl{mappare} il contenuto di un
file in una sezione dello spazio di indirizzi del processo. Il meccanismo è
-illustrato in \figref{fig:file_mmap_layout}, una sezione del file viene
+illustrato in fig.~\ref{fig:file_mmap_layout}, una sezione del file viene
riportata direttamente nello spazio degli indirizzi del programma. Tutte le
operazioni su questa zona verranno riportate indietro sul file dal meccanismo
della memoria virtuale\index{memoria virtuale} che trasferirà il contenuto di
\textit{segment violation}, e la relativa emissione del segnale
\const{SIGSEGV}.} da applicare al segmento di memoria e deve essere
specificato come maschera binaria ottenuta dall'OR di uno o più dei valori
-riportati in \tabref{tab:file_mmap_flag}; il valore specificato deve essere
+riportati in tab.~\ref{tab:file_mmap_flag}; il valore specificato deve essere
compatibile con la modalità di accesso con cui si è aperto il file.
L'argomento \param{flags} specifica infine qual'è il tipo di oggetto mappato,
modalità con cui le modifiche alla memoria mappata vengono condivise o
mantenute private al processo che le ha effettuate. Deve essere specificato
come maschera binaria ottenuta dall'OR di uno o più dei valori riportati in
-\tabref{tab:file_mmap_flag}.
+tab.~\ref{tab:file_mmap_flag}.
\begin{table}[htb]
\centering
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. Il caso più comune è
-quello illustrato in \figref{fig:file_mmap_boundary}, in cui la sezione di
+quello illustrato in fig.~\ref{fig:file_mmap_boundary}, in cui la sezione di
file non rientra nei confini di una pagina: in tal caso verrà il file sarà
mappato su un segmento di memoria che si estende fino al bordo della pagina
successiva.
contenuto del file, vale esattamente quanto visto in precedenza; invece per la
parte che eccede, fino alle dimensioni date da \param{length}, l'accesso non
sarà più possibile, ma il segnale emesso non sarà \const{SIGSEGV}, ma
-\const{SIGBUS}, come illustrato in \figref{fig:file_mmap_exceed}.
+\const{SIGBUS}, come illustrato in fig.~\ref{fig:file_mmap_exceed}.
Non tutti i file possono venire mappati in memoria, dato che, come illustrato
-in \figref{fig:file_mmap_layout}, la mappatura introduce una corrispondenza
+in fig.~\ref{fig:file_mmap_layout}, la mappatura introduce una corrispondenza
biunivoca fra una sezione di un file ed una sezione di memoria. Questo
comporta che ad esempio non è possibile mappare in memoria file descriptor
relativi a pipe, socket e fifo, per i quali non ha senso parlare di
\textsl{sezione}. Lo stesso vale anche per alcuni file di dispositivo, che non
dispongono della relativa operazione \func{mmap} (si ricordi quanto esposto in
-\secref{sec:file_vfs_work}). Si tenga presente però che esistono anche casi di
-dispositivi (un esempio è l'interfaccia al ponte PCI-VME del chip Universe)
+sez.~\ref{sec:file_vfs_work}). Si tenga presente però che esistono anche casi
+di dispositivi (un esempio è l'interfaccia al ponte PCI-VME del chip Universe)
che sono utilizzabili solo con questa interfaccia.
Dato che passando attraverso una \func{fork} lo spazio di indirizzi viene
nuovo programma.
Quando si effettua la mappatura di un file vengono pure modificati i tempi ad
-esso associati (di cui si è trattato in \secref{sec:file_file_times}). Il
+esso associati (di cui si è trattato in sez.~\ref{sec:file_file_times}). Il
valore di \var{st\_atime} può venir cambiato in qualunque istante a partire
dal momento in cui la mappatura è stata effettuata: il primo riferimento ad
una pagina mappata su un file aggiorna questo tempo. I valori di
Dato per i file mappati in memoria le operazioni di I/O sono gestite
direttamente dalla memoria virtuale, occorre essere consapevoli delle
interazioni che possono esserci con operazioni effettuate con l'interfaccia
-standard dei file di \capref{cha:file_unix_interface}. Il problema è che una
+standard dei file di cap.~\ref{cha:file_unix_interface}. Il problema è che una
volta che si è mappato un file, le operazioni di lettura e scrittura saranno
eseguite sulla memoria, e riportate su disco in maniera autonoma dal sistema
della memoria virtuale.
\end{table}
L'argomento \param{flag} è specificato come maschera binaria composta da un OR
-dei valori riportati in \tabref{tab:file_mmap_rsync}, di questi però
+dei valori riportati in tab.~\ref{tab:file_mmap_rsync}, di questi però
\const{MS\_ASYNC} e \const{MS\_SYNC} sono incompatibili; con il primo valore
infatti la funzione si limita ad inoltrare la richiesta di sincronizzazione al
meccanismo della memoria virtuale, ritornando subito, mentre con il secondo
\label{sec:file_locking}
\index{file!locking|(}
-In \secref{sec:file_sharing} abbiamo preso in esame le modalità in cui un
+In sez.~\ref{sec:file_sharing} abbiamo preso in esame le modalità in cui un
sistema unix-like gestisce la condivisione dei file da parte di processi
diversi. In quell'occasione si è visto come, con l'eccezione dei file aperti
in \textit{append mode}, quando più processi scrivono contemporaneamente sullo
il processo prosegue l'esecuzione, altrimenti (a meno di non aver richiesto un
comportamento non bloccante) viene posto in stato di sleep. Una volta finite
le operazioni sul file si deve provvedere a rimuovere il lock. La situazione
-delle varie possibilità è riassunta in \tabref{tab:file_file_lock}, dove si
+delle varie possibilità è riassunta in tab.~\ref{tab:file_file_lock}, dove si
sono riportati, per le varie tipologie di lock presenti su un file, il
risultato che si ha in corrispondenza alle due tipologie di \textit{file lock}
menzionate, nel successo della richiesta.
a seconda di quanto specificato tramite il valore dell'argomento
\param{operation}, questo viene interpretato come maschera binaria, e deve
essere passato utilizzando le costanti riportate in
-\tabref{tab:file_flock_operation}.
+tab.~\ref{tab:file_flock_operation}.
\begin{table}[htb]
\centering
differenze occorre descrivere con maggiore dettaglio come viene realizzato il
file locking nel kernel in entrambe le interfacce.
-In \figref{fig:file_flock_struct} si è riportato uno schema essenziale
+In fig.~\ref{fig:file_flock_struct} si è riportato uno schema essenziale
dell'implementazione del file locking in stile BSD in Linux; il punto
fondamentale da capire è che un lock, qualunque sia l'interfaccia che si usa,
anche se richiesto attraverso un file descriptor, agisce sempre su un file;
perciò le informazioni relative agli eventuali \textit{file lock} sono
mantenute a livello di inode\index{inode},\footnote{in particolare, come
- accennato in \figref{fig:file_flock_struct}, i \textit{file lock} sono
+ accennato in fig.~\ref{fig:file_flock_struct}, i \textit{file lock} sono
mantenuti un una \textit{linked list}\index{linked list} di strutture
\struct{file\_lock}. La lista è referenziata dall'indirizzo di partenza
mantenuto dal campo \var{i\_flock} della struttura \struct{inode} (per le
dei lock creati con \func{flock} la semantica della funzione prevede che sia
\func{dup} che \func{fork} non creino ulteriori istanze di un file lock quanto
piuttosto degli ulteriori riferimenti allo stesso. Questo viene realizzato dal
-kernel secondo lo schema di \figref{fig:file_flock_struct}, associando ad ogni
-nuovo \textit{file lock} un puntatore\footnote{il puntatore è mantenuto nel
- campo \var{fl\_file} di \struct{file\_lock}, e viene utilizzato solo per i
- lock creati con la semantica BSD.} alla voce nella \textit{file table} da
+kernel secondo lo schema di fig.~\ref{fig:file_flock_struct}, associando ad
+ogni nuovo \textit{file lock} un puntatore\footnote{il puntatore è mantenuto
+ nel campo \var{fl\_file} di \struct{file\_lock}, e viene utilizzato solo per
+ i lock creati con la semantica BSD.} alla voce nella \textit{file table} da
cui si è richiesto il lock, che così ne identifica il titolare.
Questa struttura prevede che, quando si richiede la rimozione di un file lock,
il kernel acconsenta solo se la richiesta proviene da un file descriptor che
fa riferimento ad una voce nella file table corrispondente a quella registrata
-nel lock. Allora se ricordiamo quanto visto in \secref{sec:file_dup} e
-\secref{sec:file_sharing}, e cioè che i file descriptor duplicati e quelli
+nel lock. Allora se ricordiamo quanto visto in sez.~\ref{sec:file_dup} e
+sez.~\ref{sec:file_sharing}, e cioè che i file descriptor duplicati e quelli
ereditati in un processo figlio puntano sempre alla stessa voce nella file
table, si può capire immediatamente quali sono le conseguenze nei confronti
delle funzioni \func{dup} e \func{fork}.
La seconda interfaccia per l'\textit{advisory locking} disponibile in Linux è
quella standardizzata da POSIX, basata sulla funzione \func{fcntl}. Abbiamo
già trattato questa funzione nelle sue molteplici possibilità di utilizzo in
-\secref{sec:file_fcntl}. Quando la si impiega per il \textit{file locking}
+sez.~\ref{sec:file_fcntl}. Quando la si impiega per il \textit{file locking}
essa viene usata solo secondo il prototipo:
\begin{prototype}{fcntl.h}{int fcntl(int fd, int cmd, struct flock *lock)}
al singolo byte. Inoltre la funzione permette di ottenere alcune informazioni
relative agli eventuali lock preesistenti. Per poter fare tutto questo la
funzione utilizza come terzo argomento una apposita struttura \struct{flock}
-(la cui definizione è riportata in \figref{fig:struct_flock}) nella quale
+(la cui definizione è riportata in fig.~\ref{fig:struct_flock}) nella quale
inserire tutti i dati relativi ad un determinato lock. Si tenga presente poi
che un lock fa sempre riferimento ad una regione, per cui si potrà avere un
conflitto anche se c'è soltanto una sovrapposizione parziale con un'altra
contare \var{l\_start}. Il valore di \var{l\_whence} segue la stessa semantica
dell'omonimo argomento di \func{lseek}, coi tre possibili valori
\const{SEEK\_SET}, \const{SEEK\_CUR} e \const{SEEK\_END}, (si vedano le
-relative descrizioni in \secref{sec:file_lseek}).
+relative descrizioni in sez.~\ref{sec:file_lseek}).
Si tenga presente che un lock può essere richiesto anche per una regione al di
là della corrente fine del file, così che una eventuale estensione dello
Il tipo di file lock richiesto viene specificato dal campo \var{l\_type}, esso
può assumere i tre valori definiti dalle costanti riportate in
-\tabref{tab:file_flock_type}, che permettono di richiedere rispettivamente uno
-\textit{shared lock}, un \textit{esclusive lock}, e la rimozione di un lock
-precedentemente acquisito. Infine il campo \var{l\_pid} viene usato solo in
-caso di lettura, quando si chiama \func{fcntl} con \const{F\_GETLK}, e riporta
-il \acr{pid} del processo che detiene il lock.
+tab.~\ref{tab:file_flock_type}, che permettono di richiedere rispettivamente
+uno \textit{shared lock}, un \textit{esclusive lock}, e la rimozione di un
+lock precedentemente acquisito. Infine il campo \var{l\_pid} viene usato solo
+in caso di lettura, quando si chiama \func{fcntl} con \const{F\_GETLK}, e
+riporta il \acr{pid} del processo che detiene il lock.
Oltre a quanto richiesto tramite i campi di \struct{flock}, l'operazione
effettivamente svolta dalla funzione è stabilita dal valore dall'argomento
-\param{cmd} che, come già riportato in \secref{sec:file_fcntl}, specifica
+\param{cmd} che, come già riportato in sez.~\ref{sec:file_fcntl}, specifica
l'azione da compiere; i valori relativi al file locking sono tre:
\begin{basedescript}{\desclabelwidth{2.0cm}}
\item[\const{F\_GETLK}] verifica se il file lock specificato dalla struttura
Non operando a livello di interi file, il file locking POSIX introduce
un'ulteriore complicazione; consideriamo la situazione illustrata in
-\figref{fig:file_flock_dead}, in cui il processo A blocca la regione 1 e il
+fig.~\ref{fig:file_flock_dead}, in cui il processo A blocca la regione 1 e il
processo B la regione 2. Supponiamo che successivamente il processo A richieda
un lock sulla regione 2 che non può essere acquisito per il preesistente lock
del processo 2; il processo 1 si bloccherà fintanto che il processo 2 non
Per capire meglio il funzionamento del file locking in semantica POSIX (che
-differisce alquanto rispetto da quello di BSD, visto \secref{sec:file_flock})
-esaminiamo più in dettaglio come viene gestito dal kernel. Lo schema delle
-strutture utilizzate è riportato in \figref{fig:file_posix_lock}; come si vede
-esso è molto simile all'analogo di \figref{fig:file_flock_struct}:\footnote{in
- questo caso nella figura si sono evidenziati solo i campi di
- \struct{file\_lock} significativi per la semantica POSIX, in particolare
- adesso ciascuna struttura contiene, oltre al \acr{pid} del processo in
- \var{fl\_pid}, la sezione di file che viene 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 questo caso la titolarità
-non viene identificata con il riferimento ad una voce nella file table, ma con
-il valore del \acr{pid} del processo.
+differisce alquanto rispetto da quello di BSD, visto
+sez.~\ref{sec:file_flock}) esaminiamo più in dettaglio come viene gestito dal
+kernel. Lo schema delle strutture utilizzate è riportato in
+fig.~\ref{fig:file_posix_lock}; come si vede esso è molto simile all'analogo
+di fig.~\ref{fig:file_flock_struct}:\footnote{in questo caso nella figura si
+ sono evidenziati solo i campi di \struct{file\_lock} significativi per la
+ semantica POSIX, in particolare adesso ciascuna struttura contiene, oltre al
+ \acr{pid} del processo in \var{fl\_pid}, la sezione di file che viene
+ 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
+questo caso la titolarità non viene identificata con il riferimento ad una
+voce nella file table, ma con il valore del \acr{pid} del processo.
Quando si richiede un lock il kernel effettua una scansione di tutti i lock
presenti sul file\footnote{scandisce cioè la linked list delle strutture
Per fare qualche esempio sul file locking si è scritto un programma che
permette di bloccare una sezione di un file usando la semantica POSIX, o un
-intero file usando la semantica BSD; in \figref{fig:file_flock_code} è
+intero file usando la semantica BSD; in fig.~\ref{fig:file_flock_code} è
riportata il corpo principale del codice del programma, (il testo completo è
allegato nella directory dei sorgenti).
Il comportamento della funzione dipende dal valore dell'argomento \param{cmd},
che specifica quale azione eseguire; i valori possibili sono riportati in
-\tabref{tab:file_lockf_type}.
+tab.~\ref{tab:file_lockf_type}.
\begin{table}[htb]
\centering
Per poter utilizzare il \textit{mandatory locking} è stato introdotto un
utilizzo particolare del bit \acr{sgid}. Se si ricorda quanto esposto in
-\secref{sec:file_suid_sgid}), esso viene di norma utilizzato per cambiare il
+sez.~\ref{sec:file_suid_sgid}), esso viene di norma utilizzato per cambiare il
group-ID effettivo con cui viene eseguito un programma, ed è pertanto sempre
associato alla presenza del permesso di esecuzione per il gruppo. Impostando
questo bit su un file senza permesso di esecuzione in un sistema che supporta
originariamente non contemplata, in quanto senza significato, diventa
l'indicazione della presenza o meno del \textit{mandatory
locking}.\footnote{un lettore attento potrebbe ricordare quanto detto in
- \secref{sec:file_chmod} e cioè che il bit \acr{sgid} viene cancellato (come
+ sez.~\ref{sec:file_chmod} e cioè che il bit \acr{sgid} viene cancellato (come
misura di sicurezza) quando di scrive su un file, questo non vale quando
esso viene utilizzato per attivare il \textit{mandatory locking}.}
su un file su cui è attivo un lock. Per questo motivo l'abilitazione del
mandatory locking è di norma disabilitata, e deve essere attivata filesystem
per filesystem in fase di montaggio (specificando l'apposita opzione di
-\func{mount} riportata in \tabref{tab:sys_mount_flags}, o con l'opzione
+\func{mount} riportata in tab.~\ref{tab:sys_mount_flags}, o con l'opzione
\cmd{mand} per il comando).
Si tenga presente inoltre che il \textit{mandatory locking} funziona solo
L'ultimo aspetto della interazione del \textit{mandatory locking} con le
funzioni di accesso ai file è quello relativo ai file mappati in memoria (che
-abbiamo trattato in \secref{sec:file_memory_map}); anche in tal caso infatti,
+abbiamo trattato in sez.~\ref{sec:file_memory_map}); anche in tal caso infatti,
quando si esegue la mappatura con l'opzione \const{MAP\_SHARED}, si ha un
accesso al contenuto del file. Lo standard SVID prevede che sia impossibile
eseguire il memory mapping di un file su cui sono presenti dei
\section{La gestione di file e directory}
\label{sec:file_dir}
-Come già accennato in \secref{sec:file_filesystem} in un sistema unix-like la
+Come già accennato in sez.~\ref{sec:file_filesystem} in un sistema unix-like la
gestione dei file ha delle caratteristiche specifiche che derivano
direttamente dall'architettura del sistema.
Questo è possibile anche in ambiente Unix, dove tali collegamenti sono
usualmente chiamati \textit{link}; ma data l'architettura del sistema riguardo
la gestione dei file (ed in particolare quanto trattato in
-\secref{sec:file_arch_func}) ci sono due metodi sostanzialmente diversi per
+sez.~\ref{sec:file_arch_func}) ci sono due metodi sostanzialmente diversi per
fare questa operazione.
-Come spiegato in \secref{sec:file_filesystem} l'accesso al contenuto di un
+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
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
già.
\item[\errcode{EMLINK}] ci sono troppi link al file \param{oldpath} (il
numero massimo è specificato dalla variabile \const{LINK\_MAX}, vedi
- \secref{sec:sys_limits}).
+ sez.~\ref{sec:sys_limits}).
\end{errlist}
ed inoltre \errval{EACCES}, \errval{ENAMETOOLONG}, \errval{ENOTDIR},
\errval{EFAULT}, \errval{ENOMEM}, \errval{EROFS}, \errval{ELOOP},
collegamento diretto non copia il contenuto del file, ma si limita a creare
una voce nella directory specificata da \param{newpath} e ad aumentare di uno
il numero di riferimenti al file (riportato nel campo \var{st\_nlink} della
-struttura \struct{stat}, vedi \secref{sec:file_stat}) aggiungendo il nuovo
+struttura \struct{stat}, vedi sez.~\ref{sec:file_stat}) aggiungendo il nuovo
nome ai precedenti. Si noti che uno stesso file può essere così chiamato con
vari nomi in diverse directory.
-Per quanto dicevamo in \secref{sec:file_filesystem} la creazione di un
+Per quanto dicevamo in sez.~\ref{sec:file_filesystem} la creazione di un
collegamento diretto è possibile solo se entrambi i pathname sono nello stesso
filesystem; inoltre il filesystem deve supportare i collegamenti diretti (il
meccanismo non è disponibile ad esempio con il filesystem \acr{vfat} di
l'amministratore è in grado di creare un collegamento diretto ad un'altra
directory: questo viene fatto perché con una tale operazione è possibile
creare dei \textit{loop} nel filesystem (vedi l'esempio mostrato in
-\secref{sec:file_symlink}, dove riprenderemo il discorso) che molti programmi
+sez.~\ref{sec:file_symlink}, dove riprenderemo il discorso) che molti programmi
non sono in grado di gestire e la cui rimozione diventerebbe estremamente
complicata (in genere per questo tipo di errori occorre far girare il
programma \cmd{fsck} per riparare il filesystem).
\end{prototype}
\footnotetext{questo è un valore specifico ritornato da Linux che non consente
- l'uso di \func{unlink} con le directory (vedi \secref{sec:file_remove}). Non
- è conforme allo standard POSIX, che prescrive invece l'uso di
+ l'uso di \func{unlink} con le directory (vedi sez.~\ref{sec:file_remove}).
+ Non è conforme allo standard POSIX, che prescrive invece l'uso di
\errcode{EPERM} in caso l'operazione non sia consentita o il processo non
abbia privilegi sufficienti.}
scrittura su di essa, dato che si va a rimuovere una voce dal suo contenuto, e
il diritto di esecuzione sulla directory che la contiene (affronteremo in
dettaglio l'argomento dei permessi di file e directory in
-\secref{sec:file_access_control}). Se inoltre lo \textit{sticky} bit (vedi
-\secref{sec:file_sticky}) è impostato occorrerà anche essere proprietari del
+sez.~\ref{sec:file_access_control}). Se inoltre lo \textit{sticky} bit (vedi
+sez.~\ref{sec:file_sticky}) è impostato occorrerà anche essere proprietari del
file o proprietari della directory (o root, per cui nessuna delle restrizioni
è applicata).
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
-\secref{sec:proc_atom_oper}) senza possibili interruzioni fra le due
+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.
count} mantenuto nell'inode\index{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
- \secref{cha:file_unix_interface} il kernel mantiene anche una tabella dei
+ cap.~\ref{cha:file_unix_interface} il kernel mantiene anche una tabella dei
file aperti nei vari processi, che a sua volta contiene i riferimenti agli
inode ad essi relativi. Prima di procedere alla cancellazione dello spazio
occupato su disco dal contenuto di un file il kernel controlla anche questa
temporanei su disco in caso di crash dei programmi; la tecnica è quella di
aprire il file e chiamare \func{unlink} subito dopo, in questo modo il
contenuto del file è sempre disponibile all'interno del processo attraverso il
-suo file descriptor (vedi \secref{sec:file_fd}) fintanto che il processo non
+suo file descriptor (vedi sez.~\ref{sec:file_fd}) fintanto che il processo non
chiude il file, ma non ne resta traccia in nessuna directory, e lo spazio
occupato su disco viene immediatamente rilasciato alla conclusione del
processo (quando tutti i file vengono chiusi).
Al contrario di quanto avviene con altri Unix, in Linux non è possibile usare
\func{unlink} sulle directory; per cancellare una directory si può usare la
-funzione \func{rmdir} (vedi \secref{sec:file_dir_creat_rem}), oppure la
+funzione \func{rmdir} (vedi sez.~\ref{sec:file_dir_creat_rem}), oppure la
funzione \funcd{remove}.
Questa è la funzione prevista dallo standard ANSI C per cancellare un file o
\subsection{I link simbolici}
\label{sec:file_symlink}
-Come abbiamo visto in \secref{sec:file_link} la funzione \func{link} crea
+Come abbiamo visto in sez.~\ref{sec:file_link} la funzione \func{link} crea
riferimenti agli inode\index{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
Il sistema funziona in quanto i link simbolici sono riconosciuti come tali dal
kernel\footnote{è uno dei diversi tipi di file visti in
- \tabref{tab:file_file_types}, contrassegnato come tale nell'inode, e
+ tab.~\ref{tab:file_file_types}, contrassegnato come tale nell'inode, e
riconoscibile dal valore del campo \var{st\_mode} della struttura
- \struct{stat} (vedi \secref{sec:file_stat}).} per cui alcune funzioni di
+ \struct{stat} (vedi sez.~\ref{sec:file_stat}).} per cui alcune funzioni di
libreria (come \func{open} o \func{stat}) quando ricevono come argomento un
link simbolico vengono automaticamente applicate al file da esso specificato.
La funzione che permette di creare un nuovo link simbolico è \funcd{symlink},
\textit{dangling link}, letteralmente un \textsl{link ciondolante}.
Come accennato i link simbolici sono risolti automaticamente dal kernel
-all'invocazione delle varie system call; in \tabref{tab:file_symb_effect} si è
-riportato un elenco dei comportamenti delle varie funzioni di libreria che
+all'invocazione delle varie system call; in tab.~\ref{tab:file_symb_effect} si
+è riportato un elenco dei comportamenti delle varie funzioni di libreria che
operano sui file nei confronti della risoluzione dei link simbolici,
specificando quali seguono il link simbolico e quali invece possono operare
direttamente sul suo contenuto.
Si noti che non si è specificato il comportamento delle funzioni che operano
con i file descriptor, in quanto la risoluzione del link simbolico viene in
genere effettuata dalla funzione che restituisce il file descriptor
-(normalmente la \func{open}, vedi \secref{sec:file_open}) e tutte le
+(normalmente la \func{open}, vedi sez.~\ref{sec:file_open}) e tutte le
operazioni seguenti fanno riferimento solo a quest'ultimo.
-Dato che, come indicato in \tabref{tab:file_symb_effect}, funzioni come la
+Dato che, come indicato in tab.~\ref{tab:file_symb_effect}, funzioni come la
\func{open} seguono i link simbolici, occorrono funzioni apposite per accedere
alle informazioni del link invece che a quelle del file a cui esso fa
riferimento. Quando si vuole leggere il contenuto di un link simbolico si usa
Un caso comune che si può avere con i link simbolici è la creazione dei
cosiddetti \textit{loop}. La situazione è illustrata in
-\figref{fig:file_link_loop}, che riporta la struttura della directory
+fig.~\ref{fig:file_link_loop}, che riporta la struttura della directory
\file{/boot}. Come si vede si è creato al suo interno un link simbolico che
punta di nuovo a \file{/boot}.\footnote{il loop mostrato in
- \figref{fig:file_link_loop} è un usato per poter permettere a \cmd{grub} (un
- bootloader in grado di leggere direttamente da vari filesystem il file da
- lanciare come sistema operativo) di vedere i file contenuti nella directory
- \file{/boot} con lo stesso pathname con cui verrebbero visti dal sistema
- operativo, anche se essi si trovano, come accade spesso, su una partizione
- separata (che \cmd{grub}, all'avvio, vede come radice).}
+ fig.~\ref{fig:file_link_loop} è un usato per poter permettere a \cmd{grub}
+ (un bootloader in grado di leggere direttamente da vari filesystem il file
+ da lanciare come sistema operativo) di vedere i file contenuti nella
+ directory \file{/boot} con lo stesso pathname con cui verrebbero visti dal
+ sistema operativo, anche se essi si trovano, come accade spesso, su una
+ partizione separata (che \cmd{grub}, all'avvio, vede come radice).}
Questo può causare problemi per tutti quei programmi che effettuano la
scansione di una directory senza tener conto dei link simbolici, ad esempio se
\param{dirname}. Il nome può essere indicato sia come pathname assoluto che
relativo.
-I permessi di accesso alla directory (vedi \secref{sec:file_access_control})
+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
-\tabref{tab:file_permission_const}; questi sono modificati dalla maschera di
-creazione dei file (si veda \secref{sec:file_umask}). La titolarità della
+tab.~\ref{tab:file_permission_const}; questi sono modificati dalla maschera di
+creazione dei file (si veda sez.~\ref{sec:file_umask}). La titolarità della
nuova directory è impostata secondo quanto riportato in
-\secref{sec:file_ownership}.
+sez.~\ref{sec:file_ownership}.
La funzione per la cancellazione di una directory è \funcd{rmdir}, il suo
prototipo è:
\label{sec:file_mknod}
Finora abbiamo parlato esclusivamente di file, directory e link simbolici; in
-\secref{sec:file_file_types} abbiamo visto però che il sistema prevede pure
+sez.~\ref{sec:file_file_types} abbiamo visto però che il sistema prevede pure
degli altri tipi di file speciali, come i file di dispositivo
\index{file!di dispositivo}
e le fifo (i socket\index{socket} sono un caso a parte, che
-vedremo in \capref{cha:socket_intro}).
+vedremo in cap.~\ref{cha:socket_intro}).
La manipolazione delle caratteristiche di questi file e la loro cancellazione
può essere effettuata con le stesse funzioni che operano sui file regolari; ma
La funzione permette di creare un file speciale, ma si può usare anche per
creare file regolari e fifo; l'argomento \param{mode} specifica il tipo di
file che si vuole creare ed i relativi permessi, secondo i valori riportati in
-\tabref{tab:file_mode_flags}, che vanno combinati con un OR binario. I
+tab.~\ref{tab:file_mode_flags}, che vanno combinati con un OR binario. I
permessi sono comunque modificati nella maniera usuale dal valore di
-\var{umask} (si veda \secref{sec:file_umask}).
+\var{umask} (si veda sez.~\ref{sec:file_umask}).
Per il tipo di file può essere specificato solo uno fra: \const{S\_IFREG} per
un file regolare (che sarà creato vuoto), \const{S\_IFBLK} per un device a
I nuovi inode\index{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 \secref{sec:file_ownership}) in cui si va a
+BSD per il filesystem (si veda sez.~\ref{sec:file_ownership}) in cui si va a
creare l'inode\index{inode}.
Per creare una fifo (un file speciale, su cui torneremo in dettaglio in
-\secref{sec:ipc_named_pipe}) lo standard POSIX specifica l'uso della funzione
+sez.~\ref{sec:ipc_named_pipe}) lo standard POSIX specifica l'uso della funzione
\funcd{mkfifo}, il cui prototipo è:
\begin{functions}
\headdecl{sys/types.h} \headdecl{sys/stat.h}
Ma se la scrittura e l'aggiornamento dei dati delle directory è compito del
kernel, sono molte le situazioni in cui i processi necessitano di poterne
leggere il contenuto. Benché questo possa essere fatto direttamente (vedremo
-in \secref{sec:file_open} che è possibile aprire una directory come se fosse
+in sez.~\ref{sec:file_open} che è possibile aprire una directory come se fosse
un file, anche se solo in sola lettura) in generale il formato con cui esse
sono scritte può dipendere dal tipo di filesystem, tanto che, come riportato
-in \tabref{tab:file_file_operations}, il VFS del kernel prevede una apposita
+in tab.~\ref{tab:file_file_operations}, il VFS del kernel prevede una apposita
funzione per la lettura delle directory.
Tutto questo si riflette nello standard POSIX\footnote{le funzioni sono
previste pure in BSD e SVID.} che ha introdotto una apposita interfaccia per
la lettura delle directory, basata sui cosiddetti \textit{directory stream}
(chiamati così per l'analogia con i file stream dell'interfaccia standard di
-\capref{cha:files_std_interface}). La prima funzione di questa interfaccia è
+cap.~\ref{cha:files_std_interface}). La prima funzione di questa interfaccia è
\funcd{opendir}, il cui prototipo è:
\begin{functions}
\headdecl{sys/types.h} \headdecl{dirent.h}
descriptor associato al \textit{directory stream} \param{dir}, essa è
disponibile solo definendo \macro{\_BSD\_SOURCE} o \macro{\_SVID\_SOURCE}. Di
solito si utilizza questa funzione in abbinamento alla funzione \func{fchdir}
-per cambiare la directory di lavoro (vedi \secref{sec:file_work_dir}) a quella
-relativa allo stream che si sta esaminando.
+per cambiare la directory di lavoro (vedi sez.~\ref{sec:file_work_dir}) a
+quella relativa allo stream che si sta esaminando.
La lettura di una voce della directory viene effettuata attraverso la funzione
\funcd{readdir}; il suo prototipo è:
nel file \file{/usr/include/bits/dirent.h}, essa non contempla la presenza
del campo \var{d\_namlen} che indica la lunghezza del nome del file (ed
infatti la macro \macro{\_DIRENT\_HAVE\_D\_NAMLEN} non è definita).} è
-riportata in \figref{fig:file_dirent_struct}). La funzione restituisce il
+riportata in fig.~\ref{fig:file_dirent_struct}). La funzione restituisce il
puntatore alla struttura; si tenga presente però che quest'ultima è allocata
staticamente, per cui viene sovrascritta tutte le volte che si ripete la
lettura di una voce sullo stesso stream.
possibili valori\footnote{fino alla versione 2.1 delle \acr{glibc} questo
campo, pur presente nella struttura, non è implementato, e resta sempre al
valore \const{DT\_UNKNOWN}.} sono riportati in
-\tabref{tab:file_dtype_macro}; per la conversione da e verso l'analogo valore
+tab.~\ref{tab:file_dtype_macro}; per la conversione da e verso l'analogo valore
mantenuto dentro il campo \var{st\_mode} di \struct{stat} sono definite anche
due macro di conversione \macro{IFTODT} e \macro{DTTOIF}:
\begin{functions}
dopo \func{file4}.)
Un semplice esempio dell'uso di queste funzioni è riportato in
-\figref{fig:file_my_ls}, dove si è riportata la sezione principale di un
+fig.~\ref{fig:file_my_ls}, dove si è riportata la sezione principale di un
programma che, usando la routine di scansione illustrata in
-\figref{fig:file_dirscan}, stampa i nomi dei file contenuti in una directory e
-la relativa dimensione (in sostanza una versione semplificata del comando
+fig.~\ref{fig:file_dirscan}, stampa i nomi dei file contenuti in una directory
+e la relativa dimensione (in sostanza una versione semplificata del comando
\cmd{ls}).
\begin{figure}[!htb]
\label{fig:file_my_ls}
\end{figure}
-Il programma è estremamente semplice; in \figref{fig:file_my_ls} si è omessa
+Il programma è estremamente semplice; in fig.~\ref{fig:file_my_ls} si è omessa
la parte di gestione delle opzioni (che prevede solo l'uso di una funzione per
la stampa della sintassi, anch'essa omessa) ma il codice completo potrà essere
trovato coi sorgenti allegati nel file \file{myls.c}.
\end{figure}
Tutto il grosso del lavoro è svolto dalla funzione \func{DirScan}, riportata
-in \figref{fig:file_dirscan}. La funzione è volutamente generica e permette di
-eseguire una funzione, passata come secondo argomento, su tutte le voci di una
-directory. La funzione inizia con l'aprire (\texttt{\small 19--23}) uno
+in fig.~\ref{fig:file_dirscan}. La funzione è volutamente generica e permette
+di eseguire una funzione, passata come secondo argomento, su tutte le voci di
+una directory. La funzione inizia con l'aprire (\texttt{\small 19--23}) uno
stream sulla directory passata come primo argomento, stampando un messaggio in
caso di errore.
Il passo successivo (\texttt{\small 24--25}) è cambiare directory di lavoro
-(vedi \secref{sec:file_work_dir}), usando in sequenza le funzione \func{dirfd}
-e \func{fchdir} (in realtà si sarebbe potuto usare direttamente \func{chdir}
-su \var{dirname}), in modo che durante il successivo ciclo (\texttt{\small
- 27--31}) sulle singole voci dello stream ci si trovi all'interno della
-directory.\footnote{questo è essenziale al funzionamento della funzione
- \code{do\_ls} (e ad ogni funzione che debba usare il campo \var{d\_name}, in
- quanto i nomi dei file memorizzati all'interno di una struttura
- \struct{dirent} sono sempre relativi alla directory in questione, e senza
- questo posizionamento non si sarebbe potuto usare \func{stat} per ottenere
- le dimensioni.}
+(vedi sez.~\ref{sec:file_work_dir}), usando in sequenza le funzione
+\func{dirfd} e \func{fchdir} (in realtà si sarebbe potuto usare direttamente
+\func{chdir} su \var{dirname}), in modo che durante il successivo ciclo
+(\texttt{\small 27--31}) sulle singole voci dello stream ci si trovi
+all'interno della directory.\footnote{questo è essenziale al funzionamento
+ della funzione \code{do\_ls} (e ad ogni funzione che debba usare il campo
+ \var{d\_name}, in quanto i nomi dei file memorizzati all'interno di una
+ struttura \struct{dirent} sono sempre relativi alla directory in questione,
+ e senza questo posizionamento non si sarebbe potuto usare \func{stat} per
+ ottenere le dimensioni.}
Avendo usato lo stratagemma di fare eseguire tutte le manipolazioni necessarie
alla funzione passata come secondo argomento, il ciclo di scansione della
consente di cambiarla a piacere, spostandosi da una directory ad un'altra, il
comando \cmd{pwd} la stampa sul terminale. Siccome la directory corrente
resta la stessa quando viene creato un processo figlio (vedi
-\secref{sec:proc_fork}), la directory corrente della shell diventa anche la
+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 lunghezza esatta del pathname altrimenti. In questo caso ci si deve
ricordare di disallocare la stringa una volta cessato il suo utilizzo.
-Di questa funzione esiste una versione \code{char *getwd(char *buffer)}
-fatta per compatibilità all'indietro con BSD, che non consente di specificare
-la dimensione del buffer; esso deve essere allocato in precedenza ed avere una
+Di questa funzione esiste una versione \code{char *getwd(char *buffer)} fatta
+per compatibilità all'indietro con BSD, che non consente di specificare la
+dimensione del buffer; esso deve essere allocato in precedenza ed avere una
dimensione superiore a \const{PATH\_MAX} (di solito 256 byte, vedi
-\secref{sec:sys_limits}); il problema è che in Linux non esiste una dimensione
-superiore per un pathname, per cui non è detto che il buffer sia sufficiente a
-contenere il nome del file, e questa è la ragione principale per cui questa
-funzione è deprecata.
+sez.~\ref{sec:sys_limits}); il problema è che in Linux non esiste una
+dimensione superiore per un pathname, per cui non è detto che il buffer sia
+sufficiente a contenere il nome del file, e questa è la ragione principale per
+cui questa funzione è deprecata.
Una seconda funzione simile è \code{char *get\_current\_dir\_name(void)} che è
sostanzialmente equivalente ad una \code{getcwd(NULL, 0)}, con la sola
creare il file dopo aver controllato che questo non esista, nel momento fra il
controllo e la creazione si ha giusto lo spazio per una possibile \textit{race
condition}\index{race condition} (si ricordi quanto visto in
-\secref{sec:proc_race_cond}).
+sez.~\ref{sec:proc_race_cond}).
Le \acr{glibc} provvedono varie funzioni per generare nomi di file temporanei,
di cui si abbia certezza di unicità (al momento della generazione); la prima
\begin{itemize*}
\item La variabile di ambiente \const{TMPNAME} (non ha effetto se non è
definita o se il programma chiamante è \acr{suid} o \acr{sgid}, vedi
- \secref{sec:file_suid_sgid}).
+ sez.~\ref{sec:file_suid_sgid}).
\item il valore dell'argomento \param{dir} (se diverso da \val{NULL}).
\item Il valore della costante \const{P\_tmpdir}.
\item la directory \file{/tmp}.
\errval{ENOSPC}, \errval{EROFS} e \errval{EACCES}.}
\end{prototype}
\noindent essa restituisce direttamente uno stream già aperto (in modalità
-\code{r+b}, si veda \secref{sec:file_fopen}) e pronto per l'uso, che viene
+\code{r+b}, si veda sez.~\ref{sec:file_fopen}) e pronto per l'uso, che viene
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
\noindent come per \func{mktemp} anche in questo caso \param{template} non può
essere una stringa costante. La funzione apre un file in lettura/scrittura con
la funzione \func{open}, usando l'opzione \const{O\_EXCL} (si veda
-\secref{sec:file_open}), in questo modo al ritorno della funzione si ha la
+sez.~\ref{sec:file_open}), in questo modo al ritorno della funzione si ha la
certezza di essere i soli utenti del file. I permessi sono impostati al valore
\code{0600}\footnote{questo è vero a partire dalle \acr{glibc} 2.0.7, le
versioni precedenti delle \acr{glibc} e le vecchie \acr{libc5} e \acr{libc4}
usavano il valore \code{0666} che permetteva a chiunque di leggere i
- contenuti del file.} (si veda \secref{sec:file_perm_overview}).
+ contenuti del file.} (si veda sez.~\ref{sec:file_perm_overview}).
In OpenBSD è stata introdotta un'altra funzione\footnote{introdotta anche in
Linux a partire dalle \acr{glibc} 2.1.91.} simile alle precedenti,
più gli altri eventuali codici di errore di \func{mkdir}.}
\end{prototype}
\noindent la directory è creata con permessi \code{0700} (al solito si veda
-\capref{cha:file_unix_interface} per i dettagli); dato che la creazione della
+cap.~\ref{cha:file_unix_interface} per i dettagli); dato che la creazione della
directory è sempre esclusiva i precedenti problemi di \textit{race
condition}\index{race condition} non si pongono.
\section{La manipolazione delle caratteristiche dei files}
\label{sec:file_infos}
-Come spiegato in \secref{sec:file_filesystem} tutte le informazioni generali
+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}.
memorizzati nell'inode\index{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
-\secref{sec:file_access_control}).
+sez.~\ref{sec:file_access_control}).
\subsection{Le funzioni \func{stat}, \func{fstat} e \func{lstat}}
La struttura \struct{stat} usata da queste funzioni è definita nell'header
\file{sys/stat.h} e in generale dipende dall'implementazione; la versione
-usata da Linux è mostrata in \figref{fig:file_stat_struct}, così come
+usata da Linux è mostrata in fig.~\ref{fig:file_stat_struct}, così come
riportata dalla pagina di manuale di \func{stat} (in realtà la definizione
effettivamente usata nel kernel dipende dall'architettura e ha altri campi
riservati per estensioni come tempi più precisi, o per il padding dei campi).
Si noti come i vari membri della struttura siano specificati come tipi
primitivi del sistema (di quelli definiti in
-\tabref{tab:intro_primitive_types}, e dichiarati in \file{sys/types.h}).
+tab.~\ref{tab:intro_primitive_types}, e dichiarati in \file{sys/types.h}).
\subsection{I tipi di file}
\label{sec:file_types}
-Come riportato in \tabref{tab:file_file_types} in Linux oltre ai file e alle
+Come riportato in tab.~\ref{tab:file_file_types} in Linux oltre ai file e alle
directory esistono altri oggetti che possono stare su un filesystem. Il tipo
di file è ritornato dalla \func{stat} come maschera binaria nel campo
\var{st\_mode} (che contiene anche le informazioni relative ai permessi).
queste vengono usate anche da Linux che supporta pure le estensioni allo
standard per i link simbolici e i socket\index{socket} definite da BSD;
l'elenco completo delle macro con cui è possibile estrarre l'informazione da
-\var{st\_mode} è riportato in \tabref{tab:file_type_macro}.
+\var{st\_mode} è riportato in tab.~\ref{tab:file_type_macro}.
\begin{table}[htb]
\centering
\footnotesize
\label{tab:file_type_macro}
\end{table}
-Oltre alle macro di \tabref{tab:file_type_macro} è possibile usare
+Oltre alle macro di tab.~\ref{tab:file_type_macro} è possibile usare
direttamente il valore di \var{st\_mode} per ricavare il tipo di file
controllando direttamente i vari bit in esso memorizzati. Per questo sempre in
\file{sys/stat.h} sono definite le costanti numeriche riportate in
-\tabref{tab:file_mode_flags}.
+tab.~\ref{tab:file_mode_flags}.
-Il primo valore dell'elenco di \tabref{tab:file_mode_flags} è la maschera
+Il primo valore dell'elenco di tab.~\ref{tab:file_mode_flags} è la maschera
binaria che permette di estrarre i bit nei quali viene memorizzato il tipo di
file, i valori successivi sono le costanti corrispondenti ai singoli bit, e
possono essere usati per effettuare la selezione sul tipo di file voluto, con
detto che corrisponda all'occupazione dello spazio su disco per via della
possibile esistenza dei cosiddetti \textit{holes} (letteralmente
\textsl{buchi}) che si formano tutte le volte che si va a scrivere su un file
-dopo aver eseguito una \func{lseek} (vedi \secref{sec:file_lseek}) oltre la
+dopo aver eseguito una \func{lseek} (vedi sez.~\ref{sec:file_lseek}) oltre la
sua fine.
In questo caso si avranno risultati differenti a seconda del modo in cui si
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 \figref{fig:file_stat_struct}. Il significato
-di detti tempi e dei relativi campi è riportato nello schema in
-\tabref{tab:file_file_times}, dove è anche riportato un esempio delle funzioni
-che effettuano cambiamenti su di essi.
+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.
\begin{table}[htb]
\centering
tempo di cambiamento di stato) per decidere quali file devono essere
archiviati per il backup. Il comando \cmd{ls} (quando usato con le opzioni
\cmd{-l} o \cmd{-t}) mostra i tempi dei file secondo lo schema riportato
-nell'ultima colonna di \tabref{tab:file_file_times}.
+nell'ultima colonna di tab.~\ref{tab:file_file_times}.
\begin{table}[htb]
\centering
\end{table}
L'effetto delle varie funzioni di manipolazione dei file sui tempi è
-illustrato in \tabref{tab:file_times_effects}. Si sono riportati gli effetti
+illustrato in tab.~\ref{tab:file_times_effects}. Si sono riportati gli effetti
sia per il file a cui si fa riferimento, sia per la directory che lo contiene;
questi ultimi possono essere capiti se si tiene conto di quanto già detto, e
cioè che anche le directory sono file (che contengono una lista di nomi) che
La funzione prende come argomento \param{times} una struttura
\struct{utimebuf}, la cui definizione è riportata in
-\figref{fig:struct_utimebuf}, con la quale si possono specificare i nuovi
+fig.~\ref{fig:struct_utimebuf}, con la quale si possono specificare i nuovi
valori che si vogliono impostare per tempi.
\begin{figure}[!htb]
degli identificatori di utente e gruppo (\acr{uid} e \acr{gid}). Questi valori
sono accessibili da programma tramite la funzione \func{stat}, e sono
mantenuti nei campi \var{st\_uid} e \var{st\_gid} della struttura
-\struct{stat} (si veda \secref{sec:file_stat}).\footnote{Questo è vero solo
+\struct{stat} (si veda sez.~\ref{sec:file_stat}).\footnote{Questo è vero solo
per filesystem di tipo Unix, ad esempio non è vero per il filesystem vfat di
Windows, che non fornisce nessun supporto per l'accesso multiutente, e per
il quale i permessi vengono assegnati in maniera fissa con un opzione in
I restanti tre bit (noti come \acr{suid}, \acr{sgid}, e \textsl{sticky}) sono
usati per indicare alcune caratteristiche più complesse del meccanismo del
controllo di accesso su cui torneremo in seguito (in
-\secref{sec:file_suid_sgid} e \secref{sec:file_sticky}); lo schema di
-allocazione dei bit è riportato in \figref{fig:file_perm_bit}.
+sez.~\ref{sec:file_suid_sgid} e sez.~\ref{sec:file_sticky}); lo schema di
+allocazione dei bit è 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
alcuni bit del campo \var{st\_mode} della struttura \struct{stat} (si veda di
-nuovo \figref{fig:file_stat_struct}).
+nuovo fig.~\ref{fig:file_stat_struct}).
In genere ci si riferisce ai tre livelli dei privilegi usando le lettere
\cmd{u} (per \textit{user}), \cmd{g} (per \textit{group}) e \cmd{o} (per
si parla dei permessi base come di permessi per \textit{owner}, \textit{group}
ed \textit{all}, le cui iniziali possono dar luogo a confusione. Le costanti
che permettono di accedere al valore numerico di questi bit nel campo
-\var{st\_mode} sono riportate in \tabref{tab:file_bit_perm}.
+\var{st\_mode} sono riportate in tab.~\ref{tab:file_bit_perm}.
\begin{table}[htb]
\centering
directory).
Avere il permesso di lettura per un file consente di aprirlo con le opzioni
-(si veda quanto riportato in \tabref{tab:file_open_flags}) di sola lettura o
+(si veda quanto riportato in tab.~\ref{tab:file_open_flags}) di sola lettura o
di lettura/scrittura e leggerne il contenuto. Avere il permesso di scrittura
consente di aprire un file in sola scrittura o lettura/scrittura e modificarne
il contenuto, lo stesso permesso è necessario per poter troncare il file.
appartiene vengono pure ignorati quando il link viene risolto, vengono
controllati solo quando viene richiesta la rimozione del link e quest'ultimo è
in una directory con lo \textsl{sticky bit} impostato (si veda
-\secref{sec:file_sticky}).
+sez.~\ref{sec:file_sticky}).
La procedura con cui il kernel stabilisce se un processo possiede un certo
permesso (di lettura, scrittura o esecuzione) si basa sul confronto fra
effettivo e gli eventuali group-ID supplementari del processo.\footnote{in
realtà Linux, per quanto riguarda l'accesso ai file, utilizza gli gli
identificatori del gruppo \textit{filesystem} (si ricordi quanto esposto in
- \secref{sec:proc_perms}), ma essendo questi del tutto equivalenti ai primi,
+ sez.~\ref{sec:proc_perms}), ma essendo questi del tutto equivalenti ai primi,
eccetto il caso in cui si voglia scrivere un server NFS, ignoreremo questa
differenza.}
Per una spiegazione dettagliata degli identificatori associati ai processi si
-veda \secref{sec:proc_perms}; normalmente, a parte quanto vedremo in
-\secref{sec:file_suid_sgid}, l'user-ID effettivo e il group-ID effettivo
+veda sez.~\ref{sec:proc_perms}; normalmente, a parte quanto vedremo in
+sez.~\ref{sec:file_suid_sgid}, l'user-ID effettivo e il group-ID effettivo
corrispondono ai valori dell'\acr{uid} e del \acr{gid} dell'utente che ha
lanciato il processo, mentre i group-ID supplementari sono quelli dei gruppi
cui l'utente appartiene.
\subsection{I bit \acr{suid} e \acr{sgid}}
\label{sec:file_suid_sgid}
-Come si è accennato (in \secref{sec:file_perm_overview}) nei dodici bit del
+Come si è accennato (in sez.~\ref{sec:file_perm_overview}) nei dodici bit del
campo \var{st\_mode} di \struct{stat} che vengono usati per il controllo di
accesso oltre ai bit dei permessi veri e propri, ci sono altri tre bit che
vengono usati per indicare alcune proprietà speciali dei file. Due di questi
\textit{set-group-ID bit}) che sono identificati dalle costanti
\const{S\_ISUID} e \const{S\_ISGID}.
-Come spiegato in dettaglio in \secref{sec:proc_exec}, quando si lancia un
+Come spiegato in dettaglio in sez.~\ref{sec:proc_exec}, quando si lancia un
programma il comportamento normale del kernel è quello di impostare gli
identificatori del gruppo \textit{effective} del nuovo processo al valore dei
corrispondenti del gruppo \textit{real} del processo corrente, che normalmente
normalmente l'utente che lo ha lanciato comporta vari rischi, e questo tipo di
programmi devono essere scritti accuratamente per evitare che possano essere
usati per guadagnare privilegi non consentiti (l'argomento è affrontato in
-dettaglio in \secref{sec:proc_perms}).
+dettaglio in sez.~\ref{sec:proc_perms}).
La presenza dei bit \acr{suid} e \acr{sgid} su un file può essere rilevata con
il comando \cmd{ls -l}, che visualizza una lettera \cmd{s} al posto della
\cmd{s} può essere usata nel comando \cmd{chmod} per impostare questi bit.
Infine questi bit possono essere controllati all'interno di \var{st\_mode} con
l'uso delle due costanti \const{S\_ISUID} e \const{S\_IGID}, i cui valori sono
-riportati in \tabref{tab:file_mode_flags}.
+riportati in tab.~\ref{tab:file_mode_flags}.
Gli stessi bit vengono ad assumere in significato completamente diverso per le
directory, normalmente infatti Linux usa la convenzione di SVr4 per indicare
con questi bit l'uso della semantica BSD nella creazione di nuovi file (si
-veda \secref{sec:file_ownership} per una spiegazione dettagliata al
+veda sez.~\ref{sec:file_ownership} per una spiegazione dettagliata al
proposito).
Infine Linux utilizza il bit \acr{sgid} per una ulteriore estensione mutuata
da SVr4. Il caso in cui un file ha il bit \acr{sgid} impostato senza che lo
sia anche il corrispondente bit di esecuzione viene utilizzato per attivare
per quel file il \textit{mandatory locking} (affronteremo questo argomento in
-dettaglio più avanti, in \secref{sec:file_mand_locking}).
+dettaglio più avanti, in sez.~\ref{sec:file_mand_locking}).
\subsection{Il bit \textsl{sticky}}
si poteva impostare questo bit.
L'effetto di questo bit era che il segmento di testo del programma (si veda
-\secref{sec:proc_mem_layout} per i dettagli) veniva scritto nella swap la
+sez.~\ref{sec:proc_mem_layout} per i dettagli) veniva scritto nella swap la
prima volta che questo veniva lanciato, e vi permaneva fino al riavvio della
macchina (da questo il nome di \textsl{sticky bit}); essendo la swap un file
continuo indicizzato direttamente in questo modo si poteva risparmiare in
\subsection{La titolarità di nuovi file e directory}
\label{sec:file_ownership}
-Vedremo in \secref{sec:file_base_func} con quali funzioni si possono creare
+Vedremo in sez.~\ref{sec:file_base_func} con quali funzioni si possono creare
nuovi file, in tale occasione vedremo che è possibile specificare in sede di
creazione quali permessi applicare ad un file, però non si può indicare a
quale utente e gruppo esso deve appartenere. Lo stesso problema si presenta
per la creazione di nuove directory (procedimento descritto in
-\secref{sec:file_dir_creat_rem}).
+sez.~\ref{sec:file_dir_creat_rem}).
Lo standard POSIX prescrive che l'\acr{uid} del nuovo file corrisponda
all'user-ID effettivo del processo che lo crea; per il \acr{gid} invece prevede
\subsection{La funzione \func{access}}
\label{sec:file_access}
-Come visto in \secref{sec:file_access_control} il controllo di accesso ad un
-file viene fatto utilizzando l'user-ID ed il group-ID effettivo del processo; ci
-sono casi però in cui si può voler effettuare il controllo con l'user-ID reale
-ed il group-ID reale, vale a dire usando i valori di \acr{uid} e \acr{gid}
-relativi all'utente che ha lanciato il programma, e che, come accennato in
-\secref{sec:file_suid_sgid} e spiegato in dettaglio in
-\secref{sec:proc_perms}, non è detto siano uguali a quelli effettivi.
+Come visto in sez.~\ref{sec:file_access_control} il controllo di accesso ad un
+file viene fatto utilizzando l'user-ID ed il group-ID effettivo del processo;
+ci sono casi però in cui si può voler effettuare il controllo con l'user-ID
+reale ed il group-ID reale, vale a dire usando i valori di \acr{uid} e
+\acr{gid} relativi all'utente che ha lanciato il programma, e che, come
+accennato in sez.~\ref{sec:file_suid_sgid} e spiegato in dettaglio in
+sez.~\ref{sec:proc_perms}, non è detto siano uguali a quelli effettivi.
Per far questo si può usare la funzione \funcd{access}, il cui prototipo è:
\begin{prototype}{unistd.h}
La funzione verifica i permessi di accesso, indicati da \param{mode}, per il
file indicato da \param{pathname}. I valori possibili per l'argomento
\param{mode} sono esprimibili come combinazione delle costanti numeriche
-riportate in \tabref{tab:file_access_mode_val} (attraverso un OR binario delle
-stesse). I primi tre valori implicano anche la verifica dell'esistenza del
-file, se si vuole verificare solo quest'ultima si può usare \const{F\_OK}, o
-anche direttamente \func{stat}. Nel caso in cui \param{pathname} si riferisca
-ad un link simbolico, questo viene seguito ed il controllo è fatto sul file a
-cui esso fa riferimento.
+riportate in tab.~\ref{tab:file_access_mode_val} (attraverso un OR binario
+delle stesse). I primi tre valori implicano anche la verifica dell'esistenza
+del file, se si vuole verificare solo quest'ultima si può usare \const{F\_OK},
+o anche direttamente \func{stat}. Nel caso in cui \param{pathname} si
+riferisca ad un link simbolico, questo viene seguito ed il controllo è fatto
+sul file a cui esso fa riferimento.
La funzione controlla solo i bit dei permessi di accesso, si ricordi che il
fatto che una directory abbia permesso di scrittura non significa che ci si
Entrambe le funzioni utilizzano come secondo argomento \param{mode}, una
variabile dell'apposito tipo primitivo \type{mode\_t} (vedi
-\tabref{tab:intro_primitive_types}) utilizzato per specificare i permessi sui
+tab.~\ref{tab:intro_primitive_types}) utilizzato per specificare i permessi sui
file.
\begin{table}[!htb]
\end{table}
Le costanti con cui specificare i singoli bit di \param{mode} sono riportate
-in \tabref{tab:file_permission_const}. Il valore di \param{mode} può essere
+in tab.~\ref{tab:file_permission_const}. Il valore di \param{mode} può essere
ottenuto combinando fra loro con un OR binario le costanti simboliche relative
ai vari bit, o specificato direttamente, come per l'omonimo comando di shell,
con un valore numerico (la shell lo vuole in ottale, dato che i bit dei
permessi sono divisibili in gruppi di tre), che si può calcolare direttamente
-usando lo schema si utilizzo dei bit illustrato in \figref{fig:file_perm_bit}.
+usando lo schema si utilizzo dei bit illustrato in
+fig.~\ref{fig:file_perm_bit}.
Ad esempio i permessi standard assegnati ai nuovi file (lettura e scrittura
per il proprietario, sola lettura per il gruppo e gli altri) sono
l'user-ID effettivo del processo non è zero esso viene automaticamente
cancellato (senza notifica di errore) qualora sia stato indicato in
\param{mode}.
-\item per quanto detto in \secref{sec:file_ownership} riguardo la creazione
+\item per quanto detto in sez.~\ref{sec:file_ownership} riguardo la creazione
dei nuovi file, si può avere il caso in cui il file creato da un processo è
assegnato a un gruppo per il quale il processo non ha privilegi. Per evitare
che si possa assegnare il bit \acr{sgid} ad un file appartenente a un gruppo
Le funzioni \func{chmod} e \func{fchmod} ci permettono di modificare i
permessi di un file, resta però il problema di quali sono i permessi assegnati
quando il file viene creato. Le funzioni dell'interfaccia nativa di Unix, come
-vedremo in \secref{sec:file_open}, permettono di indicare esplicitamente i
+vedremo in sez.~\ref{sec:file_open}, permettono di indicare esplicitamente i
permessi di creazione di un file, ma questo non è possibile per le funzioni
dell'interfaccia standard ANSI C che non prevede l'esistenza di utenti e
gruppi, ed inoltre il problema si pone anche per l'interfaccia nativa quando i
In tutti questi casi l'unico riferimento possibile è quello della modalità di
apertura del nuovo file (lettura/scrittura o sola lettura), che però può
fornire un valore che è lo stesso per tutti e tre i permessi di
-\secref{sec:file_perm_overview} (cioè $666$ nel primo caso e $222$ nel
+sez.~\ref{sec:file_perm_overview} (cioè $666$ nel primo caso e $222$ nel
secondo). Per questo motivo il sistema associa ad ogni processo\footnote{è
infatti contenuta nel campo \var{umask} della struttura \struct{fs\_struct},
- vedi \figref{fig:proc_task_struct}.} una maschera di bit, la cosiddetta
+ vedi fig.~\ref{fig:proc_task_struct}.} una maschera di bit, la cosiddetta
\textit{umask}, che viene utilizzata per impedire che alcuni permessi possano
essere assegnati ai nuovi file in sede di creazione. I bit indicati nella
maschera vengono infatti cancellati dai permessi quando un nuovo file viene
%La struttura fondamentale che contiene i dati essenziali relativi ai file è il
%cosiddetto \textit{inode}; questo conterrà informazioni come il
%tipo di file (file di dispositivo, directory, file di dati, per un elenco
-%completo vedi \ntab), i permessi (vedi \secref{sec:file_perms}), le date (vedi
-%\secref{sec:file_times}).
+%completo vedi \ntab), i permessi (vedi sez.~\ref{sec:file_perms}), le date (vedi
+%sez.~\ref{sec:file_times}).
\subsection{Un quadro d'insieme sui permessi}
riepilogo in cui si riassumono le caratteristiche di ciascuno di essi, in modo
da poter fornire un quadro d'insieme.
-In \tabref{tab:file_fileperm_bits} si sono riassunti gli effetti dei vari bit
-per un file; per quanto riguarda l'applicazione dei permessi per proprietario,
-gruppo ed altri si ricordi quanto illustrato in
-\secref{sec:file_perm_overview}. Si rammenti che il valore dei permessi non ha
-alcun effetto qualora il processo possieda i privilegi di amministratore.
+In tab.~\ref{tab:file_fileperm_bits} si sono riassunti gli effetti dei vari
+bit per un file; per quanto riguarda l'applicazione dei permessi per
+proprietario, gruppo ed altri si ricordi quanto illustrato in
+sez.~\ref{sec:file_perm_overview}. Si rammenti che il valore dei permessi non
+ha alcun effetto qualora il processo possieda i privilegi di amministratore.
\begin{table}[!htb]
\centering
Per compattezza, nella tabella si sono specificati i bit di \acr{suid},
\acr{sgid} e \acr{sticky} con la notazione illustrata anche in
-\figref{fig:file_perm_bit}.
+fig.~\ref{fig:file_perm_bit}.
-In \tabref{tab:file_dirperm_bits} si sono invece riassunti gli effetti dei
+In tab.~\ref{tab:file_dirperm_bits} si sono invece riassunti gli effetti dei
vari bit dei permessi per una directory; anche in questo caso si sono
specificati i bit di \acr{suid}, \acr{sgid} e \acr{sticky} con la notazione
-compatta illustrata in \figref{fig:file_perm_bit}.
+compatta illustrata in fig.~\ref{fig:file_perm_bit}.
\begin{table}[!htb]
\centering
programma ad una sezione limitata del filesystem, per cui ne parleremo in
questa sezione.
-Come accennato in \secref{sec:proc_fork} ogni processo oltre ad una directory
+Come accennato in sez.~\ref{sec:proc_fork} ogni processo oltre ad una directory
di lavoro, ha anche una directory \textsl{radice}\footnote{entrambe sono
contenute in due campi (rispettivamente \var{pwd} e \var{root}) di
- \struct{fs\_struct}; vedi \figref{fig:proc_task_struct}.} che, pur essendo
+ \struct{fs\_struct}; vedi fig.~\ref{fig:proc_task_struct}.} che, pur essendo
di norma corrispondente alla radice dell'albero di file e directory come visto
-dal kernel (ed illustrato in \secref{sec:file_organization}), ha per il
+dal kernel (ed illustrato in sez.~\ref{sec:file_organization}), ha per il
processo il significato specifico di directory rispetto alla quale vengono
risolti i pathname assoluti.\footnote{cioè quando un processo chiede la
risoluzione di un pathname, il kernel usa sempre questa directory come punto
\textsl{imprigionato}.
Solo un processo con i privilegi di amministratore può usare questa funzione,
-e la nuova radice, per quanto detto in \secref{sec:proc_fork}, sarà ereditata
+e la nuova radice, per quanto detto in sez.~\ref{sec:proc_fork}, sarà ereditata
da tutti i suoi processi figli. Si tenga presente però che la funzione non
cambia la directory di lavoro, che potrebbe restare fuori dalla \textit{chroot
jail}.
\section{Introduzione}
\label{sec:file_stream_intro}
-Come visto in \capref{cha:file_unix_interface} le operazioni di I/O sui file
+Come visto in cap.~\ref{cha:file_unix_interface} le operazioni di I/O sui file
sono gestibili a basso livello con l'interfaccia standard unix, che ricorre
direttamente alle system call messe a disposizione dal kernel.
scrittura (sia per quel che riguarda la bufferizzazione, che le
formattazioni), i file stream restano del tutto equivalenti ai file descriptor
(sui quali sono basati), ed in particolare continua a valere quanto visto in
-\secref{sec:file_sharing} a proposito dell'accesso condiviso ed in
-\secref{sec:file_access_control} per il controllo di accesso.
+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|)}
\subsection{Gli stream standard}
\label{sec:file_std_stream}
-Ai tre file descriptor standard (vedi \secref{sec:file_std_descr})
+Ai tre file descriptor standard (vedi sez.~\ref{sec:file_std_descr})
aperti per ogni processo, corrispondono altrettanti stream, che
rappresentano i canali standard di input/output prestabiliti; anche
questi tre stream sono identificabili attraverso dei nomi simbolici
legge è in modalità \textit{unbuffered}.} viene anche eseguito lo scarico di
tutti i buffer degli stream in scrittura.
-In \secref{sec:file_buffering_ctrl} vedremo come la libreria definisca delle
+In sez.~\ref{sec:file_buffering_ctrl} vedremo come la libreria definisca delle
opportune funzioni per controllare le modalità di bufferizzazione e lo scarico
dei dati.
\label{sec:file_ansi_base_func}
Esamineremo in questa sezione le funzioni base dell'interfaccia degli stream,
-analoghe a quelle di \secref{sec:file_base_func} per i file descriptor. In
+analoghe a quelle di sez.~\ref{sec:file_base_func} per i file descriptor. In
particolare vedremo come aprire, leggere, scrivere e cambiare la posizione
corrente in uno stream.
Normalmente la funzione che si usa per aprire uno stream è \func{fopen},
essa apre il file specificato nella modalità specificata da
\param{mode}, che è una stringa che deve iniziare con almeno uno dei
-valori indicati in \tabref{tab:file_fopen_mode} (sono possibili varie
+valori indicati in tab.~\ref{tab:file_fopen_mode} (sono possibili varie
estensioni che vedremo in seguito).
L'uso più comune di \func{freopen} è per redirigere uno dei tre file
-standard (vedi \secref{sec:file_std_stream}): il file \param{path} viene
+standard (vedi sez.~\ref{sec:file_std_stream}): il file \param{path} viene
associato a \param{stream} e se questo è uno stream già aperto viene
preventivamente chiuso.
\end{table}
In realtà lo standard ANSI C prevede un totale di 15 possibili valori
-diversi per \param{mode}, ma in \tabref{tab:file_fopen_mode} si sono
+diversi per \param{mode}, ma in tab.~\ref{tab:file_fopen_mode} si sono
riportati solo i sei valori effettivi, ad essi può essere aggiunto pure
il carattere \texttt{b} (come ultimo carattere o nel mezzo agli altri per
le stringhe di due caratteri) che in altri sistemi operativi serve a
Le \acr{glibc} supportano alcune estensioni, queste devono essere sempre
indicate dopo aver specificato il \param{mode} con uno dei valori di
-\tabref{tab:file_fopen_mode}. L'uso del carattere \texttt{x} serve per
+tab.~\ref{tab:file_fopen_mode}. L'uso del carattere \texttt{x} serve per
evitare di sovrascrivere un file già esistente (è analoga all'uso
dell'opzione \const{O\_EXCL} in \func{open}), se il file specificato già
esiste e si aggiunge questo carattere a \param{mode} la \func{fopen}
Nel caso si usi \func{fdopen} i valori specificati da \param{mode} devono
essere compatibili con quelli con cui il file descriptor è stato aperto.
Inoltre i modi \cmd{w} e \cmd{w+} non troncano il file. La posizione nello
-stream viene impostata a quella corrente nel file descriptor, e le variabili di
-errore e di fine del file (vedi \secref{sec:file_io}) sono cancellate. Il file
-non viene duplicato e verrà chiuso alla chiusura dello stream.
+stream viene impostata a quella corrente nel file descriptor, e le variabili
+di errore e di fine del file (vedi sez.~\ref{sec:file_io}) sono cancellate. Il
+file non viene duplicato e verrà chiuso alla chiusura dello stream.
I nuovi file saranno creati secondo quanto visto in
-\secref{sec:file_ownership} ed avranno i permessi di accesso impostati al
+sez.~\ref{sec:file_ownership} ed avranno i permessi di accesso impostati al
valore \code{S\_IRUSR|S\_IWUSR|S\_IRGRP|S\_IWGRP|S\_IROTH|S\_IWOTH} (pari a
\val{0666}) modificato secondo il valore di \acr{umask} per il processo (si
-veda \secref{sec:file_umask}).
+veda sez.~\ref{sec:file_umask}).
In caso di file aperti in lettura e scrittura occorre ricordarsi che c'è
di mezzo una bufferizzazione; per questo motivo lo standard ANSI C
sufficiente a garantire la sincronizzazione.
Una volta aperto lo stream, si può cambiare la modalità di bufferizzazione
-(si veda \secref{sec:file_buffering_ctrl}) fintanto che non si è effettuato
+(si veda sez.~\ref{sec:file_buffering_ctrl}) fintanto che non si è effettuato
alcuna operazione di I/O sul file.
Uno stream viene chiuso con la funzione \funcd{fclose} il cui prototipo è:
stream questo verrà rilasciato. La funzione effettua lo scarico solo per i
dati presenti nei buffer in user space usati dalle \acr{glibc}; se si vuole
essere sicuri che il kernel forzi la scrittura su disco occorrerà effettuare
-una \func{sync} (vedi \secref{sec:file_sync}).
+una \func{sync} (vedi sez.~\ref{sec:file_sync}).
Linux supporta anche una altra funzione, \funcd{fcloseall}, come estensione
GNU implementata dalle \acr{glibc}, accessibile avendo definito
provvista solo per i casi di emergenza, quando si è verificato un errore
ed il programma deve essere abortito, ma si vuole compiere qualche altra
operazione dopo aver chiuso i file e prima di uscire (si ricordi quanto
-visto in \secref{sec:proc_exit}).
+visto in sez.~\ref{sec:proc_exit}).
\subsection{Lettura e scrittura su uno stream}
modalità di input/output non formattato:
\begin{enumerate*}
\item\textsl{binario} in cui legge/scrive un blocco di dati alla
- volta, vedi \secref{sec:file_binary_io}.
+ volta, vedi sez.~\ref{sec:file_binary_io}.
\item\textsl{a caratteri} in cui si legge/scrive un carattere alla
volta (con la bufferizzazione gestita automaticamente dalla libreria),
- vedi \secref{sec:file_char_io}.
+ vedi sez.~\ref{sec:file_char_io}.
\item\textsl{di linea} in cui si legge/scrive una linea alla volta (terminata
- dal carattere di newline \verb|'\n'|), vedi \secref{sec:file_line_io}.
+ dal carattere di newline \verb|'\n'|), vedi sez.~\ref{sec:file_line_io}.
\end{enumerate*}
ed inoltre la modalità di input/output formattato.
il problema di come distinguerla da un errore effettivo; basarsi solo sul
valore di ritorno della funzione e controllare il valore di \var{errno}
infatti non basta, dato che quest'ultimo potrebbe essere stato impostato in
-una altra occasione, (si veda \secref{sec:sys_errno} per i dettagli del
+una altra occasione, (si veda sez.~\ref{sec:sys_errno} per i dettagli del
funzionamento di \var{errno}).
Per questo motivo tutte le implementazioni delle librerie standard
corretta la causa di un errore per evitare di mantenere i flag attivi, così da
poter rilevare una successiva ulteriore condizione di errore. Di questa
funzione esiste una analoga \func{clearerr\_unlocked} che non esegue il blocco
-dello stream (vedi \secref{sec:file_stream_thread}).
+dello stream (vedi sez.~\ref{sec:file_stream_thread}).
\subsection{Input/output binario}
Le \acr{glibc} definiscono altre due funzioni per l'I/O binario,
\funcd{fread\_unlocked} e \funcd{fwrite\_unlocked} che evitano il lock
implicito dello stream, usato per dalla librerie per la gestione delle
-applicazioni multi-thread (si veda \secref{sec:file_stream_thread} per i
+applicazioni multi-thread (si veda sez.~\ref{sec:file_stream_thread} per i
dettagli), i loro prototipi sono:
\begin{functions}
\headdecl{stdio.h}
viene implementata con una macro, per cui occorre stare attenti a cosa
le si passa come argomento, infatti \param{stream} può essere valutato
più volte nell'esecuzione, e non viene passato in copia con il
-meccanismo visto in \secref{sec:proc_var_passing}; per questo motivo se
+meccanismo visto in sez.~\ref{sec:proc_var_passing}; per questo motivo se
si passa un'espressione si possono avere effetti indesiderati.
Invece \func{fgetc} è assicurata essere sempre una funzione, per questo
Infine si tenga presente che \func{ungetc} non altera il contenuto del
file, ma opera esclusivamente sul buffer interno. Se si esegue una
qualunque delle operazioni di riposizionamento (vedi
-\secref{sec:file_fseek}) i caratteri rimandati indietro vengono
+sez.~\ref{sec:file_fseek}) i caratteri rimandati indietro vengono
scartati.
\acr{glibc} supportano una serie di altre funzioni, estensioni di tutte quelle
illustrate finora (eccetto \func{gets} e \func{puts}), che eseguono
esattamente le stesse operazioni delle loro equivalenti, evitando però il lock
-implicito dello stream (vedi \secref{sec:file_stream_thread}). Come per le
+implicito dello stream (vedi sez.~\ref{sec:file_stream_thread}). Come per le
altre forma di I/O, dette funzioni hanno lo stesso nome della loro analoga
normale, con l'aggiunta dell'estensione \code{\_unlocked}.
passata indietro (si noti infatti come per entrambi i parametri si siano
usati dei \textit{value result argument}, passando dei puntatori anziché
i valori delle variabili, secondo la tecnica spiegata in
-\secref{sec:proc_var_passing}).
+sez.~\ref{sec:proc_var_passing}).
Se si passa alla funzione l'indirizzo di un puntatore impostato a \val{NULL}
e \var{*n} è zero, la funzione provvede da sola all'allocazione della memoria
vengono passati invariati all'output, e da direttive di conversione, in cui
devono essere sempre presenti il carattere \texttt{\%}, che introduce la
direttiva, ed uno degli specificatori di conversione (riportati in
-\tabref{tab:file_format_spec}) che la conclude.
+tab.~\ref{tab:file_format_spec}) che la conclude.
\begin{table}[htb]
\centering
\begin{itemize*}
\item uno specificatore del parametro da usare (terminato da un \val{\$}),
\item uno o più flag (i cui valori possibili sono riassunti in
- \tabref{tab:file_format_flag}) che controllano il formato di stampa della
+ tab.~\ref{tab:file_format_flag}) che controllano il formato di stampa della
conversione,
\item uno specificatore di larghezza (un numero decimale), eventualmente
seguito (per i numeri in virgola mobile) da un specificatore di precisione
(un altro numero decimale),
\item uno specificatore del tipo di dato, che ne indica la dimensione (i cui
- valori possibili sono riassunti in \tabref{tab:file_format_type}).
+ valori possibili sono riassunti in tab.~\ref{tab:file_format_type}).
\end{itemize*}
Una versione alternativa delle funzioni di output formattato, che permettono
di usare il puntatore ad una lista di argomenti (vedi
-\secref{sec:proc_variadic}), sono \funcd{vprintf}, \funcd{vfprintf} e
+sez.~\ref{sec:proc_variadic}), sono \funcd{vprintf}, \funcd{vfprintf} e
\funcd{vsprintf}, i cui prototipi sono:
\begin{functions}
\headdecl{stdio.h}
si vogliono passare ad una routine di stampa, passando direttamente la lista
tramite il parametro \param{ap}. Per poter far questo ovviamente la lista dei
parametri dovrà essere opportunamente trattata (l'argomento è esaminato in
-\secref{sec:proc_variadic}), e dopo l'esecuzione della funzione l'argomento
+sez.~\ref{sec:proc_variadic}), e dopo l'esecuzione della funzione l'argomento
\param{ap} non sarà più utilizzabile (in generale dovrebbe essere eseguito un
\code{va\_end(ap)} ma in Linux questo non è necessario).
\end{functions}
Entrambe le funzioni prendono come parametro \param{strptr} che deve essere
l'indirizzo di un puntatore ad una stringa di caratteri, in cui verrà
-restituito (si ricordi quanto detto in \secref{sec:proc_var_passing} a
+restituito (si ricordi quanto detto in sez.~\ref{sec:proc_var_passing} a
proposito dei \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
L'uso di \func{fseek} è del tutto analogo a quello di \func{lseek} per i file
descriptor, ed i parametri, a parte il tipo, hanno lo stesso significato; in
particolare \param{whence} assume gli stessi valori già visti in
-\secref{sec:file_lseek}. La funzione restituisce 0 in caso di successo e -1
+sez.~\ref{sec:file_lseek}. La funzione restituisce 0 in caso di successo e -1
in caso di errore. La funzione \func{rewind} riporta semplicemente la
posizione corrente all'inizio dello stream, ma non esattamente equivalente ad
una \code{fseek(stream, 0L, SEEK\_SET)} in quanto vengono cancellati anche i
\subsection{Il controllo della bufferizzazione}
\label{sec:file_buffering_ctrl}
-Come accennato in \secref{sec:file_buffering} le librerie definiscono una
+Come accennato in sez.~\ref{sec:file_buffering} le librerie definiscono una
serie di funzioni che permettono di controllare il comportamento degli stream;
se non si è specificato nulla, la modalità di buffering viene decisa
autonomamente sulla base del tipo di file sottostante, ed i buffer vengono
\val{NULL} per \param{buf} e la funzione ignorerà il parametro \param{size}
usando il buffer allocato automaticamente dal sistema. Si potrà comunque
modificare la modalità di bufferizzazione, passando in \param{mode} uno degli
-opportuni valori elencati in \tabref{tab:file_stream_buf_mode}. Qualora si
+opportuni valori elencati in tab.~\ref{tab:file_stream_buf_mode}. Qualora si
specifichi la modalità non bufferizzata i valori di \param{buf} e \param{size}
vengono sempre ignorati.
Si ricordi comunque che lo scarico dei dati dai buffer effettuato da queste
funzioni non comporta la scrittura di questi su disco; se si vuole che il
kernel dia effettivamente avvio alle operazioni di scrittura su disco occorre
-usare \func{sync} o \func{fsync} (si veda~\secref{sec:file_sync}).
+usare \func{sync} o \func{fsync} (si veda~sez.~\ref{sec:file_sync}).
Infine esistono anche circostanze in cui si vuole scartare tutto l'output
pendente; per questo si può usare \funcd{fpurge}, il cui prototipo è:
dalle system call, che non prevede funzionalità evolute come la
bufferizzazione o funzioni di lettura o scrittura formattata, e sulla quale è
costruita anche l'interfaccia definita dallo standard ANSI C che affronteremo
-al \capref{cha:files_std_interface}.
+al cap.~\ref{cha:files_std_interface}.
\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 \secref{sec:file_vfs_work}). Questo si fa
-aprendo il file con la funzione \func{open} che provvederà a localizzare
+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
-\tabref{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.
+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.
All'interno di ogni processo i file aperti sono identificati da un intero non
negativo, chiamato appunto \textit{file descriptor}.
sua volta all'inode\index{inode} passando per la nuova struttura del VFS.}
del file.
%\item un puntatore alla tabella delle funzioni \footnote{la struttura
-% \var{f\_op} descritta in \secref{sec:file_vfs_work}} che si possono usare
+% \var{f\_op} descritta in sez.~\ref{sec:file_vfs_work}} che si possono usare
% sul file.
\end{itemize*}
-In \figref{fig:file_proc_file} si è riportato uno schema in cui è illustrata
+In fig.~\ref{fig:file_proc_file} si è riportato uno schema in cui è illustrata
questa architettura, ed in cui si sono evidenziate le interrelazioni fra le
varie strutture di dati sulla quale essa è basata.
\begin{figure}[htb]
\label{tab:file_std_files}
\end{table}
-In \figref{tab:file_std_files} si è utilizzata questa situazione come esempio,
-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}).
+In tab.~\ref{tab:file_std_files} si è utilizzata questa situazione come
+esempio, 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}).
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
descriptor dentro \struct{file\_struct}; questo limite intrinseco nei kernel
più recenti non sussiste più, dato che si è passati da un vettore ad una
lista, ma restano i limiti imposti dall'amministratore (vedi
-\secref{sec:sys_limits}).
+sez.~\ref{sec:sys_limits}).
\hline % modalità di apertura del file
\hline
\const{O\_CREAT} & se il file non esiste verrà creato, con le regole di
- titolarità del file viste in \secref{sec:file_ownership}. L'argomento
+ titolarità del file viste in sez.~\ref{sec:file_ownership}. L'argomento
\param{mode} deve essere specificato. \\
\const{O\_EXCL} & usato in congiunzione con \const{O\_CREAT} fa sì che
l'esistenza del file diventi un errore\protect\footnotemark\ che fa fallire
\const{O\_NONBLOCK} & apre il file in modalità non bloccante. Questo
valore specifica anche una modalità di operazione (vedi sotto), e
comporta che \func{open} ritorni immediatamente (l'opzione ha senso
- solo per le fifo, torneremo questo in \secref{sec:ipc_named_pipe}). \\
+ solo per le fifo, torneremo questo in sez.~\ref{sec:ipc_named_pipe}). \\
\const{O\_NOCTTY} & se \param{pathname} si riferisce ad un dispositivo di
terminale, questo non diventerà il terminale di controllo, anche se il
- processo non ne ha ancora uno (si veda \secref{sec:sess_ctrl_term}). \\
+ processo non ne ha ancora uno (si veda sez.~\ref{sec:sess_ctrl_term}). \\
\const{O\_SHLOCK} & opzione di BSD, acquisisce uno shared lock (vedi
- \secref{sec:file_locking}) sul file. Non è disponibile in Linux. \\
+ sez.~\ref{sec:file_locking}) sul file. Non è disponibile in Linux. \\
\const{O\_EXLOCK} & opzione di BSD, acquisisce uno lock esclusivo (vedi
- \secref{sec:file_locking}) sul file. Non è disponibile in Linux. \\
+ sez.~\ref{sec:file_locking}) sul file. Non è disponibile in Linux. \\
\const{O\_TRUNC} & se il file esiste ed è un file di dati e la modalità di
apertura consente la scrittura, allora la sua lunghezza verrà troncata a
zero. Se il file è un terminale o una fifo il flag verrà ignorato, negli
file. Può causare corruzione del file con NFS se più di un processo scrive
allo stesso tempo.\footnotemark\\
\const{O\_NONBLOCK} & il file viene aperto in modalità non bloccante per
- le operazioni di I/O (che tratteremo in \secref{sec:file_noblocking}):
+ le operazioni di I/O (che tratteremo in sez.~\ref{sec:file_noblocking}):
questo significa il fallimento di \func{read} in assenza di dati da
leggere e quello di \func{write} in caso di impossibilità di scrivere
immediatamente. Questa modalità ha senso solo per le fifo e per alcuni
\const{O\_NDELAY} & in Linux\footnotemark\ è sinonimo di
\const{O\_NONBLOCK}.\\
\const{O\_ASYNC} & apre il file per l'I/O in modalità
- asincrona (vedi \secref{sec:file_asyncronous_io}). Quando è impostato viene
- generato il segnale \const{SIGIO} tutte le volte che sono disponibili
+ asincrona (vedi sez.~\ref{sec:file_asyncronous_io}). Quando è impostato
+ viene generato il segnale \const{SIGIO} tutte le volte che sono disponibili
dati in input sul file. \\
\const{O\_SYNC} & apre il file per l'input/output sincrono, ogni
\func{write} bloccherà fino al completamento della scrittura di tutti dati
sul sull'hardware sottostante.\\
\const{O\_FSYNC} & sinonimo di \const{O\_SYNC}. \\
\const{O\_NOATIME} & blocca l'aggiornamento dei tempi di accesso dei
- file (vedi \secref{sec:file_file_times}). In Linux questa opzione non è
+ file (vedi sez.~\ref{sec:file_file_times}). In Linux questa opzione non è
disponibile per il singolo file ma come opzione per il filesystem in fase
di montaggio.\\
\hline
\textsl{file di lock}\index{file!di lock} possono incorrere in una race
condition\index{race condition}. Si consiglia come alternativa di usare un
file con un nome univoco e la funzione \func{link} per verificarne
- l'esistenza (vedi \secref{sec:ipc_file_lock}).}
+ l'esistenza (vedi sez.~\ref{sec:ipc_file_lock}).}
\footnotetext[3]{\textit{Denial of Service}\index{DoS}, si chiamano così
attacchi miranti ad impedire un servizio causando una qualche forma di
\footnotetext[4]{il problema è che NFS non supporta la scrittura in append, ed
il kernel deve simularla, ma questo comporta la possibilità di una race
- condition, vedi \secref{sec:file_atomic}.}
+ condition, vedi sez.~\ref{sec:file_atomic}.}
\footnotetext[5]{l'opzione origina da SVr4, dove però causava il ritorno da
una \func{read} con un valore nullo e non con un errore, questo introduce
- un'ambiguità, dato che come vedremo in \secref{sec:file_read} il ritorno di
+ un'ambiguità, dato che come vedremo in sez.~\ref{sec:file_read} il ritorno di
zero da parte di \func{read} ha il significato di una end-of-file.}
Questa caratteristica permette di prevedere qual'è il valore del file
descriptor che si otterrà al ritorno di \func{open}, e viene talvolta usata da
alcune applicazioni per sostituire i file corrispondenti ai file standard
-visti in \secref{sec:file_std_descr}: se ad esempio si chiude lo standard
+visti in sez.~\ref{sec:file_std_descr}: se ad esempio si chiude lo standard
input e si apre subito dopo un nuovo file questo diventerà il nuovo standard
input (avrà cioè il file descriptor 0). Il nuovo file descriptor non è
condiviso con nessun altro processo (torneremo sulla condivisione dei file, in
-genere accessibile dopo una \func{fork}, in \secref{sec:file_sharing}) ed è
+genere accessibile dopo una \func{fork}, in sez.~\ref{sec:file_sharing}) ed è
impostato per restare aperto attraverso una \func{exec} (come accennato in
-\secref{sec:proc_exec}); l'offset è impostato all'inizio del file.
+sez.~\ref{sec:proc_exec}); l'offset è impostato all'inizio del file.
L'argomento \param{mode} indica i permessi con cui il file viene creato; i
-valori possibili sono gli stessi già visti in \secref{sec:file_perm_overview}
+valori possibili sono gli stessi già visti in sez.~\ref{sec:file_perm_overview}
e possono essere specificati come OR binario delle costanti descritte in
-\tabref{tab:file_bit_perm}. Questi permessi sono filtrati dal valore di
-\var{umask} (vedi \secref{sec:file_umask}) per il processo.
+tab.~\ref{tab:file_bit_perm}. Questi permessi sono filtrati dal valore di
+\var{umask} (vedi sez.~\ref{sec:file_umask}) per il processo.
La funzione prevede diverse opzioni, che vengono specificate usando vari bit
dell'argomento \param{flags}. Alcuni di questi bit vanno anche a costituire
il flag di stato del file (o \textit{file status flag}), che è mantenuto nel
campo \var{f\_flags} della struttura \struct{file} (al solito si veda lo schema
-di \figref{fig:file_proc_file}). Essi sono divisi in tre categorie
+di fig.~\ref{fig:file_proc_file}). Essi sono divisi in tre categorie
principali:
\begin{itemize*}
\item \textsl{i bit delle modalità di accesso}: specificano con quale modalità
che controllano) con una \func{fcntl}.
\end{itemize*}
-In \tabref{tab:file_open_flags} sono riportate, ordinate e divise fra loro
+In tab.~\ref{tab:file_open_flags} sono riportate, ordinate e divise fra loro
secondo le tre modalità appena elencate, le costanti mnemoniche associate a
ciascuno di questi bit. Dette costanti possono essere combinate fra loro con
un OR aritmetico per costruire il valore (in forma di maschera binaria)
\end{prototype}
La chiusura di un file rilascia ogni blocco (il \textit{file
- locking}\index{file!locking} è trattato in \secref{sec:file_locking}) che il
-processo poteva avere acquisito su di esso; se \param{fd} è l'ultimo
+ locking}\index{file!locking} è trattato in sez.~\ref{sec:file_locking}) che
+il processo poteva avere acquisito su di esso; se \param{fd} è l'ultimo
riferimento (di eventuali copie) ad un file aperto, tutte le risorse nella
file table vengono rilasciate. Infine se il file descriptor era l'ultimo
riferimento ad un file su disco quest'ultimo viene cancellato.
In ogni caso una \func{close} andata a buon fine non garantisce che i dati
siano stati effettivamente scritti su disco, perché il kernel può decidere di
ottimizzare l'accesso a disco ritardandone la scrittura. L'uso della funzione
-\func{sync} (vedi \secref{sec:file_sync}) effettua esplicitamente il
+\func{sync} (vedi sez.~\ref{sec:file_sync}) effettua esplicitamente il
\emph{flush} dei dati, ma anche in questo caso resta l'incertezza dovuta al
comportamento dell'hardware (che a sua volta può introdurre ottimizzazioni
dell'accesso al disco che ritardano la scrittura dei dati, da cui l'abitudine
\subsection{La funzione \func{lseek}}
\label{sec:file_lseek}
-Come già accennato in \secref{sec:file_fd} a ciascun file aperto è associata
+Come già accennato in sez.~\ref{sec:file_fd} a ciascun file aperto è associata
una \textsl{posizione corrente nel file} (il cosiddetto \textit{file offset},
mantenuto nel campo \var{f\_pos} di \struct{file}) espressa da un numero intero
positivo come numero di byte dall'inizio del file. Tutte le operazioni di
per ottenere la nuova posizione corrente.
\end{basedescript}
-Come accennato in \secref{sec:file_file_size} con \func{lseek} è possibile
+Come accennato in sez.~\ref{sec:file_file_size} con \func{lseek} è possibile
impostare la posizione corrente anche oltre la fine del file, e alla
successiva scrittura il file sarà esteso. La chiamata non causa nessun accesso
al file, si limita a modificare la posizione corrente (cioè il valore
-\var{f\_pos} in \param{file}, vedi \figref{fig:file_proc_file}). Dato che la
+\var{f\_pos} in \param{file}, vedi fig.~\ref{fig:file_proc_file}). Dato che la
funzione ritorna la nuova posizione, usando il valore zero per \param{offset}
si può riottenere la posizione corrente nel file chiamando la funzione con
\code{lseek(fd, 0, SEEK\_CUR)}.
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
-\textit{race condition}\index{race condition}, vedi \secref{sec:file_atomic}).
+(questa è una potenziale sorgente di \textit{race condition}
+\index{race condition}, vedi sez.~\ref{sec:file_atomic}).
Non tutti i file supportano la capacità di eseguire una \func{lseek}, in
questo caso la funzione ritorna l'errore \errcode{EPIPE}. Questo, oltre che per
quando si legge da un terminale, da una fifo o da una pipe. In tal caso
infatti, se non ci sono dati in ingresso, la \func{read} si blocca (a meno di
non aver selezionato la modalità non bloccante, vedi
-\secref{sec:file_noblocking}) e ritorna solo quando ne arrivano; se il numero
+sez.~\ref{sec:file_noblocking}) e ritorna solo quando ne arrivano; se il numero
di byte richiesti eccede quelli disponibili la funzione ritorna comunque, ma
con un numero di byte inferiore a quelli richiesti.
Lo stesso comportamento avviene caso di lettura dalla rete (cioè su un
-socket\index{socket}, come vedremo in \secref{sec:sock_io_behav}), o per la
+socket\index{socket}, come vedremo in sez.~\ref{sec:sock_io_behav}), o per la
lettura da certi file di dispositivo, come le unità a nastro, che
restituiscono sempre i dati ad un singolo blocco alla volta.
\errcode{EAGAIN} non sono errori. La prima si verifica quando la \func{read} è
bloccata in attesa di dati in ingresso e viene interrotta da un segnale; in
tal caso l'azione da intraprendere è quella di rieseguire la funzione.
-Torneremo in dettaglio sull'argomento in \secref{sec:sig_gen_beha}. La
+Torneremo in dettaglio sull'argomento in sez.~\ref{sec:sig_gen_beha}. La
seconda si verifica quando il file è in modalità non bloccante (vedi
-\secref{sec:file_noblocking}) e non ci sono dati in ingresso: la funzione
+sez.~\ref{sec:file_noblocking}) e non ci sono dati in ingresso: la funzione
allora ritorna immediatamente con un errore \errcode{EAGAIN}\footnote{BSD usa
per questo errore la costante \errcode{EWOULDBLOCK}, in Linux, con le
\acr{glibc}, questa è sinonima di \errcode{EAGAIN}.} che indica soltanto che
l'emulazione per i vecchi kernel che non hanno la system call, è stato
aggiunto con la versione 2.1, in versioni precedenti sia del kernel che
delle librerie la funzione non è disponibile.} (quello che viene chiamato
-normalmente Unix98, vedi \secref{sec:intro_opengroup}) è stata introdotta la
+normalmente Unix98, vedi sez.~\ref{sec:intro_opengroup}) è stata introdotta la
definizione di un'altra funzione di lettura, \funcd{pread}, il cui prototipo è:
\begin{prototype}{unistd.h}
{ssize\_t pread(int fd, void * buf, size\_t count, off\_t offset)}
\func{read} seguita da una \func{lseek} che riporti al valore precedente la
posizione corrente sul file, ma permette di eseguire l'operazione
atomicamente. Questo può essere importante quando la posizione sul file viene
-condivisa da processi diversi (vedi \secref{sec:file_sharing}). Il valore di
+condivisa da processi diversi (vedi sez.~\ref{sec:file_sharing}). Il valore di
\param{offset} fa sempre riferimento all'inizio del file.
della gestione file in un sistema unix-like, esaminando in dettaglio il
comportamento delle funzioni base, inoltre tratteremo le funzioni che
permettono di eseguire alcune operazioni avanzate con i file (il grosso
-dell'argomento sarà comunque affrontato in \capref{cha:file_advanced}).
+dell'argomento sarà comunque affrontato in cap.~\ref{cha:file_advanced}).
\subsection{La condivisione dei files}
\label{sec:file_sharing}
-In \secref{sec:file_fd} abbiamo descritto brevemente l'architettura
+In sez.~\ref{sec:file_fd} abbiamo descritto brevemente l'architettura
dell'interfaccia con i file da parte di un processo, mostrando in
-\figref{fig:file_proc_file} le principali strutture usate dal kernel;
+fig.~\ref{fig:file_proc_file} le principali strutture usate dal kernel;
esamineremo ora in dettaglio le conseguenze che questa architettura ha nei
confronti dell'accesso allo stesso file da parte di processi diversi.
\end{figure}
Il primo caso è quello in cui due processi diversi aprono lo stesso file
-su disco; sulla base di quanto visto in \secref{sec:file_fd} avremo una
-situazione come quella illustrata in \figref{fig:file_mult_acc}: ciascun
+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
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 \secref{sec:proc_fork}). La
-situazione è illustrata in \figref{fig:file_acc_child}; dato che il processo
+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
posizione corrente sul file. Questo ha le conseguenze descritte a suo tempo in
-\secref{sec:proc_fork}: in caso di scrittura contemporanea la posizione
+sez.~\ref{sec:proc_fork}: in caso di scrittura contemporanea la posizione
corrente nel file varierà per entrambi i processi (in quanto verrà modificato
\var{f\_pos} che è lo stesso per entrambi).
maniera imprevedibile. Il sistema però fornisce in alcuni casi la possibilità
di eseguire alcune operazioni di scrittura in maniera coordinata anche senza
utilizzare meccanismi di sincronizzazione più complessi (come il \textit{file
- locking}\index{file!locking}, che esamineremo in \secref{sec:file_locking}).
+ locking}\index{file!locking}, che esamineremo in
+sez.~\ref{sec:file_locking}).
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 \secref{sec:file_lseek} impostare la posizione alla
+log). Come accennato in sez.~\ref{sec:file_lseek} impostare la posizione alla
fine del file e poi scrivere può condurre ad una \textit{race
condition}\index{race condition}: infatti può succedere che un secondo
processo scriva alla fine del file fra la \func{lseek} e la \func{write}; in
dell'esistenza del file (con relativa uscita dalla funzione con un errore) e
creazione in caso di assenza, diventa atomica essendo svolta tutta all'interno
di una singola system call (per i dettagli sull'uso di questa caratteristica
-si veda \secref{sec:ipc_file_lock}).
+si veda sez.~\ref{sec:ipc_file_lock}).
\subsection{La funzioni \func{sync} e \func{fsync}}
\label{sec:file_sync}
-Come accennato in \secref{sec:file_close} tutte le operazioni di scrittura
+Come accennato in sez.~\ref{sec:file_close} tutte le operazioni di scrittura
sono in genere bufferizzate dal kernel, che provvede ad effettuarle in maniera
asincrona (ad esempio accorpando gli accessi alla stessa zona del disco) in un
secondo tempo rispetto al momento della esecuzione della \func{write}.
\subsection{La funzioni \func{dup} e \func{dup2}}
\label{sec:file_dup}
-Abbiamo già visto in \secref{sec:file_sharing} come un processo figlio
+Abbiamo già visto in sez.~\ref{sec:file_sharing} come un processo figlio
condivida gli stessi file descriptor del padre; è possibile però ottenere un
comportamento analogo all'interno di uno stesso processo \textit{duplicando}
un file descriptor. Per far questo si usa la funzione \funcd{dup} il cui
La funzione ritorna, come \func{open}, il primo file descriptor libero. Il
file descriptor è una copia esatta del precedente ed entrambi possono essere
interscambiati nell'uso. Per capire meglio il funzionamento della funzione si
-può fare riferimento a \figref{fig:file_dup}: l'effetto della funzione è
+può fare riferimento a fig.~\ref{fig:file_dup}: l'effetto della funzione è
semplicemente quello di copiare il valore nella struttura
\struct{file\_struct}, cosicché anche il nuovo file descriptor fa riferimento
alla stessa voce nella \textit{file table}; per questo si dice che il nuovo
\label{fig:file_dup}
\end{figure}
-Si noti che per quanto illustrato in\figref{fig:file_dup} i file descriptor
+Si noti che per quanto illustrato in fig.~\ref{fig:file_dup} i file descriptor
duplicati condivideranno eventuali lock, \textit{file status flag}, e
posizione corrente. Se ad esempio si esegue una \func{lseek} per modificare la
posizione su uno dei due file descriptor, essa risulterà modificata anche
differenza fra due file descriptor duplicati è che ciascuno avrà il suo
\textit{file descriptor flag}; a questo proposito va specificato che nel caso
di \func{dup} il flag di \textit{close-on-exec}\index{close-on-exec} (vedi
-\secref{sec:proc_exec} e \secref{sec:file_fcntl}) viene sempre cancellato
+sez.~\ref{sec:proc_exec} e sez.~\ref{sec:file_fcntl}) viene sempre cancellato
nella copia.
L'uso principale di questa funzione è per la redirezione dell'input e
dell'output fra l'esecuzione di una \func{fork} e la successiva \func{exec};
diventa così possibile associare un file (o una pipe) allo standard input o
-allo standard output (torneremo sull'argomento in \secref{sec:ipc_pipe_use},
+allo standard output (torneremo sull'argomento in sez.~\ref{sec:ipc_pipe_use},
quando tratteremo le pipe). Per fare questo in genere occorre prima chiudere
il file che si vuole sostituire, cosicché il suo file descriptor possa esser
restituito alla chiamata di \func{dup}, come primo file descriptor
La duplicazione dei file descriptor può essere effettuata anche usando la
funzione di controllo dei file \func{fnctl} (che esamineremo in
-\secref{sec:file_fcntl}) con il parametro \const{F\_DUPFD}. L'operazione ha
+sez.~\ref{sec:file_fcntl}) con il parametro \const{F\_DUPFD}. L'operazione ha
la sintassi \code{fnctl(oldfd, F\_DUPFD, newfd)} e se si usa 0 come valore per
\param{newfd} diventa equivalente a \func{dup}.
\subsection{La funzione \func{fcntl}}
\label{sec:file_fcntl}
-Oltre alle operazioni base esaminate in \secref{sec:file_base_func} esistono
+Oltre alle operazioni base esaminate in sez.~\ref{sec:file_base_func} esistono
tutta una serie di operazioni ausiliarie che è possibile eseguire su un file
descriptor, che non riguardano la normale lettura e scrittura di dati, ma la
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
- \secref{sec:file_asyncronous_operation}) e il file
- locking\index{file!locking} (vedi \secref{sec:file_locking}).}
+ sez.~\ref{sec:file_asyncronous_operation}) e il file
+ locking\index{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},
numero e il tipo degli argomenti, il valore di ritorno e gli eventuali errori
sono determinati dal valore dell'argomento \param{cmd} che in sostanza
corrisponde all'esecuzione di un determinato \textsl{comando}; in
-\secref{sec:file_dup} abbiamo incontrato un esempio dell'uso di \func{fcntl}
+sez.~\ref{sec:file_dup} abbiamo incontrato un esempio dell'uso di \func{fcntl}
per la duplicazione dei file descriptor, una lista di tutti i possibili valori
per \var{cmd} è riportata di seguito:
\begin{basedescript}{\desclabelwidth{2.0cm}}
valore specificato con \param{arg}. Al momento l'unico bit usato è quello di
\textit{close-on-exec}\index{close-on-exec}, identificato dalla costante
\const{FD\_CLOEXEC}, che serve a richiedere che il file venga chiuso nella
- esecuzione di una \func{exec} (vedi \secref{sec:proc_exec}). Ritorna un
+ esecuzione di una \func{exec} (vedi sez.~\ref{sec:proc_exec}). Ritorna un
valore nullo in caso di successo e -1 in caso di errore.
\item[\const{F\_GETFD}] ritorna il valore del \textit{file descriptor flag} di
\param{fd} o -1 in caso di errore; se \const{FD\_CLOEXEC} è impostato i file
caso di successo o -1 in caso di errore; permette cioè di rileggere quei bit
impostati da \func{open} all'apertura del file che vengono memorizzati
(quelli riportati nella prima e terza sezione di
- \tabref{tab:file_open_flags}).
+ tab.~\ref{tab:file_open_flags}).
\item[\const{F\_SETFL}] imposta il \textit{file status flag} al valore
specificato da \param{arg}, ritorna un valore nullo in caso di successo o -1
in caso di errore. Possono essere impostati solo i bit riportati nella terza
- sezione di \tabref{tab:file_open_flags}.\footnote{la pagina di manuale
+ sezione di tab.~\ref{tab:file_open_flags}.\footnote{la pagina di manuale
riporta come impostabili solo \const{O\_APPEND}, \const{O\_NONBLOCK} e
\const{O\_ASYNC}.}
\item[\const{F\_GETLK}] richiede un controllo sul file lock specificato da
\param{lock}, sovrascrivendo la struttura da esso puntata con il risultato,
ritorna un valore nullo in caso di successo o -1 in caso di errore. Questa
- funzionalità è trattata in dettaglio in \secref{sec:file_posix_lock}.
+ funzionalità è trattata in dettaglio in sez.~\ref{sec:file_posix_lock}.
\item[\const{F\_SETLK}] richiede o rilascia un file lock a seconda di quanto
specificato nella struttura puntata da \param{lock}. Se il lock è tenuto da
qualcun'altro ritorna immediatamente restituendo -1 e imposta \var{errno} a
\errcode{EACCES} o \errcode{EAGAIN}, in caso di successo ritorna un valore
nullo. Questa funzionalità è trattata in dettaglio in
- \secref{sec:file_posix_lock}.
+ sez.~\ref{sec:file_posix_lock}.
\item[\const{F\_SETLKW}] identica a \const{F\_SETLK} eccetto per il fatto che
la funzione non ritorna subito ma attende che il blocco sia rilasciato. Se
l'attesa viene interrotta da un segnale la funzione restituisce -1 e imposta
\var{errno} a \errcode{EINTR}, in caso di successo ritorna un valore nullo.
- Questa funzionalità è trattata in dettaglio in \secref{sec:file_posix_lock}.
+ Questa funzionalità è trattata in dettaglio in
+ sez.~\ref{sec:file_posix_lock}.
\item[\const{F\_GETOWN}] restituisce il \acr{pid} del processo o
l'identificatore del process group\footnote{i \texttt{process group} sono
- (vedi \secref{sec:sess_proc_group}) raggruppamenti di processi usati nel
+ (vedi sez.~\ref{sec:sess_proc_group}) raggruppamenti di processi usati nel
controllo di sessione; a ciascuno di essi è associato un identificatore
(un numero positivo analogo al \acr{pid}).} che è preposto alla ricezione
dei segnali \const{SIGIO} e \const{SIGURG} per gli eventi associati al file
group}.
\item[\const{F\_GETSIG}] restituisce il valore del segnale inviato quando ci
sono dati disponibili in ingresso su un file descriptor aperto ed impostato
- per l'I/O asincrono (si veda \secref{sec:file_asyncronous_io}). Il valore 0
+ per l'I/O asincrono (si veda sez.~\ref{sec:file_asyncronous_io}). Il valore 0
indica il valore predefinito (che è \const{SIGIO}), un valore diverso da
zero indica il segnale richiesto, (che può essere anche lo stesso
\const{SIGIO}). In caso di errore ritorna -1.
valore diverso da zero (compreso lo stesso \const{SIGIO}) specifica il
segnale voluto; l'uso di un valore diverso da zero permette inoltre, se si è
installato il gestore del segnale come \var{sa\_sigaction} usando
- \const{SA\_SIGINFO}, (vedi \secref{sec:sig_sigaction}), di rendere
+ \const{SA\_SIGINFO}, (vedi sez.~\ref{sec:sig_sigaction}), di rendere
disponibili al gestore informazioni ulteriori riguardo il file che ha
generato il segnale attraverso i valori restituiti in \struct{siginfo\_t}
- (come vedremo in \secref{sec:file_asyncronous_io}).\footnote{i due comandi
+ (come vedremo in sez.~\ref{sec:file_asyncronous_io}).\footnote{i due comandi
\const{F\_SETSIG} e \const{F\_GETSIG} sono una estensione specifica di
Linux.}
\item[\const{F\_SETLEASE}] imposta o rimuove un \textit{file
di esso.} sul file descriptor \var{fd} a seconda del valore del terzo
argomento, che in questo caso è un \ctyp{int}, ritorna un valore nullo in
caso di successo o -1 in caso di errore. Questa funzionalità avanzata è
- trattata in dettaglio in \secref{sec:file_asyncronous_operation}.
+ trattata in dettaglio in sez.~\ref{sec:file_asyncronous_operation}.
\item[\const{F\_GETLEASE}] restituisce il tipo di \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
- \secref{sec:file_asyncronous_operation}.
+ sez.~\ref{sec:file_asyncronous_operation}.
\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
direttamente sulla directory cui \var{fd} fa riferimento, o su uno dei file
in essa contenuti; ritorna un valore nullo in caso di successo o -1 in caso
di errore. Questa funzionalità avanzata, disponibile dai kernel della serie
- 2.4.x, è trattata in dettaglio in \secref{sec:file_asyncronous_operation}.
+ 2.4.x, è trattata in dettaglio in sez.~\ref{sec:file_asyncronous_operation}.
\end{basedescript}
La maggior parte delle funzionalità di \func{fcntl} sono troppo avanzate per
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
-\secref{sec:file_asyncronous_operation} mentre quelle relative al \textit{file
- locking}\index{file!locking} saranno esaminate in
-\secref{sec:file_locking}).
+sez.~\ref{sec:file_asyncronous_operation} mentre quelle relative al
+\textit{file locking}\index{file!locking} saranno esaminate in
+sez.~\ref{sec:file_locking}).
Si tenga presente infine che quando si usa la funzione per determinare le
La memoria viene sempre gestita dal kernel attraverso il meccanismo della
\textsl{memoria virtuale}\index{memoria virtuale}, che consente di assegnare a
ciascun processo uno spazio di indirizzi ``\textsl{virtuale}'' (vedi
-\secref{sec:proc_memory}) che il kernel stesso, con l'ausilio della unità di
+sez.~\ref{sec:proc_memory}) che il kernel stesso, con l'ausilio della unità di
gestione della memoria, si incaricherà di rimappare automaticamente sulla
memoria disponibile, salvando su disco quando necessario (nella cosiddetta
area di \textit{swap}) le pagine di memoria in eccedenza.
Le periferiche infine vengono viste in genere attraverso un'interfaccia
astratta che permette di trattarle come fossero file, secondo il concetto per
cui \textit{everything is a file}, su cui torneremo in dettaglio in
-\capref{cha:file_intro}, (questo non è vero per le interfacce di rete, che
+cap.~\ref{cha:file_intro}, (questo non è vero per le interfacce di rete, che
hanno un'interfaccia diversa, ma resta valido il concetto generale che tutto
il lavoro di accesso e gestione a basso livello è effettuato dal kernel).
chiamate, che sono riportate nella seconda sezione del \textsl{Manuale di
programmazione di Unix} (quella cui si accede con il comando \cmd{man 2
<nome>}) e Linux non fa eccezione. Queste sono poi state codificate da vari
-standard, che esamineremo brevemente in \secref{sec:intro_standard}. Uno
+standard, che esamineremo brevemente in sez.~\ref{sec:intro_standard}. Uno
schema elementare della struttura del sistema è riportato in
-\figref{fig:intro_sys_struct}.
+fig.~\ref{fig:intro_sys_struct}.
\begin{figure}[htb]
\centering
Ogni utente è identificato da un nome (l'\textit{username}), che è quello che
viene richiesto all'ingresso nel sistema dalla procedura di \textit{login}
-(descritta in dettaglio in \secref{sec:sess_login}). Questa procedura si
+(descritta in dettaglio in sez.~\ref{sec:sess_login}). Questa procedura si
incarica di verificare l'identità dell'utente, in genere attraverso la
richiesta di una parola d'ordine (la \textit{password}), anche se sono
possibili meccanismi diversi.\footnote{Ad esempio usando la libreria PAM
appartiene ciascun processo ed impedire ad altri utenti di interferire con
quest'ultimo. Inoltre con questo sistema viene anche garantita una forma base
di sicurezza interna in quanto anche l'accesso ai file (vedi
-\secref{sec:file_access_control}) è regolato da questo meccanismo di
+sez.~\ref{sec:file_access_control}) è regolato da questo meccanismo di
identificazione.
Infine in ogni Unix è presente un utente speciale privilegiato, il cosiddetto
funzioni occorre includere con la direttiva \code{\#include} questi file nei
propri programmi; per ciascuna funzione che tratteremo in seguito
indicheremo anche gli \textit{header file} necessari ad usarla.} (anch'essi
-provvisti dalla \acr{glibc}), In \tabref{tab:intro_posix_header} si sono
+provvisti dalla \acr{glibc}), In tab.~\ref{tab:intro_posix_header} si sono
riportati i principali \textit{header file} definiti nello standard POSIX,
insieme a quelli definiti negli altri standard descritti nelle sezioni
successive.
Per questo motivo tutte le funzioni di libreria di solito non fanno
riferimento ai tipi elementari dello standard del linguaggio C, ma ad una
serie di \textsl{tipi primitivi}\index{tipo!primitivo} del sistema, riportati
-in \tabref{tab:intro_primitive_types}, e definiti nell'header file
+in tab.~\ref{tab:intro_primitive_types}, e definiti nell'header file
\file{sys/types.h}, in modo da mantenere completamente indipendenti i tipi
utilizzati dalle funzioni di sistema dai tipi elementari supportati dal
compilatore C.
Ma gli standard POSIX non si limitano alla standardizzazione delle funzioni di
libreria, e in seguito sono stati prodotti anche altri standard per la shell e
i comandi di sistema (1003.2), per le estensioni realtime e per i thread
-(1003.1d e 1003.1c) e vari altri. In \tabref{tab:intro_posix_std} è riportata
-una classificazione sommaria dei principali documenti prodotti, e di come sono
-identificati fra IEEE ed ISO; si tenga conto inoltre che molto spesso si usa
-l'estensione IEEE anche come aggiunta al nome POSIX (ad esempio si può parlare
-di POSIX.4 come di POSIX.1b).
+(1003.1d e 1003.1c) e vari altri. In tab.~\ref{tab:intro_posix_std} è
+riportata una classificazione sommaria dei principali documenti prodotti, e di
+come sono identificati fra IEEE ed ISO; si tenga conto inoltre che molto
+spesso si usa l'estensione IEEE anche come aggiunta al nome POSIX (ad esempio
+si può parlare di POSIX.4 come di POSIX.1b).
Si tenga presente inoltre che nuove specifiche e proposte di standardizzazione
si aggiungono continuamente, mentre le versioni precedenti vengono riviste;
Nelle versioni più recenti del kernel e delle librerie sono inoltre supportate
ulteriori funzionalità aggiunte dallo standard POSIX.1c per quanto riguarda i
-\textit{thread} (vedi \capref{cha:threads}), e dallo standard POSIX.1b per
+\textit{thread} (vedi cap.~\ref{cha:threads}), e dallo standard POSIX.1b per
quanto riguarda i segnali e lo scheduling real-time
-(\secref{sec:sig_real_time} e \secref{sec:proc_real_time}), la misura del
-tempo, i meccanismi di intercomunicazione (\secref{sec:ipc_posix}) e l'I/O
-asincrono (\secref{sec:file_asyncronous_io}).
+(sez.~\ref{sec:sig_real_time} e sez.~\ref{sec:proc_real_time}), la misura del
+tempo, i meccanismi di intercomunicazione (sez.~\ref{sec:ipc_posix}) e l'I/O
+asincrono (sez.~\ref{sec:file_asyncronous_io}).
Le funzionalità implementate sono principalmente il meccanismo di
intercomunicazione fra i processi e la memoria condivisa (il cosiddetto System
-V IPC, che vedremo in \secref{sec:ipc_sysv}) le funzioni della famiglia
+V IPC, che vedremo in sez.~\ref{sec:ipc_sysv}) le funzioni della famiglia
\func{hsearch} e \func{drand48}, \func{fmtmsg} e svariate funzioni
matematiche.
Le \textit{pipe} nascono sostanzialmente con Unix, e sono il primo, e tuttora
uno dei più usati, meccanismi di comunicazione fra processi. Si tratta in
-sostanza di una una coppia di file descriptor\footnote{si tenga presente che
+sostanza di una coppia di file descriptor\footnote{si tenga presente che
le pipe sono oggetti creati dal kernel e non risiedono su disco.} connessi
fra di loro in modo che se quanto scrive su di uno si può rileggere
dall'altro. Si viene così a costituire un canale di comunicazione tramite i
nel file descriptor aperto in lettura. I file descriptor infatti non sono
connessi a nessun file reale, ma ad un buffer nel kernel, la cui dimensione è
specificata dal parametro di sistema \const{PIPE\_BUF}, (vedi
-\secref{sec:sys_file_limits}). Lo schema di funzionamento di una pipe è
-illustrato in \figref{fig:ipc_pipe_singular}, in cui sono illustrati i due
+sez.~\ref{sec:sys_file_limits}). Lo schema di funzionamento di una pipe è
+illustrato in fig.~\ref{fig:ipc_pipe_singular}, in cui sono illustrati i due
capi della pipe, associati a ciascun file descriptor, con le frecce che
indicano la direzione del flusso dei dati.
\end{figure}
Chiaramente creare una pipe all'interno di un singolo processo non serve a
-niente; se però ricordiamo quanto esposto in \secref{sec:file_sharing}
+niente; se però ricordiamo quanto esposto in sez.~\ref{sec:file_sharing}
riguardo al comportamento dei file descriptor nei processi figli, è immediato
capire come una pipe possa diventare un meccanismo di intercomunicazione. Un
processo figlio infatti condivide gli stessi file descriptor del padre,
compresi quelli associati ad una pipe (secondo la situazione illustrata in
-\figref{fig:ipc_pipe_fork}). In questo modo se uno dei processi scrive su un
+fig.~\ref{fig:ipc_pipe_fork}). In questo modo se uno dei processi scrive su un
capo della pipe, l'altro può leggere.
\begin{figure}[htb]
codici a barre corrispondenti ad una qualunque stringa, mentre il secondo
serve per poter effettuare la conversione della stessa immagine in formato
JPEG. Usando una pipe potremo inviare l'output del primo sull'input del
-secondo, secondo lo schema mostrato in \figref{fig:ipc_pipe_use}, in cui la
+secondo, secondo lo schema mostrato in fig.~\ref{fig:ipc_pipe_use}, in cui la
direzione del flusso dei dati è data dalle frecce continue.
\begin{figure}[htb]
\centering
\includegraphics[height=5cm]{img/pipeuse}
\caption{Schema dell'uso di una pipe come mezzo di comunicazione fra
- due processi attraverso attraverso l'esecuzione una \func{fork} e la
- chiusura dei capi non utilizzati.}
+ due processi attraverso l'esecuzione una \func{fork} e la chiusura dei
+ capi non utilizzati.}
\label{fig:ipc_pipe_use}
\end{figure}
Il programma ci servirà anche come esempio dell'uso delle funzioni di
duplicazione dei file descriptor che abbiamo trattato in
-\secref{sec:file_dup}, in particolare di \func{dup2}. È attraverso queste
+sez.~\ref{sec:file_dup}, in particolare di \func{dup2}. È attraverso queste
funzioni infatti che è possibile dirottare gli stream standard dei processi
-(che abbiamo visto in \secref{sec:file_std_descr} e
-\secref{sec:file_std_stream}) sulla pipe. In \figref{fig:ipc_barcodepage_code}
-abbiamo riportato il corpo del programma, il cui codice completo è disponibile
-nel file \file{BarCodePage.c} che si trova nella directory dei sorgenti.
+(che abbiamo visto in sez.~\ref{sec:file_std_descr} e
+sez.~\ref{sec:file_std_stream}) sulla pipe. In
+fig.~\ref{fig:ipc_barcodepage_code} abbiamo riportato il corpo del programma,
+il cui codice completo è disponibile nel file \file{BarCodePage.c} che si
+trova nella directory dei sorgenti.
\begin{figure}[!htb]
per produrre il codice a barre; si ha cura di controllare la riuscita della
chiamata, inviando in caso di errore un messaggio invece dell'immagine
richiesta.\footnote{la funzione \func{WriteMess} non è riportata in
- \secref{fig:ipc_barcodepage_code}; essa si incarica semplicemente di
+ fig.~\ref{fig:ipc_barcodepage_code}; essa si incarica semplicemente di
formattare l'uscita alla maniera dei CGI, aggiungendo l'opportuno
\textit{mime type}, e formattando il messaggio in HTML, in modo che
quest'ultimo possa essere visualizzato correttamente da un browser.}
quindi associato allo standard input) in caso di \code{"w"}.
Lo stream restituito da \func{popen} è identico a tutti gli effetti ai file
-stream visti in \capref{cha:files_std_interface}, anche se è collegato ad una
-pipe e non ad un file, e viene sempre aperto in modalità
-\textit{fully-buffered} (vedi \secref{sec:file_buffering}); l'unica differenza
-con gli usuali stream è che dovrà essere chiuso dalla seconda delle due nuove
-funzioni, \funcd{pclose}, il cui prototipo è:
+stream visti in cap.~\ref{cha:files_std_interface}, anche se è collegato ad
+una pipe e non ad un file, e viene sempre aperto in modalità
+\textit{fully-buffered} (vedi sez.~\ref{sec:file_buffering}); l'unica
+differenza con gli usuali stream è che dovrà essere chiuso dalla seconda delle
+due nuove funzioni, \funcd{pclose}, il cui prototipo è:
\begin{prototype}{stdio.h}
{int pclose(FILE *stream)}
\func{popen}.
Per illustrare l'uso di queste due funzioni riprendiamo il problema
-precedente: il programma mostrato in \figref{fig:ipc_barcodepage_code} per
+precedente: il programma mostrato in fig.~\ref{fig:ipc_barcodepage_code} per
quanto funzionante, è (volutamente) codificato in maniera piuttosto complessa,
inoltre nella pratica sconta un problema di \cmd{gs} che non è in
grado\footnote{nella versione GNU Ghostscript 6.53 (2002-02-13).} di
Nel nostro caso, dato che ciascun processo deve scrivere il suo output sullo
standard input del successivo, occorrerà usare \func{popen} aprendo la pipe in
scrittura. Il codice del nuovo programma è riportato in
-\figref{fig:ipc_barcode_code}. Come si può notare l'ordine di invocazione dei
-programmi è l'inverso di quello in cui ci si aspetta che vengano
+fig.~\ref{fig:ipc_barcode_code}. Come si può notare l'ordine di invocazione
+dei programmi è l'inverso di quello in cui ci si aspetta che vengano
effettivamente eseguiti. Questo non comporta nessun problema dato che la
lettura su una pipe è bloccante, per cui ciascun processo, per quanto lanciato
per primo, si bloccherà in attesa di ricevere sullo standard input il
-risultato dell'elaborazione del precedente, benchè quest'ultimo venga
-invocato dopo.
+risultato dell'elaborazione del precedente, benchè quest'ultimo venga invocato
+dopo.
\begin{figure}[!htb]
\footnotesize \centering
\subsection{Le \textit{pipe} con nome, o \textit{fifo}}
\label{sec:ipc_named_pipe}
-Come accennato in \secref{sec:ipc_pipes} il problema delle \textit{pipe} è che
-esse possono essere utilizzate solo da processi con un progenitore comune o
-nella relazione padre/figlio; per superare questo problema lo standard POSIX.1
-ha definito dei nuovi oggetti, le \textit{fifo}, che hanno le stesse
+Come accennato in sez.~\ref{sec:ipc_pipes} il problema delle \textit{pipe} è
+che esse possono essere utilizzate solo da processi con un progenitore comune
+o nella relazione padre/figlio; per superare questo problema lo standard
+POSIX.1 ha definito dei nuovi oggetti, le \textit{fifo}, che hanno le stesse
caratteristiche delle pipe, ma che invece di essere strutture interne del
kernel, visibili solo attraverso un file descriptor, sono accessibili
attraverso un inode\index{inode} che risiede sul filesystem, così che i
l'inode\index{inode} allocato sul filesystem serve infatti solo a fornire un
punto di riferimento per i processi, che permetta loro di accedere alla stessa
fifo; il comportamento delle funzioni di lettura e scrittura è identico a
-quello illustrato per le pipe in \secref{sec:ipc_pipes}.
+quello illustrato per le pipe in sez.~\ref{sec:ipc_pipes}.
-Abbiamo già visto in \secref{sec:file_mknod} le funzioni \func{mknod} e
+Abbiamo già visto in sez.~\ref{sec:file_mknod} le funzioni \func{mknod} e
\func{mkfifo} che permettono di creare una fifo; per utilizzarne una un
processo non avrà che da aprire il relativo file speciale o in lettura o
scrittura; nel primo caso sarà collegato al capo di uscita della fifo, e dovrà
fondamentale che le operazioni di scrittura siano atomiche; per questo si deve
sempre tenere presente che questo è vero soltanto fintanto che non si supera
il limite delle dimensioni di \const{PIPE\_BUF} (si ricordi quanto detto in
-\secref{sec:ipc_pipes}).
+sez.~\ref{sec:ipc_pipes}).
A parte il caso precedente, che resta probabilmente il più comune, Stevens
riporta in \cite{APUE} altre due casistiche principali per l'uso delle fifo:
sull'input di parecchi altri (attraverso l'uso del comando \cmd{tee}).
\item Come canale di comunicazione fra client ed server (il modello
- \textit{client-server} è illustrato in \secref{sec:net_cliserv}).
+ \textit{client-server} è illustrato in sez.~\ref{sec:net_cliserv}).
\end{itemize}
Nel primo caso quello che si fa è creare tante fifo, da usare come standard
leggerli, quando i dati inviati sono destinati a loro.
Per risolvere questo problema, si può usare un'architettura come quella
-illustrata in \figref{fig:ipc_fifo_server_arch} in cui i client inviano le
+illustrata in fig.~\ref{fig:ipc_fifo_server_arch} in cui i client inviano le
richieste al server su una fifo nota mentre le risposte vengono reinviate dal
server a ciascuno di essi su una fifo temporanea creata per l'occasione.
un detto a caso estratto da un insieme di frasi; sia il numero delle frasi
dell'insieme, che i file da cui esse vengono lette all'avvio, sono importabili
da riga di comando. Il corpo principale del server è riportato in
-\figref{fig:ipc_fifo_server}, dove si è tralasciata la parte che tratta la
+fig.~\ref{fig:ipc_fifo_server}, dove si è tralasciata la parte che tratta la
gestione delle opzioni a riga di comando, che effettua il settaggio delle
variabili \var{fortunefilename}, che indica il file da cui leggere le frasi,
ed \var{n}, che indica il numero di frasi tenute in memoria, ad un valore
presenza di un valore nullo provoca l'uscita dal programma attraverso la
routine (non riportata) che ne stampa le modalità d'uso. Dopo di che installa
(\texttt{\small 13--15}) la funzione che gestisce i segnali di interruzione
-(anche questa non è riportata in \figref{fig:ipc_fifo_server}) che si limita a
-rimuovere dal filesystem la fifo usata dal server per comunicare.
+(anche questa non è riportata in fig.~\ref{fig:ipc_fifo_server}) che si limita
+a rimuovere dal filesystem la fifo usata dal server per comunicare.
Terminata l'inizializzazione (\texttt{\small 16}) si effettua la chiamata alla
funzione \code{FortuneParse} che legge dal file specificato in
sarà scritta. Infine (\texttt{\small 49}) si chiude la fifo di risposta che
non serve più.
-Il codice del client è invece riportato in \figref{fig:ipc_fifo_client}, anche
-in questo caso si è omessa la gestione delle opzioni e la funzione che stampa
-a video le informazioni di utilizzo ed esce, riportando solo la sezione
+Il codice del client è invece riportato in fig.~\ref{fig:ipc_fifo_client},
+anche in questo caso si è omessa la gestione delle opzioni e la funzione che
+stampa a video le informazioni di utilizzo ed esce, riportando solo la sezione
principale del programma e le definizioni delle variabili. Il codice completo
è nel file \file{FortuneClient.c} dei sorgenti allegati.
Avendo usato \func{daemon} per eseguire il server in background il comando
ritornerà immediatamente, ma potremo verificare con \cmd{ps} che in effetti il
programma resta un esecuzione in background, e senza avere associato un
-terminale di controllo (si ricordi quanto detto in \secref{sec:sess_daemon}):
+terminale di controllo (si ricordi quanto detto in sez.~\ref{sec:sess_daemon}):
\begin{verbatim}
[piccardi@gont sources]$ ps aux
...
fifo non è adatta a risolvere questo tipo di problemi, che possono essere
affrontati in maniera più semplice ed efficace o usando i
\textit{socket}\index{socket} (che tratteremo in dettaglio a partire da
-\capref{cha:socket_intro}) o ricorrendo a meccanismi di comunicazione diversi,
-come quelli che esamineremo in seguito.
+cap.~\ref{cha:socket_intro}) o ricorrendo a meccanismi di comunicazione
+diversi, come quelli che esamineremo in seguito.
Un meccanismo di comunicazione molto simile alle pipe, ma che non presenta il
problema della unidirezionalità del flusso dei dati, è quello dei cosiddetti
\textsl{socket locali} (o \textit{Unix domain socket}). Tratteremo l'argomento
-dei \textit{socket}\index{socket} in \capref{cha:socket_intro},\footnote{si
+dei \textit{socket}\index{socket} in cap.~\ref{cha:socket_intro},\footnote{si
tratta comunque di oggetti di comunicazione che, come le pipe, sono
utilizzati attraverso dei file descriptor.} nell'ambito dell'interfaccia
generale che essi forniscono per la programmazione di rete; e vedremo anche
-(in~\secref{sec:sock_sa_local}) come si possono definire dei file speciali (di
-tipo \textit{socket}, analoghi a quello associati alle fifo) cui si accede
+(in~sez.~\ref{sec:sock_sa_local}) come si possono definire dei file speciali
+(di tipo \textit{socket}, analoghi a quello associati alle fifo) cui si accede
però attraverso quella medesima interfaccia; vale però la pena esaminare qui
una modalità di uso dei socket locali\footnote{la funzione \func{socketpair} è
stata introdotta in BSD4.4, ma è supportata in genere da qualunque sistema
linea non solo dei dati, ma anche dei file descriptor: si può cioè passare da
un processo ad un altro un file descriptor, con una sorta di duplicazione
dello stesso non all'interno di uno stesso processo, ma fra processi distinti
-(torneremo su questa funzionalità in \secref{sec:xxx_fd_passing}).
+(torneremo su questa funzionalità in sez.~\ref{sec:xxx_fd_passing}).
\section{La comunicazione fra processi di System V}
specificando il relativo \textsl{identificatore}. Questo è un numero
progressivo (un po' come il \acr{pid} dei processi) che il kernel assegna a
ciascuno di essi quanto vengono creati (sul procedimento di assegnazione
-torneremo in \secref{sec:ipc_sysv_id_use}). L'identificatore viene restituito
+torneremo in sez.~\ref{sec:ipc_sysv_id_use}). L'identificatore viene restituito
dalle funzioni che creano l'oggetto, ed è quindi locale al processo che le ha
eseguite. Dato che l'identificatore viene assegnato dinamicamente dal kernel
non è possibile prevedere quale sarà, né utilizzare un qualche valore statico,
si sposta il problema dell'accesso dalla classificazione in base
all'identificatore alla classificazione in base alla chiave, una delle tante
complicazioni inutili presenti nel \textit{SysV IPC}.} Oltre la chiave, la
-struttura, la cui definizione è riportata in \figref{fig:ipc_ipc_perm},
+struttura, la cui definizione è riportata in fig.~\ref{fig:ipc_ipc_perm},
mantiene varie proprietà ed informazioni associate all'oggetto.
\begin{figure}[!htb]
identificare un oggetto, come sarebbe stato se lo si fosse associato ad in
file, e tutta l'interfaccia è inutilmente complessa. Per questo ne è stata
effettuata una revisione completa nello standard POSIX.1b, che tratteremo in
-\secref{sec:ipc_posix}.
+sez.~\ref{sec:ipc_posix}.
\subsection{Il controllo di accesso}
(nei campi \var{cuid} e \var{cgid}) e del proprietario (nei campi \var{uid} e
\var{gid}) dello stesso, e un insieme di permessi (nel campo \var{mode}). In
questo modo è possibile definire un controllo di accesso sugli oggetti di IPC,
-simile a quello che si ha per i file (vedi \secref{sec:file_perm_overview}).
+simile a quello che si ha per i file (vedi sez.~\ref{sec:file_perm_overview}).
Benché questo controllo di accesso sia molto simile a quello dei file, restano
delle importanti differenze. La prima è che il permesso di esecuzione non
permessi di lettura e scrittura (nel caso dei semafori poi quest'ultimo è più
propriamente un permesso di modifica). I valori di \var{mode} sono gli stessi
ed hanno lo stesso significato di quelli riportati in
-\secref{tab:file_mode_flags}\footnote{se però si vogliono usare le costanti
+tab.~\ref{tab:file_mode_flags}\footnote{se però si vogliono usare le costanti
simboliche ivi definite occorrerà includere il file \file{sys/stat.h},
alcuni sistemi definiscono le costanti \const{MSG\_R} (\texttt{0400}) e
\const{MSG\_W} (\texttt{0200}) per indicare i permessi base di lettura e
passi elencati non comporta il fallimento dell'accesso. Un'ulteriore
differenza rispetto a quanto avviene per i file è che per gli oggetti di IPC
il valore di \var{umask} (si ricordi quanto esposto in
-\secref{sec:file_umask}) non ha alcun significato.
+sez.~\ref{sec:file_umask}) non ha alcun significato.
\subsection{Gli identificatori ed il loro utilizzo}
\label{sec:ipc_sysv_id_use}
L'unico campo di \struct{ipc\_perm} del quale non abbiamo ancora parlato è
-\var{seq}, che in \figref{fig:ipc_ipc_perm} è qualificato con un criptico
+\var{seq}, che in fig.~\ref{fig:ipc_ipc_perm} è qualificato con un criptico
``\textsl{numero di sequenza}'', ne parliamo adesso dato che esso è
strettamente attinente alle modalità con cui il kernel assegna gli
identificatori degli oggetti del sistema di IPC.
\label{fig:ipc_sysv_idtest}
\end{figure}
-In \figref{fig:ipc_sysv_idtest} è riportato il codice di un semplice programma
-di test che si limita a creare un oggetto (specificato a riga di comando),
-stamparne il numero di identificatore e cancellarlo per un numero specificato
-di volte. Al solito non si è riportato il codice della gestione delle opzioni
-a riga di comando, che permette di specificare quante volte effettuare il
-ciclo \var{n}, e su quale tipo di oggetto eseguirlo.
+In fig.~\ref{fig:ipc_sysv_idtest} è riportato il codice di un semplice
+programma di test che si limita a creare un oggetto (specificato a riga di
+comando), stamparne il numero di identificatore e cancellarlo per un numero
+specificato di volte. Al solito non si è riportato il codice della gestione
+delle opzioni a riga di comando, che permette di specificare quante volte
+effettuare il ciclo \var{n}, e su quale tipo di oggetto eseguirlo.
La figura non riporta il codice di selezione delle opzioni, che permette di
inizializzare i valori delle variabili \var{type} al tipo di oggetto voluto, e
essere nullo e deve essere fornito come maschera binaria, impostando il bit
corrispondente al valore \const{IPC\_CREAT}. In questo caso i nove bit meno
significativi di \param{flag} saranno usati come permessi per il nuovo
-oggetto, secondo quanto illustrato in \secref{sec:ipc_sysv_access_control}.
+oggetto, secondo quanto illustrato in sez.~\ref{sec:ipc_sysv_access_control}.
Se si imposta anche il bit corrispondente a \const{IPC\_EXCL} la funzione avrà
successo solo se l'oggetto non esiste già, fallendo con un errore di
\errcode{EEXIST} altrimenti.
Le code di messaggi sono caratterizzate da tre limiti fondamentali, definiti
negli header e corrispondenti alle prime tre costanti riportate in
-\tabref{tab:ipc_msg_limits}, come accennato però in Linux è possibile
+tab.~\ref{tab:ipc_msg_limits}, come accennato però in Linux è possibile
modificare questi limiti attraverso l'uso di \func{sysctl} o scrivendo nei
file \file{msgmax}, \file{msgmnb} e \file{msgmni} di \file{/proc/sys/kernel/}.
aggiornare un puntatore), e relativamente veloce da attraversare in ordine
sequenziale (seguendo i puntatori), è invece relativamente lenta
nell'accesso casuale e nella ricerca.} i nuovi messaggi vengono inseriti in
-coda alla lista e vengono letti dalla cima, in \figref{fig:ipc_mq_schema} si è
-riportato lo schema con cui queste strutture vengono mantenute dal
-kernel.\footnote{lo schema illustrato in \figref{fig:ipc_mq_schema} è in
+coda alla lista e vengono letti dalla cima, in fig.~\ref{fig:ipc_mq_schema} si
+è riportato lo schema con cui queste strutture vengono mantenute dal
+kernel.\footnote{lo schema illustrato in fig.~\ref{fig:ipc_mq_schema} è in
realtà una semplificazione di quello usato effettivamente fino ai kernel
della serie 2.2.x, nei kernel della serie 2.4.x la gestione delle code di
messaggi è stata modificata ed è effettuata in maniera diversa; abbiamo
\end{figure}
A ciascuna coda è associata una struttura \struct{msgid\_ds}, la cui
-definizione, è riportata in \secref{fig:ipc_msqid_ds}. In questa struttura il
+definizione, è riportata in fig.~\ref{fig:ipc_msqid_ds}. In questa struttura il
kernel mantiene le principali informazioni riguardo lo stato corrente della
coda.\footnote{come accennato questo vale fino ai kernel della serie 2.2.x,
essa viene usata nei kernel della serie 2.4.x solo per compatibilità in
quanto è quella restituita dalle funzioni dell'interfaccia. Si noti come ci
sia una differenza con i campi mostrati nello schema di
- \figref{fig:ipc_mq_schema} che sono presi dalla definizione di
+ fig.~\ref{fig:ipc_mq_schema} che sono presi dalla definizione di
\file{linux/msg.h}, e fanno riferimento alla definizione della omonima
- struttura usata nel kernel.} In \figref{fig:ipc_msqid_ds} sono elencati i
+ struttura usata nel kernel.} In fig.~\ref{fig:ipc_msqid_ds} sono elencati i
campi significativi definiti in \file{sys/msg.h}, a cui si sono aggiunti gli
ultimi tre campi che sono previsti dalla implementazione originale di System
V, ma non dallo standard Unix98.
Quando si crea una nuova coda con \func{msgget} questa struttura viene
inizializzata, in particolare il campo \var{msg\_perm} viene inizializzato
-come illustrato in \secref{sec:ipc_sysv_access_control}, per quanto riguarda
+come illustrato in sez.~\ref{sec:ipc_sysv_access_control}, per quanto riguarda
gli altri campi invece:
\begin{itemize*}
\item il campo \var{msg\_qnum}, che esprime il numero di messaggi presenti
\item[\const{IPC\_RMID}] Rimuove la coda, cancellando tutti i dati, con
effetto immediato. Tutti i processi che cercheranno di accedere alla coda
riceveranno un errore di \errcode{EIDRM}, e tutti processi in attesa su
- funzioni di di lettura o di scrittura sulla coda saranno svegliati ricevendo
+ funzioni di lettura o di scrittura sulla coda saranno svegliati ricevendo
il medesimo errore. Questo comando può essere eseguito solo da un processo
con user-ID effettivo corrispondente al creatore o al proprietario della
coda, o all'amministratore.
messaggio ha lunghezza specificata da \param{msgsz} ed è passato attraverso il
l'argomento \param{msgp}. Quest'ultimo deve venire passato sempre come
puntatore ad una struttura \struct{msgbuf} analoga a quella riportata in
-\figref{fig:ipc_msbuf} che è quella che deve contenere effettivamente il
+fig.~\ref{fig:ipc_msbuf} che è quella che deve contenere effettivamente il
messaggio. La dimensione massima per il testo di un messaggio non può
comunque superare il limite \const{MSGMAX}.
-La struttura di \figref{fig:ipc_msbuf} è comunque solo un modello, tanto che
+La struttura di fig.~\ref{fig:ipc_msbuf} è comunque solo un modello, tanto che
la definizione contenuta in \file{sys/msg.h} usa esplicitamente per il secondo
campo il valore \code{mtext[1]}, che non è di nessuna utilità ai fini pratici.
La sola cosa che conta è che la struttura abbia come primo membro un campo
dimensione, e serve a contenere il testo del messaggio.
In generale pertanto per inviare un messaggio con \func{msgsnd} si usa
-ridefinire una struttura simile a quella di \figref{fig:ipc_msbuf}, adattando
+ridefinire una struttura simile a quella di fig.~\ref{fig:ipc_msbuf}, adattando
alle proprie esigenze il campo \var{mtype}, (o ridefinendo come si vuole il
corpo del messaggio, anche con più campi o con strutture più complesse) avendo
però la cura di mantenere nel primo campo un valore di tipo \ctyp{long} che ne
argomento è solo quella del messaggio, non quella di tutta la struttura, se
cioè \var{message} è una propria struttura che si passa alla funzione,
\param{msgsz} dovrà essere uguale a \code{sizeof(message)-sizeof(long)}, (se
-consideriamo il caso dell'esempio in \figref{fig:ipc_msbuf}, \param{msgsz}
+consideriamo il caso dell'esempio in fig.~\ref{fig:ipc_msbuf}, \param{msgsz}
dovrà essere pari a \const{LENGTH}).
\begin{figure}[!htb]
Per capire meglio il funzionamento della funzione riprendiamo in
considerazione la struttura della coda illustrata in
-\figref{fig:ipc_mq_schema}. Alla chiamata di \func{msgsnd} il nuovo messaggio
+fig.~\ref{fig:ipc_mq_schema}. Alla chiamata di \func{msgsnd} il nuovo messaggio
sarà aggiunto in fondo alla lista inserendo una nuova struttura \struct{msg},
il puntatore \var{msg\_last} di \struct{msqid\_ds} verrà aggiornato, come pure
il puntatore al messaggio successivo per quello che era il precedente ultimo
La funzione legge un messaggio dalla coda specificata, scrivendolo sulla
struttura puntata da \param{msgp}, che dovrà avere un formato analogo a quello
-di \figref{fig:ipc_msbuf}. Una volta estratto, il messaggio sarà rimosso dalla
-coda. L'argomento \param{msgsz} indica la lunghezza massima del testo del
-messaggio (equivalente al valore del parametro \const{LENGTH} nell'esempio di
-\figref{fig:ipc_msbuf}).
+di fig.~\ref{fig:ipc_msbuf}. Una volta estratto, il messaggio sarà rimosso
+dalla coda. L'argomento \param{msgsz} indica la lunghezza massima del testo
+del messaggio (equivalente al valore del parametro \const{LENGTH} nell'esempio
+di fig.~\ref{fig:ipc_msbuf}).
Se il testo del messaggio ha lunghezza inferiore a \param{msgsz} esso viene
rimosso dalla coda; in caso contrario, se \param{msgflg} è impostato a
L'argomento \param{msgtyp} permette di restringere la ricerca ad un
sottoinsieme dei messaggi presenti sulla coda; la ricerca infatti è fatta con
-una scansione della struttura mostrata in \figref{fig:ipc_mq_schema},
+una scansione della struttura mostrata in fig.~\ref{fig:ipc_mq_schema},
restituendo il primo messaggio incontrato che corrisponde ai criteri
specificati (che quindi, visto come i messaggi vengono sempre inseriti dalla
coda, è quello meno recente); in particolare:
\begin{itemize}
\item se \param{msgtyp} è 0 viene estratto il messaggio in cima alla coda, cioè
- quello fra i presenti che è stato inserito inserito per primo.
+ quello fra i presenti che è stato inserito per primo.
\item se \param{msgtyp} è positivo viene estratto il primo messaggio il cui
tipo (il valore del campo \var{mtype}) corrisponde al valore di
\param{msgtyp}.
utilizzava termina. Questo comporta che in caso di errori si può saturare il
sistema, e che devono comunque essere esplicitamente previste delle funzioni
di rimozione in caso di interruzioni o uscite dal programma (come vedremo in
-\figref{fig:ipc_mq_fortune_server}).
+fig.~\ref{fig:ipc_mq_fortune_server}).
L'altro problema è non facendo uso di file descriptor le tecniche di
-\textit{I/O multiplexing} descritte in \secref{sec:file_multiplexing} non
+\textit{I/O multiplexing} descritte in sez.~\ref{sec:file_multiplexing} non
possono essere utilizzate, e non si ha a disposizione niente di analogo alle
funzioni \func{select} e \func{poll}. Questo rende molto scomodo usare più di
una di queste strutture alla volta; ad esempio non si può scrivere un server
\label{fig:ipc_mq_fortune_server}
\end{figure}
-In \figref{fig:ipc_mq_fortune_server} si è riportato un estratto delle parti
+In fig.~\ref{fig:ipc_mq_fortune_server} si è riportato un estratto delle parti
principali del codice del nuovo server (il codice completo è nel file
\file{MQFortuneServer.c} nei sorgenti allegati). Il programma è basato su un
uso accorto della caratteristica di poter associate un ``tipo'' ai messaggi
\label{fig:ipc_mq_fortune_client}
\end{figure}
-In \figref{fig:ipc_mq_fortune_client} si è riportato un estratto il codice del
-programma client. Al solito il codice completo è con i sorgenti allegati, nel
-file \file{MQFortuneClient.c}. Come sempre si sono rimosse le parti relative
-alla gestione delle opzioni, ed in questo caso, anche la dichiarazione delle
-variabili, che, per la parte relative alle strutture usate per la
-comunicazione tramite le code, sono le stesse viste in
-\figref{fig:ipc_mq_fortune_server}.
+In fig.~\ref{fig:ipc_mq_fortune_client} si è riportato un estratto il codice
+del programma client. Al solito il codice completo è con i sorgenti allegati,
+nel file \file{MQFortuneClient.c}. Come sempre si sono rimosse le parti
+relative alla gestione delle opzioni, ed in questo caso, anche la
+dichiarazione delle variabili, che, per la parte relative alle strutture usate
+per la comunicazione tramite le code, sono le stesse viste in
+fig.~\ref{fig:ipc_mq_fortune_server}.
Il client in questo caso è molto semplice; la prima parte del programma
(\texttt{\small 4--9}) si occupa di accedere alla coda di messaggi, ed è
(pipe, fifo e code di messaggi) visti finora, e non consentono di scambiare
dati fra processi, ma servono piuttosto come meccanismi di sincronizzazione o
di protezione per le \textsl{sezioni critiche}\index{sezioni critiche} del
-codice (si ricordi quanto detto in \secref{sec:proc_race_cond}).
+codice (si ricordi quanto detto in sez.~\ref{sec:proc_race_cond}).
Un semaforo è uno speciale contatore, mantenuto nel kernel, che permette, a
seconda del suo valore, di consentire o meno la prosecuzione dell'esecuzione
La funzione è del tutto analoga a \func{msgget}, solo che in questo caso
restituisce l'identificatore di un insieme di semafori, in particolare è
identico l'uso degli argomenti \param{key} e \param{flag}, per cui non
-ripeteremo quanto detto al proposito in \secref{sec:ipc_sysv_mq}. L'argomento
+ripeteremo quanto detto al proposito in sez.~\ref{sec:ipc_sysv_mq}. L'argomento
\param{nsems} permette di specificare quanti semafori deve contenere l'insieme
quando se ne richieda la creazione, e deve essere nullo quando si effettua una
richiesta dell'identificatore di un insieme già esistente.
\end{figure}
A ciascun insieme di semafori è associata una struttura \struct{semid\_ds},
-riportata in \figref{fig:ipc_semid_ds}.\footnote{non si sono riportati i campi
- ad uso interno del kernel, che vedremo in \figref{fig:ipc_sem_schema}, che
- dipendono dall'implementazione.} Come nel caso delle code di messaggi quando
-si crea un nuovo insieme di semafori con \func{semget} questa struttura viene
-inizializzata, in particolare il campo \var{sem\_perm} viene inizializzato
-come illustrato in \secref{sec:ipc_sysv_access_control} (si ricordi che in
-questo caso il permesso di scrittura è in realtà permesso di alterare il
-semaforo), per quanto riguarda gli altri campi invece:
+riportata in fig.~\ref{fig:ipc_semid_ds}.\footnote{non si sono riportati i
+ campi ad uso interno del kernel, che vedremo in
+ fig.~\ref{fig:ipc_sem_schema}, che dipendono dall'implementazione.} Come nel
+caso delle code di messaggi quando si crea un nuovo insieme di semafori con
+\func{semget} questa struttura viene inizializzata, in particolare il campo
+\var{sem\_perm} viene inizializzato come illustrato in
+sez.~\ref{sec:ipc_sysv_access_control} (si ricordi che in questo caso il
+permesso di scrittura è in realtà permesso di alterare il semaforo), per
+quanto riguarda gli altri campi invece:
\begin{itemize*}
\item il campo \var{sem\_nsems}, che esprime il numero di semafori
nell'insieme, viene inizializzato al valore di \param{nsems}.
ormai è ridotta ai soli due primi membri, e gli altri vengono calcolati
dinamicamente. La si è utilizzata a scopo di esempio, perché indica tutti i
valori associati ad un semaforo, restituiti dalle funzioni di controllo, e
- citati dalle pagine di manuale.} è riportata in \figref{fig:ipc_sem}. Questa
-struttura, non è accessibile in user space, ma i valori in essa specificati
-possono essere letti in maniera indiretta, attraverso l'uso delle funzioni di
-controllo.
+ citati dalle pagine di manuale.} è riportata in fig.~\ref{fig:ipc_sem}.
+Questa struttura, non è accessibile in user space, ma i valori in essa
+specificati possono essere letti in maniera indiretta, attraverso l'uso delle
+funzioni di controllo.
\begin{figure}[!htb]
\footnotesize \centering
\label{fig:ipc_sem}
\end{figure}
-I dati mantenuti nella struttura, ed elencati in \figref{fig:ipc_sem},
+I dati mantenuti nella struttura, ed elencati in fig.~\ref{fig:ipc_sem},
indicano rispettivamente:
\begin{description*}
\item[\var{semval}] il valore numerico del semaforo.
Come per le code di messaggi anche per gli insiemi di semafori esistono una
serie di limiti, i cui valori sono associati ad altrettante costanti, che si
-sono riportate in \tabref{tab:ipc_sem_limits}. Alcuni di questi limiti sono al
-solito accessibili e modificabili attraverso \func{sysctl} o scrivendo
+sono riportate in tab.~\ref{tab:ipc_sem_limits}. Alcuni di questi limiti sono
+al solito accessibili e modificabili attraverso \func{sysctl} o scrivendo
direttamente nel file \file{/proc/sys/kernel/sem}.
La funzione che permette di effettuare le varie operazioni di controllo sui
generico, che conterrà un dato diverso a seconda dell'azione richiesta; per
unificare l'argomento esso deve essere passato come una \struct{semun}, la cui
definizione, con i possibili valori che può assumere, è riportata in
-\figref{fig:ipc_semun}.
+fig.~\ref{fig:ipc_semun}.
Come già accennato sia il comportamento della funzione che il numero di
parametri con cui deve essere invocata, dipendono dal valore dell'argomento
Il valore di ritorno della funzione in caso di successo dipende
dall'operazione richiesta; per tutte le operazioni che richiedono quattro
argomenti esso è sempre nullo, per le altre operazioni, elencate in
-\tabref{tab:ipc_semctl_returns} viene invece restituito il valore richiesto,
+tab.~\ref{tab:ipc_semctl_returns} viene invece restituito il valore richiesto,
corrispondente al campo della struttura \struct{sem} indicato nella seconda
colonna della tabella.
Il contenuto di ciascuna operazione deve essere specificato attraverso una
opportuna struttura \struct{sembuf} (la cui definizione è riportata in
-\figref{fig:ipc_sembuf}) che il programma chiamante deve avere cura di
+fig.~\ref{fig:ipc_sembuf}) che il programma chiamante deve avere cura di
allocare in un opportuno vettore. La struttura permette di indicare il
semaforo su cui operare, il tipo di operazione, ed un flag di controllo.
Il campo \var{sem\_num} serve per indicare a quale semaforo dell'insieme fa
Tutto questo però ha un problema di fondo. Per capire di cosa si tratta
occorre fare riferimento all'implementazione usata in Linux, che è riportata
-in maniera semplificata nello schema di \figref{fig:ipc_sem_schema}. Si è
+in maniera semplificata nello schema di fig.~\ref{fig:ipc_sem_schema}. Si è
presa come riferimento l'architettura usata fino al kernel 2.2.x che è più
semplice (ed illustrata in dettaglio in \cite{tlk}); nel kernel 2.4.x la
struttura del \textit{SysV IPC} è stata modificata, ma le definizioni relative
Come esempio di uso dell'interfaccia dei semafori vediamo come implementare
con essa dei semplici \textit{mutex} (cioè semafori binari), tutto il codice
in questione, contenuto nel file \file{Mutex.c} allegato ai sorgenti, è
-riportato in \figref{fig:ipc_mutex_create}. Utilizzeremo l'interfaccia per
+riportato in fig.~\ref{fig:ipc_mutex_create}. Utilizzeremo l'interfaccia per
creare un insieme contenente un singolo semaforo, per il quale poi useremo un
valore unitario per segnalare la disponibilità della risorsa, ed un valore
nullo per segnalarne l'indisponibilità.
considerata libera). Infine si tenga presente che usare \func{MutexRead} per
controllare il valore dei mutex prima di proseguire in una operazione di
sblocco non servirebbe comunque, dato che l'operazione non sarebbe atomica.
-Vedremo in \secref{sec:ipc_lock_file} come sia possibile ottenere
+Vedremo in sez.~\ref{sec:ipc_lock_file} come sia possibile ottenere
un'interfaccia analoga a quella appena illustrata, senza incorrere in questi
problemi, usando il file locking\index{file!locking}.
La funzione, come \func{semget}, è del tutto analoga a \func{msgget}, ed
identico è l'uso degli argomenti \param{key} e \param{flag} per cui non
-ripeteremo quanto detto al proposito in \secref{sec:ipc_sysv_mq}. L'argomento
+ripeteremo quanto detto al proposito in sez.~\ref{sec:ipc_sysv_mq}. L'argomento
\param{size} specifica invece la dimensione, in byte, del segmento, che viene
comunque arrotondata al multiplo superiore di \const{PAGE\_SIZE}.
\end{figure}
A ciascun segmento di memoria condivisa è associata una struttura
-\struct{shmid\_ds}, riportata in \figref{fig:ipc_shmid_ds}. Come nel caso
+\struct{shmid\_ds}, riportata in fig.~\ref{fig:ipc_shmid_ds}. Come nel caso
delle code di messaggi quando si crea un nuovo segmento di memoria condivisa
con \func{shmget} questa struttura viene inizializzata, in particolare il
campo \var{shm\_perm} viene inizializzato come illustrato in
-\secref{sec:ipc_sysv_access_control}, e valgono le considerazioni ivi fatte
+sez.~\ref{sec:ipc_sysv_access_control}, e valgono le considerazioni ivi fatte
relativamente ai permessi di accesso; per quanto riguarda gli altri campi
invece:
\begin{itemize}
\func{sysctl} o scrivendo direttamente nei rispettivi file di
\file{/proc/sys/kernel/}.
-In \tabref{tab:ipc_shm_limits} si sono riportate le
+In tab.~\ref{tab:ipc_shm_limits} si sono riportate le
costanti simboliche associate a ciascuno di essi, il loro significato, i
valori preimpostati, e, quando presente, il file in \file{/proc/sys/kernel/}
che permettono di cambiarne il valore.
\textit{memory locking}\index{memory locking}\footnote{impedisce cioè che la
memoria usata per il segmento venga salvata su disco dal meccanismo della
memoria virtuale\index{memoria virtuale}; si ricordi quanto trattato in
- \secref{sec:proc_mem_lock}.} sul segmento di memoria condivisa. Solo
+ sez.~\ref{sec:proc_mem_lock}.} sul segmento di memoria condivisa. Solo
l'amministratore può utilizzare questo comando.
\item[\const{SHM\_UNLOCK}] Disabilita il \textit{memory locking} sul segmento
di memoria condivisa. Solo l'amministratore può utilizzare questo comando.
La funzione inserisce un segmento di memoria condivisa all'interno dello
spazio di indirizzi del processo, in modo che questo possa accedervi
direttamente, la situazione dopo l'esecuzione di \func{shmat} è illustrata in
-\figref{fig:ipc_shmem_layout} (per la comprensione del resto dello schema si
-ricordi quanto illustrato al proposito in \secref{sec:proc_mem_layout}). In
+fig.~\ref{fig:ipc_shmem_layout} (per la comprensione del resto dello schema si
+ricordi quanto illustrato al proposito in sez.~\ref{sec:proc_mem_layout}). In
particolare l'indirizzo finale del segmento dati (quello impostato da
-\func{brk}, vedi \secref{sec:proc_mem_sbrk}) non viene influenzato. Si tenga
+\func{brk}, vedi sez.~\ref{sec:proc_mem_sbrk}) non viene influenzato. Si tenga
presente infine che la funzione ha successo anche se il segmento è stato
marcato per la cancellazione.
aumentato di uno.
\end{itemize*}
-Come accennato in \secref{sec:proc_fork} un segmento di memoria condivisa
+Come accennato in sez.~\ref{sec:proc_fork} un segmento di memoria condivisa
agganciato ad un processo viene ereditato da un figlio attraverso una
\func{fork}, dato che quest'ultimo riceve una copia dello spazio degli
indirizzi del padre. Invece, dato che attraverso una \func{exec} viene
Come esempio di uso di queste funzioni vediamo come implementare una serie di
funzioni di libreria che ne semplifichino l'uso, automatizzando le operazioni
più comuni; il codice, contenuto nel file \file{SharedMem.c}, è riportato in
-\figref{fig:ipc_sysv_shm_func}.
+fig.~\ref{fig:ipc_sysv_shm_func}.
La prima funzione (\texttt{\small 3--16}) è \func{ShmCreate} che, data una
chiave, crea il segmento di memoria condivisa restituendo il puntatore allo
sequenziale, altri meccanismi come le pipe, le fifo o i socket, che non
necessitano di sincronizzazione esplicita, sono da preferire. Essa diventa
l'unico meccanismo possibile quando la comunicazione non è
-sequenziale\footnote{come accennato in \secref{sec:ipc_sysv_mq} per la
+sequenziale\footnote{come accennato in sez.~\ref{sec:ipc_sysv_mq} per la
comunicazione non sequenziale si possono usare le code di messaggi,
attraverso l'uso del campo \var{mtype}, ma solo se quest'ultima può essere
effettuata in forma di messaggio.} o quando non può avvenire secondo una
segmento di memoria condivisa cui altri processi potranno accedere per
ricavare la parte di informazione che interessa.
-In \figref{fig:ipc_dirmonitor_main} si è riportata la sezione principale del
+In fig.~\ref{fig:ipc_dirmonitor_main} si è riportata la sezione principale del
corpo del programma server, insieme alle definizioni delle altre funzioni
usate nel programma e delle variabili globali, omettendo tutto quello che
riguarda la gestione delle opzioni e la stampa delle istruzioni di uso a
la directory di lavoro del programma nella directory da tenere sotto
controllo, in vista del successivo uso della funzione
\func{daemon}.\footnote{si noti come si è potuta fare questa scelta,
- nonostante le indicazioni illustrate in \secref{sec:sess_daemon}, per il
+ nonostante le indicazioni illustrate in sez.~\ref{sec:sess_daemon}, per il
particolare scopo del programma, che necessita comunque di restare
all'interno di una directory.} Infine (\texttt{\small 27--29}) si installano
i gestori per i vari segnali di terminazione che, avendo a che fare con un
accedere alla memoria condivisa, che, per come abbiamo lo abbiamo definito,
sarà vista nella forma data da \struct{DirProp}. Infine (\texttt{\small
36--39}) utilizzando sempre la stessa chiave, si crea, tramite le funzioni
-di interfaccia già descritte in \secref{sec:ipc_sysv_sem}, anche un mutex, che
-utilizzeremo per regolare l'accesso alla memoria condivisa.
+di interfaccia già descritte in sez.~\ref{sec:ipc_sysv_sem}, anche un mutex,
+che utilizzeremo per regolare l'accesso alla memoria condivisa.
\begin{figure}[!htb]
\footnotesize \centering
Si noti come per il calcolo dei valori da mantenere nella memoria condivisa si
sia usata ancora una volta la funzione \func{DirScan}, già utilizzata (e
-descritta in dettaglio) in \secref{sec:file_dir_read}, che ci permette di
+descritta in dettaglio) in sez.~\ref{sec:file_dir_read}, che ci permette di
effettuare la scansione delle voci della directory, chiamando per ciascuna di
esse la funzione \func{ComputeValues}, che esegue tutti i calcoli necessari.
-Il codice di quest'ultima è riportato in \figref{fig:ipc_dirmonitor_sub}. Come
-si vede la funzione (\texttt{\small 2--16}) è molto semplice e si limita a
-chiamare (\texttt{\small 5}) la funzione \func{stat} sul file indicato da
+Il codice di quest'ultima è riportato in fig.~\ref{fig:ipc_dirmonitor_sub}.
+Come si vede la funzione (\texttt{\small 2--16}) è molto semplice e si limita
+a chiamare (\texttt{\small 5}) la funzione \func{stat} sul file indicato da
ciascuna voce, per ottenerne i dati, che poi utilizza per incrementare i vari
contatori nella memoria condivisa, cui accede grazie alla variabile globale
\var{shmptr}.
condivisa usando \var{shmptr} per riempire i campi della struttura
\struct{DirProp}; così prima (\texttt{\small 6--7}) si sommano le dimensioni
dei file ed il loro numero, poi, utilizzando le macro di
-\tabref{tab:file_type_macro}, si contano (\texttt{\small 8--14}) quanti ce ne
-sono per ciascun tipo.
-
-In \figref{fig:ipc_dirmonitor_sub} è riportato anche il codice (\texttt{\small
- 17--23}) del gestore dei segnali di terminazione, usato per chiudere il
-programma. Esso, oltre a provocare l'uscita del programma, si incarica anche
-di cancellare tutti gli oggetti di intercomunicazione non più necessari. Per
-questo anzitutto (\texttt{\small 19}) acquisisce il mutex con
+tab.~\ref{tab:file_type_macro}, si contano (\texttt{\small 8--14}) quanti ce
+ne sono per ciascun tipo.
+
+In fig.~\ref{fig:ipc_dirmonitor_sub} è riportato anche il codice
+(\texttt{\small 17--23}) del gestore dei segnali di terminazione, usato per
+chiudere il programma. Esso, oltre a provocare l'uscita del programma, si
+incarica anche di cancellare tutti gli oggetti di intercomunicazione non più
+necessari. Per questo anzitutto (\texttt{\small 19}) acquisisce il mutex con
\func{MutexLock}, per evitare di operare mentre un client sta ancora leggendo
i dati, dopo di che (\texttt{\small 20}) distacca e rimuove il segmento di
memoria condivisa usando \func{ShmRemove}. Infine (\texttt{\small 21})
\end{figure}
Il codice del client usato per leggere le informazioni mantenute nella memoria
-condivisa è riportato in \figref{fig:ipc_dirmonitor_client}. Al solito si è
+condivisa è riportato in fig.~\ref{fig:ipc_dirmonitor_client}. Al solito si è
omessa la sezione di gestione delle opzioni e la funzione che stampa a video
le istruzioni; il codice completo è nei sorgenti allegati, nel file
\file{ReadMonitor.c}.
%% Per capire meglio il funzionamento delle funzioni facciamo ancora una volta
%% riferimento alle strutture con cui il kernel implementa i segmenti di memoria
%% condivisa; uno schema semplificato della struttura è illustrato in
-%% \figref{fig:ipc_shm_struct}.
+%% fig.~\ref{fig:ipc_shm_struct}.
%% \begin{figure}[htb]
%% \centering
\section{Tecniche alternative}
\label{sec:ipc_alternatives}
-Come abbiamo detto in \secref{sec:ipc_sysv_generic}, e ripreso nella
+Come abbiamo detto in sez.~\ref{sec:ipc_sysv_generic}, e ripreso nella
descrizione dei singoli oggetti che ne fan parte, il \textit{SysV IPC}
presenta numerosi problemi; in \cite{APUE}\footnote{in particolare nel
capitolo 14.} Stevens ne effettua una accurata analisi (alcuni dei concetti
Le code di messaggi sono probabilmente il meno usato degli oggetti del
\textit{SysV IPC}; esse infatti nacquero principalmente come meccanismo di
comunicazione bidirezionale quando ancora le pipe erano unidirezionali; con la
-disponibilità di \func{socketpair} (vedi \secref{sec:ipc_socketpair}) o
+disponibilità di \func{socketpair} (vedi sez.~\ref{sec:ipc_socketpair}) o
utilizzando una coppia di pipe, si può ottenere questo risultato senza
incorrere nelle complicazioni introdotte dal \textit{SysV IPC}.
\label{sec:ipc_file_lock}
\index{file!di lock|(}
-Come illustrato in \secref{sec:ipc_sysv_sem} i semafori del \textit{SysV IPC}
+Come illustrato in sez.~\ref{sec:ipc_sysv_sem} i semafori del \textit{SysV IPC}
presentano una interfaccia inutilmente complessa e con alcuni difetti
strutturali, per questo quando si ha una semplice esigenza di sincronizzazione
per la quale basterebbe un semaforo binario (quello che abbiamo definito come
dei \textsl{file di lock} (per i quali esiste anche una opportuna directory,
\file{/var/lock}, nel filesystem standard). Per questo si usa la
caratteristica della funzione \func{open} (illustrata in
-\secref{sec:file_open}) che prevede\footnote{questo è quanto dettato dallo
+sez.~\ref{sec:file_open}) che prevede\footnote{questo è quanto dettato dallo
standard POSIX.1, ciò non toglie che in alcune implementazioni questa
tecnica possa non funzionare; in particolare per Linux, nel caso di NFS, si
è comunque soggetti alla possibilità di una race
ad \func{unlink}.
Un esempio dell'uso di questa funzione è mostrato dalle funzioni
-\func{LockFile} ed \func{UnlockFile} riportate in \figref{fig:ipc_file_lock}
+\func{LockFile} ed \func{UnlockFile} riportate in fig.~\ref{fig:ipc_file_lock}
(sono contenute in \file{LockFile.c}, un'altro dei sorgenti allegati alla
guida) che permettono rispettivamente di creare e rimuovere un \textsl{file di
lock}. Come si può notare entrambe le funzioni sono elementari; la prima
\end{figure}
Uno dei limiti di questa tecnica è che, come abbiamo già accennato in
-\secref{sec:file_open}, questo comportamento di \func{open} può non funzionare
-(la funzione viene eseguita, ma non è garantita l'atomicità dell'operazione)
-se il filesystem su cui si va ad operare è su NFS; in tal caso si può adottare
-una tecnica alternativa che prevede l'uso della \func{link} per creare come
-\textsl{file di lock} un hard link ad un file esistente; se il link esiste già
-e la funzione fallisce, significa che la risorsa è bloccata e potrà essere
-sbloccata solo con un \func{unlink}, altrimenti il link è creato ed il lock
-acquisito; il controllo e l'eventuale acquisizione sono atomici; la soluzione
-funziona anche su NFS, ma ha un'altro difetto è che è quello di poterla usare
-solo se si opera all'interno di uno stesso filesystem.
+sez.~\ref{sec:file_open}, questo comportamento di \func{open} può non
+funzionare (la funzione viene eseguita, ma non è garantita l'atomicità
+dell'operazione) se il filesystem su cui si va ad operare è su NFS; in tal
+caso si può adottare una tecnica alternativa che prevede l'uso della
+\func{link} per creare come \textsl{file di lock} un hard link ad un file
+esistente; se il link esiste già e la funzione fallisce, significa che la
+risorsa è bloccata e potrà essere sbloccata solo con un \func{unlink},
+altrimenti il link è creato ed il lock acquisito; il controllo e l'eventuale
+acquisizione sono atomici; la soluzione funziona anche su NFS, ma ha un'altro
+difetto è che è quello di poterla usare solo se si opera all'interno di uno
+stesso filesystem.
Un generale comunque l'uso di un \textsl{file di lock} presenta parecchi
problemi, che non lo rendono una alternativa praticabile per la
Dato che i file di lock\index{file!di lock} presentano gli inconvenienti
illustrati in precedenza, la tecnica alternativa di sincronizzazione più
comune è quella di fare ricorso al \textit{file locking}\index{file!locking}
-(trattato in \secref{sec:file_locking}) usando \func{fcntl} su un file creato
+(trattato in sez.~\ref{sec:file_locking}) usando \func{fcntl} su un file creato
per l'occasione per ottenere un write lock. In questo modo potremo usare il
lock come un \textit{mutex}: per bloccare la risorsa basterà acquisire il
lock, per sbloccarla basterà rilasciare il lock. Una richiesta fatta con un
\end{figure}
Il codice delle varie funzioni usate per implementare un mutex utilizzando il
-file locking\index{file!locking} è riportato in \figref{fig:ipc_flock_mutex};
+file locking\index{file!locking} è riportato in fig.~\ref{fig:ipc_flock_mutex};
si è mantenuta volutamente una struttura analoga alle precedenti funzioni che
usano i semafori, anche se le due interfacce non possono essere completamente
equivalenti, specie per quanto riguarda la rimozione del mutex.
caso si inizializza (\texttt{\small 28--31}) la struttura \var{lock} per il
rilascio del lock, che viene effettuato (\texttt{\small 33}) con la opportuna
chiamata a \func{fcntl}. Avendo usato il file locking in semantica POSIX (si
-riveda quanto detto \secref{sec:file_posix_lock}) solo il processo che ha
+riveda quanto detto sez.~\ref{sec:file_posix_lock}) solo il processo che ha
precedentemente eseguito il lock può sbloccare il mutex.
La quinta funzione (\texttt{\small 36--39}) è \func{RemoveMutex} e serve a
Basandosi sulla semantica dei file lock POSIX valgono tutte le considerazioni
relative al comportamento di questi ultimi fatte in
-\secref{sec:file_posix_lock}; questo significa ad esempio che, al contrario di
-quanto avveniva con l'interfaccia basata sui semafori, chiamate multiple a
+sez.~\ref{sec:file_posix_lock}; questo significa ad esempio che, al contrario
+di quanto avveniva con l'interfaccia basata sui semafori, chiamate multiple a
\func{UnlockMutex} o \func{LockMutex} non si cumulano e non danno perciò
nessun inconveniente.
evitare l'uso di una memoria condivisa facendo ricorso al cosiddetto
\textit{memory mapping} anonimo.
-In \secref{sec:file_memory_map} abbiamo visto come sia possibile mappare il
+In sez.~\ref{sec:file_memory_map} abbiamo visto come sia possibile mappare il
contenuto di un file nella memoria di un processo, e che, quando viene usato
il flag \const{MAP\_SHARED}, le modifiche effettuate al contenuto del file
vengono viste da tutti i processi che lo hanno mappato. Utilizzare questa
restano in memoria e possono essere riletti secondo le stesse modalità usate
nel \textit{memory mapping} anonimo.} Vedremo come utilizzare questa tecnica
più avanti, quando realizzeremo una nuova versione del monitor visto in
-\secref{sec:ipc_sysv_shm} che possa restituisca i risultati via rete.
+sez.~\ref{sec:ipc_sysv_shm} che possa restituisca i risultati via rete.
\label{sec:ipc_posix}
Per superare i numerosi problemi del \textit{SysV IPC}, evidenziati per i suoi
-aspetti generali in coda a \secref{sec:ipc_sysv_generic} e per i singoli
+aspetti generali in coda a sez.~\ref{sec:ipc_sysv_generic} e per i singoli
oggetti nei paragrafi successivi, lo standard POSIX.1b ha introdotto dei nuovi
meccanismi di comunicazione, che vanno sotto il nome di POSIX IPC, definendo
una interfaccia completamente nuova, che tratteremo in questa sezione.
quanto riguarda la memoria condivisa, che per quanto riguarda le code di
messaggi, tutto viene creato usando come radici delle opportune directory
(rispettivamente \file{/dev/shm} e \file{/dev/mqueue}, per i dettagli si
-faccia riferimento a \secref{sec:ipc_posix_shm} e \secref{sec:ipc_posix_mq})
-ed i nomi specificati nelle relative funzioni sono considerati come un
-pathname assoluto (comprendente eventuali sottodirectory) rispetto a queste
-radici.
+faccia riferimento a sez.~\ref{sec:ipc_posix_shm} e
+sez.~\ref{sec:ipc_posix_mq}) ed i nomi specificati nelle relative funzioni
+sono considerati come un pathname assoluto (comprendente eventuali
+sottodirectory) rispetto a queste radici.
Il vantaggio degli oggetti di IPC POSIX è comunque che essi vengono inseriti
nell'albero dei file, e possono essere maneggiati con le usuali funzioni e
In particolare i permessi associati agli oggetti di IPC POSIX sono identici ai
permessi dei file, e il controllo di accesso segue esattamente la stessa
-semantica (quella illustrata in \secref{sec:file_access_control}), invece di
+semantica (quella illustrata in sez.~\ref{sec:file_access_control}), invece di
quella particolare (si ricordi quanto visto in
-\secref{sec:ipc_sysv_access_control}) usata per gli oggetti del SysV IPC. Per
+sez.~\ref{sec:ipc_sysv_access_control}) usata per gli oggetti del SysV IPC. Per
quanto riguarda l'attribuzione dell'utente e del gruppo proprietari
dell'oggetto alla creazione di quest'ultimo essa viene effettuata secondo la
semantica SysV (essi corrispondono cioè a userid e groupid effettivi del
La funzione è del tutto analoga ad \func{open} ed analoghi sono i valori che
possono essere specificati per \param{oflag}, che deve essere specificato come
maschera binaria; i valori possibili per i vari bit sono quelli visti in
-\tabref{tab:file_open_flags} dei quali però \func{mq\_open} riconosce solo i
+tab.~\ref{tab:file_open_flags} dei quali però \func{mq\_open} riconosce solo i
seguenti:
\begin{basedescript}{\desclabelwidth{2cm}\desclabelstyle{\nextlinelabel}}
\item[\const{O\_RDONLY}] Apre la coda solo per la ricezione di messaggi. Il
essere specificati anche gli attributi specifici della coda tramite
l'argomento \param{attr}; quest'ultimo è un puntatore ad una apposita
struttura \struct{mq\_attr}, la cui definizione è riportata in
-\figref{fig:ipc_mq_attr}.
+fig.~\ref{fig:ipc_mq_attr}.
\begin{figure}[!htb]
\footnotesize \centering
Il comportamento di \func{mq\_notify} dipende dal valore dell'argomento
\param{notification}, che è un puntatore ad una apposita struttura
-\struct{sigevent}, (definita in \figref{fig:file_sigevent}) introdotta dallo
+\struct{sigevent}, (definita in fig.~\ref{fig:file_sigevent}) introdotta dallo
standard POSIX.1b per gestire la notifica di eventi; per altri dettagli si può
-vedere quanto detto in \secref{sec:file_asyncronous_io} a proposito dell'uso
+vedere quanto detto in sez.~\ref{sec:file_asyncronous_io} a proposito dell'uso
della stessa struttura per l'invio dei segnali usati per l'I/O asincrono.
Attraverso questa struttura si possono impostare le modalità con cui viene
implementato.} ed il campo \var{sigev\_signo} deve indicare il valore del
segnale che sarà inviato al processo. Inoltre il campo \var{sigev\_value} è il
puntatore ad una struttura \struct{sigval\_t} (definita in
-\figref{fig:sig_sigval}) che permette di restituire al gestore del segnale un
+fig.~\ref{fig:sig_sigval}) che permette di restituire al gestore del segnale un
valore numerico o un indirizzo,\footnote{per il suo uso si riveda la
- trattazione fatta in \secref{sec:sig_real_time} a proposito dei segnali
+ trattazione fatta in sez.~\ref{sec:sig_real_time} a proposito dei segnali
real-time.} posto che questo sia installato nella forma estesa vista in
-\secref{sec:sig_sigaction}.
+sez.~\ref{sec:sig_sigaction}.
La funzione registra il processo chiamante per la notifica se
\param{notification} punta ad una struttura \struct{sigevent} opportunamente
L'invio del segnale di notifica avvalora alcuni campi di informazione
restituiti al gestore attraverso la struttura \struct{siginfo\_t} (definita in
-\figref{fig:sig_siginfo_t}). In particolare \var{si\_pid} viene impostato al
+fig.~\ref{fig:sig_siginfo_t}). In particolare \var{si\_pid} viene impostato al
valore del \acr{pid} del processo che ha emesso il segnale, \var{si\_uid}
all'userid effettivo, \var{si\_code} a \const{SI\_MESGQ}, e \var{si\_errno} a
0. Questo ci dice che, se si effettua la ricezione dei messaggi usando
esclusivamente il meccanismo di notifica, è possibile ottenere le informazioni
sul processo che ha inserito un messaggio usando un gestore per il segnale in
forma estesa\footnote{di nuovo si faccia riferimento a quanto detto al
- proposito in \secref{sec:sig_sigaction} e \secref{sec:sig_real_time}.}
+ proposito in sez.~\ref{sec:sig_sigaction} e sez.~\ref{sec:sig_real_time}.}
sincronizzazione fra processi diversi.} Esiste però anche una libreria
realizzata da Konstantin Knizhnik, che reimplementa l'interfaccia POSIX usando
i semafori di SysV IPC, e che non vale comunque la pena di usare visto che i
-problemi sottolineati in \secref{sec:ipc_sysv_sem} rimangono, anche se
+problemi sottolineati in sez.~\ref{sec:ipc_sysv_sem} rimangono, anche se
mascherati.
In realtà a partire dal kernel 2.5.7 è stato introdotto un meccanismo di
\end{prototype}
La funzione apre un segmento di memoria condivisa identificato dal nome
-\param{name}. Come già spiegato in \secref{sec:ipc_posix_generic} questo nome
+\param{name}. Come già spiegato in sez.~\ref{sec:ipc_posix_generic} questo nome
può essere specificato in forma standard solo facendolo iniziare per \file{/}
e senza ulteriori \file{/}, Linux supporta comunque nomi generici, che
verranno intepretati prendendo come radice \file{/dev/shm}.\footnote{occorre
possono essere specificati per \param{oflag}, che deve essere specificato come
maschera binaria comprendente almeno uno dei due valori \const{O\_RDONLY} e
\const{O\_RDWR}; i valori possibili per i vari bit sono quelli visti in
-\tabref{tab:file_open_flags} dei quali però \func{shm\_open} riconosce solo i
-seguenti:
+tab.~\ref{tab:file_open_flags} dei quali però \func{shm\_open} riconosce solo
+i seguenti:
\begin{basedescript}{\desclabelwidth{2.0cm}\desclabelstyle{\nextlinelabel}}
\item[\const{O\_RDONLY}] Apre il file descriptor associato al segmento di
memoria condivisa per l'accesso in sola lettura.
segmento di memoria condiviso con le stesse modalità di
\func{open}\footnote{in realtà, come accennato, \func{shm\_open} è un semplice
wrapper per \func{open}, usare direttamente quest'ultima avrebbe lo stesso
- effetto.} viste in \secref{sec:file_open}; in particolare viene impostato
+ effetto.} viste in sez.~\ref{sec:file_open}; in particolare viene impostato
il flag \const{FD\_CLOEXEC}. Chiamate effettuate da diversi processi usando
lo stesso nome, restituiranno file descriptor associati allo stesso segmento
(così come, nel caso di file di dati, essi sono associati allo stesso inode).
\const{O\_CREAT}; in tal caso il segmento avrà (così come i nuovi file)
lunghezza nulla. Dato che un segmento di lunghezza nulla è di scarsa utilità,
per impostarne la dimensione si deve usare \func{ftruncate} (vedi
-\secref{sec:file_file_size}), prima di mapparlo in memoria con \func{mmap}. Si
-tenga presente che una volta chiamata \func{mmap} si può chiudere il file
+sez.~\ref{sec:file_file_size}), prima di mapparlo in memoria con \func{mmap}.
+Si tenga presente che una volta chiamata \func{mmap} si può chiudere il file
descriptor (con \func{close}), senza che la mappatura ne risenta.
Come esempio per l'uso di queste funzioni vediamo come è possibile riscrivere
una interfaccia semplificata analoga a quella vista in
-\secref{fig:ipc_sysv_shm_func} per la memoria condivisa in stile SysV. Il
-codice, riportato in \figref{fig:ipc_posix_shmmem}, è sempre contenuto nel
+fig.~\ref{fig:ipc_sysv_shm_func} per la memoria condivisa in stile SysV. Il
+codice, riportato in fig.~\ref{fig:ipc_posix_shmmem}, è sempre contenuto nel
file \file{SharedMem.c} dei sorgenti allegati.
La prima funzione (\texttt{\small 1--24}) è \func{CreateShm} che, dato un nome
In questa appendice prenderemo in esame i vari protocolli disponibili a
livello di rete.\footnote{per la spiegazione della suddivisione in livelli dei
protocolli di rete, si faccia riferimento a quanto illustrato in
- \secref{sec:net_protocols}.} Per ciascuno di essi forniremo una descrizione
+ sez.~\ref{sec:net_protocols}.} Per ciascuno di essi forniremo una descrizione
generica delle principlai caratteristiche, del formato di dati usato e quanto
possa essere necessario per capirne meglio il funzionamento dal punto di vista
della programmazione.
Per venire incontro alle diverse esigenze gli indirizzi di rete sono stati
originariamente organizzati in \textit{classi}, (rappresentate in
-\tabref{tab:IP_ipv4class}), per consentire dispiegamenti di reti di dimensioni
-diverse.
+tab.~\ref{tab:IP_ipv4class}), per consentire dispiegamenti di reti di
+dimensioni diverse.
\begin{table}[htb]
è destinata al (non molto usato) \textit{multicast} mentre la classe E è
riservata per usi sperimentali e non viene impiegata.
-Come si può notare però la suddivisione riportata in \tabref{tab:IP_ipv4class}
-è largamente inefficiente in quanto se ad un utente necessita anche solo un
-indirizzo in più dei 256 disponibili con una classe A occorre passare a una
-classe B, con un conseguente spreco di numeri.
+Come si può notare però la suddivisione riportata in
+tab.~\ref{tab:IP_ipv4class} è largamente inefficiente in quanto se ad un
+utente necessita anche solo un indirizzo in più dei 256 disponibili con una
+classe A occorre passare a una classe B, con un conseguente spreco di numeri.
Inoltre, in particolare per le reti di classe C, la presenza di tanti
indirizzi di rete diversi comporta una crescita enorme delle tabelle di
Per questo nel 1992 è stato introdotto un indirizzamento senza classi (il
CIDR, \textit{Classless Inter-Domain Routing}) in cui il limite fra i bit
destinati a indicare il numero di rete e quello destinati a indicare l'host
-finale può essere piazzato in qualunque punto (vedi \tabref{tab:IP_ipv4cidr}),
-permettendo di accorpare più classi A su un'unica rete o suddividere una
-classe B e diminuendo al contempo il numero di indirizzi di rete da inserire
-nelle tabelle di instradamento dei router.
+finale può essere piazzato in qualunque punto (vedi
+tab.~\ref{tab:IP_ipv4cidr}), permettendo di accorpare più classi A su un'unica
+rete o suddividere una classe B e diminuendo al contempo il numero di
+indirizzi di rete da inserire nelle tabelle di instradamento dei router.
\subsection{Principali caratteristiche di IPv6}
\label{sec:IP_ipv6over}
-Per rispondere alle esigenze descritte in \secref{sec:IP_whyipv6} IPv6 nasce
+Per rispondere alle esigenze descritte in sez.~\ref{sec:IP_whyipv6} IPv6 nasce
come evoluzione di IPv4, mantendone inalterate le funzioni che si sono
dimostrate valide, eliminando quelle inutili e aggiungendone poche altre
ponendo al contempo una grande attenzione a mantenere il protocollo il più
Per capire le caratteristiche di IPv6 partiamo dall'intestazione usata dal
protocollo per gestire la trasmissione dei pacchetti; in
-\figref{fig:IP_ipv6head} è riportato il formato dell'intestazione di IPv6 da
-confrontare con quella di IPv4 in \figref{fig:IP_ipv4_head}. La spiegazione del
-significato dei vari campi delle due intestazioni è riportato rispettivamente
-in \tabref{tab:IP_ipv6field} e \tabref{tab:IP_ipv4field})
+fig.~\ref{fig:IP_ipv6head} è riportato il formato dell'intestazione di IPv6 da
+confrontare con quella di IPv4 in fig.~\ref{fig:IP_ipv4_head}. La spiegazione
+del significato dei vari campi delle due intestazioni è riportato
+rispettivamente in tab.~\ref{tab:IP_ipv6field} e tab.~\ref{tab:IP_ipv4field})
% \begin{table}[htb]
% \footnotesize
\textit{version} & 4 bit &
\textsl{versione}, nel caso specifico vale sempre 6\\
\textit{priority} & 4 bit &
- \textsl{priorità}, vedi Sez.~\ref{sec:prio} \\
+ \textsl{priorità}, vedi sez.~\ref{sec:prio} \\
\textit{flow label} & 24 bit &
- \textsl{etichetta di flusso}, vedi Sez.~\ref{sec:IP_ipv6_flow}\\
+ \textsl{etichetta di flusso}, vedi sez.~\ref{sec:IP_ipv6_flow}\\
\textit{payload length} & 16 bit &
\textsl{lunghezza del carico}, cioè del corpo dei dati che segue
l'intestazione, in byte. \\
\end{center}
\end{table}
-Abbiamo già anticipato in \secref{sec:IP_ipv6over} uno dei criteri principali
+Abbiamo già anticipato in sez.~\ref{sec:IP_ipv6over} uno dei criteri principali
nella progettazione di IPv6 è stato quello di ridurre al minimo il tempo di
processamento dei pacchetti da parte dei router, un confronto con
-l'intestazione di IPv4 (vedi \figref{fig:IP_ipv4_head}) mostra le seguenti
+l'intestazione di IPv4 (vedi fig.~\ref{fig:IP_ipv4_head}) mostra le seguenti
differenze:
\begin{itemize}
\item è stato eliminato il campo \textit{header length} in quanto le opzioni
sono state tolte dall'intestazione che ha così dimensione fissa; ci possono
essere più intestazioni opzionali (\textsl{intestazioni di estensione}, vedi
- \secref{sec:IP_ipv6_extens}), ciascuna delle quali avrà un suo campo di
+ sez.~\ref{sec:IP_ipv6_extens}), ciascuna delle quali avrà un suo campo di
lunghezza all'interno.
\item l'intestazione e gli indirizzi sono allineati a 64 bit, questo rende più
veloce il processo da parte di computer con processori a 64 bit.
\item è stato introdotto un nuovo campo \textit{flow label}, che viene usato,
insieme al campo \textit{priority} (che recupera i bit di precedenza del
campo \textit{type of service}) per implementare la gestione di una
- ``\textsl{qualità di servizio}'' (vedi \secref{sec:IP_ipv6_qos}) che
+ ``\textsl{qualità di servizio}'' (vedi sez.~\ref{sec:IP_ipv6_qos}) che
permette di identificare i pacchetti appartenenti a un ``\textsl{flusso}''
di dati per i quali si può provvedere un trattamento speciale.
\end{itemize}
indica la posizione del frammento rispetto al pacchetto originale\\
\textit{time to live} & 16 & \textsl{tempo di vita},
ha lo stesso significato di
- \textit{hop limit}, vedi Tab.~\ref{tab:IP_ipv6field}\\
+ \textit{hop limit}, vedi tab.~\ref{tab:IP_ipv6field}\\
\textit{protocol} & 8 & \textsl{protocollo}
identifica il tipo di pacchetto che segue
l'intestazione di IPv4\\
\begin{itemize}
\item il broadcasting non è previsto in IPv6, le applicazioni che lo usano
dovono essere reimplementate usando il multicasting (vedi
- \secref{sec:IP_ipv6_multicast}), che da opzionale diventa obbligatorio.
+ sez.~\ref{sec:IP_ipv6_multicast}), che da opzionale diventa obbligatorio.
\item è stato introdotto un nuovo tipo di indirizzi, gli \textit{anycast}.
\item i router non possono più frammentare i pacchetti lungo il cammino, la
frammentazione di pacchetti troppo grandi potrà essere gestita solo ai
capi della comunicazione (usando un'apposita estensione vedi
- \secref{sec:IP_ipv6_extens}).
+ sez.~\ref{sec:IP_ipv6_extens}).
\item IPv6 richiede il supporto per il \textit{path MTU discovery} (cioè il
protocollo per la selezione della massima lunghezza del pacchetto); seppure
questo sia in teoria opzionale, senza di esso non sarà possibile inviare
gruppo.
In IPv6 non ci sono più le classi ma i bit più significativi indicano il tipo
-di indirizzo; in \tabref{tab:IP_ipv6addr} sono riportati i valori di detti
+di indirizzo; in tab.~\ref{tab:IP_ipv6addr} sono riportati i valori di detti
bit e il tipo di indirizzo che loro corrispondente. I bit più significativi
costituiscono quello che viene chiamato il \textit{format prefix} ed è sulla
base di questo che i vari tipi di indirizzi vengono identificati. Come si
spazio (più del 70\%) è riservato per usi futuri.
Si noti infine che gli indirizzi \textit{anycast} non sono riportati in
-\tabref{tab:IP_ipv6addr} in quanto allocati al di fuori dello spazio di
+tab.~\ref{tab:IP_ipv6addr} in quanto allocati al di fuori dello spazio di
allocazione degli indirizzi unicast.
\subsection{Indirizzi unicast \textit{provider-based}}
efficiente di allocazione la struttura di questi indirizzi è organizzata fin
dall'inizio in maniera gerarchica; pertanto lo spazio di questi indirizzi è
stato suddiviso in una serie di campi secondo lo schema riportato in
-\tabref{tab:IP_ipv6_unicast}.
+tab.~\ref{tab:IP_ipv6_unicast}.
\begin{table}[htb]
\centering
gestione dei singoli fruitori finali, gli indirizzi \textit{provider-based}
lasciano normalmente gli ultimi 64~bit a disposizione per questo livello, la
modalità più immediata è quella di usare uno schema del tipo mostrato in
-\tabref{tab:IP_ipv6_uninterf} dove l'\textit{Interface Id} è dato dal
+tab.~\ref{tab:IP_ipv6_uninterf} dove l'\textit{Interface Id} è dato dal
MAC-address a 48~bit dello standard Ethernet, scritto in genere nell'hardware
delle scheda di rete, e si usano i restanti 16~bit per indicare la sottorete.
attribuzione degli indirizzi per i fornitori di servizi nell'ambito del/i
paese coperto dal registro nazionale con le modalità viste in precedenza.
Una tale ripartizione andrà effettuata all'interno dei soliti 56~bit come
-mostrato in \tabref{tab:IP_ipv6_uninaz}.
+mostrato in tab.~\ref{tab:IP_ipv6_uninaz}.
\begin{table}[htb]
\centering
Ci sono due tipi di indirizzi, \textit{link-local} e \textit{site-local}. Il
primo è usato per un singolo link; la struttura è mostrata in
-\tabref{tab:IP_ipv6_linklocal}, questi indirizzi iniziano sempre con un valore
-nell'intervallo \texttt{FE80}--\texttt{FEBF} e vengono in genere usati per la
-configurazione automatica dell'indirizzo al bootstrap e per la ricerca dei
-vicini (vedi \ref{sec:IP_ipv6_autoconf}); un pacchetto che abbia tale
+tab.~\ref{tab:IP_ipv6_linklocal}, questi indirizzi iniziano sempre con un
+valore nell'intervallo \texttt{FE80}--\texttt{FEBF} e vengono in genere usati
+per la configurazione automatica dell'indirizzo al bootstrap e per la ricerca
+dei vicini (vedi \ref{sec:IP_ipv6_autoconf}); un pacchetto che abbia tale
indirizzo come sorgente o destinazione non deve venire ritrasmesso dai router.
Un indirizzo \textit{site-local} invece è usato per l'indirizzamento
all'interno di un sito che non necessita di un prefisso globale; la struttura
-è mostrata in \tabref{tab:IP_ipv6_sitelocal}, questi indirizzi iniziano sempre
-con un valore nell'intervallo \texttt{FEC0}--\texttt{FEFF} e non devono venire
-ritrasmessi dai router all'esterno del sito stesso; sono in sostanza gli
-equivalenti degli indirizzi riservati per reti private definiti su IPv4. Per
-entrambi gli indirizzi il campo \textit{Interface Id} è un identificatore che
-deve essere unico nel dominio in cui viene usato, un modo immediato per
+è mostrata in tab.~\ref{tab:IP_ipv6_sitelocal}, questi indirizzi iniziano
+sempre con un valore nell'intervallo \texttt{FEC0}--\texttt{FEFF} e non devono
+venire ritrasmessi dai router all'esterno del sito stesso; sono in sostanza
+gli equivalenti degli indirizzi riservati per reti private definiti su IPv4.
+Per entrambi gli indirizzi il campo \textit{Interface Id} è un identificatore
+che deve essere unico nel dominio in cui viene usato, un modo immediato per
costruirlo è quello di usare il MAC-address delle schede di rete.
\begin{table}[!h]
di compatibilità.
Un primo tipo sono gli indirizzi \textit{IPv4 mappati su IPv6} (mostrati in
-\tabref{tab:IP_ipv6_map}), questo sono indirizzi unicast che vengono usati per
-consentire ad applicazioni IPv6 di comunicare con host capaci solo di IPv4;
-questi sono ad esempio gli indirizzi generati da un DNS quando l'host
+tab.~\ref{tab:IP_ipv6_map}), questo sono indirizzi unicast che vengono usati
+per consentire ad applicazioni IPv6 di comunicare con host capaci solo di
+IPv4; questi sono ad esempio gli indirizzi generati da un DNS quando l'host
richiesto supporta solo IPv4; l'uso di un tale indirizzo in un socket IPv6
comporta la generazione di un pacchetto IPv4 (ovviamente occorre che sia IPv4
che IPv6 siano supportati sull'host di origine).
\end{table}
Un secondo tipo di indirizzi di compatibilità sono gli \textsl{IPv4
- compatibili IPv6} (vedi \tabref{tab:IP_ipv6_comp}) usati nella transizione
+ compatibili IPv6} (vedi tab.~\ref{tab:IP_ipv6_comp}) usati nella transizione
da IPv4 a IPv6: quando un nodo che supporta sia IPv6 che IPv4 non ha un router
IPv6 deve usare nel DNS un indirizzo di questo tipo, ogni pacchetto IPv6
inviato a un tale indirizzo verrà automaticamente incapsulato in IPv4.
e il pacchetto viene inviato a tutte le interfacce di detto gruppo.
Un'interfaccia può appartenere ad un numero qualunque numero di gruppi di
multicast. Il formato degli indirizzi \textit{multicast} è riportato in
-\tabref{tab:IP_ipv6_multicast}:
+tab.~\ref{tab:IP_ipv6_multicast}:
\begin{table}[htb]
\centering
transitorio.
\item \textsl{scop} è un numero di quattro bit che indica il raggio di
validità dell'indirizzo, i valori assegnati per ora sono riportati in
- \tabref{tab:IP_ipv6_multiscope}.
+ tab.~\ref{tab:IP_ipv6_multiscope}.
\end{itemize}
Infine l'ultimo campo identifica il gruppo di multicast, sia permanente che
transitorio, all'interno del raggio di validità del medesimo. Alcuni
-indirizzi multicast, riportati in \tabref{tab:multiadd} sono già riservati
+indirizzi multicast, riportati in tab.~\ref{tab:multiadd} sono già riservati
per il funzionamento della rete.
\begin{table}[!htb]
opzioni questa sarà l'intestazione di un protocollo di trasporto del livello
superiore, per cui il campo assumerà lo stesso valore del campo
\textit{protocol} di IPv4, altrimenti assumerà il valore dell'opzione
-presente; i valori possibili sono riportati in \tabref{tab:IP_ipv6_nexthead}.
+presente; i valori possibili sono riportati in
+tab.~\ref{tab:IP_ipv6_nexthead}.
\begin{table}[htb]
\begin{center}
di integrità (ma senza riservatezza) dei pacchetti IP.
L'intestazione di autenticazione ha il formato descritto in
-\figref{fig:autent_estens}: il campo \textit{Next Header} indica
+fig.~\ref{fig:autent_estens}: il campo \textit{Next Header} indica
l'intestazione successiva, con gli stessi valori del campo omonimo
nell'intestazione principale di IPv6, il campo \textit{Length} indica la
lunghezza dell'intestazione di autenticazione in numero di parole a 32 bit, il
estensione; ad essa segue il carico del pacchetto che viene criptato.
Un pacchetto crittografato pertanto viene ad avere una struttura del tipo di
-quella mostrata in \figref{fig:ESP_criptopack}, tutti i campi sono in chiaro
+quella mostrata in fig.~\ref{fig:ESP_criptopack}, tutti i campi sono in chiaro
fino al vettore di inizializzazione, il resto è crittografato.
La procedura di configurazione è la seguente: all'avvio tutti i nodi IPv6
iniziano si devono aggregare al gruppo multicast \textit{all-nodes}
programmando la propria interfaccia per ricevere i messaggi dall'indirizzo
-multicast \texttt{FF02::1} (vedi \secref{sec:IP_ipv6_multicast}); a questo
+multicast \texttt{FF02::1} (vedi sez.~\ref{sec:IP_ipv6_multicast}); a questo
punto devono inviare un messaggio ICMP \textit{Router solicitation} a tutti i
router locali usando l'indirizzo multicast \texttt{FF02::2} usando come
sorgente il proprio indirizzo link-local.
pagine web, la posta elettronica, ftp, telnet, ssh e praticamente ogni
servizio che viene fornito tramite la rete, anche se, come abbiamo visto, il
modello è utilizzato in generale anche per programmi che, come gli esempi che
-abbiamo usato in \capref{cha:IPC} a proposito della comunicazione fra processi
-nello stesso sistema, non fanno necessariamente uso della rete.
+abbiamo usato in cap.~\ref{cha:IPC} a proposito della comunicazione fra
+processi nello stesso sistema, non fanno necessariamente uso della rete.
Normalmente si dividono i server in due categorie principali, e vengono detti
\textsl{concorrenti} o \textsl{iterativi}, sulla base del loro comportamento.
Una caratteristica comune dei protocolli di rete è il loro essere strutturati
in livelli sovrapposti; in questo modo ogni protocollo di un certo livello
realizza le sue funzionalità basandosi su un protocollo del livello
-sottostante. Questo modello di funzionamento è stato stato standardizzato
-dalla \textit{International Standards Organization} (ISO) che ha preparato fin
-dal 1984 il Modello di Riferimento \textit{Open Systems Interconnection}
-(OSI), strutturato in sette livelli, secondo quanto riportato in
-\tabref{tab:net_osilayers}.
+sottostante. Questo modello di funzionamento è stato standardizzato dalla
+\textit{International Standards Organization} (ISO) che ha preparato fin dal
+1984 il Modello di Riferimento \textit{Open Systems Interconnection} (OSI),
+strutturato in sette livelli, secondo quanto riportato in
+tab.~\ref{tab:net_osilayers}.
\begin{table}[htb]
\centering
è stata creata la frase \texttt{All people seem to need data processing}, in
cui ciascuna parola corrisponde all'iniziale di uno dei livelli.}, tanto che
usualmente si tende a suddividerlo in due parti, secondo lo schema mostrato in
-\figref{fig:net_osi_tcpip_comp}, con un \textit{upper layer} che riguarda solo
-le applicazioni, che viene realizzato in user space, ed un \textit{lower
+fig.~\ref{fig:net_osi_tcpip_comp}, con un \textit{upper layer} che riguarda
+solo le applicazioni, che viene realizzato in user space, ed un \textit{lower
layer} in cui si mescolano la gestione fatta dal kernel e le funzionalità
fornite dall'hardware.
\label{sec:net_tcpip_overview}
Così come ISO/OSI anche il modello del TCP/IP è stato strutturato in livelli
-(riassunti in \tabref{tab:net_layers}); un confronto fra i due è riportato in
-\figref{fig:net_osi_tcpip_comp} dove viene evidenziata anche la corrispondenza
-fra i rispettivi livelli (che comunque è approssimativa) e su come essi vanno
-ad inserirsi all'interno del sistema rispetto alla divisione fra user space e
-kernel space spiegata in \secref{sec:intro_unix_struct}.\footnote{in realtà è
- sempre possibile accedere dallo user space, attraverso una opportuna
- interfaccia (come vedremo in \secref{sec:sock_sa_packet}), ai livelli
- inferiori del protocollo.}
+(riassunti in tab.~\ref{tab:net_layers}); un confronto fra i due è riportato
+in fig.~\ref{fig:net_osi_tcpip_comp} dove viene evidenziata anche la
+corrispondenza fra i rispettivi livelli (che comunque è approssimativa) e su
+come essi vanno ad inserirsi all'interno del sistema rispetto alla divisione
+fra user space e kernel space spiegata in
+sez.~\ref{sec:intro_unix_struct}.\footnote{in realtà è sempre possibile
+ accedere dallo user space, attraverso una opportuna interfaccia (come
+ vedremo in sez.~\ref{sec:sock_sa_packet}), ai livelli inferiori del
+ protocollo.}
\begin{table}[htb]
\centering
\begin{basedescript}{\desclabelwidth{2.5cm}\desclabelstyle{\nextlinelabel}}
\item[\textbf{Applicazione}] É relativo ai programmi di interfaccia con la
rete, in genere questi vengono realizzati secondo il modello client-server
- (vedi \secref{sec:net_cliserv}), realizzando una comunicazione secondo un
+ (vedi sez.~\ref{sec:net_cliserv}), realizzando una comunicazione secondo un
protocollo che è specifico di ciascuna applicazione.
\item[\textbf{Trasporto}] Fornisce la comunicazione tra le due stazioni
terminali su cui girano gli applicativi, regola il flusso delle
\end{basedescript}
La comunicazione fra due stazioni remote avviene secondo le modalità
-illustrate in \figref{fig:net_tcpip_data_flux}, dove si è riportato il flusso
+illustrate in fig.~\ref{fig:net_tcpip_data_flux}, dove si è riportato il flusso
dei dati reali e i protocolli usati per lo scambio di informazione su ciascun
livello. Si è genericamente indicato \textit{ethernet} per il livello 1, anche
se in realtà i protocolli di trasmissione usati possono essere molti altri.
\end{figure}
Per chiarire meglio la struttura della comunicazione attraverso i vari
-protocolli mostrata in \figref{fig:net_tcpip_data_flux}, conviene prendere in
+protocolli mostrata in fig.~\ref{fig:net_tcpip_data_flux}, conviene prendere in
esame i singoli passaggi fatti per passare da un livello al sottostante,
la procedura si può riassumere nei seguenti passi:
\begin{itemize}
standard per Internet.}).
\item I dati delle applicazioni vengono inviati al livello di trasporto usando
un'interfaccia opportuna (i \textit{socket}\index{socket}, che esamineremo
- in dettaglio in \capref{cha:socket_intro}). Qui verranno spezzati in
+ in dettaglio in cap.~\ref{cha:socket_intro}). Qui verranno spezzati in
pacchetti di dimensione opportuna e inseriti nel protocollo di trasporto,
aggiungendo ad ogni pacchetto le informazioni necessarie per la sua
gestione. Questo processo viene svolto direttamente nel kernel, ad esempio
\section{Il protocollo TCP/IP}
\label{sec:net_tpcip}
-Come accennato in \secref{sec:net_protocols} il protocollo TCP/IP è un insieme
-di protocolli diversi, che operano su 4 livelli diversi. Per gli interessi
-della programmazione di rete però sono importanti principalmente i due livelli
-centrali, e soprattutto quello di trasporto.
+Come accennato in sez.~\ref{sec:net_protocols} il protocollo TCP/IP è un
+insieme di protocolli diversi, che operano su 4 livelli diversi. Per gli
+interessi della programmazione di rete però sono importanti principalmente i
+due livelli centrali, e soprattutto quello di trasporto.
La principale interfaccia usata nella programmazione di rete, quella dei
socket\index{socket}, è infatti un'interfaccia nei confronti di quest'ultimo.
che fare solo con dettagli specifici delle applicazioni, mentre al di sotto
vengono curati tutti i dettagli relativi alla comunicazione. È pertanto
naturale definire una interfaccia di programmazione su questo confine, tanto
-più che è proprio lì (come evidenziato in \figref{fig:net_osi_tcpip_comp}) che
-nei sistemi Unix (e non solo) viene inserita la divisione fra kernel space e
-user space.
+più che è proprio lì (come evidenziato in fig.~\ref{fig:net_osi_tcpip_comp})
+che nei sistemi Unix (e non solo) viene inserita la divisione fra kernel space
+e user space.
In realtà in un sistema Unix è possibile accedere anche agli altri livelli
inferiori (e non solo a quello di trasporto) con opportune interfacce di
-programmazione (vedi \secref{sec:sock_sa_packet}), ma queste vengono usate
+programmazione (vedi sez.~\ref{sec:sock_sa_packet}), ma queste vengono usate
solo quando si debbano fare applicazioni di sistema per il controllo della
rete a basso livello, di uso quindi molto specialistico.
\label{sec:net_tcpip_general}
Benché si parli di TCP/IP questa famiglia di protocolli è composta anche da
-molti membri. In \figref{fig:net_tcpip_overview} si è riportato uno schema che
-mostra un panorama sui principali protocolli della famiglia, e delle loro
+molti membri. In fig.~\ref{fig:net_tcpip_overview} si è riportato uno schema
+che mostra un panorama sui principali protocolli della famiglia, e delle loro
relazioni reciproche e con alcune dalle principali applicazioni che li usano.
\begin{figure}[!htbp]
\label{fig:net_tcpip_overview}
\end{figure}
-I vari protocolli riportati in \figref{fig:net_tcpip_overview} sono i
+I vari protocolli riportati in fig.~\ref{fig:net_tcpip_overview} sono i
seguenti:
\begin{basedescript}{\desclabelwidth{1.7cm}\desclabelstyle{\nextlinelabel}}
si riferisce ad esso come ICPMv4 per distinguerlo da ICMPv6.
\item[\textsl{IGMP}] \textit{Internet Group Management Protocol}. É un
protocollo di livello 2 usato per il \textit{multicasting} (vedi
- \secref{sec:xxx_multicast}). Permette alle stazioni remote di notificare ai
- router che supportano questa comunicazione a quale gruppo esse appartengono.
- Come ICMP viene implementato direttamente sopra IP.
+ sez.~\ref{sec:xxx_multicast}). Permette alle stazioni remote di notificare
+ ai router che supportano questa comunicazione a quale gruppo esse
+ appartengono. Come ICMP viene implementato direttamente sopra IP.
\item[\textsl{ARP}] \textit{Address Resolution Protocol}. È il protocollo che
mappa un indirizzo IP in un indirizzo hardware sulla rete locale. È usato in
reti di tipo broadcast come Ethernet, Token Ring o FDDI che hanno associato
\end{itemize}
Maggiori dettagli riguardo a caratteristiche, notazioni e funzionamento del
-protocollo IP sono forniti nell'appendice \secref{sec:ip_protocol}.
+protocollo IP sono forniti nell'appendice sez.~\ref{sec:ip_protocol}.
\subsection{User Datagram Protocol (UDP)}
un'applicazione usa UDP essa scrive un pacchetto di dati (il cosiddetto
\textit{datagram} che da il nome al protocollo) su un socket\index{socket}, al
pacchetto viene aggiunto un header molto semplice (per una descrizione più
-accurata vedi \secref{sec:udp_protocol}), e poi viene passato al livello
+accurata vedi sez.~\ref{sec:udp_protocol}), e poi viene passato al livello
superiore (IPv4 o IPv6 che sia) che lo spedisce verso la destinazione. Dato
che né IPv4 né IPv6 garantiscono l'affidabilità niente assicura che il
pacchetto arrivi a destinazione, né che più pacchetti arrivino nello stesso
effettuato per entrambe le direzioni di comunicazione.
%% Una descrizione più accurata del protocollo è fornita in appendice
-%% \secref{sec:tcp_protocol}.
+%% sez.~\ref{sec:tcp_protocol}.
\subsection{Limiti e dimensioni riguardanti la trasmissione dei dati}
\label{sec:net_lim_dim}
\item La dimensione massima di un pacchetto IP è di 65535 byte, compresa
l'intestazione. Questo è dovuto al fatto che la dimensione è indicata da un
campo apposito nell'header di IP che è lungo 16 bit (vedi
- \figref{fig:IP_ipv4_head}).
+ fig.~\ref{fig:IP_ipv4_head}).
\item La dimensione massima di un pacchetto normale di IPv6 è di 65575 byte,
il campo apposito nell'header infatti è sempre a 16 bit, ma la dimensione
dell'header è fissa e di 40 byte e non è compresa nel valore indicato dal
\item Molte reti fisiche hanno un MTU (\textit{maximum transfer unit}) che
dipende dal protocollo specifico usato al livello di connessione fisica. Il
più comune è quello di ethernet che è pari a 1500 byte, una serie di altri
- valori possibili sono riportati in \tabref{tab:net_mtu_values}.
+ valori possibili sono riportati in tab.~\ref{tab:net_mtu_values}.
\end{itemize}
Quando un pacchetto IP viene inviato su una interfaccia di rete e le sue
\textit{frammentazione}, i pacchetti cioè vengono suddivisi\footnote{questo
accade sia per IPv4 che per IPv6, anche se i pacchetti frammentati sono
gestiti con modalità diverse, IPv4 usa un flag nell'header, IPv6 una
- opportuna opzione, si veda \secref{sec:ipv6_protocol}.}) in blocchi più
+ opportuna opzione, si veda sez.~\ref{sec:ipv6_protocol}.}) in blocchi più
piccoli che possono essere trasmessi attraverso l'interfaccia.
\begin{table}[!htb]
Oltre alla conclusione ``\textsl{normale}'' esiste anche la possibilità di una
conclusione ``\textsl{anomala}'' del programma a causa della ricezione di un
-segnale (si veda \capref{cha:signals}) o della chiamata alla funzione
+segnale (si veda cap.~\ref{cha:signals}) o della chiamata alla funzione
\func{abort}; torneremo su questo in sez.~\ref{sec:proc_termination}.
Il valore di ritorno della funzione \func{main}, o quello usato nelle chiamate
La funzione chiude tutti i file descriptor appartenenti al processo (si tenga
presente che questo non comporta il salvataggio dei dati bufferizzati degli
stream), fa sì che ogni figlio del processo sia ereditato da \cmd{init} (vedi
-sez.~\ref{cha:process_handling}), manda un segnale \const{SIGCHLD} al processo
-padre (vedi sez.~\ref{sec:sig_job_control}) ed infine ritorna lo stato di uscita
-specificato in \param{status} che può essere raccolto usando la funzione
-\func{wait} (vedi sez.~\ref{sec:proc_wait}).
+cap.~\ref{cha:process_handling}), manda un segnale \const{SIGCHLD} al processo
+padre (vedi sez.~\ref{sec:sig_job_control}) ed infine ritorna lo stato di
+uscita specificato in \param{status} che può essere raccolto usando la
+funzione \func{wait} (vedi sez.~\ref{sec:proc_wait}).
\subsection{Le funzioni \func{atexit} e \func{on\_exit}}
Si ricordi infine che un programma può anche essere interrotto dall'esterno
attraverso l'uso di un segnale (modalità di conclusione non mostrata in
fig.~\ref{fig:proc_prog_start_stop}); torneremo su questo aspetto in
-\capref{cha:signals}.
+cap.~\ref{cha:signals}.
2Gb. Con il kernel 2.4 ed il supporto per la \textit{high-memory} il limite
è stato esteso.}
-Come accennato in \capref{cha:intro_unix} questo spazio di indirizzi è
+Come accennato in cap.~\ref{cha:intro_unix} questo spazio di indirizzi è
virtuale e non corrisponde all'effettiva posizione dei dati nella RAM del
computer; in genere detto spazio non è neppure continuo (cioè non tutti gli
indirizzi possibili sono utilizzabili, e quelli usabili non sono
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 \ref{sec:proc_mem_lock}).
+mantenere fisse delle pagine in memoria (vedi sez.~\ref{sec:proc_mem_lock}).
\subsection{La struttura della memoria di un processo}
qualunque processo può a sua volta generarne altri, detti processi figli
(\textit{child process}). Ogni processo è identificato presso il sistema da un
numero univoco, il cosiddetto \textit{process identifier} o, più brevemente,
-\acr{pid}, assegnato in forma progressiva (vedi \secref{sec:proc_pid}) quando
+\acr{pid}, assegnato in forma progressiva (vedi sez.~\ref{sec:proc_pid}) quando
il processo viene creato.
Una seconda caratteristica di un sistema Unix è che la generazione di un
partire tutti gli altri processi necessari al funzionamento del sistema,
inoltre \cmd{init} è essenziale per svolgere una serie di compiti
amministrativi nelle operazioni ordinarie del sistema (torneremo su alcuni di
-essi in \secref{sec:proc_termination}) e non può mai essere terminato. La
+essi in sez.~\ref{sec:proc_termination}) e non può mai essere terminato. La
struttura del sistema comunque consente di lanciare al posto di \cmd{init}
qualunque altro programma, e in casi di emergenza (ad esempio se il file di
\cmd{init} si fosse corrotto) è ad esempio possibile lanciare una shell al suo
possono classificare i processi con la relazione padre/figlio in
un'organizzazione gerarchica ad albero, in maniera analoga a come i file sono
organizzati in un albero di directory (si veda
-\secref{sec:file_organization}); in \figref{fig:proc_tree} si è mostrato il
+sez.~\ref{sec:file_organization}); in fig.~\ref{fig:proc_tree} si è mostrato il
risultato del comando \cmd{pstree} che permette di visualizzare questa
struttura, alla cui base c'è \cmd{init} che è progenitore di tutti gli altri
processi.
\file{linux/sched.h}, ed uno schema semplificato, che riporta la struttura
delle principali informazioni contenute nella \struct{task\_struct} (che in
seguito incontreremo a più riprese), è mostrato in
-\figref{fig:proc_task_struct}.
+fig.~\ref{fig:proc_task_struct}.
\begin{figure}[htb]
\centering
\label{fig:proc_task_struct}
\end{figure}
-Come accennato in \secref{sec:intro_unix_struct} è lo
+Come accennato in sez.~\ref{sec:intro_unix_struct} è lo
\textit{scheduler}\index{scheduler} che decide quale processo mettere in
esecuzione; esso viene eseguito ad ogni system call ed ad ogni
interrupt,\footnote{più in una serie di altre occasioni. NDT completare questa
Hertz.\footnote{Il valore usuale di questa costante è 100, per tutte le
architetture eccetto l'alpha, per la quale è 1000. Occorre fare attenzione a
non confondere questo valore con quello dei clock tick (vedi
- \secref{sec:sys_unix_time}).}
+ sez.~\ref{sec:sys_unix_time}).}
%Si ha cioè un interrupt dal timer ogni centesimo di secondo.
Ogni volta che viene eseguito, lo \textit{scheduler}\index{scheduler} effettua
il calcolo delle priorità dei vari processi attivi (torneremo su questo in
-\secref{sec:proc_priority}) e stabilisce quale di essi debba essere posto in
+sez.~\ref{sec:proc_priority}) e stabilisce quale di essi debba essere posto in
esecuzione fino alla successiva invocazione.
\textsl{figlio}) creato dalla \func{fork} è una copia identica del processo
processo originale (detto \textsl{padre}), ma ha un nuovo \acr{pid} e viene
eseguito in maniera indipendente (le differenze fra padre e figlio sono
-affrontate in dettaglio in \secref{sec:proc_fork}).
+affrontate in dettaglio in sez.~\ref{sec:proc_fork}).
Se si vuole che il processo padre si fermi fino alla conclusione del processo
figlio questo deve essere specificato subito dopo la \func{fork} chiamando la
funzione \func{wait} o la funzione \func{waitpid} (si veda
-\secref{sec:proc_wait}); queste funzioni restituiscono anche un'informazione
+sez.~\ref{sec:proc_wait}); queste funzioni restituiscono anche un'informazione
abbastanza limitata sulle cause della terminazione del processo figlio.
Quando un processo ha concluso il suo compito o ha incontrato un errore non
risolvibile esso può essere terminato con la funzione \func{exit} (si veda
-quanto discusso in \secref{sec:proc_conclusion}). La vita del processo però
+quanto discusso in sez.~\ref{sec:proc_conclusion}). La vita del processo però
termina solo quando la notifica della sua conclusione viene ricevuta dal
processo padre, a quel punto tutte le risorse allocate nel sistema ad esso
associate vengono rilasciate.
Il \acr{pid} viene assegnato in forma progressiva\footnote{in genere viene
assegnato il numero successivo a quello usato per l'ultimo processo creato,
a meno che questo numero non sia già utilizzato per un altro \acr{pid},
- \acr{pgid} o \acr{sid} (vedi \secref{sec:sess_proc_group}).} ogni volta che
-un nuovo processo viene creato, fino ad un limite che, essendo il \acr{pid} un
-numero positivo memorizzato in un intero a 16 bit, arriva ad un massimo di
-32768. Oltre questo valore l'assegnazione riparte dal numero più basso
-disponibile a partire da un minimo di 300,\footnote{questi valori, fino al
- kernel 2.4.x, sono definiti dalla macro \const{PID\_MAX} in \file{threads.h}
- e direttamente in \file{fork.c}, con il kernel 2.5.x e la nuova interfaccia
- per i thread creata da Ingo Molnar anche il meccanismo di allocazione dei
- \acr{pid} è stato modificato.} che serve a riservare i \acr{pid} più bassi
-ai processi eseguiti direttamente dal kernel. Per questo motivo, come visto
-in \secref{sec:proc_hierarchy}, il processo di avvio (\cmd{init}) ha sempre il
-\acr{pid} uguale a uno.
+ \acr{pgid} o \acr{sid} (vedi sez.~\ref{sec:sess_proc_group}).} ogni volta
+che un nuovo processo viene creato, fino ad un limite che, essendo il
+\acr{pid} un numero positivo memorizzato in un intero a 16 bit, arriva ad un
+massimo di 32768. Oltre questo valore l'assegnazione riparte dal numero più
+basso disponibile a partire da un minimo di 300,\footnote{questi valori, fino
+ al kernel 2.4.x, sono definiti dalla macro \const{PID\_MAX} in
+ \file{threads.h} e direttamente in \file{fork.c}, con il kernel 2.5.x e la
+ nuova interfaccia per i thread creata da Ingo Molnar anche il meccanismo di
+ allocazione dei \acr{pid} è stato modificato.} che serve a riservare i
+\acr{pid} più bassi ai processi eseguiti direttamente dal kernel. Per questo
+motivo, come visto in sez.~\ref{sec:proc_hierarchy}, il processo di avvio
+(\cmd{init}) ha sempre il \acr{pid} uguale a uno.
Tutti i processi inoltre memorizzano anche il \acr{pid} del genitore da cui
sono stati creati, questo viene chiamato in genere \acr{ppid} (da
\bodydesc{Entrambe le funzioni non riportano condizioni di errore.}
\end{functions}
\noindent esempi dell'uso di queste funzioni sono riportati in
-\figref{fig:proc_fork_code}, nel programma \file{ForkTest.c}.
+fig.~\ref{fig:proc_fork_code}, nel programma \file{ForkTest.c}.
Il fatto che il \acr{pid} sia un numero univoco per il sistema lo rende un
candidato per generare ulteriori indicatori associati al processo di cui
diventa possibile garantire l'unicità: ad esempio in alcune implementazioni la
-funzione \func{tmpname} (si veda \secref{sec:file_temp_file}) usa il \acr{pid}
-per generare un pathname univoco, che non potrà essere replicato da un altro
-processo che usi la stessa funzione.
+funzione \func{tmpname} (si veda sez.~\ref{sec:file_temp_file}) usa il
+\acr{pid} per generare un pathname univoco, che non potrà essere replicato da
+un altro processo che usi la stessa funzione.
Tutti i processi figli dello stesso processo padre sono detti
\textit{sibling}, questa è una delle relazioni usate nel \textsl{controllo di
sessione}, in cui si raggruppano i processi creati su uno stesso terminale,
o relativi allo stesso login. Torneremo su questo argomento in dettaglio in
-\secref{cha:session}, dove esamineremo gli altri identificativi associati ad
+cap.~\ref{cha:session}, dove esamineremo gli altri identificativi associati ad
un processo e le varie relazioni fra processi utilizzate per definire una
sessione.
Oltre al \acr{pid} e al \acr{ppid}, (e a quelli che vedremo in
-\secref{sec:sess_proc_group}, relativi al controllo di sessione), ad ogni
+sez.~\ref{sec:sess_proc_group}, relativi al controllo di sessione), ad ogni
processo vengono associati degli altri identificatori che vengono usati per il
controllo di accesso. Questi servono per determinare se un processo può
eseguire o meno le operazioni richieste, a seconda dei privilegi e
dell'identità di chi lo ha posto in esecuzione; l'argomento è complesso e sarà
-affrontato in dettaglio in \secref{sec:proc_perms}.
+affrontato in dettaglio in sez.~\ref{sec:proc_perms}.
\subsection{La funzione \func{fork}}
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, stack e dati (vedi
-\secref{sec:proc_mem_layout}), ed esegue esattamente lo stesso codice del
+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.
avere più figli, ed il valore di ritorno di \func{fork} è l'unico modo che gli
permette di identificare quello appena creato; al contrario un figlio ha
sempre un solo padre (il cui \acr{pid} può sempre essere ottenuto con
-\func{getppid}, vedi \secref{sec:proc_pid}) per cui si usa il valore nullo,
+\func{getppid}, vedi sez.~\ref{sec:proc_pid}) per cui si usa il valore nullo,
che non è il \acr{pid} di nessun processo.
\begin{figure}[!htb]
sono già troppi processi nel sistema (il che di solito è sintomo che
qualcos'altro non sta andando per il verso giusto) o si è ecceduto il limite
sul numero totale di processi permessi all'utente (vedi
-\secref{sec:sys_resource_limit}, ed in particolare
-\tabref{tab:sys_rlimit_values}).
+sez.~\ref{sec:sys_resource_limit}, ed in particolare
+tab.~\ref{tab:sys_rlimit_values}).
L'uso di \func{fork} avviene secondo due modalità principali; la prima è
quella in cui all'interno di un programma si creano processi figli cui viene
affidata l'esecuzione di una certa sezione di codice, mentre il processo padre
ne esegue un'altra. È il caso tipico dei programmi server (il modello
-\textit{client-server} è illustrato in \secref{sec:net_cliserv}) in cui il
+\textit{client-server} è illustrato in sez.~\ref{sec:net_cliserv}) in cui il
padre riceve ed accetta le richieste da parte dei programmi client, per
ciascuna delle quali pone in esecuzione un figlio che è incaricato di fornire
il servizio.
La seconda modalità è quella in cui il processo vuole eseguire un altro
programma; questo è ad esempio il caso della shell. In questo caso il processo
crea un figlio la cui unica operazione è quella di fare una \func{exec} (di
-cui parleremo in \secref{sec:proc_exec}) subito dopo la \func{fork}.
+cui parleremo in sez.~\ref{sec:proc_exec}) subito dopo la \func{fork}.
Alcuni sistemi operativi (il VMS ad esempio) combinano le operazioni di questa
seconda modalità (una \func{fork} seguita da una \func{exec}) in un'unica
relativamente facile intervenire sulle le modalità di esecuzione del nuovo
programma.
-In \figref{fig:proc_fork_code} è riportato il corpo del codice del programma
+In fig.~\ref{fig:proc_fork_code} è riportato il corpo del codice del programma
di esempio \cmd{forktest}, che permette di illustrare molte caratteristiche
dell'uso della funzione \func{fork}. Il programma crea un numero di figli
specificato da linea di comando, e prende anche alcune opzioni per indicare
occorrerà provvedere ad espliciti meccanismi di sincronizzazione, pena il
rischio di incorrere nelle cosiddette
\textit{race condition}\index{race condition}
-(vedi \secref{sec:proc_race_cond}).
+(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
che come si vede è completamente diverso da quanto ottenevamo sul terminale.
Il comportamento delle varie funzioni di interfaccia con i file è analizzato
-in gran dettaglio in \capref{cha:file_unix_interface} e in
-\secref{cha:files_std_interface}. Qui basta accennare che si sono usate le
+in gran dettaglio in cap.~\ref{cha:file_unix_interface} e in
+cap.~\ref{cha:files_std_interface}. Qui basta accennare che si sono usate le
funzioni standard della libreria del C che prevedono l'output bufferizzato; e
-questa bufferizzazione (trattata in dettaglio in \secref{sec:file_buffering})
+questa bufferizzazione (trattata in dettaglio in sez.~\ref{sec:file_buffering})
varia a seconda che si tratti di un file su disco (in cui il buffer viene
scaricato su disco solo quando necessario) o di un terminale (nel qual caso il
buffer viene scaricato ad ogni carattere di a capo).
valido anche per l'esempio precedente, ma meno evidente: il fatto cioè che non
solo processi diversi possono scrivere in contemporanea sullo stesso file
(l'argomento della condivisione dei file è trattato in dettaglio in
-\secref{sec:file_sharing}), ma anche che, a differenza di quanto avviene per
+sez.~\ref{sec:file_sharing}), ma anche che, a differenza di quanto avviene per
le variabili, la posizione corrente sul file è condivisa fra il padre e tutti
i processi figli.
lo stesso avviene anche per tutti i figli; la funzione \func{fork} infatti ha
la caratteristica di duplicare nei figli tutti i file descriptor aperti nel
padre (allo stesso modo in cui lo fa la funzione \func{dup}, trattata in
-\secref{sec:file_dup}), il che comporta che padre e figli condividono le
+sez.~\ref{sec:file_dup}), il che comporta che padre e figli condividono le
stesse voci della \textit{file table} (per la spiegazione di questi termini si
-veda \secref{sec:file_sharing}) fra cui c'è anche la posizione corrente nel
+veda sez.~\ref{sec:file_sharing}) fra cui c'è anche la posizione corrente nel
file.
In questo modo se un processo scrive sul file aggiornerà la posizione corrente
\begin{itemize*}
\item i file aperti e gli eventuali flag di
\textit{close-on-exec}\index{close-on-exec} impostati (vedi
- \secref{sec:proc_exec} e \secref{sec:file_fcntl}).
+ 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
- \secref{sec:proc_access_id}).
+ 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
- \secref{sec:sess_proc_group}).
+ sez.~\ref{sec:sess_proc_group}).
\item la directory di lavoro e la directory radice (vedi
- \secref{sec:file_work_dir} e \secref{sec:file_chroot}).
-\item la maschera dei permessi di creazione (vedi \secref{sec:file_umask}).
-\item la maschera dei segnali bloccati (vedi \secref{sec:sig_sigmask}) e le
- azioni installate (vedi \secref{sec:sig_gen_beha}).
+ sez.~\ref{sec:file_work_dir} e sez.~\ref{sec:file_chroot}).
+\item la maschera dei permessi di creazione (vedi sez.~\ref{sec:file_umask}).
+\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
- \secref{sec:ipc_sysv_shm}).
-\item i limiti sulle risorse (vedi \secref{sec:sys_resource_limit}).
-\item le variabili di ambiente (vedi \secref{sec:proc_environ}).
+ sez.~\ref{sec:ipc_sysv_shm}).
+\item i limiti sulle risorse (vedi sez.~\ref{sec:sys_resource_limit}).
+\item le variabili di ambiente (vedi sez.~\ref{sec:proc_environ}).
\end{itemize*}
le differenze fra padre e figlio dopo la \func{fork} invece sono:
\begin{itemize*}
\item il \acr{ppid} (\textit{parent process id}), quello del figlio viene
impostato al \acr{pid} del padre.
\item i valori dei tempi di esecuzione della struttura \struct{tms} (vedi
- \secref{sec:sys_cpu_times}) che nel figlio sono posti a zero.
-\item i \textit{lock} sui file (vedi \secref{sec:file_locking}), che non
+ sez.~\ref{sec:sys_cpu_times}) che nel figlio sono posti a zero.
+\item i \textit{lock} sui file (vedi sez.~\ref{sec:file_locking}), che non
vengono ereditati dal figlio.
-\item gli allarmi ed i segnali pendenti (vedi \secref{sec:sig_gen_beha}), che
+\item gli allarmi ed i segnali pendenti (vedi sez.~\ref{sec:sig_gen_beha}), che
per il figlio vengono cancellati.
\end{itemize*}
\subsection{La conclusione di un processo.}
\label{sec:proc_termination}
-In \secref{sec:proc_conclusion} abbiamo già affrontato le modalità con cui
+In sez.~\ref{sec:proc_conclusion} abbiamo già affrontato le modalità con cui
chiudere un programma, ma dall'interno del programma stesso; avendo a che fare
con un sistema multitasking resta da affrontare l'argomento dal punto di vista
di come il sistema gestisce la conclusione dei processi.
-Abbiamo visto in \secref{sec:proc_conclusion} le tre modalità con cui un
+Abbiamo visto in sez.~\ref{sec:proc_conclusion} le tre modalità con cui un
programma viene terminato in maniera normale: la chiamata di \func{exit} (che
esegue le funzioni registrate per l'uscita e chiude gli stream), il ritorno
dalla funzione \func{main} (equivalente alla chiamata di \func{exit}), e la
\item ad ogni processo figlio viene assegnato un nuovo padre (in genere
\cmd{init}).
\item viene inviato il segnale \const{SIGCHLD} al processo padre (vedi
- \secref{sec:sig_sigchld}).
+ sez.~\ref{sec:sig_sigchld}).
\item se il processo è un leader di sessione ed il suo terminale di controllo
è quello della sessione viene mandato un segnale di \const{SIGHUP} a tutti i
processi del gruppo di foreground e il terminale di controllo viene
- disconnesso (vedi \secref{sec:sess_ctrl_term}).
+ disconnesso (vedi sez.~\ref{sec:sess_ctrl_term}).
\item se la conclusione di un processo rende orfano un \textit{process
group} ciascun membro del gruppo viene bloccato, e poi gli vengono
inviati in successione i segnali \const{SIGHUP} e \const{SIGCONT}
- (vedi ancora \secref{sec:sess_ctrl_term}).
+ (vedi ancora sez.~\ref{sec:sess_ctrl_term}).
\end{itemize*}
Oltre queste operazioni è però necessario poter disporre di un meccanismo
scelto consiste nel riportare lo stato di terminazione (il cosiddetto
\textit{termination status}) al processo padre.
-Nel caso di conclusione normale, abbiamo visto in \secref{sec:proc_conclusion}
-che lo stato di uscita del processo viene caratterizzato tramite il valore del
-cosiddetto \textit{exit status}, cioè il valore passato alle funzioni
-\func{exit} o \func{\_exit} (o dal valore di ritorno per \func{main}). Ma se
-il processo viene concluso in maniera anomala il programma non può specificare
-nessun \textit{exit status}, ed è il kernel che deve generare autonomamente il
-\textit{termination status} per indicare le ragioni della conclusione anomala.
+Nel caso di conclusione normale, abbiamo visto in
+sez.~\ref{sec:proc_conclusion} che lo stato di uscita del processo viene
+caratterizzato tramite il valore del cosiddetto \textit{exit status}, cioè il
+valore passato alle funzioni \func{exit} o \func{\_exit} (o dal valore di
+ritorno per \func{main}). Ma se il processo viene concluso in maniera anomala
+il programma non può specificare nessun \textit{exit status}, ed è il kernel
+che deve generare autonomamente il \textit{termination status} per indicare le
+ragioni della conclusione anomala.
Si noti la distinzione fra \textit{exit status} e \textit{termination status}:
quello che contraddistingue lo stato di chiusura del processo e viene
riportato attraverso le funzioni \func{wait} o \func{waitpid} (vedi
-\secref{sec:proc_wait}) è sempre quest'ultimo; in caso di conclusione normale
+sez.~\ref{sec:proc_wait}) è sempre quest'ultimo; in caso di conclusione normale
il kernel usa il primo (nel codice eseguito da \func{\_exit}) per produrre il
secondo.
Questo viene fatto mantenendo attiva la voce nella tabella dei processi, e
memorizzando alcuni dati essenziali, come il \acr{pid}, i tempi di CPU usati
-dal processo (vedi \secref{sec:sys_unix_time}) e lo stato di terminazione,
+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
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 \tabref{tab:proc_proc_states}). Quando il
-padre effettuerà la lettura dello stato di uscita anche questa informazione,
-non più necessaria, verrà scartata e la terminazione potrà dirsi completamente
-conclusa.
+colonna che ne indica lo stato (vedi tab.~\ref{tab:proc_proc_states}). Quando
+il padre effettuerà la lettura dello stato di uscita anche questa
+informazione, non più necessaria, verrà scartata e la terminazione potrà dirsi
+completamente conclusa.
Possiamo utilizzare il nostro programma di prova per analizzare anche questa
condizione: lanciamo il comando \cmd{forktest} in background, indicando al
a lungo e creare molti figli. In questo caso si deve sempre avere cura di far
leggere l'eventuale stato di uscita di tutti i figli (in genere questo si fa
attraverso un apposito \textit{signal handler}, che chiama la funzione
-\func{wait}, vedi \secref{sec:sig_sigchld} e \secref{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.
+\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.
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
Al ritorno della funzione lo stato di terminazione del figlio viene salvato
nella variabile puntata da \param{status} e tutte le risorse del kernel
-relative al processo (vedi \secref{sec:proc_termination}) vengono rilasciate.
+relative al processo (vedi sez.~\ref{sec:proc_termination}) vengono rilasciate.
Nel caso un processo abbia più figli il valore di ritorno (il \acr{pid} del
figlio) permette di identificare qual'è quello che è uscito.
Per questo motivo lo standard POSIX.1 ha introdotto la funzione
\funcd{waitpid} che effettua lo stesso servizio, ma dispone di una serie di
funzionalità più ampie, legate anche al controllo di sessione (si veda
-\secref{sec:sess_job_control}). Dato che è possibile ottenere lo stesso
+sez.~\ref{sec:sess_job_control}). Dato che è possibile ottenere lo stesso
comportamento di \func{wait} si consiglia di utilizzare sempre questa
funzione, il cui prototipo è:
\begin{functions}
possibilità si specificare un'opzione \const{WNOHANG} che ne previene il
blocco; inoltre \func{waitpid} può specificare in maniera flessibile quale
processo attendere, sulla base del valore fornito dall'argomento \param{pid},
-secondo lo specchietto riportato in \tabref{tab:proc_waidpid_pid}.
+secondo lo specchietto riportato in tab.~\ref{tab:proc_waidpid_pid}.
\begin{table}[!htb]
\centering
\hline
\hline
$<-1$& -- & attende per un figlio il cui \textit{process group} (vedi
- \secref{sec:sess_proc_group}) è uguale al
+ sez.~\ref{sec:sess_proc_group}) è uguale al
valore assoluto di \param{pid}. \\
$-1$ & \const{WAIT\_ANY} & attende per un figlio qualsiasi, usata in
questa maniera è equivalente a \func{wait}.\\
come maschera binaria ottenuta con l'OR delle suddette costanti con zero.
In genere si utilizza \const{WUNTRACED} all'interno del controllo di sessione,
-(l'argomento è trattato in \secref{sec:sess_job_control}). In tal caso infatti
-la funzione ritorna, restituendone il \acr{pid}, quando c'è un processo figlio
-che è entrato in stato di sleep (vedi \tabref{tab:proc_proc_states}) e del
-quale non si è ancora letto lo stato (con questa stessa opzione). In Linux
-sono previste altre opzioni non standard relative al comportamento con i
-thread, che riprenderemo in \secref{sec:thread_xxx}.
+(l'argomento è trattato in sez.~\ref{sec:sess_job_control}). In tal caso
+infatti la funzione ritorna, restituendone il \acr{pid}, quando c'è un
+processo figlio che è entrato in stato di sleep (vedi
+tab.~\ref{tab:proc_proc_states}) e del quale non si è ancora letto lo stato
+(con questa stessa opzione). In Linux sono previste altre opzioni non standard
+relative al comportamento con i thread, che riprenderemo in
+sez.~\ref{sec:thread_xxx}.
La terminazione di un processo figlio è chiaramente un evento asincrono
rispetto all'esecuzione di un programma e può avvenire in un qualunque
momento. Per questo motivo, come accennato nella sezione precedente, una delle
azioni prese dal kernel alla conclusione di un processo è quella di mandare un
segnale di \const{SIGCHLD} al padre. L'azione predefinita (si veda
-\secref{sec:sig_base}) per questo segnale è di essere ignorato, ma la sua
+sez.~\ref{sec:sig_base}) per questo segnale è di essere ignorato, ma la sua
generazione costituisce il meccanismo di comunicazione asincrona con cui il
kernel avverte il processo padre che uno dei suoi figli è terminato.
\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 \secref{sec:sig_example}). In questo caso infatti, dato che il segnale è
+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à.
\val{WIFEXITED} ha restituito un valore non nullo.\\
\macro{WIFSIGNALED(s)} & Vera se il processo figlio è terminato
in maniera anomala a causa di un segnale che non è stato catturato (vedi
- \secref{sec:sig_notification}).\\
+ sez.~\ref{sec:sig_notification}).\\
\macro{WTERMSIG(s)} & restituisce il numero del segnale che ha causato
la terminazione anomala del processo. Può essere valutata solo se
\val{WIFSIGNALED} ha restituito un valore non nullo.\\
Lo standard POSIX.1 definisce una serie di macro di preprocessore da usare per
analizzare lo stato di uscita. Esse sono definite sempre in
-\file{<sys/wait.h>} ed elencate in \tabref{tab:proc_status_macro} (si tenga
+\file{<sys/wait.h>} ed elencate in tab.~\ref{tab:proc_status_macro} (si tenga
presente che queste macro prendono come parametro la variabile di tipo
\ctyp{int} puntata da \param{status}).
Si tenga conto che nel caso di conclusione anomala il valore restituito da
\val{WTERMSIG} può essere confrontato con le costanti definite in
-\file{signal.h} ed elencate in \tabref{tab:sig_signal_list}, e stampato usando
-le apposite funzioni trattate in \secref{sec:sig_strsignal}.
+\file{signal.h} ed elencate in tab.~\ref{tab:sig_signal_list}, e stampato
+usando le apposite funzioni trattate in sez.~\ref{sec:sig_strsignal}.
\subsection{Le funzioni \func{wait3} e \func{wait4}}
\noindent
la struttura \struct{rusage} è definita in \file{sys/resource.h}, e viene
utilizzata anche dalla funzione \func{getrusage} (vedi
-\secref{sec:sys_resource_use}) per ottenere le risorse di sistema usate da un
-processo; la sua definizione è riportata in \figref{fig:sys_rusage_struct}.
+sez.~\ref{sec:sys_resource_use}) per ottenere le risorse di sistema usate da un
+processo; la sua definizione è riportata in fig.~\ref{fig:sys_rusage_struct}.
\subsection{Le funzioni \func{exec}}
Ci sono sei diverse versioni di \func{exec} (per questo la si è chiamata
famiglia di funzioni) che possono essere usate per questo compito, in realtà
-(come mostrato in \figref{fig:proc_exec_relat}), sono tutte un front-end a
+(come mostrato in fig.~\ref{fig:proc_exec_relat}), sono tutte un front-end a
\funcd{execve}. Il prototipo di quest'ultima è:
\begin{prototype}{unistd.h}
{int execve(const char *filename, char *const argv[], char *const envp[])}
\end{functions}
Per capire meglio le differenze fra le funzioni della famiglia si può fare
-riferimento allo specchietto riportato in \tabref{tab:proc_exec_scheme}. La
+riferimento allo specchietto riportato in tab.~\ref{tab:proc_exec_scheme}. La
prima differenza riguarda le modalità di passaggio dei parametri che poi
andranno a costituire gli argomenti a linea di comando (cioè i valori di
\param{argv} e \param{argc} visti dalla funzione \func{main} del programma
Con lo mnemonico \code{e} vengono indicate quelle funzioni che necessitano di
un vettore di parametri \var{envp[]} analogo a quello usato per gli argomenti
a riga di comando (terminato quindi da un \val{NULL}), le altre usano il
-valore della variabile \var{environ} (vedi \secref{sec:proc_environ}) del
+valore della variabile \var{environ} (vedi sez.~\ref{sec:proc_environ}) del
processo di partenza per costruire l'ambiente.
Oltre a mantenere lo stesso \acr{pid}, il nuovo programma fatto partire da
\item il \textit{process id} (\acr{pid}) ed il \textit{parent process id}
(\acr{ppid}).
\item l'\textsl{user-ID reale}, il \textit{group-ID reale} ed i
- \textsl{group-ID supplementari} (vedi \secref{sec:proc_access_id}).
+ \textsl{group-ID supplementari} (vedi sez.~\ref{sec:proc_access_id}).
\item il \textit{session id} (\acr{sid}) ed il \textit{process group-ID}
- (\acr{pgid}), vedi \secref{sec:sess_proc_group}.
-\item il terminale di controllo (vedi \secref{sec:sess_ctrl_term}).
-\item il tempo restante ad un allarme (vedi \secref{sec:sig_alarm_abort}).
+ (\acr{pgid}), vedi sez.~\ref{sec:sess_proc_group}.
+\item il terminale di controllo (vedi sez.~\ref{sec:sess_ctrl_term}).
+\item il tempo restante ad un allarme (vedi sez.~\ref{sec:sig_alarm_abort}).
\item la directory radice e la directory di lavoro corrente (vedi
- \secref{sec:file_work_dir}).
+ sez.~\ref{sec:file_work_dir}).
\item la maschera di creazione dei file (\var{umask}, vedi
- \secref{sec:file_umask}) ed i \textit{lock} sui file (vedi
- \secref{sec:file_locking}).
+ sez.~\ref{sec:file_umask}) ed i \textit{lock} sui file (vedi
+ sez.~\ref{sec:file_locking}).
\item i segnali sospesi (\textit{pending}) e la maschera dei segnali (si veda
- \secref{sec:sig_sigmask}).
-\item i limiti sulle risorse (vedi \secref{sec:sys_resource_limit}).
+ sez.~\ref{sec:sig_sigmask}).
+\item i limiti sulle risorse (vedi sez.~\ref{sec:sys_resource_limit}).
\item i valori delle variabili \var{tms\_utime}, \var{tms\_stime},
- \var{tms\_cutime}, \var{tms\_ustime} (vedi \secref{sec:sys_cpu_times}).
+ \var{tms\_cutime}, \var{tms\_ustime} (vedi sez.~\ref{sec:sys_cpu_times}).
\end{itemize*}
Inoltre i segnali che sono stati impostati per essere ignorati nel processo
gli altri segnali vengono impostati alla loro azione predefinita. Un caso
speciale è il segnale \const{SIGCHLD} che, quando impostato a
\const{SIG\_IGN}, può anche non essere reimpostato a \const{SIG\_DFL} (si veda
-\secref{sec:sig_gen_beha}).
+sez.~\ref{sec:sig_gen_beha}).
La gestione dei file aperti dipende dal valore che ha il flag di
\textit{close-on-exec}\index{close-on-exec} (vedi anche
-\secref{sec:file_fcntl}) per ciascun file descriptor. I file per cui è
+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
attraverso una \func{exec}, a meno di una chiamata esplicita a \func{fcntl}
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 \secref{sec:file_dir_read}) che effettua da sola
+\func{opendir} (vedi sez.~\ref{sec:file_dir_read}) che effettua da sola
l'impostazione del flag di \textit{close-on-exec}\index{close-on-exec} sulle
directory che apre, in maniera trasparente all'utente.
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 \secref{sec:proc_access_id}), tranne
+di questi identificatori è trattato in sez.~\ref{sec:proc_access_id}), tranne
quando il file che si va ad eseguire abbia o il \acr{suid} bit o lo \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 dettagli vedi \secref{sec:proc_perms}).
+gruppo cui il file appartiene (per i dettagli vedi sez.~\ref{sec:proc_perms}).
Se il file da eseguire è in formato \emph{a.out} e necessita di librerie
condivise, viene lanciato il \textit{linker} dinamico \cmd{ld.so} prima del
\subsection{Gli identificatori del controllo di accesso}
\label{sec:proc_access_id}
-Come accennato in \secref{sec:intro_multiuser} il modello base\footnote{in
+Come accennato in sez.~\ref{sec:intro_multiuser} il modello base\footnote{in
realtà già esistono estensioni di questo modello base, che lo rendono più
flessibile e controllabile, come le \textit{capabilities}, le ACL per i file
o il \textit{Mandatory Access Control} di SELinux; inoltre basandosi sul
identificatori univoci, lo user-ID ed il group-ID; questi servono al kernel per
identificare uno specifico utente o un gruppo di utenti, per poi poter
controllare che essi siano autorizzati a compiere le operazioni richieste. Ad
-esempio in \secref{sec:file_access_control} vedremo come ad ogni file vengano
+esempio in sez.~\ref{sec:file_access_control} vedremo come ad ogni file vengano
associati un utente ed un gruppo (i suoi \textsl{proprietari}, indicati
appunto tramite un \acr{uid} ed un \acr{gid}) che vengono controllati dal
kernel nella gestione dei permessi di accesso.
rispettivamente \textit{real} ed \textit{effective} (cioè \textsl{reali} ed
\textsl{effettivi}). Nel caso di Linux si aggiungono poi altri due gruppi, il
\textit{saved} (\textsl{salvati}) ed il \textit{filesystem} (\textsl{di
- filesystem}), secondo la situazione illustrata in \tabref{tab:proc_uid_gid}.
+ filesystem}), secondo la situazione illustrata in
+tab.~\ref{tab:proc_uid_gid}.
\begin{table}[htb]
\footnotesize
reale}: questi vengono impostati al login ai valori corrispondenti
all'utente con cui si accede al sistema (e relativo gruppo principale).
Servono per l'identificazione dell'utente e normalmente non vengono mai
-cambiati. In realtà vedremo (in \secref{sec:proc_setuid}) che è possibile
+cambiati. In realtà vedremo (in sez.~\ref{sec:proc_setuid}) che è possibile
modificarli, ma solo ad un processo che abbia i privilegi di amministratore;
questa possibilità è usata proprio dal programma \cmd{login} che, una volta
completata la procedura di autenticazione, lancia una shell per la quale
supplementari} dei gruppi dei quali l'utente fa parte). Questi sono invece
gli identificatori usati nella verifiche dei permessi del processo e per il
controllo di accesso ai file (argomento affrontato in dettaglio in
-\secref{sec:file_perm_overview}).
+sez.~\ref{sec:file_perm_overview}).
Questi identificatori normalmente sono identici ai corrispondenti del gruppo
\textit{real} tranne nel caso in cui, come accennato in
-\secref{sec:proc_exec}, il programma che si è posto in esecuzione abbia i bit
+sez.~\ref{sec:proc_exec}, il programma che si è posto in esecuzione abbia i bit
\acr{suid} o \acr{sgid} impostati (il significato di questi bit è affrontato
-in dettaglio in \secref{sec:file_suid_sgid}). In questo caso essi saranno
+in dettaglio in sez.~\ref{sec:file_suid_sgid}). In questo caso essi saranno
impostati all'utente e al gruppo proprietari del file. Questo consente, per
programmi in cui ci sia necessità, di dare a qualunque utente normale
privilegi o permessi di un altro (o dell'amministratore).
L'\textsl{user-ID di filesystem} e il \textsl{group-ID di filesystem} sono
un'estensione introdotta in Linux per rendere più sicuro l'uso di NFS
-(torneremo sull'argomento in \secref{sec:proc_setfsuid}). Essi sono una
+(torneremo sull'argomento in sez.~\ref{sec:proc_setfsuid}). Essi sono una
replica dei corrispondenti identificatori del gruppo \textit{effective}, ai
quali si sostituiscono per tutte le operazioni di verifica dei permessi
-relativi ai file (trattate in \secref{sec:file_perm_overview}). Ogni
+relativi ai file (trattate in sez.~\ref{sec:file_perm_overview}). Ogni
cambiamento effettuato sugli identificatori effettivi viene automaticamente
riportato su di essi, per cui in condizioni normali si può tranquillamente
ignorarne l'esistenza, in quanto saranno del tutto equivalenti ai precedenti.
Le due funzioni che vengono usate per cambiare identità (cioè utente e gruppo
di appartenenza) ad un processo sono rispettivamente \funcd{setuid} e
-\funcd{setgid}; come accennato in \secref{sec:proc_access_id} in Linux esse
+\funcd{setgid}; come accennato in sez.~\ref{sec:proc_access_id} in Linux esse
seguono la semantica POSIX che prevede l'esistenza dell'\textit{user-ID
salvato} e del \textit{group-ID salvato}; i loro prototipi sono:
\begin{functions}
Come accennato l'uso principale di queste funzioni è quello di poter
consentire ad un programma con i bit \acr{suid} o \acr{sgid} impostati (vedi
-\secref{sec:file_suid_sgid}) di riportare l'\textsl{user-ID effettivo} a quello
-dell'utente che ha lanciato il programma, effettuare il lavoro che non
+sez.~\ref{sec:file_suid_sgid}) di riportare l'\textsl{user-ID effettivo} a
+quello dell'utente che ha lanciato il programma, effettuare il lavoro che non
necessita di privilegi aggiuntivi, ed eventualmente tornare indietro.
Come esempio per chiarire l'uso di queste funzioni prendiamo quello con cui
Questo comportamento è corretto per l'uso che ne fa \cmd{login} una volta che
crea una nuova shell per l'utente; ma quando si vuole cambiare soltanto
l'\textsl{user-ID effettivo} del processo per cedere i privilegi occorre
-ricorrere ad altre funzioni (si veda ad esempio \secref{sec:proc_seteuid}).
+ricorrere ad altre funzioni (si veda ad esempio sez.~\ref{sec:proc_seteuid}).
\subsection{Le funzioni \func{setreuid} e \func{setregid}}
\end{functions}
La due funzioni sono analoghe ed il loro comportamento è identico; quanto
-detto per la prima prima riguardo l'user-ID, si applica immediatamente alla
-seconda per il group-ID. I processi non privilegiati possono impostare solo i
-valori del loro user-ID effettivo o reale; valori diversi comportano il
-fallimento della chiamata; l'amministratore invece può specificare un valore
-qualunque. Specificando un argomento di valore -1 l'identificatore
-corrispondente verrà lasciato inalterato.
+detto per la prima riguardo l'user-ID, si applica immediatamente alla seconda
+per il group-ID. I processi non privilegiati possono impostare solo i valori
+del loro user-ID effettivo o reale; valori diversi comportano il fallimento
+della chiamata; l'amministratore invece può specificare un valore qualunque.
+Specificando un argomento di valore -1 l'identificatore corrispondente verrà
+lasciato inalterato.
Con queste funzioni si possono scambiare fra loro gli user-ID reale e
effettivo, e pertanto è possibile implementare un comportamento simile a
Queste funzioni servono per impostare gli identificatori del gruppo
\textit{filesystem} che sono usati da Linux per il controllo dell'accesso ai
-file. Come già accennato in \secref{sec:proc_access_id} Linux definisce
+file. Come già accennato in sez.~\ref{sec:proc_access_id} Linux definisce
questo ulteriore gruppo di identificatori, che in circostanze normali sono
assolutamente equivalenti a quelli del gruppo \textit{effective}, dato che
ogni cambiamento di questi ultimi viene immediatamente riportato su di essi.
gruppi supplementari cui un utente può appartenere. Ogni processo può avere
almeno \const{NGROUPS\_MAX} gruppi supplementari\footnote{il numero massimo di
gruppi secondari può essere ottenuto con \func{sysconf} (vedi
- \secref{sec:sys_sysconf}), leggendo il parametro
+ sez.~\ref{sec:sys_sysconf}), leggendo il parametro
\texttt{\_SC\_NGROUPS\_MAX}.} in aggiunta al gruppo primario; questi vengono
ereditati dal processo padre e possono essere cambiati con queste funzioni.
La funzione legge i gruppi supplementari dell'utente specificato da
\param{user}, eseguendo una scansione del database dei gruppi (si veda
-\secref{sec:sys_user_group}). Ritorna poi in \param{groups} la lista di quelli
-a cui l'utente appartiene. Si noti che \param{ngroups} è passato come
+sez.~\ref{sec:sys_user_group}). Ritorna poi in \param{groups} la lista di
+quelli a cui l'utente appartiene. Si noti che \param{ngroups} è passato come
puntatore perché, qualora il valore specificato sia troppo piccolo, la
funzione ritorna -1, passando indietro il numero dei gruppi trovati.
specificati nel vettore passato con l'argomento \param{list}, di dimensioni
date dall'argomento \param{size}. Il numero massimo di gruppi supplementari è
un parametro di sistema, che può essere ricavato con le modalità spiegate in
-\secref{sec:sys_characteristics}.
+sez.~\ref{sec:sys_characteristics}.
Se invece si vogliono impostare i gruppi supplementari del processo a quelli di
un utente specifico, si può usare \funcd{initgroups} il cui prototipo è:
contrario di altri sistemi (che usano invece il cosiddetto \textit{cooperative
multitasking}) non sono i singoli processi, ma il kernel stesso a decidere
quando la CPU deve essere passata ad un altro processo. Come accennato in
-\secref{sec:proc_hierarchy} questa scelta viene eseguita da una sezione
+sez.~\ref{sec:proc_hierarchy} questa scelta viene eseguita da una sezione
apposita del kernel, lo \textit{scheduler}\index{scheduler}, il cui scopo è
quello di distribuire al meglio il tempo di CPU fra i vari processi.
Tutte queste possibilità sono caratterizzate da un diverso \textsl{stato} del
processo, in Linux un processo può trovarsi in uno degli stati riportati in
-\tabref{tab:proc_proc_states}; ma soltanto i processi che sono nello stato
+tab.~\ref{tab:proc_proc_states}; ma soltanto i processi che sono nello stato
\textit{runnable} concorrono per l'esecuzione. Questo vuol dire che, qualunque
sia la sua priorità, un processo non potrà mai essere messo in esecuzione
fintanto che esso si trova in uno qualunque degli altri stati.
abbia risultati significativi in termini di prestazioni.
Il meccanismo tradizionale di scheduling di Unix (che tratteremo in
-\secref{sec:proc_sched_stand}) è sempre stato basato su delle \textsl{priorità
- dinamiche}, in modo da assicurare che tutti i processi, anche i meno
-importanti, possano ricevere un po' di tempo di CPU. In sostanza quando un
-processo ottiene la CPU la sua priorità viene diminuita. In questo modo alla
-fine, anche un processo con priorità iniziale molto bassa, finisce per avere
-una priorità sufficiente per essere eseguito.
+sez.~\ref{sec:proc_sched_stand}) è sempre stato basato su delle
+\textsl{priorità dinamiche}, in modo da assicurare che tutti i processi, anche
+i meno importanti, possano ricevere un po' di tempo di CPU. In sostanza quando
+un processo ottiene la CPU la sua priorità viene diminuita. In questo modo
+alla fine, anche un processo con priorità iniziale molto bassa, finisce per
+avere una priorità sufficiente per essere eseguito.
Lo standard POSIX.1b però ha introdotto il concetto di \textsl{priorità
assoluta}, (chiamata anche \textsl{priorità statica}, in contrapposizione
eseguiti (cioè nello stato \textit{runnable}). La priorità assoluta viene in
genere indicata con un numero intero, ed un valore più alto comporta una
priorità maggiore. Su questa politica di scheduling torneremo in
-\secref{sec:proc_real_time}.
+sez.~\ref{sec:proc_real_time}.
In generale quello che succede in tutti gli Unix moderni è che ai processi
normali viene sempre data una priorità assoluta pari a zero, e la decisione di
La funzione permette, a seconda del valore di \param{which}, di leggere la
priorità di un processo, di un gruppo di processi (vedi
-\secref{sec:sess_proc_group}) o di un utente, specificando un corrispondente
-valore per \param{who} secondo la legenda di \tabref{tab:proc_getpriority}; un
-valore nullo di quest'ultimo indica il processo, il gruppo di processi o
+sez.~\ref{sec:sess_proc_group}) o di un utente, specificando un corrispondente
+valore per \param{who} secondo la legenda di tab.~\ref{tab:proc_getpriority};
+un valore nullo di quest'ultimo indica il processo, il gruppo di processi o
l'utente correnti.
\begin{table}[htb]
\subsection{Il meccanismo di \textit{scheduling real-time}}
\label{sec:proc_real_time}
-Come spiegato in \secref{sec:proc_sched} lo standard POSIX.1b ha introdotto le
-priorità assolute per permettere la gestione di processi real-time. In realtà
-nel caso di Linux non si tratta di un vero hard real-time, in quanto in
+Come spiegato in sez.~\ref{sec:proc_sched} lo standard POSIX.1b ha introdotto
+le priorità assolute per permettere la gestione di processi real-time. In
+realtà nel caso di Linux non si tratta di un vero hard real-time, in quanto in
presenza di eventuali interrupt il kernel interrompe l'esecuzione di un
processo qualsiasi sia la sua priorità,\footnote{questo a meno che non si
siano installate le patch di RTLinux, RTAI o Adeos, con i quali è possibile
più elevata di un \textit{interrupt handler}.} mentre con l'incorrere in un
page fault\index{page fault} si possono avere ritardi non previsti. Se
l'ultimo problema può essere aggirato attraverso l'uso delle funzioni di
-controllo della memoria virtuale (vedi \secref{sec:proc_mem_lock}), il primo
+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.
La funzione esegue l'impostazione per il processo specificato dall'argomento
\param{pid}; un valore nullo esegue l'impostazione per il processo corrente.
La politica di scheduling è specificata dall'argomento \param{policy} i cui
-possibili valori sono riportati in \tabref{tab:proc_sched_policy}; un valore
+possibili valori sono riportati in tab.~\ref{tab:proc_sched_policy}; un valore
negativo per \param{policy} mantiene la politica di scheduling corrente.
Solo un processo con i privilegi di amministratore può impostare priorità
assolute diverse da zero o politiche \const{SCHED\_FIFO} e \const{SCHED\_RR}.
\end{table}
Il valore della priorità è passato attraverso la struttura
-\struct{sched\_param} (riportata in \figref{fig:sig_sched_param}), il cui solo
-campo attualmente definito è \var{sched\_priority}, che nel caso delle
+\struct{sched\_param} (riportata in fig.~\ref{fig:sig_sched_param}), il cui
+solo campo attualmente definito è \var{sched\_priority}, che nel caso delle
priorità assolute deve essere specificato nell'intervallo fra un valore
massimo ed uno minimo, che nel caso sono rispettivamente 1 e 99 (il valore
zero è legale, ma indica i processi normali).
\end{prototype}
La funzione restituisce il valore (secondo quanto elencato in
-\tabref{tab:proc_sched_policy}) della politica di scheduling per il processo
+tab.~\ref{tab:proc_sched_policy}) della politica di scheduling per il processo
specificato; se \param{pid} è nullo viene restituito quello del processo
chiamante.
La funzione restituisce il valore dell'intervallo di tempo usato per la
politica \textit{round robin} in una struttura \struct{timespec}, (la cui
-definizione si può trovare in \figref{fig:sys_timeval_struct}).
+definizione si può trovare in fig.~\ref{fig:sys_timeval_struct}).
Come accennato ogni processo che usa lo scheduling real-time può rilasciare
altro processo o dalla ricezione di un segnale; occorre pertanto essere
accorti nei confronti delle possibili
\textit{race condition}\index{race condition} (vedi
-\secref{sec:proc_race_cond}) derivanti da operazioni interrotte in una fase in
-cui non erano ancora state completate.
+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
fare con meccanismi di intercomunicazione (che esamineremo in dettaglio in
-\capref{cha:IPC}) o nelle operazioni con i file (vedremo alcuni esempi in
-\secref{sec:file_atomic}). In questi casi in genere l'uso delle appropriate
+cap.~\ref{cha:IPC}) o nelle operazioni con i file (vedremo alcuni esempi in
+sez.~\ref{sec:file_atomic}). In questi casi in genere l'uso delle appropriate
funzioni di libreria per compiere le operazioni necessarie è garanzia
sufficiente di atomicità in quanto le system call con cui esse sono realizzate
non possono essere interrotte (o subire interferenze pericolose) da altri
sono compiute nello stesso spazio di indirizzi del processo. Per questo, anche
il solo accesso o l'assegnazione di una variabile possono non essere più
operazioni atomiche (torneremo su questi aspetti in
-\secref{sec:sig_control}).
+sez.~\ref{sec:sig_control}).
In questo caso il sistema provvede un tipo di dato, il \type{sig\_atomic\_t},
il cui accesso è assicurato essere atomico. In pratica comunque si può
codice in cui si compiono le operazioni sulle risorse condivise (le cosiddette
\textsl{sezioni critiche}\index{sezioni critiche}) del programma, siano
opportunamente protette da meccanismi di sincronizzazione (torneremo su queste
-problematiche di questo tipo in \capref{cha:IPC}).
+problematiche di questo tipo in cap.~\ref{cha:IPC}).
Un caso particolare di \textit{race condition}\index{race condition} sono poi
i cosiddetti \textit{deadlock}\index{deadlock}, particolarmente gravi in
diventerà perpetua (da cui il nome di \textit{deadlock}\index{deadlock}).
In tutti questi casi è di fondamentale importanza il concetto di atomicità
-visto in \secref{sec:proc_atom_oper}; questi problemi infatti possono essere
+visto in sez.~\ref{sec:proc_atom_oper}; questi problemi infatti possono essere
risolti soltanto assicurandosi, quando essa sia richiesta, che sia possibile
eseguire in maniera atomica le operazioni necessarie.
\chapter{Terminali e sessioni di lavoro}
\label{cha:session}
-I terminali per lungo tempo tempo sono stati l'unico modo per accedere al
-sistema, per questo anche oggi che esistono molte altre interfacce, essi
-continuano a coprire un ruolo particolare, restando strettamente legati al
-funzionamento dell'interfaccia a linea di comando.
+I terminali per lungo tempo sono stati l'unico modo per accedere al sistema,
+per questo anche oggi che esistono molte altre interfacce, essi continuano a
+coprire un ruolo particolare, restando strettamente legati al funzionamento
+dell'interfaccia a linea di comando.
Nella prima parte del capitolo esamineremo i concetti base del sistema delle
sessioni di lavoro, vale a dire il metodo con cui il kernel permette ad un
supporto sia da parte della shell (quasi tutte ormai lo fanno), che da parte
del kernel; in particolare il kernel deve assicurare sia la presenza di un
driver per i terminali abilitato al \textit{job control} che quella dei
-relativi segnali illustrati in \secref{sec:sig_job_control}.
+relativi segnali illustrati in sez.~\ref{sec:sig_job_control}.
In un sistema che supporta il \textit{job control}, una volta completato il
login, l'utente avrà a disposizione una shell dalla quale eseguire i comandi e
potrà iniziare quella che viene chiamata una \textsl{sessione}, che riunisce
-(vedi \secref{sec:sess_proc_group}) tutti i processi eseguiti all'interno
+(vedi sez.~\ref{sec:sess_proc_group}) tutti i processi eseguiti all'interno
dello stesso login (esamineremo tutto il processo in dettaglio in
-\secref{sec:sess_login}).
+sez.~\ref{sec:sess_login}).
Siccome la shell è collegata ad un solo terminale, che viene usualmente
-chiamato \textsl{terminale di controllo}, (vedi \secref{sec:sess_ctrl_term})
+chiamato \textsl{terminale di controllo}, (vedi sez.~\ref{sec:sess_ctrl_term})
un solo comando alla volta (quello che viene detto in \textit{foreground}),
potrà scrivere e leggere dal terminale. La shell però può eseguire anche più
comandi in contemporanea, mandandoli in \textit{background} (aggiungendo una
nella gestione del job control non si può far riferimento ai singoli processi.
Per questo il kernel prevede la possibilità di raggruppare più processi in un
\textit{process group} (detto anche \textsl{raggruppamento di processi}, vedi
-\secref{sec:sess_proc_group}) e la shell farà sì che tutti i processi che
+sez.~\ref{sec:sess_proc_group}) e la shell farà sì che tutti i processi che
originano da una riga di comando appartengano allo stesso raggruppamento, in
modo che le varie funzioni di controllo, ed i segnali inviati dal terminale,
possano fare riferimento ad esso.
\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 \secref{sec:sess_ctrl_term}).
+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
in grado, grazie all'uso di \func{waitpid}, di rilevare sia i processi che
sono terminati, sia i raggruppamenti che sono bloccati (in questo caso usando
l'opzione \const{WUNTRACED}, secondo quanto illustrato in
-\secref{sec:proc_wait}).
+sez.~\ref{sec:proc_wait}).
\subsection{I \textit{process group} e le \textsl{sessioni}}
\label{sec:sess_proc_group}
-Come accennato in \secref{sec:sess_job_control_overview} nel job control i
+Come accennato in sez.~\ref{sec:sess_job_control_overview} nel job control i
processi vengono raggruppati in \textit{process group} e \textit{sessioni};
per far questo vengono utilizzati due ulteriori identificatori (oltre quelli
-visti in \secref{sec:proc_pid}) che il kernel associa a ciascun
+visti in sez.~\ref{sec:proc_pid}) che il kernel associa a ciascun
processo:\footnote{in Linux questi identificatori sono mantenuti nei campi
\var{pgrp} e \var{session} della struttura \struct{task\_struct} definita in
\file{sched.h}.} l'identificatore del \textit{process group} e
è mantenuta in maniera indipendente con un apposito campo \var{leader} in
\struct{task\_struct}.} se il suo \acr{sid} è uguale al suo \acr{pid}) ed
unico componente. Inoltre la funzione distacca il processo da ogni terminale
-di controllo (torneremo sull'argomento in \secref{sec:sess_ctrl_term}) cui
+di controllo (torneremo sull'argomento in sez.~\ref{sec:sess_ctrl_term}) cui
fosse in precedenza associato.
La funzione ha successo soltanto se il processo non è già leader di un
avendo questo lo stesso \acr{pgid} del padre ma un \acr{pid} diverso, non ci
siano possibilità di errore.\footnote{potrebbe sorgere il dubbio che, per il
riutilizzo dei valori dei \acr{pid} fatto nella creazione dei nuovi processi
- (vedi \secref{sec:proc_pid}), il figlio venga ad assumere un valore
+ (vedi sez.~\ref{sec:proc_pid}), il figlio venga ad assumere un valore
corrispondente ad un process group esistente; questo viene evitato dal
kernel che considera come disponibili per un nuovo \acr{pid} solo valori che
non corrispondono ad altri \acr{pid}, \acr{pgid} o \acr{sid} in uso nel
sistema.} Questa funzione viene usata di solito nel processo di login (per i
-dettagli vedi \secref{sec:sess_login}) per raggruppare in una sessione tutti i
-comandi eseguiti da un utente dalla sua shell.
+dettagli vedi sez.~\ref{sec:sess_login}) per raggruppare in una sessione tutti
+i comandi eseguiti da un utente dalla sua shell.
\subsection{Il terminale di controllo e il controllo di sessione}
\label{sec:sess_ctrl_term}
-Come accennato in \secref{sec:sess_job_control_overview}, nel sistema del
+Come accennato in sez.~\ref{sec:sess_job_control_overview}, nel sistema del
\textit{job control} i processi all'interno di una sessione fanno riferimento
ad un terminale di controllo (ad esempio quello su cui si è effettuato il
login), sul quale effettuano le operazioni di lettura e
l'implementazione; in Linux anch'esso viene mantenuto nella solita struttura
\struct{task\_struct}, nel campo \var{tty}.} In generale ogni processo
eredita dal padre, insieme al \acr{pgid} e al \acr{sid} anche il terminale di
-controllo (vedi \secref{sec:proc_fork}). In questo modo tutti processi
+controllo (vedi sez.~\ref{sec:proc_fork}). In questo modo tutti processi
originati dallo stesso leader di sessione mantengono lo stesso terminale di
controllo.
Alla creazione di una nuova sessione con \func{setsid} ogni associazione con
il precedente terminale di controllo viene cancellata, ed il processo che è
divenuto un nuovo leader di sessione dovrà riottenere\footnote{solo quando ciò
- è necessario, cosa che, come vedremo in \secref{sec:sess_daemon}, non è
+ è necessario, cosa che, come vedremo in sez.~\ref{sec:sess_daemon}, non è
sempre vera.}, un terminale di controllo. In generale questo viene fatto
automaticamente dal sistema\footnote{a meno di non avere richiesto
esplicitamente che questo non diventi un terminale di controllo con il flag
- \const{O\_NOCTTY} (vedi \secref{sec:file_open}). In questo Linux segue la
+ \const{O\_NOCTTY} (vedi sez.~\ref{sec:file_open}). In questo Linux segue la
semantica di SVr4; BSD invece richiede che il terminale venga allocato
esplicitamente con una \func{ioctl} con il comando \const{TIOCSCTTY}.}
quando viene aperto il primo terminale (cioè uno dei vari file di dispositivo
\noindent la funzione può essere eseguita con successo solo da
un processo nella stessa sessione e con lo stesso terminale di controllo.
-Come accennato in \secref{sec:sess_job_control_overview}, tutti i processi (e
+Come accennato in sez.~\ref{sec:sess_job_control_overview}, tutti i processi (e
relativi raggruppamenti) che non fanno parte del gruppo di \textit{foreground}
sono detti in \textit{background}; se uno si essi cerca di accedere al
terminale di controllo provocherà l'invio da parte del kernel di uno dei due
segnali \const{SIGTTIN} o \const{SIGTTOU} (a seconda che l'accesso sia stato
in lettura o scrittura) a tutto il suo \textit{process group}; dato che il
comportamento di default di questi segnali (si riveda quanto esposto in
-\secref{sec:sig_job_control}) è di fermare il processo, di norma questo
+sez.~\ref{sec:sig_job_control}) è di fermare il processo, di norma questo
comporta che tutti i membri del gruppo verranno fermati, ma non si avranno
condizioni di errore.\footnote{la shell in genere notifica comunque un
avvertimento, avvertendo la presenza di processi bloccati grazie all'uso di
utilizzando su di esso le combinazioni di tasti speciali (\cmd{C-z},
\cmd{C-c}, \cmd{C-y} e \verb|C-\|) si farà sì che il kernel invii i
corrispondenti segnali (rispettivamente \const{SIGTSTP}, \const{SIGINT},
-\const{SIGQUIT} e \const{SIGTERM}, trattati in \secref{sec:sig_job_control}) a
-tutti i processi del raggruppamento di \textit{foreground}; in questo modo la
-shell può gestire il blocco e l'interruzione dei vari comandi.
+\const{SIGQUIT} e \const{SIGTERM}, trattati in sez.~\ref{sec:sig_job_control})
+a tutti i processi del raggruppamento di \textit{foreground}; in questo modo
+la shell può gestire il blocco e l'interruzione dei vari comandi.
Per completare la trattazione delle caratteristiche del job control legate al
terminale di controllo, occorre prendere in considerazione i vari casi legati
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 \secref{sec:proc_termination}.}
+ \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
del gruppo (gli altri possono derivare dal primo). Alla terminazione del
leader di sessione però avremo che, come visto in
-\secref{sec:proc_termination}, tutti i suoi figli vengono adottati da
+sez.~\ref{sec:proc_termination}, tutti i suoi figli vengono adottati da
\cmd{init}, che è fuori dalla sessione. Questo renderà orfani tutti i process
group creati direttamente dal leader di sessione (a meno di non aver spostato
con \func{setpgid} un processo da un gruppo ad un altro, cosa che di norma non
connessione di rete. Dato che i concetti base sono gli stessi, e dato che alla
fine le differenze sono\footnote{in generale nel caso di login via rete o di
terminali lanciati dall'interfaccia grafica cambia anche il processo da cui
- ha origine l'esecuzione della shell.} nel dispositivo cui il kernel associa i
-file standard (vedi \secref{sec:file_std_descr}) per l'I/O, tratteremo solo il
-caso classico del terminale.
+ ha origine l'esecuzione della shell.} nel dispositivo cui il kernel associa
+i file standard (vedi sez.~\ref{sec:file_std_descr}) per l'I/O, tratteremo
+solo il caso classico del terminale.
-Abbiamo già brevemente illustrato in \secref{sec:intro_kern_and_sys} le
+Abbiamo già brevemente illustrato in sez.~\ref{sec:intro_kern_and_sys} le
modalità con cui il sistema si avvia, e di come, a partire da \cmd{init},
vengano lanciati tutti gli altri processi. Adesso vedremo in maniera più
dettagliata le modalità con cui il sistema arriva a fornire ad un utente la
rimanda alla lettura delle pagine di manuale di \cmd{init} e di
\file{inittab}) quello che comunque viene sempre fatto è di eseguire almeno
una istanza di un programma che permetta l'accesso ad un terminale. Uno schema
-di massima della procedura è riportato in \figref{fig:sess_term_login}.
+di massima della procedura è riportato in fig.~\ref{fig:sess_term_login}.
\begin{figure}[htb]
\centering
Un terminale, che esso sia un terminale effettivo, attaccato ad una seriale o
ad un altro tipo di porta di comunicazione, o una delle console virtuali
-associate allo schermo, viene sempre visto attraverso attraverso un device
-driver che ne presenta un'interfaccia comune su un apposito file di
-dispositivo.
+associate allo schermo, viene sempre visto attraverso un device driver che ne
+presenta un'interfaccia comune su un apposito file di dispositivo.
Per controllare un terminale si usa di solito il programma \cmd{getty} (od una
delle sue varianti), che permette di mettersi in ascolto su uno di questi
A sua volta \cmd{login}, che mantiene i privilegi di amministratore, usa il
nome dell'utente per effettuare una ricerca nel database degli
utenti,\footnote{in genere viene chiamata \func{getpwnam}, che abbiamo visto
- in \secref{sec:sys_user_group}, per leggere la password e gli altri dati dal
- database degli utenti.} e richiede una password. Se l'utente non esiste o se
-la password non corrisponde\footnote{il confronto non viene effettuato con un
- valore in chiaro; quanto immesso da terminale viene invece a sua volta
- criptato, ed è il risultato che viene confrontato con il valore che viene
- mantenuto nel database degli utenti.} la richiesta viene ripetuta un certo
-numero di volte dopo di che \cmd{login} esce ed \cmd{init} provvede a
+ in sez.~\ref{sec:sys_user_group}, per leggere la password e gli altri dati
+ dal database degli utenti.} e richiede una password. Se l'utente non esiste
+o se la password non corrisponde\footnote{il confronto non viene effettuato
+ con un valore in chiaro; quanto immesso da terminale viene invece a sua
+ volta criptato, ed è il risultato che viene confrontato con il valore che
+ viene mantenuto nel database degli utenti.} la richiesta viene ripetuta un
+certo numero di volte dopo di che \cmd{login} esce ed \cmd{init} provvede a
rilanciare un'altra istanza di \func{getty}.
Se invece la password corrisponde \cmd{login} esegue \func{chdir} per settare
valori per le variabili di ambiente, come \texttt{HOME}, \texttt{SHELL}, ecc.
Infine attraverso l'uso di \func{setuid}, \func{setpid} e \func{initgroups}
verrà cambiata l'identità del proprietario del processo, infatti, come
-spiegato in \secref{sec:proc_setuid}, avendo invocato tali funzioni con i
+spiegato in sez.~\ref{sec:proc_setuid}, avendo invocato tali funzioni con i
privilegi di amministratore, tutti gli user-ID ed i group-ID (reali, effettivi
e salvati) saranno settati a quelli dell'utente.
A questo punto \cmd{login} provvederà (fatte salve eventuali altre azioni
iniziali, come la stampa di messaggi di benvenuto o il controllo della posta)
ad eseguire con un'altra \func{exec} la shell, che si troverà con un ambiente
-già pronto con i file standard di \secref{sec:file_std_descr} impostati sul
+già pronto con i file standard di sez.~\ref{sec:file_std_descr} impostati sul
terminale, e pronta, nel ruolo di leader di sessione e di processo di
controllo per il terminale, a gestire l'esecuzione dei comandi come illustrato
-in \secref{sec:sess_job_control_overview}.
+in sez.~\ref{sec:sess_job_control_overview}.
Dato che il processo padre resta sempre \cmd{init} quest'ultimo potrà
provvedere, ricevendo un \const{SIGCHLD} all'uscita della shell quando la
\subsection{Prescrizioni per un programma \textit{daemon}}
\label{sec:sess_daemon}
-Come sottolineato fin da \secref{sec:intro_base_concept}, in un sistema
+Come sottolineato fin da sez.~\ref{sec:intro_base_concept}, in un sistema
unix-like tutte le operazioni sono eseguite tramite processi, comprese quelle
operazioni di sistema (come l'esecuzione dei comandi periodici, o la consegna
della posta, ed in generale tutti i programmi di servizio) che non hanno
un terminale di controllo e mantenuto all'interno di una sessione, e anche se
può essere mandato in background e non eseguire più nessun I/O su terminale,
si avranno comunque tutte le conseguenze che abbiamo appena visto in
-\secref{sec:sess_ctrl_term} (in particolare l'invio dei segnali in
+sez.~\ref{sec:sess_ctrl_term} (in particolare l'invio dei segnali in
corrispondenza dell'uscita del leader di sessione).
Per questo motivo un programma che deve funzionare come demone deve sempre
problema di come fare per la notifica di eventuali errori, non potendosi più
utilizzare lo standard error; per il normale I/O infatti ciascun demone avrà
le sue modalità di interazione col sistema e gli utenti a seconda dei compiti
-e delle funzionalità che sono sono previste; ma gli errori devono normalmente
+e delle funzionalità che sono previste; ma gli errori devono normalmente
essere notificati all'amministratore del sistema.
Una soluzione può essere quella di scrivere gli eventuali messaggi su uno
in un sistema unix-like, viene gestito attraverso un apposito programma,
\cmd{syslogd}, che è anch'esso un \textsl{demone}. In generale i messaggi di
errore vengono raccolti dal file speciale \file{/dev/log}, un
-\textit{socket}\index{socket} locale (vedi \secref{sec:sock_sa_local})
+\textit{socket}\index{socket} locale (vedi sez.~\ref{sec:sock_sa_local})
dedicato a questo scopo, o via rete, con un \textit{socket} UDP, o da un
apposito demone, \cmd{klogd}, che estrae i messaggi del kernel.\footnote{i
messaggi del kernel sono tenuti in un buffer circolare e scritti tramite la
L'argomento è interpretato come una maschera binaria, e pertanto è possibile
inviare i messaggi su più categorie alla volta; i valori delle costanti che
identificano ciascuna categoria sono riportati in
-\tabref{tab:sess_syslog_facility}, il valore di \param{facility} deve essere
+tab.~\ref{tab:sess_syslog_facility}, il valore di \param{facility} deve essere
specificato con un OR aritmetico.
\begin{table}[htb]
funzione \func{openlog} e delle modalità con cui le successive chiamate
scriveranno i messaggi, esso viene specificato come maschera binaria composta
con un OR aritmetico di una qualunque delle costanti riportate in
-\tabref{tab:sess_openlog_option}.
+tab.~\ref{tab:sess_openlog_option}.
\begin{table}[htb]
\footnotesize
Il comportamento della funzione è analogo quello di \func{printf}, e il valore
dell'argomento \param{format} è identico a quello descritto nella pagina di
manuale di quest'ultima (per i valori principali si può vedere la trattazione
-sommaria che se ne è fatto in \secref{sec:file_formatted_io}); l'unica
+sommaria che se ne è fatto in sez.~\ref{sec:file_formatted_io}); l'unica
differenza è che la sequenza \val{\%m} viene rimpiazzata dalla stringa
restituita da \code{strerror(errno)}. Gli argomenti seguenti i primi due
devono essere forniti secondo quanto richiesto da \param{format}.
\param{priority} sono occupati da questo valore, mentre i restanti bit più
significativi vengono usati per specificare la \textit{facility}.}
specificabile attraverso le costanti riportate in
-\secref{tab:sess_syslog_priority}. Nel caso si voglia specificare anche la
+tab.~\ref{tab:sess_syslog_priority}. Nel caso si voglia specificare anche la
\textit{facility} basta eseguire un OR aritmetico del valore della priorità
-con la maschera binaria delle costanti di \tabref{tab:sess_syslog_facility}.
+con la maschera binaria delle costanti di tab.~\ref{tab:sess_syslog_facility}.
\begin{table}[htb]
\footnotesize
registrata. La registrazione viene disabilitata per tutte quelle priorità che
non rientrano nella maschera; questa viene settata usando la macro
\macro{LOG\_MASK(p)} dove \code{p} è una delle costanti di
-\secref{tab:sess_syslog_priority}. É inoltre disponibile anche la macro
+tab.~\ref{tab:sess_syslog_priority}. É inoltre disponibile anche la macro
\macro{LOG\_UPTO(p)} che permette di specificare automaticamente tutte le
priorità fino ad un certo valore.
\label{sec:term_design}
I terminali sono una classe speciale di dispositivi a caratteri (si ricordi la
-classificazione di \secref{sec:file_file_types}); un terminale ha infatti una
+classificazione di sez.~\ref{sec:file_file_types}); un terminale ha infatti una
caratteristica che lo contraddistingue da un qualunque altro dispositivo, e
cioè che è destinato a gestire l'interazione con un utente (deve essere cioè
in grado di fare da terminale di controllo per una sessione), che comporta la
fintanto che non si preme il tasto di ritorno a capo: a questo punto la
linea sarà completa e la funzione ritornerà.} ed in cui alcuni caratteri
vengono interpretati per compiere operazioni (come la generazione dei segnali
-illustrati in \secref{sec:sig_job_control}), questa di norma è la modalità in
+illustrati in sez.~\ref{sec:sig_job_control}), questa di norma è la modalità in
cui funziona la shell.
Un terminale in modo non canonico invece non effettua nessun accorpamento dei
Per capire le caratteristiche dell'I/O sui terminali, occorre esaminare le
modalità con cui esso viene effettuato; l'accesso, come per tutti i
dispositivi, viene gestito da un driver apposito, la cui struttura generica è
-mostrata in \secref{fig:term_struct}. Ad un terminale sono sempre associate
+mostrata in fig.~\ref{fig:term_struct}. Ad un terminale sono sempre associate
due code per gestire l'input e l'output, che ne implementano una
bufferizzazione\footnote{completamente indipendente dalla eventuale ulteriore
bufferizzazione fornita dall'interfaccia standard dei file.} all'interno del
La coda di ingresso mantiene i caratteri che sono stati letti dal terminale ma
non ancora letti da un processo, la sua dimensione è definita dal parametro di
-sistema \const{MAX\_INPUT} (si veda \secref{sec:sys_file_limits}), che ne
+sistema \const{MAX\_INPUT} (si veda sez.~\ref{sec:sys_file_limits}), che ne
specifica il limite minimo, in realtà la coda può essere più grande e cambiare
dimensione dinamicamente. Se è stato abilitato il controllo di flusso in
ingresso il driver emette i caratteri di STOP e START per bloccare e sbloccare
\param{s}. La memoria per contenere la stringa deve essere stata allocata in
precedenza ed essere lunga almeno
\const{L\_ctermid}\footnote{\const{L\_ctermid} è una delle varie costanti del
- sistema, non trattata esplicitamente in \secref{sec:sys_characteristics} che
- indica la dimensione che deve avere una stringa per poter contenere il nome
- di un terminale.} caratteri.
+ sistema, non trattata esplicitamente in sez.~\ref{sec:sys_characteristics}
+ che indica la dimensione che deve avere una stringa per poter contenere il
+ nome di un terminale.} caratteri.
Esiste infine una versione rientrante \funcd{ttyname\_r} della funzione
\func{ttyname}, che non presenta il problema dell'uso di una zona di memoria
I vari attributi vengono mantenuti per ciascun terminale in una struttura
\struct{termios}, (la cui definizione è riportata in
-\figref{fig:term_termios}), usata dalle varie funzioni dell'interfaccia. In
-\figref{fig:term_termios} si sono riportati tutti i campi della definizione
+fig.~\ref{fig:term_termios}), usata dalle varie funzioni dell'interfaccia. In
+fig.~\ref{fig:term_termios} si sono riportati tutti i campi della definizione
usata in Linux; di questi solo i primi cinque sono previsti dallo standard
POSIX.1, ma le varie implementazioni ne aggiungono degli altri per mantenere
ulteriori informazioni.\footnote{la definizione della struttura si trova in
terminale, come il controllo di parità, il controllo di flusso, la gestione
dei caratteri speciali; un elenco dei vari bit, del loro significato e delle
costanti utilizzate per identificarli è riportato in
-\tabref{tab:sess_termios_iflag}.
+tab.~\ref{tab:sess_termios_iflag}.
Si noti come alcuni di questi flag (come quelli per la gestione del flusso)
fanno riferimento a delle caratteristiche che ormai sono completamente
come l'impacchettamento dei caratteri sullo schermo, la traslazione degli a
capo, la conversione dei caratteri speciali; un elenco dei vari bit, del loro
significato e delle costanti utilizzate per identificarli è riportato in
-\tabref{tab:sess_termios_oflag}.
+tab.~\ref{tab:sess_termios_oflag}.
-Si noti come alcuni dei valori riportati in \tabref{tab:sess_termios_oflag}
+Si noti come alcuni dei valori riportati in tab.~\ref{tab:sess_termios_oflag}
fanno riferimento a delle maschere di bit; essi infatti vengono utilizzati per
impostare alcuni valori numerici relativi ai ritardi nell'output di alcuni
caratteri: una caratteristica originaria dei primi terminali su telescrivente,
\const{PARENB} & Se impostato abilita la generazione il controllo di
parità. La reazione in caso di errori dipende dai
relativi valori per \var{c\_iflag}, riportati in
- \tabref{tab:sess_termios_iflag}. Se non è impostato i bit
- di parità non vengono
+ tab.~\ref{tab:sess_termios_iflag}. Se non è impostato i
+ bit di parità non vengono
generati e i caratteri non vengono controllati.\\
\const{PARODD} & Ha senso solo se è attivo anche \const{PARENB}. Se
impostato viene usata una parità è dispari, altrimenti
della parità, il funzionamento del controllo di flusso; esso ha senso solo per
i terminali connessi a linee seriali. Un elenco dei vari bit, del loro
significato e delle costanti utilizzate per identificarli è riportato in
-\tabref{tab:sess_termios_cflag}.
+tab.~\ref{tab:sess_termios_cflag}.
I valori di questo flag sono molto specifici, e completamente indirizzati al
controllo di un terminale mantenuto su una linea seriale; essi pertanto non
seriali all'interno dei flag; come accennato in Linux questo viene fatto
(seguendo l'esempio di BSD) attraverso due campi aggiuntivi, \var{c\_ispeed} e
\var{c\_ospeed}, nella struttura \struct{termios} (mostrati in
-\figref{fig:term_termios}).
+fig.~\ref{fig:term_termios}).
\begin{table}[b!ht]
\footnotesize
driver e l'utente, come abilitare l'eco, gestire i caratteri di controllo e
l'emissione dei segnali, impostare modo canonico o non canonico; un elenco dei
vari bit, del loro significato e delle costanti utilizzate per identificarli è
-riportato in \tabref{tab:sess_termios_lflag}. Con i terminali odierni l'unico
+riportato in tab.~\ref{tab:sess_termios_lflag}. Con i terminali odierni l'unico
flag con cui probabilmente si può avere a che fare è questo, in quanto è con
questo che si impostano le caratteristiche generiche comuni a tutti i
terminali.
vettore, i vari elementi vengono indicizzati attraverso delle opportune
costanti, il cui nome corrisponde all'azione ad essi associata. Un elenco
completo dei caratteri di controllo, con le costanti e delle funzionalità
-associate è riportato in \tabref{tab:sess_termios_cc}, usando quelle
+associate è riportato in tab.~\ref{tab:sess_termios_cc}, usando quelle
definizioni diventa possibile assegnare un nuovo carattere di controllo con un
codice del tipo:
\includecodesnip{listati/value_c_cc.c}
La maggior parte di questi caratteri (tutti tranne \const{VTIME} e
\const{VMIN}) hanno effetto solo quando il terminale viene utilizzato in modo
-canonico; per alcuni devono essere essere soddisfatte ulteriori richieste, ad
-esempio \const{VINTR}, \const{VSUSP}, e \const{VQUIT} richiedono sia settato
+canonico; per alcuni devono essere soddisfatte ulteriori richieste, ad esempio
+\const{VINTR}, \const{VSUSP}, e \const{VQUIT} richiedono sia settato
\const{ISIG}; \const{VSTART} e \const{VSTOP} richiedono sia settato
\const{IXON}; \const{VLNEXT}, \const{VWERASE}, \const{VREPRINT} richiedono sia
settato \const{IEXTEN}. In ogni caso quando vengono attivati i caratteri
specificabili attraverso l'argomento \param{optional\_actions}, che permette
di stabilire come viene eseguito il cambiamento delle impostazioni del
terminale, i valori possibili sono riportati in
-\tabref{tab:sess_tcsetattr_option}; di norma (come fatto per le due funzioni
+tab.~\ref{tab:sess_tcsetattr_option}; di norma (come fatto per le due funzioni
di esempio) si usa sempre \const{TCSANOW}, le altre opzioni possono essere
utili qualora si cambino i parametri di output.
valore corrente delle impostazioni con \func{tcgetattr} per poi modificare i
valori impostati.
-In \figref{fig:term_set_attr} e \figref{fig:term_unset_attr} si è riportato
+In fig.~\ref{fig:term_set_attr} e fig.~\ref{fig:term_unset_attr} si è riportato
rispettivamente il codice delle due funzioni \func{SetTermAttr} e
\func{UnSetTermAttr}, che possono essere usate per impostare o rimuovere, con
le dovute precauzioni, un qualunque bit di \var{c\_lflag}. Il codice di
\subsection{La gestione della disciplina di linea.}
\label{sec:term_line_discipline}
-Come illustrato dalla struttura riportata in \figref{fig:term_struct} tutti i
-terminali hanno un insieme di funzionalità comuni, che prevedono la presenza
+Come illustrato dalla struttura riportata in fig.~\ref{fig:term_struct} tutti
+i terminali hanno un insieme di funzionalità comuni, che prevedono la presenza
di code di ingresso ed uscita; in generale si fa riferimento ad esse con il
-nome di \textsl{discipline di linea}.
+nome di \textsl{discipline di linea}.
Lo standard POSIX prevede alcune funzioni che permettono di intervenire
vengono considerate, dal punto di vista dell'accesso al terminale, come delle
funzioni di scrittura, pertanto se usate da processi in background sul loro
terminale di controllo provocano l'emissione di \const{SIGTTOU} come
-illustrato in \secref{sec:sess_ctrl_term}.\footnote{con la stessa eccezione,
+illustrato in sez.~\ref{sec:sess_ctrl_term}.\footnote{con la stessa eccezione,
già vista per \func{tcsetaddr}, che quest'ultimo sia bloccato o ignorato dal
processo chiamante.}
La funzione agisce sul terminale associato a \param{fd}, l'argomento
\param{queue} permette di specificare su quale coda (ingresso, uscita o
entrambe), operare. Esso può prendere i valori riportati in
-\tabref{tab:sess_tcflush_queue}, nel caso si specifichi la coda di ingresso
+tab.~\ref{tab:sess_tcflush_queue}, nel caso si specifichi la coda di ingresso
cancellerà i dati ricevuti ma non ancora letti, nel caso si specifichi la coda
di uscita cancellerà i dati scritti ma non ancora trasmessi.
flusso dei dati fra il terminale ed il sistema sia in ingresso che in uscita.
Il comportamento della funzione è regolato dall'argomento \param{action}, i
cui possibili valori, e relativa azione eseguita dalla funzione, sono
-riportati in \secref{tab:sess_tcflow_action}.
+riportati in tab.~\ref{tab:sess_tcflow_action}.
\begin{table}[htb]
\footnotesize
\func{read} quando è stata letta una determinata quantità di dati o è passato
un certo tempo.
-Come accennato nella relativa spiegazione in \tabref{tab:sess_termios_cc},
+Come accennato nella relativa spiegazione in tab.~\ref{tab:sess_termios_cc},
TIME e MIN non sono in realtà caratteri ma valori numerici. Il comportamento
del sistema per un terminale in modalità non canonica prevede quattro casi
distinti:
In questo caso è possibile una situazione in cui i segnali possono essere
perduti. Si consideri il segmento di codice riportato in
-\secref{fig:sig_old_handler}, nel programma principale viene installato un
+fig.~\ref{fig:sig_old_handler}, nel programma principale viene installato un
gestore (\texttt{\small 5}), ed in quest'ultimo la prima operazione
(\texttt{\small 11}) è quella di reinstallare se stesso. Se nell'esecuzione
del gestore un secondo segnale arriva prima che esso abbia potuto eseguire la
semantica viene chiamata \textsl{inaffidabile}; infatti la ricezione del
segnale e la reinstallazione del suo gestore non sono operazioni
atomiche, e sono sempre possibili delle race condition\index{race condition}
-(sull'argomento vedi quanto detto in \secref{sec:proc_multi_prog}).
+(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
segnali quando non si vuole che arrivino; i processi possono ignorare il
\textsl{generati} dal kernel per un processo all'occorrenza dell'evento che
causa il segnale. In genere questo viene fatto dal kernel impostando l'apposito
campo della \struct{task\_struct} del processo nella process table (si veda
-\figref{fig:proc_task_struct}).
+fig.~\ref{fig:proc_task_struct}).
Si dice che il segnale viene \textsl{consegnato} al processo (dall'inglese
\textit{delivered}) quando viene eseguita l'azione per esso prevista, mentre
Si tenga presente che il kernel stabilisce cosa fare con un segnale che è
stato bloccato al momento della consegna, non quando viene generato; questo
consente di cambiare l'azione per il segnale prima che esso venga consegnato,
-e si può usare la funzione \func{sigpending} (vedi \secref{sec:sig_sigmask})
+e si può usare la funzione \func{sigpending} (vedi sez.~\ref{sec:sig_sigmask})
per determinare quali segnali sono bloccati e quali sono pendenti.
\end{itemize*}
Un programma può specificare queste scelte usando le due funzioni
-\func{signal} e \func{sigaction} (vedi \secref{sec:sig_signal} e
-\secref{sec:sig_sigaction}). Se si è installato un gestore sarà
+\func{signal} e \func{sigaction} (vedi sez.~\ref{sec:sig_signal} e
+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 race
condition\index{race condition}).
Nel caso non sia stata specificata un'azione, viene utilizzata l'azione
-standard che (come vedremo in \secref{sec:sig_standard}) è propria di ciascun
+standard che (come vedremo in sez.~\ref{sec:sig_standard}) è propria di ciascun
segnale; nella maggior parte dei casi essa porta alla terminazione del
processo, ma alcuni segnali che rappresentano eventi innocui vengono ignorati.
Quando un segnale termina un processo, il padre può determinare la causa della
terminazione esaminando il codice di stato riportato delle funzioni
-\func{wait} e \func{waitpid} (vedi \secref{sec:proc_wait}); questo è il modo
+\func{wait} e \func{waitpid} (vedi sez.~\ref{sec:proc_wait}); questo è il modo
in cui la shell determina i motivi della terminazione di un programma e scrive
un eventuale messaggio di errore.
Il numero totale di segnali presenti è dato dalla macro \const{NSIG}, e dato
che i numeri dei segnali sono allocati progressivamente, essa corrisponde
anche al successivo del valore numerico assegnato all'ultimo segnale definito.
-In \tabref{tab:sig_signal_list} si è riportato l'elenco completo dei segnali
+In tab.~\ref{tab:sig_signal_list} si è riportato l'elenco completo dei segnali
definiti in Linux (estratto dalle pagine di manuale), comparati con quelli
definiti in vari standard.
\hline
\end{tabular}
\caption{Legenda delle azioni predefinite dei segnali riportate in
- \tabref{tab:sig_signal_list}.}
+ tab.~\ref{tab:sig_signal_list}.}
\label{tab:sig_action_leg}
\end{table}
-In \tabref{tab:sig_signal_list} si sono anche riportate le azioni predefinite
+In tab.~\ref{tab:sig_signal_list} si sono anche riportate le azioni predefinite
di ciascun segnale (riassunte con delle lettere, la cui legenda completa è in
-\tabref{tab:sig_action_leg}), quando nessun gestore è installato un
+tab.~\ref{tab:sig_action_leg}), quando nessun gestore è installato un
segnale può essere ignorato o causare la terminazione del processo. Nella
colonna standard sono stati indicati anche gli standard in cui ciascun segnale
-è definito, secondo lo schema di \tabref{tab:sig_standard_leg}.
+è definito, secondo lo schema di tab.~\ref{tab:sig_standard_leg}.
\begin{table}[htb]
\hline
\end{tabular}
\caption{Legenda dei valori della colonna \textbf{Standard} di
- \tabref{tab:sig_signal_list}.}
+ tab.~\ref{tab:sig_signal_list}.}
\label{tab:sig_standard_leg}
\end{table}
avuto successo.
\item[\const{SIGURG}] Questo segnale è inviato quando arrivano dei dati
urgenti o \textit{out-of-band} su di un socket\index{socket}; per maggiori
- dettagli al proposito si veda \secref{sec:TCP_urgent_data}.
+ dettagli al proposito si veda sez.~\ref{sec:TCP_urgent_data}.
\item[\const{SIGPOLL}] Questo segnale è equivalente a \const{SIGIO}, è
definito solo per compatibilità con i sistemi System V.
\end{basedescript}
\begin{basedescript}{\desclabelwidth{2.0cm}}
\item[\const{SIGCHLD}] Questo è il segnale mandato al processo padre quando un
figlio termina o viene fermato. L'azione predefinita è di ignorare il
- segnale, la sua gestione è trattata in \secref{sec:proc_wait}.
+ segnale, la sua gestione è trattata in sez.~\ref{sec:proc_wait}.
\item[\const{SIGCLD}] Per Linux questo è solo un segnale identico al
precedente, il nome è obsoleto e andrebbe evitato.
\item[\const{SIGCONT}] Il nome sta per \textit{continue}. Il segnale viene
se viene fermato e riavviato, come per esempio riscrivere un prompt, o
inviare un avviso.
\item[\const{SIGSTOP}] Il segnale ferma un processo (lo porta cioè in uno
- stato di sleep, vedi \secref{sec:proc_sched}); il segnale non può essere né
+ stato di sleep, vedi sez.~\ref{sec:proc_sched}); il segnale non può essere né
intercettato, né ignorato, né bloccato.
\item[\const{SIGTSTP}] Il nome sta per \textit{interactive stop}. Il segnale
ferma il processo interattivamente, ed è generato dal carattere SUSP
sessione di lavoro in \textit{background}. Quando un processo in background
tenta di leggere da un terminale viene inviato questo segnale a tutti i
processi della sessione di lavoro. L'azione predefinita è di fermare il
- processo. L'argomento è trattato in \secref{sec:sess_job_control_overview}.
+ processo. L'argomento è trattato in
+ sez.~\ref{sec:sess_job_control_overview}.
\item[\const{SIGTTOU}] Segnale analogo al precedente \const{SIGTTIN}, ma
generato quando si tenta di scrivere o modificare uno dei modi del
terminale. L'azione predefinita è di fermare il processo, l'argomento è
- trattato in \secref{sec:sess_job_control_overview}.
+ trattato in sez.~\ref{sec:sess_job_control_overview}.
\end{basedescript}
\item[\const{SIGPIPE}] Sta per \textit{Broken pipe}. Se si usano delle pipe,
(o delle FIFO o dei socket) è necessario, prima che un processo inizi a
scrivere su una di esse, che un'altro l'abbia aperta in lettura (si veda
- \secref{sec:ipc_pipes}). Se il processo in lettura non è partito o è
+ sez.~\ref{sec:ipc_pipes}). Se il processo in lettura non è partito o è
terminato inavvertitamente alla scrittura sulla pipe il kernel genera questo
segnale. Se il segnale è bloccato, intercettato o ignorato la chiamata che
lo ha causato fallisce, restituendo l'errore \errcode{EPIPE}.
situazione precedente.
\item[\const{SIGXCPU}] Sta per \textit{CPU time limit exceeded}. Questo
segnale è generato quando un processo eccede il limite impostato per il
- tempo di CPU disponibile, vedi \secref{sec:sys_resource_limit}.
+ tempo di CPU disponibile, vedi sez.~\ref{sec:sys_resource_limit}.
\item[\const{SIGXFSZ}] Sta per \textit{File size limit exceeded}. Questo
segnale è generato quando un processo tenta di estendere un file oltre le
dimensioni specificate dal limite impostato per le dimensioni massime di un
- file, vedi \secref{sec:sys_resource_limit}.
+ file, vedi sez.~\ref{sec:sys_resource_limit}.
\end{basedescript}
terminazione di un processo figlio o di un gestore che gestisce più segnali);
la prima funzione, \funcd{strsignal}, è una estensione GNU, accessibile avendo
definito \macro{\_GNU\_SOURCE}, ed è analoga alla funzione \func{strerror} (si
-veda \secref{sec:sys_strerror}) per gli errori:
+veda sez.~\ref{sec:sys_strerror}) per gli errori:
\begin{prototype}{string.h}{char *strsignal(int signum)}
Ritorna il puntatore ad una stringa che contiene la descrizione del segnale
\param{signum}.
necessario copiarlo.
La seconda funzione, \funcd{psignal}, deriva da BSD ed è analoga alla funzione
-\func{perror} descritta sempre in \secref{sec:sys_strerror}; il suo prototipo
+\func{perror} descritta sempre in sez.~\ref{sec:sys_strerror}; il suo prototipo
è:
\begin{prototype}{signal.h}{void psignal(int sig, const char *s)}
Stampa sullo standard error un messaggio costituito dalla stringa \param{s},
\subsection{Il comportamento generale del sistema.}
\label{sec:sig_gen_beha}
-Abbiamo già trattato in \secref{sec:sig_intro} le modalità con cui il sistema
+Abbiamo già trattato in sez.~\ref{sec:sig_intro} le modalità con cui il sistema
gestisce l'interazione fra segnali e processi, ci resta da esaminare però il
comportamento delle system call; in particolare due di esse, \func{fork} ed
\func{exec}, dovranno essere prese esplicitamente in considerazione, data la
loro stretta relazione con la creazione di nuovi processi.
-Come accennato in \secref{sec:proc_fork} quando viene creato un nuovo processo
-esso eredita dal padre sia le azioni che sono state impostate per i singoli
-segnali, che la maschera dei segnali bloccati (vedi \secref{sec:sig_sigmask}).
-Invece tutti i segnali pendenti e gli allarmi vengono cancellati; essi infatti
-devono essere recapitati solo al padre, al figlio dovranno arrivare solo i
-segnali dovuti alle sue azioni.
+Come accennato in sez.~\ref{sec:proc_fork} quando viene creato un nuovo
+processo esso eredita dal padre sia le azioni che sono state impostate per i
+singoli segnali, che la maschera dei segnali bloccati (vedi
+sez.~\ref{sec:sig_sigmask}). Invece tutti i segnali pendenti e gli allarmi
+vengono cancellati; essi infatti devono essere recapitati solo al padre, al
+figlio dovranno arrivare solo i segnali dovuti alle sue azioni.
Quando si mette in esecuzione un nuovo programma con \func{exec} (si ricordi
-quanto detto in \secref{sec:proc_exec}) tutti i segnali per i quali è stato
+quanto detto in sez.~\ref{sec:proc_exec}) tutti i segnali per i quali è stato
installato un gestore vengono reimpostati a \const{SIG\_DFL}. Non ha più
senso infatti fare riferimento a funzioni definite nel programma originario,
che non sono presenti nello spazio di indirizzi del nuovo programma.
\item la scrittura sugli stessi file, nel caso in cui dati non possano essere
accettati immediatamente.
\item l'apertura di un file di dispositivo che richiede operazioni non
- immediate per una una risposta.
+ immediate per una risposta.
\item le operazioni eseguite con \func{ioctl} che non è detto possano essere
eseguite immediatamente.
\item le funzioni di intercomunicazione che si bloccano in attesa di risposte
Linux e le \acr{glibc} consentono di utilizzare entrambi gli approcci,
attraverso una opportuna opzione di \func{sigaction} (vedi
-\secref{sec:sig_sigaction}). È da chiarire comunque che nel caso di
+sez.~\ref{sec:sig_sigaction}). È da chiarire comunque che nel caso di
interruzione nel mezzo di un trasferimento parziale di dati, le system call
ritornano sempre indicando i byte trasferiti.
comportamento, pur mantenendone immutato il prototipo\footnote{in realtà in
alcune vecchie implementazioni (SVr4 e 4.3+BSD in particolare) vengono usati
alcuni parametri aggiuntivi per definire il comportamento della funzione,
- vedremo in \secref{sec:sig_sigaction} che questo è possibile usando la
+ vedremo in sez.~\ref{sec:sig_sigaction} che questo è possibile usando la
funzione \func{sigaction}.} che è:
\begin{prototype}{signal.h}
{sighandler\_t signal(int signum, sighandler\_t handler)}
segnale.
Il numero di segnale passato in \param{signum} può essere indicato
-direttamente con una delle costanti definite in \secref{sec:sig_standard}. Il
+direttamente con una delle costanti definite in sez.~\ref{sec:sig_standard}. Il
gestore \param{handler} invece, oltre all'indirizzo della funzione da chiamare
all'occorrenza del segnale, può assumere anche i due valori costanti
\const{SIG\_IGN} con cui si dice ignorare il segnale e \const{SIG\_DFL} per
e bloccando il segnale durante l'esecuzione dello stesso. Con l'utilizzo delle
\acr{glibc} dalla versione 2 anche Linux è passato a questo comportamento. Il
comportamento della versione originale della funzione, il cui uso è deprecato
-per i motivi visti in \secref{sec:sig_semantics}, può essere ottenuto
+per i motivi visti in sez.~\ref{sec:sig_semantics}, può essere ottenuto
chiamando \func{sysv\_signal}, una volta che si sia definita la macro
\macro{\_XOPEN\_SOURCE}. In generale, per evitare questi problemi, l'uso di
\func{signal} (ed ogni eventuale ridefinizine della stessa) è da evitare;
\subsection{Le funzioni \func{kill} e \func{raise}}
\label{sec:sig_kill_raise}
-Come accennato in \secref{sec:sig_types}, un segnale può essere generato
+Come accennato in sez.~\ref{sec:sig_types}, un segnale può essere generato
direttamente da un processo attraverso una opportuna system call. Le funzioni
che si usano di solito per inviare un segnale generico sono due, \func{raise} e
\func{kill}.
Il valore di \param{sig} specifica il segnale che si vuole inviare e può
essere specificato con una delle macro definite in
-\secref{sec:sig_classification}. In genere questa funzione viene usata per
+sez.~\ref{sec:sig_classification}. In genere questa funzione viene usata per
riprodurre il comportamento predefinito di un segnale che sia stato
intercettato. In questo caso, una volta eseguite le operazioni volute, il
gestore dovrà prima reinstallare l'azione predefinita, per poi attivarla
in tal caso si otterrà un errore \errcode{EPERM} se non si hanno i permessi
necessari ed un errore \errcode{ESRCH} se il processo specificato non esiste.
Si tenga conto però che il sistema ricicla i \acr{pid} (come accennato in
-\secref{sec:proc_pid}) per cui l'esistenza di un processo non significa che
+sez.~\ref{sec:proc_pid}) per cui l'esistenza di un processo non significa che
esso sia realmente quello a cui si intendeva mandare il segnale.
Il valore dell'argomento \param{pid} specifica il processo (o i processi) di
destinazione a cui il segnale deve essere inviato e può assumere i valori
-riportati in \tabref{tab:sig_kill_values}.
+riportati in tab.~\ref{tab:sig_kill_values}.
Si noti pertanto che la funzione \code{raise(sig)} può essere definita in
termini di \func{kill}, ed è sostanzialmente equivalente ad una
errore, gli errori sono gli stessi di \func{kill}.}
\end{prototype}
\noindent e che permette di inviare un segnale a tutto un \textit{process
- group} (vedi \secref{sec:sess_proc_group}).
+ group} (vedi sez.~\ref{sec:sess_proc_group}).
\begin{table}[htb]
\footnotesize
destinazione. Fa eccezione il caso in cui il segnale inviato sia
\const{SIGCONT}, nel quale occorre che entrambi i processi appartengano alla
stessa sessione. Inoltre, dato il ruolo fondamentale che riveste nel sistema
-(si ricordi quanto visto in \secref{sec:sig_termination}), non è possibile
+(si ricordi quanto visto in sez.~\ref{sec:sig_termination}), non è possibile
inviare al processo 1 (cioè a \cmd{init}) segnali per i quali esso non abbia
un gestore installato.
predisporre le opportune misure per gestire il caso di necessità di più
interruzioni.
-In \secref{sec:sys_unix_time} abbiamo visto che ad ogni processo sono
+In sez.~\ref{sec:sys_unix_time} abbiamo visto che ad ogni processo sono
associati tre tempi diversi: il \textit{clock time}, l'\textit{user time} ed
il \textit{system time}. Per poterli calcolare il kernel mantiene per ciascun
processo tre diversi timer:
\item un \textit{profiling timer} che calcola la somma dei tempi di processore
utilizzati direttamente dal processo in user space, e dal kernel nelle
system call ad esso relative (che corrisponde a quello che in
- \secref{sec:sys_unix_time} abbiamo chiamato \textit{CPU time}). La scadenza
+ sez.~\ref{sec:sys_unix_time} abbiamo chiamato \textit{CPU time}). La scadenza
di questo timer provoca l'emissione di \const{SIGPROF}.
\end{itemize}
Il valore di \param{which} permette di specificare quale dei tre timer
illustrati in precedenza usare; i possibili valori sono riportati in
-\tabref{tab:sig_setitimer_values}.
+tab.~\ref{tab:sig_setitimer_values}.
\begin{table}[htb]
\footnotesize
\centering
Il valore della struttura specificata \param{value} viene usato per impostare
il timer, se il puntatore \param{ovalue} non è nullo il precedente valore
viene salvato qui. I valori dei timer devono essere indicati attraverso una
-struttura \struct{itimerval}, definita in \figref{fig:file_stat_struct}.
+struttura \struct{itimerval}, definita in fig.~\ref{fig:file_stat_struct}.
La struttura è composta da due membri, il primo, \var{it\_interval} definisce
il periodo del timer; il secondo, \var{it\_value} il tempo mancante alla
definita direttamente nello standard POSIX.1, può a sua volta essere espressa
in termini di \func{setitimer}, come evidenziato dal manuale delle \acr{glibc}
\cite{glibc} che ne riporta la definizione mostrata in
-\figref{fig:sig_alarm_def}.
+fig.~\ref{fig:sig_alarm_def}.
\begin{figure}[!htb]
\footnotesize \centering
conto poi che in caso di sistema molto carico, si può avere il caso patologico
in cui un timer scade prima che il segnale di una precedente scadenza sia
stato consegnato; in questo caso, per il comportamento dei segnali descritto
-in \secref{sec:sig_sigchld}, un solo segnale sarà consegnato.
+in sez.~\ref{sec:sig_sigchld}, un solo segnale sarà consegnato.
Dato che sia \func{alarm} che \func{setitimer} non consentono di leggere il
L'ultima funzione che permette l'invio diretto di un segnale è \funcd{abort};
-che, come accennato in \secref{sec:proc_termination}, permette di abortire
+che, come accennato in sez.~\ref{sec:proc_termination}, permette di abortire
l'esecuzione di un programma tramite l'invio di \const{SIGABRT}. Il suo
prototipo è:
\begin{prototype}{stdlib.h}{void abort(void)}
sono apposite funzioni che permettono di mettere un processo in stato di
attesa.\footnote{si tratta in sostanza di funzioni che permettono di portare
esplicitamente il processo in stato di \textit{sleep}, vedi
- \secref{sec:proc_sched}.}
+ sez.~\ref{sec:proc_sched}.}
Il metodo tradizionale per fare attendere ad un processo fino all'arrivo di un
segnale è quello di usare la funzione \funcd{pause}, il cui prototipo è:
In alcune implementazioni inoltre l'uso di \func{sleep} può avere conflitti
con quello di \const{SIGALRM}, dato che la funzione può essere realizzata con
l'uso di \func{pause} e \func{alarm} (in maniera analoga all'esempio che
-vedremo in \secref{sec:sig_example}). In tal caso mescolare chiamata di
+vedremo in sez.~\ref{sec:sig_example}). In tal caso mescolare chiamata di
\func{alarm} e \func{sleep} o modificare l'azione di \const{SIGALRM}, può
causare risultati indefiniti. Nel caso delle \acr{glibc} è stata usata una
implementazione completamente indipendente e questi problemi non ci sono.
utilizzando direttamente il timer del kernel.} e sia utilizzabile senza
interferenze con l'uso di \const{SIGALRM}. La funzione prende come parametri
delle strutture di tipo \struct{timespec}, la cui definizione è riportata in
-\figref{fig:sys_timeval_struct}, che permettono di specificare un tempo con
+fig.~\ref{fig:sys_timeval_struct}, che permettono di specificare un tempo con
una precisione (teorica) fino al nanosecondo.
La funzione risolve anche il problema di proseguire l'attesa dopo
Un semplice esempio per illustrare il funzionamento di un gestore di segnale è
quello della gestione di \const{SIGCHLD}. Abbiamo visto in
-\secref{sec:proc_termination} che una delle azioni eseguite dal kernel alla
+sez.~\ref{sec:proc_termination} che una delle azioni eseguite dal kernel alla
conclusione di un processo è quella di inviare questo segnale al
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
\func{waitpid} per completare la procedura di terminazione in modo da evitare
la formazione di zombie\index{zombie}.
-In \figref{fig:sig_sigchld_handl} è mostrato il codice contenente una
+In fig.~\ref{fig:sig_sigchld_handl} è mostrato il codice contenente una
implementazione generica di una routine di gestione per \const{SIGCHLD}, (che
si trova nei sorgenti allegati nel file \file{SigHand.c}); se ripetiamo i test
-di \secref{sec:proc_termination}, invocando \cmd{forktest} con l'opzione
+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}.
\end{figure}
Il codice del gestore è di lettura immediata; come buona norma di
-programmazione (si ricordi quanto accennato \secref{sec:sys_errno}) si
+programmazione (si ricordi quanto accennato sez.~\ref{sec:sys_errno}) si
comincia (\texttt{\small 12-13}) con il salvare lo stato corrente di
\var{errno}, in modo da poterlo ripristinare prima del ritorno del gestore
(\texttt{\small 22-23}). In questo modo si preserva il valore della variabile
generazione di un segnale e l'esecuzione del gestore possa passare un certo
lasso di tempo e niente ci assicura che il gestore venga eseguito prima della
generazione di ulteriori segnali dello stesso tipo. In questo caso normalmente
-i segnali segnali successivi vengono ``\textsl{fusi}'' col primo ed al
-processo ne viene recapitato soltanto uno.
+i segnali successivi vengono ``\textsl{fusi}'' col primo ed al processo ne
+viene recapitato soltanto uno.
Questo può essere un caso comune proprio con \const{SIGCHLD}, qualora capiti
che molti processi figli terminino in rapida successione. Esso inoltre si
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
-ancora ricevere lo stato di terminazione (si veda \secref{sec:proc_wait} per
+ancora ricevere lo stato di terminazione (si veda sez.~\ref{sec:proc_wait} per
la sintassi della funzione). Si noti anche come la funzione venga invocata con
il parametro \const{WNOHANG} che permette di evitare il suo blocco quando
tutti gli stati di terminazione sono stati ricevuti.
\subsection{Alcune problematiche aperte}
\label{sec:sig_example}
-Come accennato in \secref{sec:sig_pause_sleep} è possibile implementare
+Come accennato in sez.~\ref{sec:sig_pause_sleep} è possibile implementare
\func{sleep} a partire dall'uso di \func{pause} e \func{alarm}. A prima vista
questo può sembrare di implementazione immediata; ad esempio una semplice
versione di \func{sleep} potrebbe essere quella illustrata in
-\figref{fig:sig_sleep_wrong}.
+fig.~\ref{fig:sig_sleep_wrong}.
Dato che è nostra intenzione utilizzare \const{SIGALRM} il primo passo della
nostra implementazione di sarà quello di installare il relativo gestore
interrotta (se non in caso di un altro segnale).
Questo problema può essere risolto (ed è la modalità con cui veniva fatto in
-SVr2) usando la funzione \func{longjmp} (vedi \secref{sec:proc_longjmp}) per
+SVr2) usando la funzione \func{longjmp} (vedi sez.~\ref{sec:proc_longjmp}) per
uscire dal gestore; in questo modo, con una condizione sullo stato di
uscita di quest'ultima, si può evitare la chiamata a \func{pause}, usando un
-codice del tipo di quello riportato in \figref{fig:sig_sleep_incomplete}.
+codice del tipo di quello riportato in fig.~\ref{fig:sig_sleep_incomplete}.
\begin{figure}[!htb]
\footnotesize \centering
\end{figure}
In questo caso il gestore (\texttt{\small 18-26}) non ritorna come in
-\figref{fig:sig_sleep_wrong}, ma usa \func{longjmp} (\texttt{\small 24}) per
+fig.~\ref{fig:sig_sleep_wrong}, ma usa \func{longjmp} (\texttt{\small 24}) per
rientrare nel corpo principale del programma; dato che in questo caso il
valore di uscita di \func{setjmp} è 1, grazie alla condizione in
(\texttt{\small 9-12}) si evita comunque che \func{pause} sia chiamata a
qualche forma di evento; in genere quello che si fa in questo caso è impostare
nel gestore un opportuno flag da controllare nel corpo principale del
programma (con un codice del tipo di quello riportato in
-\figref{fig:sig_event_wrong}).
+fig.~\ref{fig:sig_event_wrong}).
\begin{figure}[!htb]
\footnotesize\centering
quale potrà determinare, osservandone il contenuto, l'occorrenza o meno del
segnale, e prendere le relative azioni conseguenti (\texttt{\small 6-11}).
-Questo è il tipico esempio di caso, già citato in \secref{sec:proc_race_cond},
-in cui si genera una race condition\index{race condition}; se infatti il
-segnale arriva immediatamente dopo l'esecuzione del controllo (\texttt{\small
- 6}) ma prima della cancellazione del flag (\texttt{\small 7}), la sua
-occorrenza sarà perduta.
+Questo è il tipico esempio di caso, già citato in
+sez.~\ref{sec:proc_race_cond}, in cui si genera una race condition\index{race
+ condition}; se infatti il segnale arriva immediatamente dopo l'esecuzione
+del controllo (\texttt{\small 6}) ma prima della cancellazione del flag
+(\texttt{\small 7}), la sua occorrenza sarà perduta.
Questi esempi ci mostrano che per una gestione effettiva dei segnali occorrono
funzioni più sofisticate di quelle illustrate finora, che hanno origine dalla
In genere si usa un insieme di segnali per specificare quali segnali si vuole
bloccare, o per riottenere dalle varie funzioni di gestione la maschera dei
-segnali attivi (vedi \secref{sec:sig_sigmask}). Essi possono essere definiti
+segnali attivi (vedi sez.~\ref{sec:sig_sigmask}). Essi possono essere definiti
in due diverse maniere, aggiungendo i segnali voluti ad un insieme vuoto
ottenuto con \func{sigemptyset} o togliendo quelli che non servono da un
insieme completo ottenuto con \func{sigfillset}. Infine \func{sigismember}
\subsection{La funzione \func{sigaction}}
\label{sec:sig_sigaction}
-Abbiamo già accennato in \secref{sec:sig_signal} i problemi di compatibilità
+Abbiamo già accennato in sez.~\ref{sec:sig_signal} i problemi di compatibilità
relativi all'uso di \func{signal}. Per ovviare a tutto questo lo standard
POSIX.1 ha ridefinito completamente l'interfaccia per la gestione dei segnali,
rendendola molto più flessibile e robusta, anche se leggermente più complessa.
Entrambi i puntatori fanno riferimento alla struttura \struct{sigaction},
tramite la quale si specificano tutte le caratteristiche dell'azione associata
ad un segnale. Anch'essa è descritta dallo standard POSIX.1 ed in Linux è
-definita secondo quanto riportato in \figref{fig:sig_sigaction}. Il campo
+definita secondo quanto riportato in fig.~\ref{fig:sig_sigaction}. Il campo
\var{sa\_restorer}, non previsto dallo standard, è obsoleto e non deve essere
più usato.
sempre aggiunto il segnale che ne ha causato la chiamata, a meno che non si
sia specificato con \var{sa\_flag} un comportamento diverso. Quando il
gestore ritorna comunque la maschera dei segnali bloccati (vedi
-\secref{sec:sig_sigmask}) viene ripristinata al valore precedente
+sez.~\ref{sec:sig_sigmask}) viene ripristinata al valore precedente
l'invocazione.
L'uso di questo campo permette ad esempio di risolvere il problema residuo
dell'implementazione di \code{sleep} mostrata in
-\secref{fig:sig_sleep_incomplete}. In quel caso infatti se il segnale di
+fig.~\ref{fig:sig_sleep_incomplete}. In quel caso infatti se il segnale di
allarme avesse interrotto un altro gestore questo non sarebbe stato
eseguito correttamente; la cosa poteva essere prevenuta installando gli altri
gestori usando \var{sa\_mask} per bloccare \const{SIGALRM} durante la
loro esecuzione. Il valore di \var{sa\_flag} permette di specificare vari
aspetti del comportamento di \func{sigaction}, e della reazione del processo
ai vari segnali; i valori possibili ed il relativo significato sono riportati
-in \tabref{tab:sig_sa_flag}.
+in tab.~\ref{tab:sig_sa_flag}.
\begin{table}[htb]
\footnotesize
\var{sa\_sigaction} al posto di \var{sa\_handler}.\\
\const{SA\_ONSTACK} & Stabilisce l'uso di uno stack alternativo per
l'esecuzione del gestore (vedi
- \secref{sec:sig_specific_features}).\\
+ sez.~\ref{sec:sig_specific_features}).\\
\hline
\end{tabular}
\caption{Valori del campo \var{sa\_flag} della struttura \struct{sigaction}.}
\label{tab:sig_sa_flag}
\end{table}
-Come si può notare in \figref{fig:sig_sigaction} \func{sigaction}
+Come si può notare in fig.~\ref{fig:sig_sigaction} \func{sigaction}
permette\footnote{La possibilità è prevista dallo standard POSIX.1b, ed è
stata aggiunta nei kernel della serie 2.1.x con l'introduzione dei segnali
- real-time (vedi \secref{sec:sig_real_time}). In precedenza era possibile
+ real-time (vedi sez.~\ref{sec:sig_real_time}). In precedenza era possibile
ottenere alcune informazioni addizionali usando \var{sa\_handler} con un
secondo parametro addizionale di tipo \var{sigcontext}, che adesso è
deprecato.} di utilizzare due forme diverse di gestore, da specificare, a
è quella classica usata anche con \func{signal}, mentre la prima permette di
usare un gestore più complesso, in grado di ricevere informazioni più
dettagliate dal sistema, attraverso la struttura \struct{siginfo\_t},
-riportata in \figref{fig:sig_siginfo_t}.
+riportata in fig.~\ref{fig:sig_siginfo_t}.
\begin{figure}[!htb]
\footnotesize \centering
altre informazioni specifiche. In tutti i casi il valore del campo è
riportato attraverso delle costanti (le cui definizioni si trovano
\file{bits/siginfo.h}) il cui elenco dettagliato è disponibile nella pagina di
-manuale di di \func{sigaction}.
+manuale di \func{sigaction}.
Il resto della struttura è definito come \ctyp{union} ed i valori
eventualmente presenti dipendono dal segnale, così \const{SIGCHLD} ed i
-segnali real-time (vedi \secref{sec:sig_real_time}) inviati tramite
+segnali real-time (vedi sez.~\ref{sec:sig_real_time}) inviati tramite
\func{kill} avvalorano \var{si\_pid} e \var{si\_uid} coi valori corrispondenti
al processo che ha emesso il segnale, \const{SIGILL}, \const{SIGFPE},
\const{SIGSEGV} e \const{SIGBUS} avvalorano \var{si\_addr} con l'indirizzo cui
-è avvenuto l'errore, \const{SIGIO} (vedi \secref{sec:file_asyncronous_io})
+è avvenuto l'errore, \const{SIGIO} (vedi sez.~\ref{sec:file_asyncronous_io})
avvalora \var{si\_fd} con il numero del file descriptor e \var{si\_band} per i
dati urgenti su un socket\index{socket}.
Per questo motivo si è provveduto, per mantenere un'interfaccia semplificata
che abbia le stesse caratteristiche di \func{signal}, a definire attraverso
\func{sigaction} una funzione equivalente, il cui codice è riportato in
-\figref{fig:sig_Signal_code} (il codice completo si trova nel file
+fig.~\ref{fig:sig_Signal_code} (il codice completo si trova nel file
\file{SigHand.c} nei sorgenti allegati). Si noti come, essendo la funzione
estremamente semplice, è definita come \direct{inline}.\footnote{la direttiva
\direct{inline} viene usata per dire al compilatore di trattare la funzione
\textit{signal mask}}
\label{sec:sig_sigmask}
-Come spiegato in \secref{sec:sig_semantics} tutti i moderni sistemi unix-like
+Come spiegato in sez.~\ref{sec:sig_semantics} tutti i moderni sistemi unix-like
permettono si bloccare temporaneamente (o di eliminare completamente,
impostando \const{SIG\_IGN} come azione) la consegna dei segnali ad un
processo. Questo è fatto specificando la cosiddetta \textsl{maschera dei
segnali} (o \textit{signal mask}) del processo\footnote{nel caso di Linux
essa è mantenuta dal campo \var{blocked} della \struct{task\_struct} del
processo.} cioè l'insieme dei segnali la cui consegna è bloccata. Abbiamo
-accennato in \secref{sec:proc_fork} che la \textit{signal mask} viene
+accennato in sez.~\ref{sec:proc_fork} che la \textit{signal mask} viene
ereditata dal padre alla creazione di un processo figlio, e abbiamo visto al
paragrafo precedente che essa può essere modificata, durante l'esecuzione di
un gestore, attraverso l'uso dal campo \var{sa\_mask} di \struct{sigaction}.
-Uno dei problemi evidenziatisi con l'esempio di \secref{fig:sig_event_wrong} è
-che in molti casi è necessario proteggere delle sezioni di codice (nel caso in
-questione la sezione fra il controllo e la eventuale cancellazione del flag
+Uno dei problemi evidenziatisi con l'esempio di fig.~\ref{fig:sig_event_wrong}
+è che in molti casi è necessario proteggere delle sezioni di codice (nel caso
+in questione la sezione fra il controllo e la eventuale cancellazione del flag
che testimon