X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=intro.tex;h=d2833478591e6539840f760e020d0ee240da36ae;hp=34950b5ded552bdc8e96438b8d629664acf444db;hb=2567503eef2f6e35067c3795a744d04bc9317c91;hpb=4ad4523de32d786ae4c24ef157bd4b8fe4aac534 diff --git a/intro.tex b/intro.tex index 34950b5..d283347 100644 --- a/intro.tex +++ b/intro.tex @@ -12,12 +12,12 @@ GNU/Linux (che sono comunque comuni a tutti i sistemi \textit{unix-like}) ed introdurremo alcuni degli standard principali a cui viene fatto riferimento. -\section{Una panoramica sulla struttura} +\section{Una panoramica} \label{sec:intro_unix_struct} -In questa prima sezione faremo una panoramica sulla struttura di un sistema -\textit{unix-like} come GNU/Linux. Chi avesse già una conoscenza di questa -materia può tranquillamente saltare questa sezione. +In questa prima sezione faremo una breve panoramica sull'architettura del +sistema. Chi avesse già una conoscenza di questa materia può tranquillamente +saltare questa sezione. Il concetto base di un sistema unix-like è quello di un nucleo del sistema (il cosiddetto \textit{kernel}) a cui si demanda la gestione delle risorse @@ -242,65 +242,65 @@ tipi di dati. \subsection{Prototipi e puntatori} \label{sec:intro_function} -\subsection{La misura del tempo in unix} -\label{sec:intro_unix_time} - -Storicamente i sistemi unix-like hanno sempre mantenuto due distinti valori -per i tempi all'interno del sistema, essi sono rispettivamente chiamati -\textit{calendar time} e \textit{process time}, secondo le definizioni: -\begin{itemize} -\item \textit{calendar time}: è il numero di secondi dalla mezzanotte del - primo gennaio 1970, in tempo universale coordinato (o UTC), data che viene - usualmente indicata con 00:00:00 Jan, 1 1970 (UTC) e chiamata \textit{the - Epoch}. Questo tempo viene anche chiamato anche GMT (Greenwich Mean Time) - dato che l'UTC corrisponde all'ora locale di Greenwich. È il tempo su cui - viene mantenuto l'orologio del calcolatore, e viene usato ad esempio per - indicare le date di modifica dei file o quelle di avvio dei processi. Per - memorizzare questo tempo è stato riservato il tipo primitivo \func{time\_t}. -\item \textit{process time}: talvolta anche detto tempo di CPU. Viene misurato - in \textit{clock tick}, corrispondenti al numero di interruzioni effettuate - dal timer di sistema, e che per Linux avvengono ogni centesimo di - secondo\footnote{eccetto per la piattaforma alpha dove avvengono ogni - millesimo di secondo}. Il dato primitivo usato per questo tempo è - \func{clock\_t}, inoltre la costante \macro{HZ} restituisce la frequenza di - operazione del timer, e corrisponde dunque al numero di tick al secondo. Lo - standard POSIX definisce allo stesso modo la costante \macro{CLK\_TCK}); - questo valore può comunque essere ottenuto con \func{sysconf} (vedi - \secref{sec:intro_limits}). -\end{itemize} - -In genere si usa il \textit{calendar time} per tenere le date dei file e le -informazioni analoghe che riguardano i tempi di ``orologio'', usati ad esempio -per i demoni che compiono lavori amministrativi ad ore definite, come -\cmd{cron}. Di solito questo vene convertito automaticamente dal valore in UTC -al tempo locale, utilizzando le opportune informazioni di localizzazione -(specificate in \file{/etc/timezone}). E da tenere presente che questo tempo è -mantenuto dal sistema e non corrisponde all'orologio hardware del calcolatore. - -Il \textit{process time} di solito si esprime in secondi e viene usato appunto -per tenere conto dei tempi di esecuzione dei processi. Per ciascun processo il -kernel tiene tre di questi tempi: -\begin{itemize} -\item \textit{clock time} -\item \textit{user time} -\item \textit{system time} -\end{itemize} -il primo è il tempo ``reale'' (viene anche chiamato \textit{wall clock time}) -dall'avvio del processo, e misura il tempo trascorso fino alla sua -conclusione; chiaramente un tale tempo dipende anche dal carico del sistema e -da quanti altri processi stavano girando nello stesso periodo. Il secondo -tempo è quello che la CPU ha speso nell'esecuzione delle istruzioni del -processo in user space. Il terzo è il tempo impiegato dal kernel per eseguire -delle system call per conto del processo medesimo (tipo quello usato per -eseguire una \func{write} su un file). In genere la somma di user e system -time viene chiamato \textit{CPU time}. \subsection{Lo standard ANSI C} \label{sec:intro_ansiC} +Lo standard ANSI C è stato definito nel 1989 dall'\textit{American National + Standard Institute}, come standard del linguaggio C ed è stato +successivamente adottatto dalla \textit{International Standard Organisation} +come standard internazionale con la sigla ISO/IEC 9899:1990. + +Scopo dello standard è quello di garantire la portabilità dei programmi C fra +sistemi operativi diversi, ma oltre alla sintassi e alla semantica del +linguaggio C (operatori, parole chiave, tipi di dati) lo standard prevede +anche una libreria di funzioni standard che devono poter essere implementate +su qualunque sistema operativo. + +Linux, come molti unix moderni, provvede la compatibilità con questo standard, +fornendo le funzioni di libreria da esso previste; queste sono dichiarate in +quindici header files, uno per ciascuna delle quindici aree in cui è stata +suddivisa la libreria. In \ntab\ si sono riportati questi header, insieme a +quelli definiti negli altri standard descritti nelle sezioni successive. + \subsection{Lo standard POSIX} \label{sec:intro_posix} +In realtà POSIX è una famiglia di standard diversi, il nome, suggerito da +Richard Stallman, sta per \textit{Portable Operating System Interface}, ma la +X finale denuncia la sua stretta relazione con i sistemi unix. Esso nasce dal +lavoro dell'IEEE (\textit{Institute of Electrical and Electronics Engeneers}) +che ne ha prodotto un primo una prima versione, nota come IEEE 1003.1-1988, +mirante a standardizzare l'interfaccia con il sistema operativo. + +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 +le utilities di sistema (1003.2), per le estensioni realtime e per i thread +(1003.1d e 1003.1c) e molti altri. + +Benchè lo standard POSIX sia basato sui sistemi unix esso definisce comunque +una interfaccia e non fa riferimento ad una specifica implementazione (per cui +esiste ad esempio anche una implementazione di questo standard pure sotto +Windows NT). Lo standard si è evoluto nel tempo ed una nuova versione (quella +che viene normalmente denominata POSIX.1) è stata rilasciata come standard +internazionale con la sigla ISO/IEC 9945-1:1990. + + +\subsection{Lo standard X/Open -- XPG3} +\label{sec:intro_xopen} + +Il consorzio X/Open nasce come consorzio di venditori di sistemi unix, che nel +1989 produsse una voluminosa guida chiamata \textit{X/Open Portability Guide, + Issue 3} al cui interno definiva una ulteriore standardizzazione +dell'interfaccia ad un sistema unix. + +Questo standard, detto anche XPG3 dal nome della suddetta guida, è sempre +basato sullo standard POSIX.1, ma prevede una serie di funzionalità +aggiuntive. + +Il consorzio + + \subsection{Valori e limiti del sistema} \label{sec:intro_limits} @@ -309,153 +309,3 @@ time viene chiamato \textit{CPU time}. \label{sec:intro_data_types} - - -\section{La gestione degli errori} -\label{sec:intro_errors} - -La gestione degli errori è in genere una materia complessa. Inoltre il modello -utilizzato dai sistema unix-like è basato sull'architettura a processi, e -presenta una serie di problemi nel caso lo si debba usare con i thread. -Esamineremo in questa sezione le sue caratteristiche principali. - - -\subsection{La variabile \func{errno}} -\label{sec:intro_errno} - -Quasi tutte le funzioni delle librerie del C sono in grado di individuare e -riportare condizioni di errore, ed è una buona norma di programmazione -controllare sempre che le funzioni chiamate si siano concluse correttamente. - -In genere le funzioni di libreria usano un valore speciale per indicare che -c'è stato un errore. Di solito questo valore è -1 o un puntatore nullo o la -costante \macro{EOF} (a seconda della funzione); ma questo valore segnala solo -che c'è stato un errore, non il tipo di errore. - -Per riportare il tipo di errore il sistema usa la variabile globale -\var{errno}\footnote{L'uso di una variabile globale può comportare alcuni - 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 -variabile è in genere definita come \var{volatile} dato che può essere -cambiata in modo asincrono da un segnale (per una descrizione dei segnali si -veda \secref{cha:signals}), ma dato che un manipolatore di segnale scritto -bene salva e ripristina il valore della variabile, di questo non è necessario -preoccuparsi nella programmazione normale. - -I valori che può assumere \var{errno} sono riportati in \capref{cha:errors}, -nell'header \file{errno.h} sono anche definiti i nomi simbolici per le -costanti numeriche che identificano i vari errori; essi iniziano tutti per -\macro{E} e si possono considerare come nomi riservati. In seguito faremo -sempre rifermento a tali valori, quando descriveremo i possibili errori -restituiti dalle funzioni. Il programma di esempio \cmd{errcode} stampa il -codice relativo ad un valore numerico con l'opzione \cmd{-l}. - -Il valore di \var{errno} viene sempre settato a zero all'avvio di un -programma, gran parte delle funzioni di libreria settano \var{errno} ad un -valore diverso da zero in caso di errore. Il valore è invece indefinito in -caso di successo, perché anche se una funzione ha successo, può chiamarne -altre al suo interno che falliscono, modificando così \var{errno}. - -Pertanto un valore non nullo di \var{errno} non è sintomo di errore (potrebbe -essere il risultato di un errore precedente) e non lo si può usare per -determinare quando o se una chiamata a funzione è fallita. La procedura da -seguire è sempre quella di controllare \var{errno} immediatamente dopo aver -verificato il fallimento della funzione attraverso il suo codice di ritorno. - - -\subsection{Le funzioni \func{strerror} e \func{perror}} -\label{sec:intro_strerror} - -Benché gli errori siano identificati univocamente dal valore numerico di -\var{errno} le librerie provvedono alcune funzioni e variabili utili per -riportare in opportuni messaggi le condizioni di errore verificatesi. La -prima funzione che si può usare per ricavare i messaggi di errore è -\func{strerror}, il cui prototipo è: -\begin{prototype}{string.h}{char * strerror(int errnum)} - La funzione ritorna una stringa (statica) che descrive l'errore il cui - codice è passato come parametro. -\end{prototype} - -In generale \func{strerror} viene usata passando \var{errno} come parametro; -nel caso si specifichi un codice sbagliato verrà restituito un messaggio di -errore sconosciuto. La funzione utilizza una stringa statica che non deve -essere modificata dal programma e che è utilizzabile solo fino ad una chiamata -successiva a \func{strerror}; nel caso si usino i thread è -provvista\footnote{questa funzione è una estensione GNU, non fa parte dello - standard POSIX} una versione apposita: -\begin{prototype}{string.h} -{char * strerror\_r(int errnum, char * buff, size\_t size)} - La funzione è analoga a \func{strerror} ma ritorna il messaggio in un buffer - specificato da \var{buff} di lunghezza massima (compreso il terminatore) - \var{size}. -\end{prototype} -che utilizza un buffer che il singolo thread deve allocare, per evitare i -problemi connessi alla condivisione del buffer statico. Infine, per completare -la caratterizzazione dell'errore, si può usare anche la variabile -globale\footnote{anche questa è una estensione GNU} -\var{program\_invocation\_short\_name} che riporta il nome del programma -attualmente in esecuzione. - -Una seconda funzione usata per riportare i codici di errore in maniera -automatizzata sullo standard error (vedi \secref{sec:file_stdfiles}) è -\func{perror}, il cui prototipo è: -\begin{prototype}{stdio.h}{void perror (const char *message)} - La funzione stampa il messaggio di errore relativo al valore corrente di - \var{errno} sullo standard error; preceduto dalla stringa \var{message}. -\end{prototype} -i messaggi di errore stampati sono gli stessi di \func{strerror}, (riportati -in \capref{cha:errors}), e, usando il valore corrente di \var{errno}, si -riferiscono all'ultimo errore avvenuto. La stringa specificata con -\var{message} viene stampato prime del messaggio d'errore, seguita dai due -punti e da uno spazio, il messaggio è terminato con un a capo. - -Il messaggio può essere riportato anche usando altre variabili globali -dichiarate in \file{errno.h}: -\begin{verbatim} - const char *sys_errlist[]; - int sys_nerr; -\end{verbatim} -la prima contiene i puntatori alle stringhe di errore indicizzati da -\var{errno}; la seconda esprime il valore più alto per un codice di errore, -l'utilizzo di questa stringa è sostanzialmente equivalente a quello di -\func{strerror}. - -In \nfig\ è riportata la sezione attinente del codice del programma -\cmd{errcode}, che può essere usato per stampare i messaggi di errore e le -costanti usate per identificare i singoli errori; il sorgente completo del -programma è allegato nel file \file{ErrCode.c} e contiene pure la gestione -delle opzioni e tutte le definizioni necessarie ad associare il valore -numerico alla costante simbolica. In particolare si è riportata la sezione che -converte la stringa passata come parametro in un intero (\texttt{\small - 1--2}), controllando con i valori di ritorno di \func{strtol} che la -conversione sia avvenuta correttamente (\texttt{\small 4--10}), e poi stampa, -a seconda dell'opzione scelta il messaggio di errore (\texttt{\small 11--14}) -o la macro (\texttt{\small 15--17}) associate a quel codice. - -\begin{figure}[!htb] - \footnotesize - \begin{lstlisting}{} - /* convert string to number */ - err = strtol(argv[optind], NULL, 10); - /* testing error condition on conversion */ - if (err==LONG_MIN) { - perror("Underflow on error code"); - return 1; - } else if (err==LONG_MIN) { - perror("Overflow on error code"); - return 1; - } - /* conversion is fine */ - if (message) { - printf("Error message for %d is %s\n", err, strerror(err)); - } - if (label) { - printf("Error label for %d is %s\n", err, err_code[err]); - } - \end{lstlisting} - \caption{Codice per la stampa del messaggio di errore standard.} - \label{fig:intro_err_mess} -\end{figure} -