avrebbe il blocco.
\item \errcode{EFAULT} \textit{Bad address}. Una stringa passata come
argomento è fuori dello spazio di indirizzi del processo, in genere questa
- situazione provoca direttamente l'emissione di un segnale di \textit{segment
- violation} (\const{SIGSEGV}).
+ situazione provoca direttamente l'emissione di un segnale di
+ \itindex{segment~violation} \textit{segment violation} (\const{SIGSEGV}).
\item \errcode{EINVAL} \textit{Invalid argument}. Errore utilizzato per
segnalare vari tipi di problemi dovuti all'aver passato un argomento
sbagliato ad una funzione di libreria.
In generale questa interfaccia è completamente astratta e può essere
implementata sia direttamente nel kernel, che in user space attraverso l'uso
-di thread. Per le versioni del kernel meno recenti esiste una implementazione
-di questa interfaccia fornita delle \acr{glibc}, che è realizzata
-completamente in user space, ed è accessibile linkando i programmi con la
-libreria \file{librt}. Nelle versioni più recenti (a partire dalla 2.5.32) è
-stato introdotto direttamente nel kernel un nuovo layer per l'I/O asincrono.
+di \itindex{thread} \textit{thread}. Per le versioni del kernel meno recenti
+esiste una implementazione di questa interfaccia fornita delle \acr{glibc},
+che è realizzata completamente in user space, ed è accessibile linkando i
+programmi con la libreria \file{librt}. Nelle versioni più recenti (a partire
+dalla 2.5.32) è stato introdotto direttamente nel kernel un nuovo layer per
+l'I/O asincrono.
Lo standard prevede che tutte le operazioni di I/O asincrono siano controllate
attraverso l'uso di una apposita struttura \struct{aiocb} (il cui nome sta per
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}
- con argomento \var{sigev\_value}, e con gli attributi specificati da
- \var{sigev\_notify\_attribute}.
+ \itindex{thread} \textit{thread} che esegue la funzione specificata da
+ \var{sigev\_notify\_function} con argomento \var{sigev\_value}, e con gli
+ attributi specificati da \var{sigev\_notify\_attribute}.
\end{basedescript}
Le due funzioni base dell'interfaccia per l'I/O asincrono sono
\label{tab:file_mmap_prot}
\end{table}
-Il valore dell'argomento \param{prot} indica la protezione\footnote{in Linux
- la memoria reale è divisa in pagine: ogni processo vede la sua memoria
- attraverso uno o più segmenti lineari di memoria virtuale. Per ciascuno di
- questi segmenti il kernel mantiene nella \itindex{page~table} \textit{page
- table} la mappatura sulle pagine di memoria reale, ed le modalità di
- accesso (lettura, esecuzione, scrittura); una loro violazione causa quella
- che si chiama una \textit{segment violation}, e la relativa emissione del
- segnale \const{SIGSEGV}.} da applicare al segmento di memoria e deve essere
+Il valore dell'argomento \param{prot} indica la protezione\footnote{come
+ accennato in sez.~\ref{sec:proc_memory} in Linux la memoria reale è divisa
+ in pagine: ogni processo vede la sua memoria attraverso uno o più segmenti
+ lineari di memoria virtuale. Per ciascuno di questi segmenti il kernel
+ mantiene nella \itindex{page~table} \textit{page table} la mappatura sulle
+ pagine di memoria reale, ed le modalità di accesso (lettura, esecuzione,
+ scrittura); una loro violazione causa quella una \itindex{segment~violation}
+ \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 tab.~\ref{tab:file_mmap_prot}; il valore specificato deve essere
compatibile con la modalità di accesso con cui si è aperto il file.
un \const{SIGSEGV}.\\
\const{MAP\_LOCKED} & Se impostato impedisce lo swapping delle pagine
mappate.\\
- \const{MAP\_GROWSDOWN} & Usato per gli \itindex{stack} stack. Indica
- che la mappatura deve essere effettuata con gli
- indirizzi crescenti verso il basso.\\
+ \const{MAP\_GROWSDOWN} & Usato per gli \itindex{stack} \textit{stack}.
+ Indica che la mappatura deve essere effettuata
+ con gli indirizzi crescenti verso il basso.\\
\const{MAP\_ANONYMOUS} & La mappatura non è associata a nessun file. Gli
argomenti \param{fd} e \param{offset} sono
ignorati.\footnotemark\\
staticamente, per cui viene sovrascritta tutte le volte che si ripete la
lettura di una voce sullo stesso stream.
-Di questa funzione esiste anche una versione rientrante, \func{readdir\_r},
-che non usa una struttura allocata staticamente, e può essere utilizzata anche
-con i thread; il suo prototipo è:
+Di questa funzione esiste anche una versione \index{funzioni!rientranti}
+rientrante, \func{readdir\_r}, che non usa una struttura allocata
+staticamente, e può essere utilizzata anche con i \itindex{thread}
+\textit{thread}; il suo prototipo è:
\begin{functions}
\headdecl{sys/types.h} \headdecl{dirent.h}
massimo di \const{TMP\_MAX} volte. Al nome viene automaticamente aggiunto come
prefisso la directory specificata da \const{P\_tmpdir}.
-Di questa funzione esiste una versione rientrante, \func{tmpnam\_r}, che non
-fa nulla quando si passa \val{NULL} come argomento. Una funzione simile,
-\funcd{tempnam}, permette di specificare un prefisso per il file
-esplicitamente, il suo prototipo è:
+Di questa funzione esiste una versione \index{funzioni!rientranti} rientrante,
+\func{tmpnam\_r}, che non fa nulla quando si passa \val{NULL} come argomento.
+Una funzione simile, \funcd{tempnam}, permette di specificare un prefisso per
+il file esplicitamente, il suo prototipo è:
\begin{prototype}{stdio.h}{char *tempnam(const char *dir, const char *pfx)}
Restituisce il puntatore ad una stringa contente un nome di file valido e
non esistente al momento dell'invocazione.
\end{prototype}
La funzione alloca con \code{malloc} la stringa in cui restituisce il nome,
-per cui è sempre rientrante, occorre però ricordarsi di disallocare il
-puntatore che restituisce. L'argomento \param{pfx} specifica un prefisso di
-massimo 5 caratteri per il nome provvisorio. La funzione assegna come
-directory per il file temporaneo (verificando che esista e sia accessibili),
-la prima valida delle seguenti:
+per cui è sempre \index{funzioni!rientranti} rientrante, occorre però
+ricordarsi di disallocare il puntatore che restituisce. L'argomento
+\param{pfx} specifica un prefisso di massimo 5 caratteri per il nome
+provvisorio. La funzione assegna come directory per il file temporaneo
+(verificando che esista e sia accessibili), la prima valida delle seguenti:
\begin{itemize*}
\item La variabile di ambiente \const{TMPNAME} (non ha effetto se non è
definita o se il programma chiamante è \itindex{suid~bit} \acr{suid} o
automaticamente cancellato alla sua chiusura o all'uscita dal programma. Lo
standard non specifica in quale directory verrà aperto il file, ma le
\acr{glibc} prima tentano con \const{P\_tmpdir} e poi con \file{/tmp}. Questa
-funzione è rientrante e non soffre di problemi di \itindex{race~condition}
-\textit{race condition}.
+funzione è \index{funzioni!rientranti} rientrante e non soffre di problemi di
+\itindex{race~condition} \textit{race condition}.
Alcune versioni meno recenti di Unix non supportano queste funzioni; in questo
caso si possono usare le vecchie funzioni \funcd{mktemp} e \func{mkstemp} che
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 sez.~\ref{sec:file_stream_thread} per i
-dettagli), i loro prototipi sono:
+applicazioni \itindex{thread} \textit{multi-thread} (si veda
+sez.~\ref{sec:file_stream_thread} per i dettagli), i loro prototipi sono:
\begin{functions}
\headdecl{stdio.h}
In questa sezione esamineremo alcune funzioni avanzate che permettono di
eseguire operazioni particolari sugli stream, come leggerne gli attributi,
controllarne le modalità di bufferizzazione, gestire direttamente i lock
-impliciti per la programmazione multi thread.
+impliciti per la programmazione \itindex{thread} \textit{multi-thread}.
\subsection{Le funzioni di controllo}
compresi gli eventuali caratteri rimandati indietro con \func{ungetc}.
-\subsection{Gli stream e i thread}
+\subsection{Gli \textit{stream} e i \textit{thread}}
\label{sec:file_stream_thread}
-Gli stream possono essere usati in applicazioni multi-thread allo stesso
-modo in cui sono usati nelle applicazioni normali, ma si deve essere
+\itindbeg{thread}
+
+Gli stream possono essere usati in applicazioni \textit{multi-thread} allo
+stesso modo in cui sono usati nelle applicazioni normali, ma si deve essere
consapevoli delle possibili complicazioni anche quando non si usano i
-thread, dato che l'implementazione delle librerie è influenzata
-pesantemente dalle richieste necessarie per garantirne l'uso con i thread.
+\textit{thread}, dato che l'implementazione delle librerie è influenzata
+pesantemente dalle richieste necessarie per garantirne l'uso con i
+\textit{thread}.
Lo standard POSIX richiede che le operazioni sui file siano atomiche rispetto
-ai thread, per questo le operazioni sui buffer effettuate dalle funzioni di
-libreria durante la lettura e la scrittura di uno stream devono essere
-opportunamente protette (in quanto il sistema assicura l'atomicità solo per le
-system call). Questo viene fatto associando ad ogni stream un opportuno blocco
-che deve essere implicitamente acquisito prima dell'esecuzione di qualunque
-operazione.
-
-Ci sono comunque situazioni in cui questo non basta, come quando un thread
-necessita di compiere più di una operazione sullo stream atomicamente, per
-questo motivo le librerie provvedono anche delle funzioni \funcd{flockfile},
-\funcd{ftrylockfile} e \funcd{funlockfile}, che permettono la gestione
-esplicita dei blocchi sugli stream; esse sono disponibili definendo
-\macro{\_POSIX\_THREAD\_SAFE\_FUNCTIONS} ed i loro prototipi sono:
+ai \textit{thread}, per questo le operazioni sui buffer effettuate dalle
+funzioni di libreria durante la lettura e la scrittura di uno stream devono
+essere opportunamente protette (in quanto il sistema assicura l'atomicità solo
+per le system call). Questo viene fatto associando ad ogni stream un opportuno
+blocco che deve essere implicitamente acquisito prima dell'esecuzione di
+qualunque operazione.
+
+Ci sono comunque situazioni in cui questo non basta, come quando un
+\textit{thread} necessita di compiere più di una operazione sullo stream
+atomicamente, per questo motivo le librerie provvedono anche delle funzioni
+\funcd{flockfile}, \funcd{ftrylockfile} e \funcd{funlockfile}, che permettono
+la gestione esplicita dei blocchi sugli stream; esse sono disponibili
+definendo \macro{\_POSIX\_THREAD\_SAFE\_FUNCTIONS} ed i loro prototipi sono:
\begin{functions}
\headdecl{stdio.h}
Ma, vista la complessità delle strutture di dati coinvolte, le operazioni di
blocco non sono del tutto indolori, e quando il locking dello stream non è
-necessario (come in tutti i programmi che non usano i thread), tutta la
-procedura può comportare dei costi pesanti in termini di prestazioni. Per
+necessario (come in tutti i programmi che non usano i \textit{thread}), tutta
+la procedura può comportare dei costi pesanti in termini di prestazioni. Per
questo motivo abbiamo visto come alle usuali funzioni di I/O non formattato
siano associate delle versioni \code{\_unlocked} (alcune previste dallo stesso
standard POSIX, altre aggiunte come estensioni dalle \acr{glibc}) che possono
accade per \func{getc} e \func{putc}) sono realizzate come macro.
La sostituzione di tutte le funzioni di I/O con le relative versioni
-\code{\_unlocked} in un programma che non usa i thread è però un lavoro
-abbastanza noioso; per questo motivo le \acr{glibc} forniscono al
+\code{\_unlocked} in un programma che non usa i \textit{thread} è però un
+lavoro abbastanza noioso; per questo motivo le \acr{glibc} forniscono al
programmatore pigro un'altra via\footnote{anche questa mutuata da estensioni
introdotte in Solaris.} da poter utilizzare per disabilitare in blocco il
locking degli stream: l'uso della funzione \funcd{\_\_fsetlocking}, il cui
di blocco dello stream.
\end{basedescript}
+\itindend{thread}
+
+
%%% Local Variables:
%%% mode: latex
anche in FreeBSD, senza limiti di allineamento dei buffer. In Linux è stata
introdotta con il kernel 2.4.10, le versioni precedenti la ignorano.}
-\footnotetext[7]{introdotto con il kernel 2.6.23, per evitare una \textit{race
- condition} che si può verificare con i thread, fra l'apertura del file e
- l'impostazione della suddetta modalità con \func{fcntl}.}
+\footnotetext[7]{introdotto con il kernel 2.6.23, per evitare una
+ \itindex{race~condition} \textit{race condition} che si può verificare con i
+ \itindex{thread} \textit{thread}, fra l'apertura del file e l'impostazione
+ della suddetta modalità con \func{fcntl}.}
Questa caratteristica permette di prevedere qual è il valore del file
descriptor che si otterrà al ritorno di \func{open}, e viene talvolta usata da
di una \itindex{race~condition} \textit{race condition}.
Inoltre come già accennato, la directory di lavoro corrente è una proprietà
-del singolo processo; questo significa che quando si lavora con i thread essa
-sarà la stessa per tutti, ma esistono molti casi in cui sarebbe invece utile
-che ogni singolo thread avesse la sua directory di lavoro.
+del singolo processo; questo significa che quando si lavora con i
+\itindex{thread} \textit{thread} essa sarà la stessa per tutti, ma esistono
+molti casi in cui sarebbe invece utile che ogni singolo \itindex{thread}
+\textit{thread} avesse la sua directory di lavoro.
Per risolvere questi problemi, riprendendo una interfaccia già presente in
Solaris, a fianco delle normali funzioni che operano sui file (come
L'idea è che si apra prima la directory che si vuole usare come base dei
pathname relativo, e si passi il file descriptor alla funzione che userà
quella directory come punto di partenza per la risoluzione.\footnote{in questo
- modo, anche quando si lavora con i thread, si può mantenere anche una
- directory di lavoro diversa per ciascuno di essi.} Con queste funzioni si
-possono anche ottenere grossi aumenti di prestazioni quando si devono eseguire
-operazioni su delle sezioni di albero dei file che prevedono gerarchie molto
-profonde e grandi quantità di file e directory, dato che basta eseguire la
-risoluzione di un pathname una sola volta (nell'apertura della directory) e
-non per ciascun file che essa contiene.
+ modo, anche quando si lavora con i \itindex{thread} \textit{thread}, si può
+ mantenere anche una directory di lavoro diversa per ciascuno di essi.} Con
+queste funzioni si possono anche ottenere grossi aumenti di prestazioni quando
+si devono eseguire operazioni su delle sezioni di albero dei file che
+prevedono gerarchie molto profonde e grandi quantità di file e directory, dato
+che basta eseguire la risoluzione di un pathname una sola volta (nell'apertura
+della directory) e non per ciascun file che essa contiene.
La sintassi generale di queste nuove funzioni è che esse prendano come primo
argomento il file descriptor della directory da usare come base, mentre gli
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 \textit{real-time} e per i
-thread (rispettivamente 1003.1d e 1003.1c) per i socket (1003.1g) 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 è più comune parlare di POSIX.4
-come di POSIX.1b.
+\itindex{thread} \textit{thread} (rispettivamente 1003.1d e 1003.1c) per i
+socket (1003.1g) 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 è più comune
+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;
POSIX.2 & 1003.2 & 9945-2& Comandi \\
POSIX.3 & 2003 &TR13210& Metodi di test \\
POSIX.4 & 1003.1b & --- & Estensioni real-time \\
- POSIX.4a& 1003.1c & --- & Thread \\
+ POSIX.4a& 1003.1c & --- & \itindex{thread} Thread \\
POSIX.4b& 1003.1d &9945-1& Ulteriori estensioni real-time \\
POSIX.5 & 1003.5 & 14519& Interfaccia per il linguaggio ADA \\
POSIX.6 & 1003.2c,1e& 9945-2& Sicurezza \\
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 cap.~\ref{cha:threads}), e dallo standard POSIX.1b per
-quanto riguarda i segnali e lo \itindex{scheduler} scheduling real-time
-(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}).
+\itindex{thread} \textit{thread} (vedi cap.~\ref{cha:threads}), e dallo
+standard POSIX.1b per quanto riguarda i segnali e lo \itindex{scheduler}
+scheduling real-time (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}).
Lo standard principale resta comunque POSIX.1, che continua ad evolversi; la
versione più nota, cui gran parte delle implementazioni fanno riferimento, e
\item un valore maggiore o uguale a ``\texttt{199506L}'' rende disponibili
le funzionalità previste dallo standard POSIX.1 specificate nell'edizione
del 1996 (\textit{ISO/IEC 9945-1:1996}), ed in particolare le definizioni
- dello standard POSIX.1c per i \textit{thread};
+ dello standard POSIX.1c per i \itindex{thread} \textit{thread};
\item a partire dalla versione 2.3.3 delle \acr{glibc} un valore maggiore o
uguale a ``\texttt{200112L}'' rende disponibili le funzionalità di base
previste dallo standard POSIX.1-2001, escludendo le estensioni XSI;
Si tenga inoltre presente che la preferenza verso le versioni delle funzioni
usate da BSD viene mantenuta soltanto se nessuna delle ulteriori macro di
- specificazione di standard successivi (\macro{\_SVID\_SOURCE},
- \macro{\_POSIX\_SOURCE}, \macro{\_POSIX\_C\_SOURCE},
+ specificazione di standard successivi (vale a dire una fra
+ \macro{\_POSIX\_C\_SOURCE}, \macro{\_POSIX\_SOURCE}, \macro{\_SVID\_SOURCE},
\macro{\_XOPEN\_SOURCE}, \macro{\_XOPEN\_SOURCE\_EXTENDED} o
\macro{\_GNU\_SOURCE}) è stata a sua volta attivata, nel qual caso queste
- hanno la precedenza.
+ hanno la precedenza. Se però si definisce \macro{\_BSD\_SOURCE} dopo aver
+ definito una di queste macro, l'effetto sarà quello di dare la precedenza
+ alle funzioni in forma BSD.
\item[\macro{\_SVID\_SOURCE}] definendo questa macro si rendono disponibili le
funzionalità derivate da SVID. Esse comprendono anche quelle definite negli
\item[\macro{\_XOPEN\_SOURCE}] definendo questa macro si rendono disponibili
le funzionalità descritte nella \textit{X/Open Portability Guide}. Anche
- queste sono un sovrainsieme di quelle definite in POSIX.1 e POSIX.2 ed in
- effetti sia \macro{\_POSIX\_SOURCE} che \macro{\_POSIX\_C\_SOURCE} vengono
- automaticamente definite. Sono incluse anche ulteriori funzionalità
- disponibili in BSD e SVID:
+ queste sono un sovrainsieme di quelle definite negli standard POSIX.1 e
+ POSIX.2 ed in effetti sia \macro{\_POSIX\_SOURCE} che
+ \macro{\_POSIX\_C\_SOURCE} vengono automaticamente definite. Sono incluse
+ anche ulteriori funzionalità disponibili in BSD e SVID, più una serie di
+ estensioni a secondo dei seguenti valori:
\begin{itemize}
\item la definizione della macro ad un valore qualunque attiva le
funzionalità specificate negli standard POSIX.1, POSIX.2 e XPG4;
compatibilità.
\item[\macro{\_GNU\_SOURCE}] definendo questa macro si rendono disponibili
- tutte le funzionalità disponibili nei vari standard oltre a varie
- estensioni. Gli standard coperti sono: ISO C89, ISO C99, POSIX.1, POSIX.2,
- BSD, SVID, X/Open, SUS.
+ tutte le funzionalità disponibili nei vari standard oltre a varie estensioni
+ specifiche presenti solo nelle \acr{glibc} ed in Linux. Gli standard coperti
+ sono: ISO C89, ISO C99, POSIX.1, POSIX.2, BSD, SVID, X/Open, SUS.
L'uso di \macro{\_GNU\_SOURCE} è equivalente alla definizione contemporanea
delle macro: \macro{\_BSD\_SOURCE}, \macro{\_SVID\_SOURCE},
``\texttt{199506L}'' per le versioni delle \acr{glibc} precedenti la 2.5),
\macro{\_XOPEN\_SOURCE\_EXTENDED} e \macro{\_XOPEN\_SOURCE} con valore 600
(o 500 per le versioni delle \acr{glibc} precedenti la 2.2); oltre a queste
- vengono pure attivate le ulteriori \macro{\_ATFILE\_SOURCE} e
+ vengono pure attivate le ulteriori due macro \macro{\_ATFILE\_SOURCE} e
\macro{\_LARGEFILE64\_SOURCE} che definiscono funzioni previste
esclusivamente dalle \acr{glibc}.
\end{basedescript}
Benché Linux supporti in maniera estensiva gli standard più diffusi, esistono
-comunque delle estensioni specifiche e delle funzionalità specifiche, non
-presenti in altri standard e lo stesso vale per le \acr{glibc} stesse, che
-definiscono anche delle ulteriori funzioni di libreria. Ovviamente l'uso di
-queste funzionalità deve essere evitato se si ha a cuore la portabilità, ma
-qualora questo non sia un requisito esse possono rivelarsi molto utili.
+comunque delle estensioni e funzionalità specifiche, non presenti in altri
+standard e lo stesso vale per le \acr{glibc} stesse, che definiscono anche
+delle ulteriori funzioni di libreria. Ovviamente l'uso di queste funzionalità
+deve essere evitato se si ha a cuore la portabilità, ma qualora questo non sia
+un requisito esse possono rivelarsi molto utili.
Come per l'aderenza ai vari standard, le funzionalità aggiuntive possono
essere rese esplicitamente disponibili tramite la definizione di opportune
-macro di preprocessore, che si sono illustrate nel seguente elenco:
+macro di preprocessore, alcune di queste vengono attivate con la definizione
+di \macro{\_GNU\_SOURCE}, mentre altre devono essere attivate esplicitamente,
+inoltre alcune estensioni possono essere attivate indipendentemente tramite
+una opportuna macro; queste estensioni sono illustrate nel seguente elenco:
+
\begin{basedescript}{\desclabelwidth{3cm}\desclabelstyle{\nextlinelabel}}
\item[\macro{\_LARGEFILE\_SOURCE}] definendo questa macro si rendono
macro non ha nessun effetto.
\item[\macro{\_ATFILE\_SOURCE}] definendo questa macro si rendono disponibili
- le funzioni
-
-\item[\macro{\_FORTIFY\_SOURCE}] definendo questa macro si rendono
- disponibili le estensioni delle funzioni di creazione di file e directory
- che consentono una specificazione coerente dei pathname relativi illustrate
- in sez.~\ref{sec:file_openat}.
-
-\item[\macro{\_REENTRANT}] definendo questa macro si rendono disponibili
+ le estensioni delle funzioni di creazione di file e directory che risolvono
+ i problemi di sicurezza insiti nell'uso di pathname relativi con programmi
+ \itindex{thread} \textit{multi-thread} illustrate in
+ sez.~\ref{sec:file_openat}.
+
+\item[\macro{\_REENTRANT}] definendo questa macro, o la equivalente
+ \macro{\_THREAD\_SAFE} (fornita per compatibilità) si rendono disponibili le
+ versioni \index{funzioni!rientranti} rientranti (vedi
+ sez.~\ref{sec:proc_reentrant}) di alcune funzioni, necessarie quando si
+ usano i \itindex{thread} \textit{thread}. Alcune di queste funzioni sono
+ anche previste nello standard POSIX.1c, ma ve ne sono altre che sono
+ disponibili soltanto su alcuni sistemi, o specifiche del \acr{glibc}, e
+ possono essere utilizzate una volta definita la macro.
+
+\item[\macro{\_FORTIFY\_SOURCE}] definendo questa macro viene abilitata
+ l'inserimento di alcuni controlli per alcune funzioni di allocazione e
+ manipolazione di memoria e stringhe che consentono di rilevare
+ automaticamente alcuni errori di \textit{buffer overflow} nell'uso delle
+ stesse. La funzionalità è stata introdotta a partire dalla versione 2.3.4
+ delle \acr{glibc} e richiede anche il supporto da parte del compilatore, che
+ è disponibile solo a partire dalla versione 4.0 del \texttt{gcc}.
+
+ Le funzioni di libreria che vengono messe sotto controllo quando questa
+ funzionalità viene attivata sono, al momento della stesura di queste note,
+ le seguenti: \func{memcpy}, \func{mempcpy}, \func{memmove}, \func{memset},
+ \func{stpcpy}, \func{strcpy}, \func{strncpy}, \func{strcat}, \func{strncat},
+ \func{sprintf}, \func{snprintf}, \func{vsprintf}, \func{vsnprintf}, e
+ \func{gets}.
+
+ La macro prevede due valori, con \texttt{1} vengono eseguiti dei controlli
+ di base che non cambiano il comportamento dei programmi se si richiede una
+ ottimizzazione di livello uno o superiore,\footnote{vale a dire se si usa
+ l'opzione \texttt{-O1} o superiore del \texttt{gcc}.} mentre con il
+ valore \texttt{2} vengono aggiunti maggiori controlli.
\end{basedescript}
-In particolare è da sottolineare che le \acr{glibc} supportano alcune
-estensioni specifiche GNU, che non sono comprese in nessuno degli standard
-citati. Per poterle utilizzare esse devono essere attivate esplicitamente
-definendo la macro \macro{\_GNU\_SOURCE} prima di includere i vari header
-file.
-
-
% vedi anche man feature_test_macros
-%% \subsection{Gli standard di GNU/Linux}
-%% \label{sec:intro_linux_std}
-
-% TODO Da fare (o cassare, a seconda del tempo e della voglia).
-
-
% LocalWords: like kernel multitasking scheduler preemptive sez swap is cap VM
% LocalWords: everything bootstrap init shell Windows Foundation system call
% LocalWords: LARGEFILE Support LFS dell' black rectangle node fill cpu draw
% LocalWords: ellipse mem anchor west proc SysV SV Definition SCO Austin XSI
% LocalWords: Technical TC SUS Opengroup features STRICT std ATFILE fseeko
-% LocalWords: ftello fseek ftell lseek FORTIFY REENTRANT
+% LocalWords: ftello fseek ftell lseek FORTIFY REENTRANT SAFE overflow memcpy
+% LocalWords: mempcpy memmove memset stpcpy strcpy strncpy strcat strncat gets
+% LocalWords: sprintf snprintf vsprintf vsnprintf
%%% Local Variables:
%%% mode: latex
simultaneo a detto file.\footnote{il problema potrebbe essere superato
determinando in anticipo un nome appropriato per il file temporaneo, che
verrebbe utilizzato dai vari sotto-processi, e cancellato alla fine della
- loro esecuzione; ma a questo le cose non sarebbero più tanto semplici.}
-L'uso di una pipe invece permette di risolvere il problema in maniera semplice
-ed elegante, oltre ad essere molto più efficiente, dato che non si deve
-scrivere su disco.
+ loro esecuzione; ma a questo punto le cose non sarebbero più tanto
+ semplici.} L'uso di una pipe invece permette di risolvere il problema in
+maniera semplice ed elegante, oltre ad essere molto più efficiente, dato che
+non si deve scrivere su disco.
Il programma ci servirà anche come esempio dell'uso delle funzioni di
duplicazione dei file descriptor che abbiamo trattato in
L'uso di \const{SHM\_RDONLY} permette di agganciare il segmento in sola
lettura (si ricordi che anche le pagine di memoria hanno dei permessi), in tal
-caso un tentativo di scrivere sul segmento comporterà una violazione di
-accesso con l'emissione di un segnale di \const{SIGSEGV}. Il comportamento
-usuale di \func{shmat} è quello di agganciare il segmento con l'accesso in
-lettura e scrittura (ed il processo deve aver questi permessi in
-\var{shm\_perm}), non è prevista la possibilità di agganciare un segmento in
-sola scrittura.
+caso un tentativo di scrivere sul segmento comporterà una
+\itindex{segment~violation} violazione di accesso con l'emissione di un
+segnale di \const{SIGSEGV}. Il comportamento usuale di \func{shmat} è quello
+di agganciare il segmento con l'accesso in lettura e scrittura (ed il processo
+deve aver questi permessi in \var{shm\_perm}), non è prevista la possibilità
+di agganciare un segmento in sola scrittura.
In caso di successo la funzione aggiorna anche i seguenti campi di
\struct{shmid\_ds}:
Oggi Linux supporta tutti gli oggetti definito nello standard POSIX per l'IPC,
ma a lungo non è stato così; la memoria condivisa è presente a partire dal
kernel 2.4.x, i semafori sono forniti dalle \acr{glibc} nella sezione che
-implementa i thread POSIX di nuova generazione che richiedono il kernel 2.6,
-le code di messaggi sono supportate a partire dal kernel 2.6.6.
+implementa i \itindex{thread} \textit{thread} POSIX di nuova generazione che
+richiedono il kernel 2.6, le code di messaggi sono supportate a partire dal
+kernel 2.6.6.
La caratteristica fondamentale dell'interfaccia POSIX è l'abbandono dell'uso
degli identificatori e delle chiavi visti nel SysV IPC, per passare ai
Attraverso questa struttura si possono impostare le modalità con cui viene
effettuata la notifica; in particolare il campo \var{sigev\_notify} deve
essere posto a \const{SIGEV\_SIGNAL}\footnote{il meccanismo di notifica basato
- sui thread, specificato tramite il valore \const{SIGEV\_THREAD}, non è
- 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
-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 sez.~\ref{sec:sig_real_time} a proposito dei segnali
- real-time.} posto che questo sia installato nella forma estesa vista in
-sez.~\ref{sec:sig_sigaction}.
+ sui \itindex{thread} \textit{thread}, specificato tramite il valore
+ \const{SIGEV\_THREAD}, non è 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 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 sez.~\ref{sec:sig_real_time} a proposito dei
+ segnali real-time.} posto che questo sia installato nella forma estesa vista
+in sez.~\ref{sec:sig_sigaction}.
La funzione registra il processo chiamante per la notifica se
\param{notification} punta ad una struttura \struct{sigevent} opportunamente
\label{sec:ipc_posix_sem}
Fino alla serie 2.4.x del kernel esisteva solo una implementazione parziale
-dei semafori POSIX che li realizzava solo a livello di thread e non di
-processi,\footnote{questo significava che i semafori erano visibili solo
- all'interno dei thread creati da un singolo processo, e non potevano essere
- usati come meccanismo di sincronizzazione fra processi diversi.} fornita
-attraverso la sezione delle estensioni \textit{real-time} delle
-\acr{glibc}.\footnote{quelle che si accedono collegandosi alla libreria
- \texttt{librt}.} Esisteva inoltre una libreria che realizzava (parzialmente)
-l'interfaccia POSIX usando le funzioni dei semafori di SysV IPC (mantenendo
-così tutti i problemi sottolineati in sez.~\ref{sec:ipc_sysv_sem}).
+dei semafori POSIX che li realizzava solo a livello di \itindex{thread}
+\textit{thread} e non di processi,\footnote{questo significava che i semafori
+ erano visibili solo all'interno dei \itindex{thread} \textit{thread} creati
+ da un singolo processo, e non potevano essere usati come meccanismo di
+ sincronizzazione fra processi diversi.} fornita attraverso la sezione delle
+estensioni \textit{real-time} delle \acr{glibc}.\footnote{quelle che si
+ accedono collegandosi alla libreria \texttt{librt}.} Esisteva inoltre una
+libreria che realizzava (parzialmente) l'interfaccia POSIX usando le funzioni
+dei semafori di SysV IPC (mantenendo così tutti i problemi sottolineati in
+sez.~\ref{sec:ipc_sysv_sem}).
A partire dal kernel 2.5.7 è stato introdotto un meccanismo di
sincronizzazione completamente nuovo, basato sui cosiddetti
La funzione incrementa di uno il valore corrente del semaforo indicato
dall'argomento \param{sem}, se questo era nullo la relativa risorsa risulterà
-sbloccata, cosicché un altro processo (o thread) eventualmente bloccato in una
-\func{sem\_wait} sul semaforo potrà essere svegliato e rimesso in esecuzione.
-Si tenga presente che la funzione è sicura \index{funzioni~sicure} per l'uso
-all'interno di un gestore di segnali (si ricordi quanto detto in
-sez.~\ref{sec:sig_signal_handler}).
+sbloccata, cosicché un altro processo (o \itindex{thread} \textit{thread})
+eventualmente bloccato in una \func{sem\_wait} sul semaforo potrà essere
+svegliato e rimesso in esecuzione. Si tenga presente che la funzione è sicura
+\index{funzioni!sicure} per l'uso all'interno di un gestore di segnali (si
+ricordi quanto detto in sez.~\ref{sec:sig_signal_handler}).
Se invece di operare su un semaforo se ne vuole solamente leggere il valore,
si può usare la funzione \funcd{sem\_getvalue}, il cui prototipo è:
La funzione inizializza un semaforo all'indirizzo puntato dall'argomento
\param{sem}, e come per \func{sem\_open} consente di impostare un valore
iniziale con \param{value}. L'argomento \param{pshared} serve ad indicare se
-il semaforo deve essere utilizzato dai \itindex{thread} thread di uno stesso
-processo (con un valore nullo) o condiviso fra processi diversi (con un valore
-non nullo).
+il semaforo deve essere utilizzato dai \itindex{thread} \textit{thread} di uno
+stesso processo (con un valore nullo) o condiviso fra processi diversi (con un
+valore non nullo).
-Qualora il semaforo debba essere condiviso dai \itindex{thread} thread di uno
-stesso processo (nel qual caso si parla di \textit{thread-shared semaphore}),
-occorrerà che \param{sem} sia l'indirizzo di una variabile visibile da tutti i
-\itindex{thread} thread, si dovrà usare cioè una variabile globale o una
-variabile allocata dinamicamente nello \itindex{heap} heap.
+Qualora il semaforo debba essere condiviso dai \itindex{thread}
+\textit{thread} di uno stesso processo (nel qual caso si parla di
+\textit{thread-shared semaphore}), occorrerà che \param{sem} sia l'indirizzo
+di una variabile visibile da tutti i \itindex{thread} \textit{thread}, si
+dovrà usare cioè una variabile globale o una variabile allocata dinamicamente
+nello \itindex{heap} heap.
Qualora il semaforo debba essere condiviso fra più processi (nel qual caso si
parla di \textit{process-shared semaphore}) la sola scelta possibile per
essere stato inizializzato con \func{sem\_init}; non deve quindi essere
applicata a semafori creati con \func{sem\_open}. Inoltre si deve essere
sicuri che il semaforo sia effettivamente inutilizzato, la distruzione di un
-semaforo su cui sono presenti processi (o thread) in attesa (cioè bloccati in
-una \func{sem\_wait}) provoca un comportamento indefinito.
+semaforo su cui sono presenti processi (o \itindex{thread} \textit{thread}) in
+attesa (cioè bloccati in una \func{sem\_wait}) provoca un comportamento
+indefinito.
Si tenga presente infine che utilizzare un semaforo che è stato distrutto con
\func{sem\_destroy} di nuovo può dare esito a comportamenti indefiniti. Nel
diventa di nuovo disponibile.
Un \textsl{server concorrente} al momento di trattare la richiesta crea un
-processo figlio (o un thread) incaricato di fornire i servizi richiesti, per
-porsi immediatamente in attesa di ulteriori richieste. In questo modo, con
-sistemi multitasking, più richieste possono essere soddisfatte
-contemporaneamente. Una volta che il processo figlio ha concluso il suo lavoro
-esso di norma viene terminato, mentre il server originale resta sempre attivo.
+processo figlio (o un \itindex{thread} \textit{thread}) incaricato di fornire
+i servizi richiesti, per porsi immediatamente in attesa di ulteriori
+richieste. In questo modo, con sistemi multitasking, più richieste possono
+essere soddisfatte contemporaneamente. Una volta che il processo figlio ha
+concluso il suo lavoro esso di norma viene terminato, mentre il server
+originale resta sempre attivo.
\subsection{Il modello \textit{peer-to-peer}}
tutte le parti uguali siano condivise), avrà un suo spazio di indirizzi,
variabili proprie e sarà eseguito in maniera completamente indipendente da
tutti gli altri.\footnote{questo non è del tutto vero nel caso di un programma
- \textit{multi-thread}, ma la gestione dei \textit{thread} in Linux sarà
- trattata a parte.}
+ \textit{multi-thread}, ma la gestione dei \itindex{thread} \textit{thread}
+ in Linux sarà trattata a parte in cap.~\ref{cha:threads}.}
\subsection{La funzione \func{main}}
Benché lo spazio di indirizzi virtuali copra un intervallo molto ampio, solo
una parte di essi è effettivamente allocato ed utilizzabile dal processo; il
tentativo di accedere ad un indirizzo non allocato è un tipico errore che si
-commette quando si è manipolato male un puntatore e genera quello che viene
-chiamato un \textit{segmentation fault}. Se si tenta cioè di leggere o
-scrivere da un indirizzo per il quale non esiste un'associazione della pagina
-virtuale, il kernel risponde al relativo \itindex{page~fault} \textit{page
- fault} mandando un segnale \const{SIGSEGV} al processo, che normalmente ne
-causa la terminazione immediata.
+commette quando si è manipolato male un puntatore e genera quella che viene
+chiamata una \itindex{segment~violation} \textit{segment violation}. Se si
+tenta cioè di leggere o scrivere da un indirizzo per il quale non esiste
+un'associazione della pagina virtuale, il kernel risponde al relativo
+\itindex{page~fault} \textit{page fault} mandando un segnale \const{SIGSEGV}
+al processo, che normalmente ne causa la terminazione immediata.
È pertanto importante capire come viene strutturata \index{memoria~virtuale}
\textsl{la memoria virtuale} di un processo. Essa viene divisa in
automaticamente il codice necessario, seguendo quella che viene chiamata
una \textit{calling convention}; quella standard usata con il C ed il C++
è detta \textit{cdecl} e prevede che gli argomenti siano caricati nello
- stack dal chiamante da destra a sinistra, e che si il chiamante stesso ad
- eseguire la ripulitura dello stack al ritorno della funzione, se ne
- possono però utilizzare di alternative (ad esempio nel pascal gli
- argomenti sono inseriti da sinistra a destra ed è compito del chiamato
- ripulire lo stack), in genere non ci si deve preoccupare di questo
- fintanto che non si mescolano funzioni scritte con linguaggi diversi.}
+ \textit{stack} dal chiamante da destra a sinistra, e che si il chiamante
+ stesso ad eseguire la ripulitura dello \textit{stack} al ritorno della
+ funzione, se ne possono però utilizzare di alternative (ad esempio nel
+ pascal gli argomenti sono inseriti da sinistra a destra ed è compito del
+ chiamato ripulire lo \textit{stack}), in genere non ci si deve preoccupare
+ di questo fintanto che non si mescolano funzioni scritte con linguaggi
+ diversi.}
La dimensione di questo segmento aumenta seguendo la crescita dello
\itindex{stack} \textit{stack} del programma, ma non viene ridotta quando
uso una versione meno efficiente delle funzioni suddette, che però è più
tollerante nei confronti di piccoli errori come quello di chiamate doppie a
\func{free}. In particolare:
-\begin{itemize*}
+\begin{itemize}
\item se la variabile è posta a zero gli errori vengono ignorati;
\item se è posta ad 1 viene stampato un avviso sullo \textit{standard error}
(vedi sez.~\ref{sec:file_std_stream});
\item se è posta a 2 viene chiamata \func{abort}, che in genere causa
l'immediata conclusione del programma.
-\end{itemize*}
+\end{itemize}
Il problema più comune e più difficile da risolvere che si incontra con le
funzioni di allocazione è quando non viene opportunamente liberata la memoria
\textit{Electric Fence} di Bruce Perens.} di eseguire diagnostiche anche
molto complesse riguardo l'allocazione della memoria.
-
Una possibile alternativa all'uso di \func{malloc}, che non soffre dei
problemi di \itindex{memory~leak} \textit{memory leak} descritti in
precedenza, è la funzione \funcd{alloca}, che invece di allocare la memoria
\textit{stack} della funzione corrente. La sintassi è identica a quella di
\func{malloc}, il suo prototipo è:
\begin{prototype}{stdlib.h}{void *alloca(size\_t size)}
- Alloca \param{size} byte nello stack.
+ Alloca \param{size} byte nello \textit{stack}.
- \bodydesc{La funzione restituisce il puntatore alla zona di memoria allocata
- in caso di successo e \val{NULL} in caso di fallimento, nel qual caso
- \var{errno} assumerà il valore \errval{ENOMEM}.}
+ \bodydesc{La funzione restituisce il puntatore alla zona di memoria
+ allocata.}
\end{prototype}
La funzione alloca la quantità di memoria (non inizializzata) richiesta
non può essere usata nella lista degli argomenti di una funzione, perché lo
spazio verrebbe allocato nel mezzo degli stessi.
-% Questo è riportato solo dal manuale delle glibc, nelle pagine di manuale non c'è
-% traccia di tutto ciò
-%
-%Inoltre se si
-%cerca di allocare troppa memoria non si ottiene un messaggio di errore, ma un
-%segnale di \textit{segment violation} analogo a quello che si avrebbe da una
-%ricorsione infinita.
-% TODO inserire più informazioni su alloca come da man page
-
-
Inoltre non è chiaramente possibile usare \func{alloca} per allocare memoria
che deve poi essere usata anche al di fuori della funzione in cui essa viene
chiamata, dato che all'uscita dalla funzione lo spazio allocato diventerebbe
Questo è lo stesso problema che si può avere con le variabili automatiche, su
cui torneremo in sez.~\ref{sec:proc_auto_var}.
+Infine non esiste un modo di sapere se l'allocazione ha avuto successo, la
+funzione infatti viene realizzata inserendo del codice \textit{inline} nel
+programma\footnote{questo comporta anche il fatto che non è possibile
+ sostituirla con una propria versione o modificarne il comportamento
+ collegando il proprio programma con un'altra libreria.} che si limita a
+modificare il puntatore nello \itindex{stack} \textit{stack} e non c'è modo di
+sapere se se ne sono superate le dimensioni, per cui in caso di fallimento
+nell'allocazione il comportamento del programma può risultare indefinito,
+dando luogo ad una \itindex{segment~violation} \textit{segment violation} la
+prima volta che cercherà di accedere alla memoria non effettivamente
+disponibile.
Le due funzioni seguenti\footnote{le due funzioni sono state definite con BSD
- 4.3, non fanno parte delle librerie standard del C e mentre sono state
- esplicitamente escluse dallo standard POSIX.} vengono utilizzate soltanto
-quando è necessario effettuare direttamente la gestione della memoria
-associata allo spazio dati di un processo, ad esempio qualora si debba
-implementare la propria versione delle funzioni di allocazione della memoria.
-La prima funzione è \funcd{brk}, ed il suo prototipo è:
+ 4.3, sono marcate obsolete in SUSv2 e non fanno parte delle librerie
+ standard del C e mentre sono state esplicitamente rimosse dallo standard
+ POSIX/1-2001.} vengono utilizzate soltanto quando è necessario effettuare
+direttamente la gestione della memoria associata allo spazio dati di un
+processo, ad esempio qualora si debba implementare la propria versione delle
+funzioni di allocazione della memoria. Per poterle utilizzare è necessario
+definire una della macro di funzionalità (vedi
+sez.~\ref{sec:intro_gcc_glibc_std}) fra \macro{\_BSD\_SOURCE},
+\macro{\_SVID\_SOURCE} e \macro{\_XOPEN\_SOURCE} (ad un valore maggiore o
+ugiale di 500). La prima funzione è \funcd{brk}, ed il suo prototipo è:
\begin{prototype}{unistd.h}{int brk(void *end\_data\_segment)}
Sposta la fine del segmento dei dati.
fallimento, nel qual caso \var{errno} assumerà il valore \errval{ENOMEM}.}
\end{prototype}
-La funzione è un'interfaccia diretta all'omonima system call ed imposta
-l'indirizzo finale del \index{segmento!dati} segmento dati di un processo
-all'indirizzo specificato da \param{end\_data\_segment}. Quest'ultimo deve
-essere un valore ragionevole, ed inoltre la dimensione totale del segmento non
-deve comunque eccedere un eventuale limite (si veda
-sez.~\ref{sec:sys_resource_limit}) imposto sulle dimensioni massime dello
-spazio dati del processo.
-
-Una seconda funzione per la manipolazione delle dimensioni
+La funzione è un'interfaccia all'omonima system call ed imposta l'indirizzo
+finale del \index{segmento!dati} segmento dati di un processo all'indirizzo
+specificato da \param{end\_data\_segment}. Quest'ultimo deve essere un valore
+ragionevole, ed inoltre la dimensione totale del segmento non deve comunque
+eccedere un eventuale limite (si veda sez.~\ref{sec:sys_resource_limit})
+imposto sulle dimensioni massime dello spazio dati del processo.
+
+Il valore di ritorno della funzione fa riferimento alla versione fornita dalle
+\acr{glibc}, in realtà in Linux la \textit{system call} corrispondente
+restituisce come valore di ritorno il nuovo valore della fine del
+\index{segmento!dati} segmento dati in caso di successo e quello corrente in
+caso di fallimento, è la funzione di interfaccia usata dalle \acr{glibc} che
+fornisce i valori di ritorno appena descritti, questo può non accadere se si
+usano librerie diverse.
+
+Una seconda funzione per la manipolazione diretta delle dimensioni
\index{segmento!dati} del segmento dati\footnote{in questo caso si tratta
soltanto di una funzione di libreria, e non di una system call.} è
\funcd{sbrk}, ed il suo prototipo è:
effettua il riordinamento del vettore \param{argv}.
-\subsection{Opzioni in formato esteso}
-\label{sec:proc_opt_extended}
-
-Un'estensione di questo schema è costituita dalle cosiddette
-\textit{long-options} espresse nella forma \cmd{-{}-option=parameter}, anche
-la gestione di queste ultime è stata standardizzata attraverso l'uso di una
-versione estesa di \func{getopt}.
-
-(NdA: questa parte verrà inserita in seguito).
-% TODO opzioni in formato esteso
-
\subsection{Le variabili di ambiente}
\label{sec:proc_environ}
``\textsl{sicura}'' da zero.
+\subsection{Opzioni in formato esteso}
+\label{sec:proc_opt_extended}
+
+Oltre alla modalità ordinaria di gestione delle opzioni trattata in
+sez.~\ref{sec:proc_opt_handling} le \acr{glibc} forniscono una modalità
+alternativa costituita dalle cosiddette \textit{long-options}, che consente di
+esprimere le opzioni in una forma più descrittiva che nel caso più generale è
+qualcosa del tipo di ``\texttt{-{}-option-name=parameter}''.
+
+(NdA: questa parte verrà inserita in seguito).
+
+% TODO opzioni in formato esteso
+
+
+
\section{Problematiche di programmazione generica}
\label{sec:proc_gen_prog}
% LocalWords: SUCCESS FAILURE void atexit stream fclose unistd descriptor init
% LocalWords: SIGCHLD wait function glibc SunOS arg argp execve fig high kb Mb
% LocalWords: memory alpha swap table printf Unit MMU paging fault SIGSEGV BSS
-% LocalWords: multitasking segmentation text segment NULL Block Started Symbol
+% LocalWords: multitasking text segment NULL Block Started Symbol
% LocalWords: heap stack calling convention size malloc calloc realloc nmemb
% LocalWords: ENOMEM ptr uClib cfree error leak smartpointers hook Dmalloc brk
% LocalWords: Gray Watson Electric Fence Bruce Perens sbrk longjmp SUSv BSD ap
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; il valore massimo è
- impostabile attraverso il file \procfile{/proc/sys/kernel/pid\_max} e di
- default vale 32768.} 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.
+ nuova interfaccia per i \itindex{thread} \textit{thread} creata da Ingo
+ Molnar anche il meccanismo di allocazione dei \acr{pid} è stato modificato;
+ il valore massimo è impostabile attraverso il file
+ \procfile{/proc/sys/kernel/pid\_max} e di default vale 32768.} 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
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 \index{segmento!testo} segmenti di
-testo, \itindex{stack} stack e \index{segmento!dati} dati (vedi
+testo, \itindex{stack} \textit{stack} e \index{segmento!dati} dati (vedi
sez.~\ref{sec:proc_mem_layout}), ed esegue esattamente lo stesso codice del
padre. Si tenga presente però che la memoria è copiata, non condivisa,
pertanto padre e figlio vedono variabili diverse.
deve essere specificato come maschera binaria dei flag riportati in
tab.~\ref{tab:proc_waitpid_options},\footnote{oltre a queste in Linux sono
previste del altre opzioni non standard, relative al comportamento con i
- thread, che riprenderemo in sez.~\ref{sec:thread_xxx}.} che possono essere
-combinati fra loro con un OR aritmetico.
+ \itindex{thread} \textit{thread}, che riprenderemo in
+ sez.~\ref{sec:thread_xxx}.} che possono essere combinati fra loro con un OR
+aritmetico.
L'uso dell'opzione \const{WNOHANG} consente di prevenire il blocco della
funzione qualora nessun figlio sia uscito (o non si siano verificate le altre
avviene nelle architetture NUMA).
Infine se un gruppo di processi accede alle stesse risorse condivise (ad
-esempio una applicazione con più thread) può avere senso usare lo stesso
-processore in modo da sfruttare meglio l'uso della sua cache; questo
-ovviamente riduce i benefici di un sistema multiprocessore nell'esecuzione
-contemporanea dei thread, ma in certi casi (quando i thread sono inerentemente
+esempio una applicazione con più \itindex{thread} \textit{thread}) può avere
+senso usare lo stesso processore in modo da sfruttare meglio l'uso della sua
+cache; questo ovviamente riduce i benefici di un sistema multiprocessore
+nell'esecuzione contemporanea dei \itindex{thread} \textit{thread}, ma in
+certi casi (quando i \itindex{thread} \textit{thread} sono inerentemente
serializzati nell'accesso ad una risorsa) possono esserci sufficienti vantaggi
nell'evitare la perdita della cache da rendere conveniente l'uso dell'affinità
di processore.
\subsection{Le funzioni rientranti}
\label{sec:proc_reentrant}
+\index{funzioni!rientranti|(}
+
Si dice \textsl{rientrante} una funzione che può essere interrotta in
qualunque punto della sua esecuzione ed essere chiamata una seconda volta da
-un altro thread di esecuzione senza che questo comporti nessun problema
-nell'esecuzione della stessa. La problematica è comune nella programmazione
-multi-thread, ma si hanno gli stessi problemi quando si vogliono chiamare
-delle funzioni all'interno dei gestori dei segnali.
+un altro \itindex{thread} \textit{thread} di esecuzione senza che questo
+comporti nessun problema nell'esecuzione della stessa. La problematica è
+comune nella programmazione \itindex{thread} \textit{multi-thread}, ma si
+hanno gli stessi problemi quando si vogliono chiamare delle funzioni
+all'interno dei gestori dei segnali.
Fintanto che una funzione opera soltanto con le variabili locali è rientrante;
-queste infatti vengono allocate nello \itindex{stack} stack, ed un'altra
-invocazione non fa altro che allocarne un'altra copia. Una funzione può non
-essere rientrante quando opera su memoria che non è nello \itindex{stack}
-stack. Ad esempio una funzione non è mai rientrante se usa una variabile
-globale o statica.
+queste infatti vengono allocate nello \itindex{stack} \textit{stack}, ed
+un'altra invocazione non fa altro che allocarne un'altra copia. Una funzione
+può non essere rientrante quando opera su memoria che non è nello
+\itindex{stack} \textit{stack}. Ad esempio una funzione non è mai rientrante
+se usa una variabile globale o statica.
Nel caso invece la funzione operi su un oggetto allocato dinamicamente, la
cosa viene a dipendere da come avvengono le operazioni: se l'oggetto è creato
In genere le funzioni di libreria non sono rientranti, molte di esse ad
esempio utilizzano variabili statiche, le \acr{glibc} però mettono a
-disposizione due macro di compilatore, \macro{\_REENTRANT} e
+disposizione due macro di compilatore,\footnote{si ricordi quanto illustrato
+ in sez.~\ref{sec:intro_gcc_glibc_std}.} \macro{\_REENTRANT} e
\macro{\_THREAD\_SAFE}, la cui definizione attiva le versioni rientranti di
varie funzioni di libreria, che sono identificate aggiungendo il suffisso
\code{\_r} al nome della versione normale.
+\index{funzioni!rientranti|)}
+
+
% LocalWords: multitasking like VMS child process identifier pid sez shell fig
% LocalWords: parent kernel init pstree keventd kswapd table struct linux call
% LocalWords: nell'header scheduler system interrupt timer HZ asm Hertz clock
% LocalWords: l'alpha tick fork wait waitpid exit exec image glibc int pgid ps
-% LocalWords: sid threads thread Ingo Molnar ppid getpid getppid sys unistd LD
+% LocalWords: sid thread Ingo Molnar ppid getpid getppid sys unistd LD
% LocalWords: void ForkTest tempnam pathname sibling cap errno EAGAIN ENOMEM
% LocalWords: stack read only copy write tab client spawn forktest sleep PATH
% LocalWords: source LIBRARY scheduling race condition printf descriptor dup
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
-statica; il suo prototipo è:
+Esiste infine una versione \index{funzioni!rientranti} rientrante
+\funcd{ttyname\_r} della funzione \func{ttyname}, che non presenta il problema
+dell'uso di una zona di memoria statica; il suo prototipo è:
\begin{prototype}{unistd.h}{int ttyname\_r(int desc, char *buff, size\_t len)}
Restituisce il nome del terminale associato al file \param{desc}.
I segnali che rappresentano errori del programma (divisione per zero o
violazioni di accesso) hanno anche la caratteristica di scrivere un file di
\itindex{core~dump} \textit{core dump} che registra lo stato del processo (ed
-in particolare della memoria e dello \itindex{stack} stack) prima della
-terminazione. Questo può essere esaminato in seguito con un debugger per
-investigare sulla causa dell'errore. Lo stesso avviene se i suddetti segnali
-vengono generati con una \func{kill}.
+in particolare della memoria e dello \itindex{stack} \textit{stack}) prima
+della terminazione. Questo può essere esaminato in seguito con un debugger
+per investigare sulla causa dell'errore. Lo stesso avviene se i suddetti
+segnali vengono generati con una \func{kill}.
\section{La classificazione dei segnali}
file (posto nella directory corrente del processo e chiamato \file{core}) su
cui viene salvata un'immagine della memoria del processo (il cosiddetto
\itindex{core~dump} \textit{core dump}), che può essere usata da un debugger
-per esaminare lo stato dello \itindex{stack} stack e delle variabili al
-momento della ricezione del segnale.
+per esaminare lo stato dello \itindex{stack} \textit{stack} e delle variabili
+al momento della ricezione del segnale.
\begin{table}[htb]
\footnotesize
file eseguibile è corrotto o si stanno cercando di eseguire dei dati.
Quest'ultimo caso può accadere quando si passa un puntatore sbagliato al
posto di un puntatore a funzione, o si eccede la scrittura di un vettore di
- una variabile locale, andando a corrompere lo \itindex{stack} stack. Lo
- stesso segnale viene generato in caso di overflow dello \itindex{stack}
- stack o di problemi nell'esecuzione di un gestore. Se il gestore ritorna il
- comportamento del processo è indefinito.
-\item[\const{SIGSEGV}] Il nome deriva da \textit{segment violation}, e
- significa che il programma sta cercando di leggere o scrivere in una zona di
- memoria protetta al di fuori di quella che gli è stata riservata dal
- sistema. In genere è il meccanismo della protezione della memoria che si
- accorge dell'errore ed il kernel genera il segnale. Se il gestore
- ritorna il comportamento del processo è indefinito.
+ una variabile locale, andando a corrompere lo \itindex{stack}
+ \textit{stack}. Lo stesso segnale viene generato in caso di overflow dello
+ \itindex{stack} \textit{stack} o di problemi nell'esecuzione di un gestore.
+ Se il gestore ritorna il comportamento del processo è indefinito.
+\item[\const{SIGSEGV}] Il nome deriva da \itindex{segment~violation}
+ \textit{segment violation}, e significa che il programma sta cercando di
+ leggere o scrivere in una zona di memoria protetta al di fuori di quella che
+ gli è stata riservata dal sistema. In genere è il meccanismo della
+ protezione della memoria che si accorge dell'errore ed il kernel genera il
+ segnale. Se il gestore ritorna il comportamento del processo è indefinito.
È tipico ottenere questo segnale dereferenziando un puntatore nullo o non
inizializzato leggendo al di là della fine di un vettore.
\const{SIGSEGV} questo è un segnale che viene generato di solito quando si
dereferenzia un puntatore non inizializzato, la differenza è che
\const{SIGSEGV} indica un accesso non permesso su un indirizzo esistente
- (tipo fuori dallo heap o dallo \itindex{stack} stack), mentre \const{SIGBUS}
- indica l'accesso ad un indirizzo non valido, come nel caso di un puntatore
- non allineato.
+ (tipo fuori dallo heap o dallo \itindex{stack} \textit{stack}), mentre
+ \const{SIGBUS} indica l'accesso ad un indirizzo non valido, come nel caso di
+ un puntatore non allineato.
\item[\const{SIGABRT}] Il nome deriva da \textit{abort}. Il segnale indica che
il programma stesso ha rilevato un errore che viene riportato chiamando la
funzione \func{abort} che genera questo segnale.
semantica inaffidabile.\\
\const{SA\_ONESHOT} & Nome obsoleto, sinonimo non standard di
\const{SA\_RESETHAND}; da evitare.\\
- \const{SA\_ONSTACK} & Stabilisce l'uso di uno \itindex{stack} stack
- alternativo per l'esecuzione del gestore (vedi
- sez.~\ref{sec:sig_specific_features}).\\
+ \const{SA\_ONSTACK} & Stabilisce l'uso di uno \itindex{stack}
+ \textit{stack} alternativo per l'esecuzione del
+ gestore (vedi
+ sez.~\ref{sec:sig_specific_features}).\\
\const{SA\_RESTART} & Riavvia automaticamente le \textit{slow system
call} quando vengono interrotte dal suddetto
segnale; riproduce cioè il comportamento standard
le funzioni piccole ed usate di frequente (in particolare nel kernel, dove
in certi casi le ottimizzazioni dal compilatore, tarate per l'uso in user
space, non sono sempre adatte). In tal caso infatti le istruzioni per creare
- un nuovo frame nello \itindex{stack} stack per chiamare la funzione
+ un nuovo frame nello \itindex{stack} \textit{stack} per chiamare la funzione
costituirebbero una parte rilevante del codice, appesantendo inutilmente il
programma. Originariamente questo comportamento veniva ottenuto con delle
macro, ma queste hanno tutta una serie di problemi di sintassi nel passaggio
rispetto a quanto potrebbe essere in un qualunque momento successivo.
Una delle caratteristiche di BSD, disponibile anche in Linux, è la possibilità
-di usare uno \itindex{stack} stack alternativo per i segnali; è cioè possibile
-fare usare al sistema un altro \itindex{stack} stack (invece di quello
-relativo al processo, vedi sez.~\ref{sec:proc_mem_layout}) solo durante
-l'esecuzione di un gestore. L'uso di uno stack alternativo è del tutto
-trasparente ai gestori, occorre però seguire una certa procedura:
+di usare uno \itindex{stack} \textit{stack} alternativo per i segnali; è cioè
+possibile fare usare al sistema un altro \itindex{stack} \textit{stack}
+(invece di quello relativo al processo, vedi sez.~\ref{sec:proc_mem_layout})
+solo durante l'esecuzione di un gestore. L'uso di uno \textit{stack}
+alternativo è del tutto trasparente ai gestori, occorre però seguire una certa
+procedura:
\begin{enumerate}
\item Allocare un'area di memoria di dimensione sufficiente da usare come
- stack alternativo;
+ \textit{stack} alternativo;
\item Usare la funzione \func{sigaltstack} per rendere noto al sistema
- l'esistenza e la locazione dello stack alternativo;
+ l'esistenza e la locazione dello \textit{stack} alternativo;
\item Quando si installa un gestore occorre usare \func{sigaction}
specificando il flag \const{SA\_ONSTACK} (vedi tab.~\ref{tab:sig_sa_flag})
- per dire al sistema di usare lo stack alternativo durante l'esecuzione del
- gestore.
+ per dire al sistema di usare lo \textit{stack} alternativo durante
+ l'esecuzione del gestore.
\end{enumerate}
In genere il primo passo viene effettuato allocando un'opportuna area di
memoria con \code{malloc}; in \file{signal.h} sono definite due costanti,
\const{SIGSTKSZ} e \const{MINSIGSTKSZ}, che possono essere utilizzate per
allocare una quantità di spazio opportuna, in modo da evitare overflow. La
-prima delle due è la dimensione canonica per uno \itindex{stack} stack di
-segnali e di norma è sufficiente per tutti gli usi normali.
+prima delle due è la dimensione canonica per uno \itindex{stack}
+\textit{stack} di segnali e di norma è sufficiente per tutti gli usi normali.
La seconda è lo spazio che occorre al sistema per essere in grado di lanciare
-il gestore e la dimensione di uno stack alternativo deve essere sempre
-maggiore di questo valore. Quando si conosce esattamente quanto è lo spazio
-necessario al gestore gli si può aggiungere questo valore per allocare uno
-\itindex{stack} stack di dimensione sufficiente.
-
-Come accennato, per poter essere usato, lo \itindex{stack} stack per i segnali
-deve essere indicato al sistema attraverso la funzione \funcd{sigaltstack}; il
-suo prototipo è:
+il gestore e la dimensione di uno \textit{stack} alternativo deve essere
+sempre maggiore di questo valore. Quando si conosce esattamente quanto è lo
+spazio necessario al gestore gli si può aggiungere questo valore per allocare
+uno \itindex{stack} \textit{stack} di dimensione sufficiente.
+
+Come accennato, per poter essere usato, lo \itindex{stack} \textit{stack} per
+i segnali deve essere indicato al sistema attraverso la funzione
+\funcd{sigaltstack}; il suo prototipo è:
\begin{prototype}{signal.h}
{int sigaltstack(const stack\_t *ss, stack\_t *oss)}
-Installa un nuovo stack per i segnali.
+Installa un nuovo \textit{stack} per i segnali.
\bodydesc{La funzione restituisce zero in caso di successo e $-1$ per un
errore, nel qual caso \var{errno} assumerà i valori:
\begin{errlist}
- \item[\errcode{ENOMEM}] la dimensione specificata per il nuovo stack è minore
- di \const{MINSIGSTKSZ}.
+ \item[\errcode{ENOMEM}] la dimensione specificata per il nuovo
+ \textit{stack} è minore di \const{MINSIGSTKSZ}.
\item[\errcode{EPERM}] uno degli indirizzi non è valido.
- \item[\errcode{EFAULT}] si è cercato di cambiare lo stack alternativo mentre
- questo è attivo (cioè il processo è in esecuzione su di esso).
+ \item[\errcode{EFAULT}] si è cercato di cambiare lo \textit{stack}
+ alternativo mentre questo è attivo (cioè il processo è in esecuzione su di
+ esso).
\item[\errcode{EINVAL}] \param{ss} non è nullo e \var{ss\_flags} contiene un
valore diverso da zero che non è \const{SS\_DISABLE}.
\end{errlist}}
La funzione prende come argomenti puntatori ad una struttura di tipo
\var{stack\_t}, definita in fig.~\ref{fig:sig_stack_t}. I due valori
\param{ss} e \param{oss}, se non nulli, indicano rispettivamente il nuovo
-\itindex{stack} stack da installare e quello corrente (che viene restituito
-dalla funzione per un successivo ripristino).
+\itindex{stack} \textit{stack} da installare e quello corrente (che viene
+restituito dalla funzione per un successivo ripristino).
\begin{figure}[!htb]
\footnotesize \centering
\end{figure}
Il campo \var{ss\_sp} di \struct{stack\_t} indica l'indirizzo base dello
-\itindex{stack} stack, mentre \var{ss\_size} ne indica la dimensione; il campo
-\var{ss\_flags} invece indica lo stato dello stack. Nell'indicare un nuovo
-stack occorre inizializzare \var{ss\_sp} e \var{ss\_size} rispettivamente al
-puntatore e alla dimensione della memoria allocata, mentre \var{ss\_flags}
-deve essere nullo. Se invece si vuole disabilitare uno stack occorre indicare
-\const{SS\_DISABLE} come valore di \var{ss\_flags} e gli altri valori saranno
-ignorati.
+\itindex{stack} \textit{stack}, mentre \var{ss\_size} ne indica la dimensione;
+il campo \var{ss\_flags} invece indica lo stato dello \textit{stack}.
+Nell'indicare un nuovo \textit{stack} occorre inizializzare \var{ss\_sp} e
+\var{ss\_size} rispettivamente al puntatore e alla dimensione della memoria
+allocata, mentre \var{ss\_flags} deve essere nullo. Se invece si vuole
+disabilitare uno \textit{stack} occorre indicare \const{SS\_DISABLE} come
+valore di \var{ss\_flags} e gli altri valori saranno ignorati.
Se \param{oss} non è nullo verrà restituito dalla funzione indirizzo e
-dimensione dello \itindex{stack} stack corrente nei relativi campi, mentre
-\var{ss\_flags} potrà assumere il valore \const{SS\_ONSTACK} se il processo è
-in esecuzione sullo stack alternativo (nel qual caso non è possibile
-cambiarlo) e \const{SS\_DISABLE} se questo non è abilitato.
-
-In genere si installa uno \itindex{stack} stack alternativo per i segnali
-quando si teme di avere problemi di esaurimento dello stack standard o di
-superamento di un limite (vedi sez.~\ref{sec:sys_resource_limit}) imposto con
-chiamate del tipo \code{setrlimit(RLIMIT\_STACK, \&rlim)}. In tal caso
-infatti si avrebbe un segnale di \const{SIGSEGV}, che potrebbe essere gestito
-soltanto avendo abilitato uno \itindex{stack} stack alternativo.
-
-Si tenga presente che le funzioni chiamate durante l'esecuzione sullo stack
-alternativo continueranno ad usare quest'ultimo, che, al contrario di quanto
-avviene per lo \itindex{stack} stack ordinario dei processi, non si accresce
-automaticamente (ed infatti eccederne le dimensioni può portare a conseguenze
-imprevedibili). Si ricordi infine che una chiamata ad una funzione della
-famiglia \func{exec} cancella ogni stack alternativo.
+dimensione dello \itindex{stack} \textit{stack} corrente nei relativi campi,
+mentre \var{ss\_flags} potrà assumere il valore \const{SS\_ONSTACK} se il
+processo è in esecuzione sullo \textit{stack} alternativo (nel qual caso non è
+possibile cambiarlo) e \const{SS\_DISABLE} se questo non è abilitato.
+
+In genere si installa uno \itindex{stack} \textit{stack} alternativo per i
+segnali quando si teme di avere problemi di esaurimento dello \textit{stack}
+standard o di superamento di un limite (vedi
+sez.~\ref{sec:sys_resource_limit}) imposto con chiamate del tipo
+\code{setrlimit(RLIMIT\_STACK, \&rlim)}. In tal caso infatti si avrebbe un
+segnale di \const{SIGSEGV}, che potrebbe essere gestito soltanto avendo
+abilitato uno \itindex{stack} \textit{stack} alternativo.
+
+Si tenga presente che le funzioni chiamate durante l'esecuzione sullo
+\textit{stack} alternativo continueranno ad usare quest'ultimo, che, al
+contrario di quanto avviene per lo \itindex{stack} \textit{stack} ordinario
+dei processi, non si accresce automaticamente (ed infatti eccederne le
+dimensioni può portare a conseguenze imprevedibili). Si ricordi infine che
+una chiamata ad una funzione della famiglia \func{exec} cancella ogni
+\textit{stack} alternativo.
Abbiamo visto in fig.~\ref{fig:sig_sleep_incomplete} come si possa usare
\func{longjmp} per uscire da un gestore rientrando direttamente nel corpo
\headdecl{setjmp.h}
\funcdecl{int sigsetjmp(sigjmp\_buf env, int savesigs)} Salva il contesto
- dello stack per un \index{salto~non-locale} salto non-locale.
+ dello \textit{stack} per un \index{salto~non-locale} salto non-locale.
\funcdecl{void siglongjmp(sigjmp\_buf env, int val)} Esegue un salto
non-locale su un precedente contesto.
\end{functions}
Le due funzioni prendono come primo argomento la variabile su cui viene
-salvato il contesto dello \itindex{stack} stack per permettere il
+salvato il contesto dello \itindex{stack} \textit{stack} per permettere il
\index{salto~non-locale} salto non-locale; nel caso specifico essa è di tipo
\type{sigjmp\_buf}, e non \type{jmp\_buf} come per le analoghe di
sez.~\ref{sec:proc_longjmp} in quanto in questo caso viene salvata anche la
ed ad esempio può essere problematico chiamare all'interno di un gestore di
segnali la stessa funzione che dal segnale è stata interrotta.
-\index{funzioni~sicure|(}
+\index{funzioni!sicure|(}
Il concetto è comunque più generale e porta ad una distinzione fra quelle che
che POSIX chiama \textsl{funzioni insicure} (\textit{n'Usane function}) e
\label{fig:sig_safe_functions}
\end{figure}
-\index{funzioni~sicure|)}
+\index{funzioni!sicure|)}
Per questo motivo è opportuno mantenere al minimo indispensabile le operazioni
effettuate all'interno di un gestore di segnali, qualora si debbano compiere
\section{Funzionalità avanzate}
-\label{sec:sig_real_time}
+\label{sec:sig_advanced_signal}
Tratteremo in questa ultima sezione alcune funzionalità avanzate relativa ai
Lo standard POSIX.1b definisce inoltre delle nuove funzioni che permettono di
gestire l'attesa di segnali specifici su una coda, esse servono in particolar
-modo nel caso dei thread, in cui si possono usare i segnali real-time come
-meccanismi di comunicazione elementare; la prima di queste funzioni è
-\funcd{sigwait}, il cui prototipo è:
+modo nel caso dei \itindex{thread} \textit{thread}, in cui si possono usare i
+segnali real-time come meccanismi di comunicazione elementare; la prima di
+queste funzioni è \funcd{sigwait}, il cui prototipo è:
\begin{prototype}{signal.h}
{int sigwait(const sigset\_t *set, int *sig)}
prevedibile.
Lo standard POSIX.1b definisce altre due funzioni, anch'esse usate
-prevalentemente con i thread; \funcd{sigwaitinfo} e \funcd{sigtimedwait}, i
-relativi prototipi sono:
+prevalentemente con i \itindex{thread} \textit{thread}; \funcd{sigwaitinfo} e
+\funcd{sigtimedwait}, i relativi prototipi sono:
\begin{functions}
\headdecl{signal.h}
immediatamente; in questo modo si può eliminare un segnale dalla coda senza
dover essere bloccati qualora esso non sia presente.
+\itindbeg{thread}
+
L'uso di queste funzioni è principalmente associato alla gestione dei segnali
-con i thread. In genere esse vengono chiamate dal thread incaricato della
-gestione, che al ritorno della funzione esegue il codice che usualmente
-sarebbe messo nel gestore, per poi ripetere la chiamata per mettersi in attesa
-del segnale successivo. Questo ovviamente comporta che non devono essere
-installati gestori, che solo il thread di gestione deve usare \func{sigwait} e
-che, per evitare che venga eseguita l'azione predefinita, i segnali gestiti in
-questa maniera devono essere mascherati per tutti i thread, compreso quello
-dedicato alla gestione, che potrebbe riceverlo fra due chiamate successive.
+con i \textit{thread}. In genere esse vengono chiamate dal \textit{thread}
+incaricato della gestione, che al ritorno della funzione esegue il codice che
+usualmente sarebbe messo nel gestore, per poi ripetere la chiamata per
+mettersi in attesa del segnale successivo. Questo ovviamente comporta che non
+devono essere installati gestori, che solo il \textit{thread} di gestione deve
+usare \func{sigwait} e che, per evitare che venga eseguita l'azione
+predefinita, i segnali gestiti in questa maniera devono essere mascherati per
+tutti i \textit{thread}, compreso quello dedicato alla gestione, che potrebbe
+riceverlo fra due chiamate successive.
+
+\itindend{thread}
\subsection{La gestione avanzata delle temporizzazioni}
Le funzioni illustrate finora hanno un difetto: utilizzando una area di
memoria interna per allocare i contenuti della struttura \struct{hostent} non
-possono essere rientranti. Questo comporta anche che in due successive
-chiamate i dati potranno essere sovrascritti. Si tenga presente poi che
-copiare il contenuto della sola struttura non è sufficiente per salvare tutti
-i dati, in quanto questa contiene puntatori ad altri dati, che pure possono
-essere sovrascritti; per questo motivo, se si vuole salvare il risultato di
-una chiamata, occorrerà eseguire quella che si chiama una \itindex{deep~copy}
-\textit{deep copy}.\footnote{si chiama così quella tecnica per cui, quando si
- deve copiare il contenuto di una struttura complessa (con puntatori che
- puntano ad altri dati, che a loro volta possono essere puntatori ad altri
- dati) si deve copiare non solo il contenuto della struttura, ma eseguire una
- scansione per risolvere anche tutti i puntatori contenuti in essa (e così
- via se vi sono altre sotto-strutture con altri puntatori) e copiare anche i
- dati da questi referenziati.}
+possono essere\index{funzioni!rientranti} rientranti. Questo comporta anche
+che in due successive chiamate i dati potranno essere sovrascritti. Si tenga
+presente poi che copiare il contenuto della sola struttura non è sufficiente
+per salvare tutti i dati, in quanto questa contiene puntatori ad altri dati,
+che pure possono essere sovrascritti; per questo motivo, se si vuole salvare
+il risultato di una chiamata, occorrerà eseguire quella che si chiama una
+\itindex{deep~copy} \textit{deep copy}.\footnote{si chiama così quella tecnica
+ per cui, quando si deve copiare il contenuto di una struttura complessa (con
+ puntatori che puntano ad altri dati, che a loro volta possono essere
+ puntatori ad altri dati) si deve copiare non solo il contenuto della
+ struttura, ma eseguire una scansione per risolvere anche tutti i puntatori
+ contenuti in essa (e così via se vi sono altre sotto-strutture con altri
+ puntatori) e copiare anche i dati da questi referenziati.}
Per ovviare a questi problemi nelle \acr{glibc} sono definite anche delle
-versioni rientranti delle precedenti funzioni, al solito queste sono
-caratterizzate dall'avere un suffisso \texttt{\_r}, pertanto avremo le due
-funzioni \funcd{gethostbyname\_r} e \funcd{gethostbyname2\_r} i cui prototipi
-sono:
+versioni \index{funzioni!rientranti} rientranti delle precedenti funzioni, al
+solito queste sono caratterizzate dall'avere un suffisso \texttt{\_r},
+pertanto avremo le due funzioni \funcd{gethostbyname\_r} e
+\funcd{gethostbyname2\_r} i cui prototipi sono:
\begin{functions}
\headdecl{netdb.h}
\headdecl{sys/socket.h}
altrimenti restituiscono un codice di errore negativo e all'indirizzo puntato
da \param{result} sarà salvato un puntatore nullo, mentre a quello puntato da
\param{h\_errnop} sarà salvato il valore del codice di errore, dato che per
-essere rientrante la funzione non può la variabile globale \var{h\_errno}. In
-questo caso il codice di errore, oltre ai valori di
+essere \index{funzioni!rientranti} rientrante la funzione non può la variabile
+globale \var{h\_errno}. In questo caso il codice di errore, oltre ai valori di
tab.~\ref{tab:h_errno_values}, può avere anche quello di \errcode{ERANGE}
qualora il buffer allocato su \param{buf} non sia sufficiente a contenere i
dati, in tal caso si dovrà semplicemente ripetere l'esecuzione della funzione
una apposita struttura \struct{servent} contenente tutti i risultati,
altrimenti viene restituito un puntatore nullo. Si tenga presente che anche
in questo caso i dati vengono mantenuti in una area di memoria statica e che
-quindi la funzione non è rientrante.
+quindi la funzione non è \index{funzioni!rientranti} rientrante.
\begin{figure}[!htb]
\footnotesize \centering
variabile (di tipo puntatore ad una struttura \struct{addrinfo}) che verrà
utilizzata dalla funzione per riportare (come \itindex{value~result~argument}
\textit{value result argument}) i propri risultati. La funzione infatti è
-rientrante, ed alloca autonomamente tutta la memoria necessaria in cui
-verranno riportati i risultati della risoluzione. La funzione scriverà
-all'indirizzo puntato da \param{res} il puntatore iniziale ad una
-\itindex{linked~list} \textit{linked list} di strutture di tipo
-\struct{addrinfo} contenenti tutte le informazioni ottenute.
+\index{funzioni!rientranti} rientrante, ed alloca autonomamente tutta la
+memoria necessaria in cui verranno riportati i risultati della risoluzione.
+La funzione scriverà all'indirizzo puntato da \param{res} il puntatore
+iniziale ad una \itindex{linked~list} \textit{linked list} di strutture di
+tipo \struct{addrinfo} contenenti tutte le informazioni ottenute.
\begin{figure}[!htb]
\footnotesize \centering
dell'indirizzo (espresso in \textit{network order}) restituendo il puntatore
alla stringa che contiene l'espressione in formato dotted decimal. Si deve
tenere presente che la stringa risiede in memoria statica, per cui questa
-funzione non è rientrante.
+funzione non è \index{funzioni!rientranti} rientrante.
\subsection{Le funzioni \func{inet\_pton} e \func{inet\_ntop}}
motivo viene sovrascritta ad ogni nuova invocazione, lo stesso dicasi per la
memoria dove sono scritte le stringhe a cui i puntatori in essa contenuti
fanno riferimento. Ovviamente questo implica che dette funzioni non possono
-essere rientranti; per questo motivo ne esistono anche due versioni
-alternative (denotate dalla solita estensione \code{\_r}), i cui prototipi
-sono:
+essere \index{funzioni!rientranti} rientranti; per questo motivo ne esistono
+anche due versioni alternative (denotate dalla solita estensione \code{\_r}),
+i cui prototipi sono:
\begin{functions}
\headdecl{pwd.h}
impostato a \val{NULL}).
Del tutto analoghe alle precedenti sono le funzioni \funcd{getgrnam} e
-\funcd{getgrgid} (e le relative analoghe rientranti con la stessa estensione
-\code{\_r}) che permettono di leggere le informazioni relative ai gruppi, i
-loro prototipi sono:
+\funcd{getgrgid} (e le relative analoghe \index{funzioni!rientranti}
+rientranti con la stessa estensione \code{\_r}) che permettono di leggere le
+informazioni relative ai gruppi, i loro prototipi sono:
\begin{functions}
\headdecl{grp.h}
\headdecl{sys/types.h}
\hline
\func{fgetpwent} & Legge una voce dal file di registro degli utenti
specificato.\\
- \func{fgetpwent\_r}& Come la precedente, ma rientrante.\\
+ \func{fgetpwent\_r}& Come la precedente, ma \index{funzioni!rientranti}
+ rientrante.\\
\func{putpwent} & Immette una voce in un file di registro degli
utenti.\\
\func{getpwent} & Legge una voce da \conffile{/etc/passwd}.\\
- \func{getpwent\_r} & Come la precedente, ma rientrante.\\
+ \func{getpwent\_r} & Come la precedente, ma \index{funzioni!rientranti}
+ rientrante.\\
\func{setpwent} & Ritorna all'inizio di \conffile{/etc/passwd}.\\
\func{endpwent} & Chiude \conffile{/etc/passwd}.\\
\func{fgetgrent} & Legge una voce dal file di registro dei gruppi
specificato.\\
- \func{fgetgrent\_r}& Come la precedente, ma rientrante.\\
+ \func{fgetgrent\_r}& Come la precedente, ma \index{funzioni!rientranti}
+ rientrante.\\
\func{putgrent} & Immette una voce in un file di registro dei gruppi.\\
\func{getgrent} & Legge una voce da \conffile{/etc/group}.\\
- \func{getgrent\_r} & Come la precedente, ma rientrante.\\
+ \func{getgrent\_r} & Come la precedente, ma \index{funzioni!rientranti}
+ rientrante.\\
\func{setgrent} & Ritorna all'inizio di \conffile{/etc/group}.\\
\func{endgrent} & Chiude \conffile{/etc/group}.\\
\hline
sinonimi delle funzioni appena viste.
Come visto in sez.~\ref{sec:sys_user_group}, l'uso di strutture allocate
-staticamente rende le funzioni di lettura non rientranti; per questo motivo le
-\acr{glibc} forniscono anche delle versioni rientranti: \func{getutent\_r},
-\func{getutid\_r}, \func{getutline\_r}, che invece di restituire un puntatore
-restituiscono un intero e prendono due argomenti aggiuntivi. Le funzioni si
-comportano esattamente come le analoghe non rientranti, solo che restituiscono
-il risultato all'indirizzo specificato dal primo argomento aggiuntivo (di tipo
-\code{struct utmp *buffer}) mentre il secondo (di tipo \code{struct utmp
- **result)} viene usato per restituire il puntatore allo stesso buffer.
+staticamente rende le funzioni di lettura non \index{funzioni!rientranti}
+rientranti; per questo motivo le \acr{glibc} forniscono anche delle versioni
+\index{funzioni!rientranti} rientranti: \func{getutent\_r}, \func{getutid\_r},
+\func{getutline\_r}, che invece di restituire un puntatore restituiscono un
+intero e prendono due argomenti aggiuntivi. Le funzioni si comportano
+esattamente come le analoghe non \index{funzioni!rientranti} rientranti, solo
+che restituiscono il risultato all'indirizzo specificato dal primo argomento
+aggiuntivo (di tipo \code{struct utmp *buffer}) mentre il secondo (di tipo
+\code{struct utmp **result)} viene usato per restituire il puntatore allo
+stesso buffer.
Infine le \acr{glibc} forniscono come estensione per la scrittura delle voci
in \file{wmtp} altre due funzioni, \funcd{updwtmp} e \funcd{logwtmp}, i cui
esse falliranno con un errore di
\errcode{ENOMEM}, mentre se il superamento viene
causato dalla crescita dello \itindex{stack}
- stack il processo riceverà un segnale di
+ \textit{stack} il processo riceverà un segnale di
\const{SIGSEGV}.\\
\const{RLIMIT\_CORE} & La massima dimensione per di un file di
\itindex{core~dump} \textit{core dump} (vedi
si potrà sempre inviare un segnale che non sia
già presente su una coda.\footnotemark\\
\const{RLIMIT\_STACK} & La massima dimensione dello \itindex{stack}
- stack del
- processo. Se il processo esegue operazioni che
- estendano lo stack oltre questa dimensione
+ \textit{stack} del processo. Se il processo
+ esegue operazioni che estendano lo
+ \textit{stack} oltre questa dimensione
riceverà un segnale di \const{SIGSEGV}.\\
\const{RLIMIT\_RSS} & L'ammontare massimo di pagine di memoria dato al
\index{segmento!testo} testo del processo. Il
e impostano anche la variabile \var{tzname} con l'informazione della
\textit{time zone} corrente; \func{ctime} è banalmente definita in termini di
\func{asctime} come \code{asctime(localtime(t)}. Dato che l'uso di una stringa
-statica rende le funzioni non rientranti POSIX.1c e SUSv2 prevedono due
-sostitute rientranti, il cui nome è al solito ottenuto aggiungendo un
-\code{\_r}, che prendono un secondo argomento \code{char *buf}, in cui
-l'utente deve specificare il buffer su cui la stringa deve essere copiata
-(deve essere di almeno 26 caratteri).
+statica rende le funzioni non \index{funzioni!rientranti} rientranti POSIX.1c
+e SUSv2 prevedono due sostitute \index{funzioni!rientranti} rientranti, il cui
+nome è al solito ottenuto aggiungendo un \code{\_r}, che prendono un secondo
+argomento \code{char *buf}, in cui l'utente deve specificare il buffer su cui
+la stringa deve essere copiata (deve essere di almeno 26 caratteri).
Le altre tre funzioni, \func{gmtime}, \func{localtime} e \func{mktime} servono
per convertire il tempo dal formato \type{time\_t} a quello di \struct{tm} e
Anche in questo caso le prime due funzioni restituiscono l'indirizzo di una
struttura allocata staticamente, per questo sono state definite anche altre
-due versioni rientranti (con la solita estensione \code{\_r}), che prevedono
-un secondo argomento \code{struct tm *result}, fornito dal chiamante, che deve
-preallocare la struttura su cui sarà restituita la conversione.
+due versioni \index{funzioni!rientranti} rientranti (con la solita estensione
+\code{\_r}), che prevedono un secondo argomento \code{struct tm *result},
+fornito dal chiamante, che deve preallocare la struttura su cui sarà
+restituita la conversione.
Come mostrato in fig.~\ref{fig:sys_tm_struct} il \textit{broken-down time}
permette di tenere conto anche della differenza fra tempo universale e ora
semplicemente usando un opportuno valore di ritorno della funzione invocata.
Inoltre il sistema di classificazione degli errori è basato sull'architettura
a processi, e presenta una serie di problemi nel caso lo si debba usare con i
-thread.
+\itindex{thread} \textit{thread}.
\subsection{La variabile \var{errno}}
Per riportare il tipo di errore il sistema usa la variabile globale
\var{errno},\footnote{l'uso di una variabile globale può comportare alcuni
- problemi (ad esempio nel caso dei thread) ma lo standard ISO C consente
- anche di definire \var{errno} come un \textit{modifiable lvalue}, quindi si
- può anche usare una macro, e questo è infatti il modo usato da Linux per
- renderla locale ai singoli thread.} definita nell'header \file{errno.h}; la
+ problemi (ad esempio nel caso dei \itindex{thread} \textit{thread}) ma lo
+ standard ISO C consente anche di definire \var{errno} come un
+ \textit{modifiable lvalue}, quindi si può anche usare una macro, e questo è
+ infatti il modo usato da Linux per renderla locale ai singoli
+ \itindex{thread} \textit{thread}.} definita nell'header \file{errno.h}; la
variabile è in genere definita come \direct{volatile} dato che può essere
cambiata in modo asincrono da un segnale (si veda sez.~\ref{sec:sig_sigchld}
per un esempio, ricordando quanto trattato in sez.~\ref{sec:proc_race_cond}),
programma; essa è utilizzabile solo fino ad una chiamata successiva a
\func{strerror} o \func{perror}, nessun'altra funzione di libreria tocca
questa stringa. In ogni caso l'uso di una stringa statica rende la funzione
-non rientrante, per cui nel caso si usino i thread le librerie
-forniscono\footnote{questa funzione è la versione prevista dalle \acr{glibc},
- ed effettivamente definita in \file{string.h}, ne esiste una analoga nello
- standard SUSv3 (quella riportata dalla pagina di manuale), che restituisce
- \code{int} al posto di \code{char *}, e che tronca la stringa restituita a
- \param{size}.} una apposita versione rientrante \func{strerror\_r}, il cui
-prototipo è:
+non \index{funzioni!rientranti} rientrante, per cui nel caso si usino i
+\itindex{thread} \textit{thread} le librerie forniscono\footnote{questa
+ funzione è la versione prevista dalle \acr{glibc}, ed effettivamente
+ definita in \file{string.h}, ne esiste una analoga nello standard SUSv3
+ (quella riportata dalla pagina di manuale), che restituisce \code{int} al
+ posto di \code{char *}, e che tronca la stringa restituita a
+ \param{size}.} una apposita versione \index{funzioni!rientranti} rientrante
+\func{strerror\_r}, il cui prototipo è:
\begin{prototype}{string.h}
{char * strerror\_r(int errnum, char *buf, size\_t size)}
\noindent
La funzione è analoga a \func{strerror} ma restituisce la stringa di errore
-nel buffer \param{buf} che il singolo thread deve allocare autonomamente per
-evitare i problemi connessi alla condivisione del buffer statico. Il messaggio
-è copiato fino alla dimensione massima del buffer, specificata dall'argomento
+nel buffer \param{buf} che il singolo \itindex{thread} \textit{thread} deve
+allocare autonomamente per evitare i problemi connessi alla condivisione del
+buffer statico. Il messaggio è copiato fino alla dimensione massima del
+buffer, specificata dall'argomento
\param{size}, che deve comprendere pure il carattere di terminazione;
altrimenti la stringa viene troncata.
\chapter{I thread}
\label{cha:threads}
+
+\itindbeg{thread}
+
Tratteremo in questo capitolo un modello di programmazione multitasking,
quello dei \textit{thread}, alternativo al modello classico dei processi,
tipico di Unix. Ne esamineremo le caratteristiche, vantaggi e svantaggi, e le
diverse realizzazioni che sono disponibili per Linux; nella seconda parte
tratteremo in dettaglio quella che è l'implementazione principale, che fa
-riferimento all'interfaccia standardizzata da POSIX.1e.
+riferimento all'interfaccia standardizzata da POSIX.1e.
\section{Introduzione ai \textit{thread}}
\section{Posix \textit{thread}}
-\label{sec:thread_intro}
+\label{sec:thread_posix_intro}
Tratteremo in questa sezione l'interfaccia di programmazione con i
\label{sec:pthread_cond}
+\itindend{thread}
+
+
% LocalWords: thread multitasking POSIX sez Posix Library kernel glibc mutex