X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=process.tex;h=f14150aa94728ffda3e09f31c8d270eda6ec0e28;hp=be725cdfa077dceb0143a4e0b48c180415233a1d;hb=b0f9e84fb388f894bf26c87ffa304847bddfa3b0;hpb=9b7af600ff0f73bc946c9d160c320667c7a91347 diff --git a/process.tex b/process.tex index be725cd..f14150a 100644 --- a/process.tex +++ b/process.tex @@ -1,6 +1,6 @@ %% process.tex %% -%% Copyright (C) 2000-2015 by Simone Piccardi. Permission is granted to +%% Copyright (C) 2000-2018 by Simone Piccardi. Permission is granted to %% copy, distribute and/or modify this document under the terms of the GNU Free %% Documentation License, Version 1.1 or any later version published by the %% Free Software Foundation; with the Invariant Sections being "Un preambolo", @@ -36,7 +36,7 @@ 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. 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 in cap.~\ref{cha:threads}. +trattata a parte\unavref{in cap.~\ref{cha:threads}}. \subsection{L'avvio e l'esecuzione di un programma} @@ -44,9 +44,9 @@ trattata a parte in cap.~\ref{cha:threads}. \itindbeg{link-loader} \itindbeg{shared~objects} -Quando un programma viene messo in esecuzione cosa che può essere fatta solo -con una funzione della famiglia \func{exec} (vedi sez.~\ref{sec:proc_exec}) il -kernel esegue un opportuno codice di avvio, il cosiddetto +Quando un programma viene messo in esecuzione, cosa che può essere fatta solo +con una funzione della famiglia \func{exec} (vedi sez.~\ref{sec:proc_exec}), +il kernel esegue un opportuno codice di avvio, il cosiddetto \textit{link-loader}, costituito dal programma \cmd{ld-linux.so}. Questo programma è una parte fondamentale del sistema il cui compito è quello della gestione delle cosiddette \textsl{librerie condivise}, quelle che nel mondo @@ -64,15 +64,15 @@ una sola volta per tutti i programmi che lo usano. Questo significa però che normalmente il codice di un programma è incompleto, contenendo solo i riferimenti alle funzioni di libreria che vuole utilizzare e non il relativo codice. Per questo motivo all'avvio del programma è necessario -l'intervento del \textit{link-loader} il cui compito è -caricare in memoria le librerie condivise eventualmente assenti, ed effettuare -poi il collegamento dinamico del codice del programma alle funzioni di -libreria da esso utilizzate prima di metterlo in esecuzione. +l'intervento del \textit{link-loader} il cui compito è caricare in memoria le +librerie condivise eventualmente assenti, ed effettuare poi il collegamento +dinamico del codice del programma alle funzioni di libreria da esso utilizzate +prima di metterlo in esecuzione. Il funzionamento di \cmd{ld-linux.so} è controllato da alcune variabili di -ambiente e dal contenuto del file \conffile{/etc/ld.so.conf}, che consentono -di elencare le directory un cui cercare le librerie e determinare quali -verranno utilizzate. In particolare con la variabile di ambiente +ambiente e dal contenuto del file \conffile{/etc/ld.so.conf} che consentono di +elencare le directory un cui cercare le librerie e determinare quali verranno +utilizzate. In particolare con la variabile di ambiente \envvar{LD\_LIBRARY\_PATH} si possono indicare ulteriori directory rispetto a quelle di sistema in cui inserire versioni personali delle librerie che hanno la precedenza su quelle di sistema, mentre con la variabile di ambiente @@ -213,27 +213,28 @@ definizioni. & ANSI C& POSIX& \\ \hline \hline - \headfile{assert.h}&$\bullet$& -- & Verifica le asserzioni fatte in un - programma.\\ - \headfile{ctype.h} &$\bullet$& -- & Tipi standard.\\ - \headfile{dirent.h}& -- &$\bullet$& Manipolazione delle directory.\\ - \headfile{errno.h} & -- &$\bullet$& Errori di sistema.\\ - \headfile{fcntl.h} & -- &$\bullet$& Controllo sulle opzioni dei file.\\ - \headfile{limits.h}& -- &$\bullet$& Limiti e parametri del sistema.\\ - \headfile{malloc.h}&$\bullet$& -- & Allocazione della memoria.\\ - \headfile{setjmp.h}&$\bullet$& -- & Salti non locali.\\ - \headfile{signal.h}& -- &$\bullet$& Gestione dei segnali.\\ - \headfile{stdarg.h}&$\bullet$& -- & Gestione di funzioni a argomenti + \headfiled{assert.h}&$\bullet$& -- & Verifica le asserzioni fatte in un + programma.\\ + \headfiled{ctype.h} &$\bullet$& -- & Tipi standard.\\ + \headfiled{dirent.h}& -- &$\bullet$& Manipolazione delle directory.\\ + \headfiled{errno.h} & -- &$\bullet$& Errori di sistema.\\ + \headfiled{fcntl.h} & -- &$\bullet$& Controllo sulle opzioni dei + file.\\ + \headfiled{limits.h}& -- &$\bullet$& Limiti e parametri del sistema.\\ + \headfiled{malloc.h}&$\bullet$& -- & Allocazione della memoria.\\ + \headfiled{setjmp.h}&$\bullet$& -- & Salti non locali.\\ + \headfiled{signal.h}& -- &$\bullet$& Gestione dei segnali.\\ + \headfiled{stdarg.h}&$\bullet$& -- & Gestione di funzioni a argomenti variabili.\\ - \headfile{stdio.h} &$\bullet$& -- & I/O bufferizzato in standard ANSI - C.\\ - \headfile{stdlib.h}&$\bullet$& -- & Definizioni della libreria - standard.\\ - \headfile{string.h}&$\bullet$& -- & Manipolazione delle stringhe.\\ - \headfile{time.h} & -- &$\bullet$& Gestione dei tempi.\\ - \headfile{times.h} &$\bullet$& -- & Gestione dei tempi.\\ - \headfile{unistd.h}& -- &$\bullet$& Unix standard library.\\ - \headfile{utmp.h} & -- &$\bullet$& Registro connessioni utenti.\\ + \headfiled{stdio.h} &$\bullet$& -- & I/O bufferizzato in standard ANSI + C.\\ + \headfiled{stdlib.h}&$\bullet$& -- & Definizioni della libreria + standard.\\ + \headfiled{string.h}&$\bullet$& -- & Manipolazione delle stringhe.\\ + \headfiled{time.h} & -- &$\bullet$& Gestione dei tempi.\\ + \headfiled{times.h} &$\bullet$& -- & Gestione dei tempi.\\ + \headfiled{unistd.h}& -- &$\bullet$& Unix standard library.\\ + \headfiled{utmp.h} & -- &$\bullet$& Registro connessioni utenti.\\ \hline \end{tabular} \caption{Elenco dei principali \textit{header file} definiti dagli standard @@ -248,8 +249,7 @@ di quelli installati con il sistema,\footnote{in un sistema GNU/Linux che segue le specifiche del \textit{Filesystem Hierarchy Standard} (per maggiori informazioni si consulti sez.~1.2.3 di \cite{AGL}) si trovano sotto \texttt{/usr/include}.} o fra virgolette, nel qual caso si fa riferimento -ad una versione locale, da indicare con un \itindsub{pathname}{relativo} -\textit{pathname} relativo: +ad una versione locale, da indicare con un \textit{pathname} relativo: \includecodesnip{listati/main_include.c} Si tenga presente che oltre ai nomi riservati a livello generale di cui si è @@ -274,7 +274,7 @@ esempio si avrà che: ``\texttt{TC}'' e con ``\texttt{B}'' seguito da un numero, \item in \headfile{grp.h} vengono riservati i nomi che iniziano con ``\texttt{gr\_}'', -\item in \headfile{pwd.h}vengono riservati i nomi che iniziano con +\item in \headfile{pwd.h} vengono riservati i nomi che iniziano con ``\texttt{pw\_}'', \end{itemize*} @@ -292,18 +292,28 @@ una qualunque funzione ordinaria, la situazione è totalmente diversa nell'esecuzione del programma. Una funzione ordinaria infatti viene eseguita, esattamente come il codice che si è scritto nel corpo del programma, in \textit{user space}. Quando invece si esegue una \textit{system call} -l'esecuzione ordinaria del programma viene interrotta, i dati forniti (come -argomenti della chiamata) vengono trasferiti al kernel che esegue il codice -della \textit{system call} (che è codice del kernel) in \textit{kernel space}. +l'esecuzione ordinaria del programma viene interrotta con quello che viene +usualmente chiamato un \itindex{context~switch} \textit{context + switch};\footnote{in realtà si parla più comunemente di \textit{context + switch} quando l'esecuzione di un processo viene interrotta dal kernel + (tramite lo \textit{scheduler}) per metterne in esecuzione un altro, ma il + concetto generale resta lo stesso: l'esecuzione del proprio codice in + \textit{user space} viene interrotta e lo stato del processo deve essere + salvato per poterne riprendere l'esecuzione in un secondo tempo.} il +contesto di esecuzione del processo viene salvato in modo da poterne +riprendere in seguito l'esecuzione ed i dati forniti (come argomenti della +chiamata) vengono trasferiti al kernel che esegue il codice della +\textit{system call} (che è codice del kernel) in \textit{kernel space}; al +completamento della \textit{system call} i dati salvati nel \textit{context + switch} saranno usati per riprendere l'esecuzione ordinaria del programma. Dato che il passaggio dei dati ed il salvataggio del contesto di esecuzione -del programma che consentirà di riprenderne l'esecuzione ordinaria al -completamento della \textit{system call} sono operazioni critiche per le -prestazioni del sistema, per rendere il più veloce possibile questa -operazione, usualmente chiamata \textit{context switch} sono state sviluppate -una serie di ottimizzazioni che richiedono alcune preparazioni abbastanza -complesse dei dati, che in genere dipendono dall'architettura del processore -sono scritte direttamente in \textit{assembler}. +sono operazioni critiche per le prestazioni del sistema, per rendere il più +veloce possibile questa operazione sono state sviluppate una serie di +ottimizzazioni che richiedono alcune preparazioni abbastanza complesse dei +dati, che in genere dipendono dall'architettura del processore e sono scritte +direttamente in \textit{assembler}. + % % TODO:trattare qui, quando sarà il momento vsyscall e vDSO, vedi: @@ -325,14 +335,19 @@ associazione, e lavorare a basso livello con una specifica versione, oppure si può voler utilizzare una \textit{system call} che non è stata ancora associata ad una funzione di libreria. In tal caso, per evitare di dover effettuare esplicitamente le operazioni di preparazione citate, all'interno della -\textsl{glibc} è fornita una specifica funzione, \funcd{syscall}, che consente -eseguire direttamente una \textit{system call}; il suo prototipo, accessibile -se si è definita la macro \macro{\_GNU\_SOURCE}, è: +\textsl{glibc} è fornita una specifica funzione, +\funcd{syscall},\footnote{fino a prima del kernel 2.6.18 per l'esecuzione + diretta delle \textit{system call} erano disponibili anche una serie di + macro \texttt{\_syscall\textsl{N}} (con $N$ pari al numero di argomenti + della \textit{system call}); queste sono deprecate e pertanto non ne + parleremo ulteriormente.} che consente eseguire direttamente una +\textit{system call}; il suo prototipo, accessibile se si è definita la macro +\macro{\_GNU\_SOURCE}, è: \begin{funcproto}{ \fhead{unistd.h} \fhead{sys/syscall.h} - \fdecl{int syscall(int number, ...)} + \fdecl{long syscall(int number, ...)} \fdesc{Esegue la \textit{system call} indicata da \param{number}.} } {La funzione ritorna un intero dipendente dalla \textit{system call} invocata, @@ -353,7 +368,7 @@ dall'architettura,\footnote{in genere le vecchie \textit{system call} non ciascuna \textit{system call} viene in genere identificata da una costante nella forma \texttt{SYS\_*} dove al prefisso viene aggiunto il nome che spesso corrisponde anche alla omonima funzione di libreria. Queste costanti sono -definite nel file \headfile{sys/syscall.h}, ma si possono anche usare +definite nel file \headfiled{sys/syscall.h}, ma si possono anche usare direttamente valori numerici. @@ -366,7 +381,7 @@ linguaggio C all'interno della stessa, o se si richiede esplicitamente la chiusura invocando direttamente la funzione \func{exit}. Queste due modalità sono assolutamente equivalenti, dato che \func{exit} viene chiamata in maniera trasparente anche quando \code{main} ritorna, passandogli come argomento il -valore di ritorno (che essendo . +valore di ritorno. La funzione \funcd{exit}, che è completamente generale, essendo definita dallo standard ANSI C, è quella che deve essere invocata per una terminazione @@ -427,18 +442,22 @@ usare un multiplo di 256, di avere uno stato di uscita uguale a zero, che verrebbe interpretato come un successo. Per questo motivo in \headfile{stdlib.h} sono definite, seguendo lo standard -POSIX, le due costanti \const{EXIT\_SUCCESS} e \const{EXIT\_FAILURE}, da usare -sempre per specificare lo stato di uscita di un processo. Su Linux, ed in -generale in qualunque sistema POSIX, ad esse sono assegnati rispettivamente i -valori 0 e 1. +POSIX, le due costanti \constd{EXIT\_SUCCESS} e \constd{EXIT\_FAILURE}, da +usare sempre per specificare lo stato di uscita di un processo. Su Linux, ed +in generale in qualunque sistema POSIX, ad esse sono assegnati rispettivamente +i valori 0 e 1. \itindend{exit~status} Una forma alternativa per effettuare una terminazione esplicita di un programma è quella di chiamare direttamente la \textit{system call} \funcd{\_exit},\footnote{la stessa è definita anche come \funcd{\_Exit} in - \headfile{stdlib.h}.} che restituisce il controllo direttamente al kernel, -concludendo immediatamente il processo, il suo prototipo è: + \headfile{stdlib.h}, inoltre a partire dalle \acr{glibc} 2.3 usando questa + funzione viene invocata \func{exit\_group} che termina tutti i + \textit{thread} del processo e non solo quello corrente (fintanto che non si + usano i \textit{thread}\unavref{, vedi sez.~\ref{cha:threads},} questo non + fa nessuna differenza).} che restituisce il controllo direttamente al +kernel, concludendo immediatamente il processo, il suo prototipo è: \begin{funcproto}{ \fhead{unistd.h} \fdecl{void \_exit(int status)} \fdesc{Causa la conclusione immediata del programma.} } {La funzione non @@ -482,7 +501,7 @@ chiamata ad una funzione che effettui tali operazioni all'uscita dal programma. A questo scopo lo standard ANSI C prevede la possibilità di registrare un certo numero di funzioni che verranno eseguite all'uscita dal programma,\footnote{nel caso di \func{atexit} lo standard POSIX.1-2001 - richiede che siano registrabili almeno \const{ATEXIT\_MAX} funzioni (il + richiede che siano registrabili almeno \constd{ATEXIT\_MAX} funzioni (il valore può essere ottenuto con \func{sysconf}, vedi sez.~\ref{sec:sys_limits}).} sia per la chiamata ad \func{exit} che per il ritorno di \code{main}. La prima funzione che si può utilizzare a tal fine è @@ -663,7 +682,7 @@ bit e di 8kb sulle alpha. Con le versioni più recenti del kernel è possibile anche utilizzare pagine di dimensioni maggiori (di 4Mb, dette \textit{huge page}), per sistemi con grandi quantitativi di memoria in cui l'uso di pagine troppo piccole comporta una perdita di prestazioni. In alcuni sistemi -la costante \const{PAGE\_SIZE}, definita in \headfile{limits.h}, indica la +la costante \constd{PAGE\_SIZE}, definita in \headfile{limits.h}, indica la dimensione di una pagina in byte, con Linux questo non avviene e per ottenere questa dimensione si deve ricorrere alla funzione \func{getpagesize} (vedi sez.~\ref{sec:sys_memory_res}). @@ -754,10 +773,10 @@ processo. Essa viene divisa in \textsl{segmenti}, cioè un insieme contiguo di indirizzi virtuali ai quali il processo può accedere. Solitamente un programma C viene suddiviso nei seguenti segmenti: \index{segmento!testo|(} -\index{segmento!dati(} +\index{segmento!dati|(} \itindbeg{heap} \itindbeg{stack} -\begin{enumerate*} +\begin{enumerate} \item Il \textsl{segmento di testo} o \textit{text segment}. Contiene il codice del programma, delle funzioni di librerie da esso utilizzate, e le costanti. Normalmente viene condiviso fra tutti i processi che eseguono lo @@ -783,7 +802,7 @@ programma C viene suddiviso nei seguenti segmenti: globale è che essa può essere vista solo all'interno della funzione in cui è dichiarata.} e la memoria allocata dinamicamente. Di norma è diviso in tre parti: - \begin{itemize*} + \begin{itemize} \item Il segmento dei dati inizializzati, che contiene le variabili il cui valore è stato assegnato esplicitamente. Ad esempio se si definisce: \includecodesnip{listati/pi.c} @@ -810,7 +829,7 @@ programma C viene suddiviso nei seguenti segmenti: disallocare la memoria dinamica con le apposite funzioni (vedi sez.~\ref{sec:proc_mem_alloc}), ma il suo limite inferiore, quello adiacente al segmento dei dati non inizializzati, ha una posizione fissa. - \end{itemize*} + \end{itemize} \item Il segmento di \textit{stack}, che contiene quello che viene chiamato lo ``\textit{stack}'' del programma. Tutte le volte che si effettua una chiamata ad una funzione è qui che viene salvato l'indirizzo di ritorno e le @@ -834,7 +853,7 @@ programma C viene suddiviso nei seguenti segmenti: La dimensione di questo segmento aumenta seguendo la crescita dello \textit{stack} del programma, ma non viene ridotta quando quest'ultimo si restringe. -\end{enumerate*} +\end{enumerate} \begin{figure}[htb] \centering @@ -878,7 +897,7 @@ mai salvato sul file che contiene l'eseguibile, dato che viene sempre inizializzato a zero al caricamento del programma. \index{segmento!testo|)} -\index{segmento!dati)} +\index{segmento!dati|)} \itindend{heap} \itindend{stack} @@ -1074,25 +1093,23 @@ Il problema è che l'esaurimento della memoria può avvenire in qualunque momento, in corrispondenza ad una qualunque chiamata di \func{malloc} che può essere in una sezione del codice che non ha alcuna relazione con la funzione che contiene l'errore. Per questo motivo è sempre molto difficile trovare un -\textit{memory leak}. - -In C e C++ il problema è particolarmente sentito. In C++, per mezzo della -programmazione ad oggetti, il problema dei \textit{memory leak} si può -notevolmente ridimensionare attraverso l'uso accurato di appositi oggetti come -gli \textit{smartpointers}. Questo però in genere va a scapito delle -prestazioni dell'applicazione in esecuzione. - -% TODO decidere cosa fare di questo che segue -% In altri linguaggi come il java e recentemente il C\# il problema non si pone -% nemmeno perché la gestione della memoria viene fatta totalmente in maniera -% automatica, ovvero il programmatore non deve minimamente preoccuparsi di -% liberare la memoria allocata precedentemente quando non serve più, poiché -% l'infrastruttura del linguaggio gestisce automaticamente la cosiddetta -% \index{\textit{garbage~collection}} \textit{garbage collection}. In tal caso, -% attraverso meccanismi simili a quelli del \textit{reference counting}, quando -% una zona di memoria precedentemente allocata non è più riferita da nessuna -% parte del codice in esecuzione, può essere deallocata automaticamente in -% qualunque momento dall'infrastruttura. +\textit{memory leak}. In C e C++ il problema è particolarmente sentito. In +C++, per mezzo della programmazione ad oggetti, il problema dei \textit{memory + leak} si può notevolmente ridimensionare attraverso l'uso accurato di +appositi oggetti come gli \textit{smartpointers}. Questo però in genere va a +scapito delle prestazioni dell'applicazione in esecuzione. + +% TODO decidere cosa fare di questo che segue In altri linguaggi come il java +% e recentemente il C\# il problema non si pone nemmeno perché la gestione +% della memoria viene fatta totalmente in maniera automatica, ovvero il +% programmatore non deve minimamente preoccuparsi di liberare la memoria +% allocata precedentemente quando non serve più, poiché l'infrastruttura del +% linguaggio gestisce automaticamente la cosiddetta +% \itindex{garbage~collection} \textit{garbage collection}. In tal caso, +% attraverso meccanismi simili a quelli del \textit{reference counting}, +% quando una zona di memoria precedentemente allocata non è più riferita da +% nessuna parte del codice in esecuzione, può essere deallocata +% automaticamente in qualunque momento dall'infrastruttura. % Anche questo va a scapito delle prestazioni dell'applicazione in esecuzione % (inoltre le applicazioni sviluppate con tali linguaggi di solito non sono @@ -1155,7 +1172,7 @@ Gli svantaggi sono che questa funzione non è disponibile su tutti gli Unix, e non è inserita né nello standard POSIX né in SUSv3 (ma è presente in BSD), il suo utilizzo quindi limita la portabilità dei programmi. Inoltre la funzione non può essere usata nella lista degli argomenti di una funzione, perché lo -spazio verrebbe allocato nel mezzo degli stessi. Inoltre non è chiaramente +spazio verrebbe allocato nel mezzo degli stessi. 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 libero, e potrebbe @@ -1174,7 +1191,6 @@ comportamento del programma può risultare indefinito, dando luogo ad una \textit{segment violation} la prima volta che cercherà di accedere alla memoria non effettivamente disponibile. - \index{segmento!dati|(} \itindbeg{heap} @@ -1200,9 +1216,9 @@ uguale di 500). La prima funzione è \funcd{brk}, ed il suo prototipo è: La funzione è un'interfaccia all'omonima \textit{system call} ed imposta l'indirizzo finale del segmento dati di un processo (più precisamente dello \textit{heap}) all'indirizzo specificato da \param{addr}. Quest'ultimo deve -essere un valore ragionevole, e la dimensione totale non deve comunque -eccedere un eventuale limite (vedi sez.~\ref{sec:sys_resource_limit}) imposto -sulle dimensioni massime del segmento dati del processo. +essere un valore ragionevole e la dimensione totale non deve comunque eccedere +un eventuale limite (vedi sez.~\ref{sec:sys_resource_limit}) sulle dimensioni +massime del segmento dati del processo. Il valore di ritorno della funzione fa riferimento alla versione fornita dalla \acr{glibc}, in realtà in Linux la \textit{system call} corrispondente @@ -1227,12 +1243,12 @@ segmento dati\footnote{in questo caso si tratta soltanto di una funzione di caso \var{errno} assumerà il valore \errcode{ENOMEM}.} \end{funcproto} -La funzione incrementa la dimensione dello \textit{heap} di un -programma del valore indicato dall'argomento \param{increment}, restituendo il -nuovo indirizzo finale dello stesso. L'argomento è definito come di tipo -\type{intptr\_t}, ma a seconda della versione delle librerie e del sistema può -essere indicato con una serie di tipi equivalenti come \ctyp{ptrdiff\_t}, -\ctyp{ssize\_t}, \ctyp{int}. Se invocata con un valore nullo la funzione +La funzione incrementa la dimensione dello \textit{heap} di un programma del +valore indicato dall'argomento \param{increment}, restituendo il nuovo +indirizzo finale dello stesso. L'argomento è definito come di tipo +\typed{intptr\_t}, ma a seconda della versione delle librerie e del sistema +può essere indicato con una serie di tipi equivalenti come \type{ptrdiff\_t}, +\type{ssize\_t}, \ctyp{int}. Se invocata con un valore nullo la funzione permette di ottenere l'attuale posizione della fine del segmento dati. Queste due funzioni sono state deliberatamente escluse dallo standard POSIX.1 @@ -1370,7 +1386,7 @@ sez.~\ref{sec:proc_exec}). Il sistema pone dei limiti all'ammontare di memoria di un processo che può essere bloccata e al totale di memoria fisica che si può dedicare a questo, lo standard POSIX.1 richiede che sia definita in \headfile{unistd.h} la macro -\macro{\_POSIX\_MEMLOCK\_RANGE} per indicare la capacità di eseguire il +\macrod{\_POSIX\_MEMLOCK\_RANGE} per indicare la capacità di eseguire il \textit{memory locking}. Siccome la richiesta di un \textit{memory lock} da parte di un processo riduce @@ -1426,6 +1442,9 @@ blocco. Con kernel diversi da Linux si può ottenere un errore di pagine di memoria, pertanto se si ha a cuore la portabilità si deve avere cura di allinearne correttamente il valore. +% TODO trattare mlock2, introdotta con il kernel 4.4 (vedi +% http://lwn.net/Articles/650538/) + Altre due funzioni di sistema, \funcd{mlockall} e \funcd{munlockall}, consentono di bloccare genericamente la paginazione per l'intero spazio di indirizzi di un processo. I prototipi di queste funzioni sono: @@ -1454,10 +1473,10 @@ espressi dalle costanti riportate in tab.~\ref{tab:mlockall_flags}. \textbf{Valore} & \textbf{Significato} \\ \hline \hline - \const{MCL\_CURRENT}& blocca tutte le pagine correntemente mappate nello - spazio di indirizzi del processo.\\ - \const{MCL\_FUTURE} & blocca tutte le pagine che verranno mappate nello - spazio di indirizzi del processo.\\ + \constd{MCL\_CURRENT}& blocca tutte le pagine correntemente mappate nello + spazio di indirizzi del processo.\\ + \constd{MCL\_FUTURE} & blocca tutte le pagine che verranno mappate nello + spazio di indirizzi del processo.\\ \hline \end{tabular} \caption{Valori e significato dell'argomento \param{flags} della funzione @@ -1636,20 +1655,20 @@ tipologia di errore riscontrata. \textbf{Valore} & \textbf{Significato} \\ \hline \hline - \const{MCHECK\_OK} & Riportato a \func{mprobe} se nessuna - inconsistenza è presente.\\ - \const{MCHECK\_DISABLED}& Riportato a \func{mprobe} se si è chiamata - \func{mcheck} dopo aver già usato - \func{malloc}.\\ - \const{MCHECK\_HEAD} & I dati immediatamente precedenti il buffer sono - stati modificati, avviene in genere quando si - decrementa eccessivamente il valore di un - puntatore scrivendo poi prima dell'inizio del - buffer.\\ - \const{MCHECK\_TAIL} & I dati immediatamente seguenti il buffer sono - stati modificati, succede quando si va scrivere - oltre la dimensione corretta del buffer.\\ - \const{MCHECK\_FREE} & Il buffer è già stato disallocato.\\ + \constd{MCHECK\_OK} & Riportato a \func{mprobe} se nessuna + inconsistenza è presente.\\ + \constd{MCHECK\_DISABLED}& Riportato a \func{mprobe} se si è chiamata + \func{mcheck} dopo aver già usato + \func{malloc}.\\ + \constd{MCHECK\_HEAD} & I dati immediatamente precedenti il buffer sono + stati modificati, avviene in genere quando si + decrementa eccessivamente il valore di un + puntatore scrivendo poi prima dell'inizio del + buffer.\\ + \constd{MCHECK\_TAIL} & I dati immediatamente seguenti il buffer sono + stati modificati, succede quando si va scrivere + oltre la dimensione corretta del buffer.\\ + \constd{MCHECK\_FREE} & Il buffer è già stato disallocato.\\ \hline \end{tabular} \caption{Valori dello stato dell'allocazione di memoria ottenibili dalla @@ -1860,7 +1879,7 @@ Normalmente \func{getopt} compie una permutazione degli elementi di opzioni sono spostati in coda al vettore. Oltre a questa esistono altre due modalità di gestire gli elementi di \param{argv}; se \param{optstring} inizia con il carattere ``\texttt{+}'' (o è impostata la variabile di ambiente -\macro{POSIXLY\_CORRECT}) la scansione viene fermata non appena si incontra un +\cmd{POSIXLY\_CORRECT}) la scansione viene fermata non appena si incontra un elemento che non è un'opzione. L'ultima modalità, usata quando un programma può gestire la mescolanza fra @@ -2319,7 +2338,7 @@ relativo puntatore fra le funzioni. \subsection{Il passaggio di un numero variabile di argomenti} \label{sec:proc_variadic} -\index{funzioni!variadic|(} +\index{funzioni!\textit{variadic}|(} Come vedremo nei capitoli successivi, non sempre è possibile specificare un numero fisso di argomenti per una funzione. Lo standard ISO C prevede nella @@ -2377,6 +2396,8 @@ quelli variabili vengono indicati in maniera generica dalla pertanto quella sequenziale, in cui vengono estratti dallo \textit{stack} secondo l'ordine in cui sono stati scritti nel prototipo della funzione. +\macrobeg{va\_start} + Per fare questo in \headfile{stdarg.h} sono definite delle macro specifiche, previste dallo standard ISO C89, che consentono di eseguire questa operazione. La prima di queste macro è \macro{va\_start}, che inizializza opportunamente @@ -2391,10 +2412,12 @@ una lista degli argomenti, la sua definizione è: } \end{funcbox}} -La macro inizializza il puntatore alla lista di argomenti \param{ap} che -deve essere una apposita variabile di tipo \type{va\_list}; il +La macro inizializza il puntatore alla lista di argomenti \param{ap} che deve +essere una apposita variabile di tipo \type{va\_list}; il parametro \param{last} deve indicare il nome dell'ultimo degli argomenti fissi -dichiarati nel prototipo della funzione \textit{variadic}. +dichiarati nel prototipo della funzione \textit{variadic}. + +\macrobeg{va\_arg} La seconda macro di gestione delle liste di argomenti di una funzione \textit{variadic} è \macro{va\_arg}, che restituisce in successione un @@ -2423,8 +2446,10 @@ effettivamente forniti si otterranno dei valori indefiniti. Si avranno risultati indefiniti anche quando si chiama \macro{va\_arg} specificando un tipo che non corrisponde a quello usato per il corrispondente argomento. +\macrobeg{va\_end} + Infine una volta completata l'estrazione occorre indicare che si sono concluse -le operazioni con la macro \macro{va\_end}, la cui definizione è: +le operazioni con la macro \macrod{va\_end}, la cui definizione è: {\centering \begin{funcbox}{ @@ -2467,6 +2492,10 @@ caso però al ritorno della funzione \macro{va\_arg} non può più essere usata (anche se non si era completata l'estrazione) dato che il valore di \param{ap} risulterebbe indefinito. +\macroend{va\_start} +\macroend{va\_arg} +\macroend{va\_end} + Esistono dei casi in cui è necessario eseguire più volte la scansione degli argomenti e poter memorizzare una posizione durante la stessa. In questo caso sembrerebbe naturale copiarsi la lista degli argomenti \param{ap} con una @@ -2478,18 +2507,18 @@ assolutamente normale pensare di poter effettuare questa operazione. \index{tipo!opaco|(} In generale però possono esistere anche realizzazioni diverse, ed è per questo -motivo che invece che di un semplice puntatore viene \type{va\_list} è quello -che viene chiamato un \textsl{tipo opaco}. Si chiamano così quei tipi di dati, -in genere usati da una libreria, la cui struttura interna non deve essere -vista dal programma chiamante (da cui deriva il nome opaco) che li devono -utilizzare solo attraverso dalle opportune funzioni di gestione. +motivo che invece che un semplice puntatore, \typed{va\_list} è quello che +viene chiamato un \textsl{tipo opaco}. Si chiamano così quei tipi di dati, in +genere usati da una libreria, la cui struttura interna non deve essere vista +dal programma chiamante (da cui deriva il nome opaco) che li devono utilizzare +solo attraverso dalle opportune funzioni di gestione. \index{tipo!opaco|)} -Per questo motivo una variabile di tipo \type{va\_list} non può essere +Per questo motivo una variabile di tipo \typed{va\_list} non può essere assegnata direttamente ad un'altra variabile dello stesso tipo, ma lo standard ISO C99\footnote{alcuni sistemi che non hanno questa macro provvedono al suo - posto \macro{\_\_va\_copy} che era il nome proposto in una bozza dello + posto \macrod{\_\_va\_copy} che era il nome proposto in una bozza dello standard.} ha previsto una macro ulteriore che permette di eseguire la copia di una lista degli argomenti: @@ -2503,7 +2532,7 @@ copia di una lista degli argomenti: La macro copia l'attuale della lista degli argomenti \param{src} su una nuova lista \param{dest}. Anche in questo caso è buona norma chiudere ogni -esecuzione di una \macro{va\_copy} con una corrispondente \macro{va\_end} sul +esecuzione di una \macrod{va\_copy} con una corrispondente \macro{va\_end} sul nuovo puntatore alla lista degli argomenti. La chiamata di una funzione con un numero variabile di argomenti, posto che la @@ -2535,7 +2564,7 @@ valore speciale per l'ultimo argomento, come fa ad esempio \func{execl} che usa un puntatore \val{NULL} per indicare la fine della lista degli argomenti (vedi sez.~\ref{sec:proc_exec}). -\index{funzioni!variadic|)} +\index{funzioni!\textit{variadic}|)} \subsection{Il controllo di flusso non locale} \label{sec:proc_longjmp} @@ -2591,7 +2620,7 @@ di salvare il contesto dello \textit{stack} è \funcd{setjmp}, il cui prototipo Quando si esegue la funzione il contesto corrente dello \textit{stack} viene salvato nell'argomento \param{env}, una variabile di tipo -\type{jmp\_buf}\footnote{anche questo è un classico esempio di variabile di +\typed{jmp\_buf}\footnote{anche questo è un classico esempio di variabile di \textsl{tipo opaco}.} che deve essere stata definita in precedenza. In genere le variabili di tipo \type{jmp\_buf} vengono definite come variabili globali in modo da poter essere viste in tutte le funzioni del programma. @@ -2625,10 +2654,10 @@ dell'argomento \param{val} deve essere sempre diverso da zero, se si è specificato 0 sarà comunque restituito 1 al suo posto. In sostanza l'esecuzione di \func{longjmp} è analoga a quella di una -istruzione \instruction{return}, solo che invece di ritornare alla riga +istruzione \instr{return}, solo che invece di ritornare alla riga successiva della funzione chiamante, il programma in questo caso ritorna alla posizione della relativa \func{setjmp}. L'altra differenza fondamentale con -\instruction{return} è che il ritorno può essere effettuato anche attraverso +\instr{return} è che il ritorno può essere effettuato anche attraverso diversi livelli di funzioni annidate. L'implementazione di queste funzioni comporta alcune restrizioni dato che esse @@ -2652,13 +2681,13 @@ dei seguenti casi: In generale, dato che l'unica differenza fra la chiamata diretta e quella ottenuta nell'uscita con un \func{longjmp} è costituita dal valore di ritorno di \func{setjmp}, pertanto quest'ultima viene usualmente chiamata all'interno -di un una istruzione \instruction{if} che permetta di distinguere i due casi. +di un una istruzione \instr{if} che permetta di distinguere i due casi. Uno dei punti critici dei salti non-locali è quello del valore delle variabili, ed in particolare quello delle variabili automatiche della funzione a cui si ritorna. In generale le variabili globali e statiche mantengono i valori che avevano al momento della chiamata di \func{longjmp}, ma quelli -delle variabili automatiche (o di quelle dichiarate \direct{register}) sono in +delle variabili automatiche (o di quelle dichiarate \dirct{register}) sono in genere indeterminati. Quello che succede infatti è che i valori delle variabili che sono tenute in @@ -2680,6 +2709,10 @@ dichiarandole tutte come \direct{volatile}.\footnote{la direttiva \index{salto~non-locale|)} +% TODO trattare qui le restartable sequences (vedi +% https://lwn.net/Articles/664645/ e https://lwn.net/Articles/650333/) se e +% quando saranno introdotte + \subsection{La \textit{endianness}} \label{sec:endianness}