From: Simone Piccardi Date: Wed, 25 Dec 2002 17:30:06 +0000 (+0000) Subject: Finita la revisione dell'indicizzazione delle funzioni. X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=commitdiff_plain;h=da0899b61653d07d75c8df134906261f1afd2485 Finita la revisione dell'indicizzazione delle funzioni. --- diff --git a/fileadv.tex b/fileadv.tex index 2d3ce01..8765038 100644 --- a/fileadv.tex +++ b/fileadv.tex @@ -314,7 +314,7 @@ L'uso di \param{sigmask} race condition\footnote{in Linux però, non esistendo una system call apposita, la funzione è implementata nelle \acr{glibc} usando \func{select}, e la possibilità di una race condition resta.} quando si deve eseguire un test su -una variabile assegnata da un manipolatore sulla base dell'occorrenza di un +una variabile assegnata da un gestore sulla base dell'occorrenza di un segnale per decidere se lanciare \func{select}. Fra il test e l'esecuzione è presente una finestra in cui potrebbe arrivare il segnale che non sarebbe rilevato; la race condition diventa superabile disabilitando il segnale prima @@ -362,14 +362,14 @@ pi Linux però supporta le estensioni POSIX.1b dei segnali che permettono di superare il problema facendo ricorso alle informazioni aggiuntive restituite attraverso la struttura \struct{siginfo\_t}, utilizzando la forma estesa -\var{sa\_sigaction} del manipolatore (si riveda quanto illustrato in +\var{sa\_sigaction} del gestore (si riveda quanto illustrato in \secref{sec:sig_sigaction}). Per far questo però occorre utilizzare le funzionalità dei segnali real-time (vedi \secref{sec:sig_real_time}) impostando esplicitamente con il comando \const{F\_SETSIG} di \func{fcntl} un segnale real-time da inviare in caso di I/O asincrono (il segnale predefinito è \const{SIGIO}). In questo caso il -manipolatore tutte le volte che riceverà \const{SI\_SIGIO} come valore del +gestore tutte le volte che riceverà \const{SI\_SIGIO} come valore del campo \var{si\_code}\footnote{il valore resta \const{SI\_SIGIO} qualunque sia il segnale che si è associato all'I/O asincrono, ed indica appunto che il segnale è stato generato a causa di attività nell'I/O asincrono.} di @@ -495,7 +495,7 @@ che indica le modalit \item[\const{SIGEV\_NONE}] Non viene inviata nessuna notifica. \item[\const{SIGEV\_SIGNAL}] La notifica viene effettuata inviando al processo chiamante il segnale specificato nel campo \var{sigev\_signo}, se il - manipolatore è installato con \const{SA\_SIGINFO}, il gli verrà restituito + gestore è installato con \const{SA\_SIGINFO}, il gli verrà restituito il valore di \var{sigev\_value} in come valore del campo \var{si\_value} per \struct{siginfo\_t}. \item[\const{SIGEV\_THREAD}] La notifica viene effettuata creando un nuovo diff --git a/filedir.tex b/filedir.tex index 9b4025e..0264b90 100644 --- a/filedir.tex +++ b/filedir.tex @@ -515,7 +515,7 @@ per creare una directory \end{functions} La funzione crea una nuova directory vuota, che contiene cioè solo le due voci -standard \file{.} e \file{..}, con il nome indicato dall'argomento +standard (\file{.} e \file{..}), con il nome indicato dall'argomento \param{dirname}. Il nome può essere indicato sia come pathname assoluto che relativo. @@ -752,11 +752,9 @@ directory corrente di qualunque comando da essa lanciato. In genere il kernel tiene traccia per ciascun processo dell'inode\index{inode} della directory di lavoro corrente, per ottenere il pathname occorre usare una -apposita funzione di libreria, \func{getcwd}, il cui prototipo è: +apposita funzione di libreria, \funcd{getcwd}, il cui prototipo è: \begin{prototype}{unistd.h}{char *getcwd(char *buffer, size\_t size)} - Restituisce il filename completo della directory di lavoro corrente nella - stringa puntata da \param{buffer}, che deve essere precedentemente allocata, - per una dimensione massima di \param{size}. + Legge il pathname della directory di lavoro corrente. \bodydesc{La funzione restituisce il puntatore \param{buffer} se riesce, \val{NULL} se fallisce, in quest'ultimo caso la variabile @@ -772,15 +770,19 @@ apposita funzione di libreria, \func{getcwd}, il cui prototipo \end{errlist}} \end{prototype} -Il buffer deve essere sufficientemente lungo da poter contenere il pathname +La funzione restituisce il pathname completo della directory di lavoro +corrente nella stringa puntata da \param{buffer}, che deve essere +precedentemente allocata, per una dimensione massima di \param{size}. Il +buffer deve essere sufficientemente lungo da poter contenere il pathname completo più lo zero di terminazione della stringa. Qualora esso ecceda le -dimensioni specificate con \param{size} la funzione restituisce un errore. Si -può anche specificare un puntatore nullo come \param{buffer},\footnote{questa è - un'estensione allo standard POSIX.1, supportata da Linux.} nel qual caso la -stringa sarà allocata automaticamente per una dimensione pari a \param{size} -qualora questa sia diversa da zero, o della lunghezza esatta del pathname -altrimenti. In questo caso ci si deve ricordare di disallocare la stringa una -volta cessato il suo utilizzo. +dimensioni specificate con \param{size} la funzione restituisce un errore. + +Si può anche specificare un puntatore nullo come +\param{buffer},\footnote{questa è un'estensione allo standard POSIX.1, + supportata da Linux.} nel qual caso la stringa sarà allocata automaticamente +per una dimensione pari a \param{size} qualora questa sia diversa da zero, o +della lunghezza esatta del pathname altrimenti. In questo caso ci si deve +ricordare di disallocare la stringa una volta cessato il suo utilizzo. Di questa funzione esiste una versione \code{char *getwd(char *buffer)} fatta per compatibilità all'indietro con BSD, che non consente di specificare @@ -800,7 +802,7 @@ risalendo all'indietro l'albero della directory, si perderebbe traccia di ogni passaggio attraverso eventuali link simbolici. Per cambiare la directory di lavoro corrente si può usare la funzione -\func{chdir} (equivalente del comando di shell \cmd{cd}) il cui nome sta +\funcd{chdir} (equivalente del comando di shell \cmd{cd}) il cui nome sta appunto per \textit{change directory}, il suo prototipo è: \begin{prototype}{unistd.h}{int chdir(const char *pathname)} Cambia la directory di lavoro corrente in \param{pathname}. @@ -820,7 +822,7 @@ quale si hanno i permessi di accesso. Dato che anche le directory sono file, è possibile riferirsi ad esse anche tramite il file descriptor, e non solo tramite il filename, per fare questo si -usa \func{fchdir}, il cui prototipo è: +usa \funcd{fchdir}, il cui prototipo è: \begin{prototype}{unistd.h}{int fchdir(int fd)} Identica a \func{chdir}, ma usa il file descriptor \param{fd} invece del pathname. @@ -849,7 +851,7 @@ controllo e la creazione si ha giusto lo spazio per una possibile \textit{race Le \acr{glibc} provvedono varie funzioni per generare nomi di file temporanei, di cui si abbia certezza di unicità (al momento della generazione); la prima -di queste funzioni è \func{tmpnam} il cui prototipo è: +di queste funzioni è \funcd{tmpnam} il cui prototipo è: \begin{prototype}{stdio.h}{char *tmpnam(char *string)} Restituisce il puntatore ad una stringa contente un nome di file valido e non esistente al momento dell'invocazione. @@ -868,7 +870,7 @@ 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 parametro. Una funzione simile, -\func{tempnam}, permette di specificare un prefisso per il file +\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 @@ -904,7 +906,7 @@ queste funzioni occorre sempre aprire il nuovo file in modalit esistente. Per evitare di dovere effettuare a mano tutti questi controlli, lo standard -POSIX definisce la funzione \func{tempfile}, il cui prototipo è: +POSIX definisce la funzione \funcd{tempfile}, il cui prototipo è: \begin{prototype}{stdio.h}{FILE *tmpfile (void)} Restituisce un file temporaneo aperto in lettura/scrittura. @@ -927,10 +929,10 @@ funzione condition}\index{race condition}. Alcune versioni meno recenti di Unix non supportano queste funzioni; in questo -caso si possono usare le vecchie funzioni \func{mktemp} e \func{mkstemp} che +caso si possono usare le vecchie funzioni \funcd{mktemp} e \func{mkstemp} che modificano una stringa di input che serve da modello e che deve essere conclusa da 6 caratteri \code{X} che verranno sostituiti da un codice -unico. La prima delle due è analoga a \func{tmpnam} e genera un nome casuale, +unico. La prima delle due è analoga a \funcd{tmpnam} e genera un nome casuale, il suo prototipo è: \begin{prototype}{stlib.h}{char *mktemp(char *template)} Genera un filename univoco sostituendo le \code{XXXXXX} finali di @@ -953,9 +955,7 @@ possibilit indovinare. Per tutti questi motivi la funzione è deprecata e non dovrebbe mai essere usata. - - -La seconda funzione, \func{mkstemp} è sostanzialmente equivalente a +La seconda funzione, \funcd{mkstemp} è sostanzialmente equivalente a \func{tmpfile}, ma restituisce un file descriptor invece di uno stream; il suo prototipo è: \begin{prototype}{stlib.h}{int mkstemp(char *template)} @@ -982,7 +982,7 @@ certezza di essere i soli utenti del file. I permessi sono impostati al valore In OpenBSD è stata introdotta un'altra funzione\footnote{introdotta anche in Linux a partire dalle \acr{glibc} 2.1.91.} simile alle precedenti, -\func{mkdtemp}, che crea una directory temporanea; il suo prototipo è: +\funcd{mkdtemp}, che crea una directory temporanea; il suo prototipo è: \begin{prototype}{stlib.h}{char *mkdtemp(char *template)} Genera una directory temporaneo il cui nome è ottenuto sostituendo le \code{XXXXXX} finali di \param{template}. @@ -1410,7 +1410,7 @@ avr \label{sec:file_utime} I tempi di ultimo accesso e modifica possono essere cambiati usando la -funzione \func{utime}, il cui prototipo è: +funzione \funcd{utime}, il cui prototipo è: \begin{prototype}{utime.h} {int utime(const char *filename, struct utimbuf *times)} @@ -1500,33 +1500,27 @@ Esistono varie estensioni a questo modello,\footnote{come le \textit{Access come il \textit{mandatory access control} di SE-Linux.} ma nella maggior parte dei casi il meccanismo standard è più che sufficiente a soddisfare tutte le necessità più comuni. I tre permessi di base associati ad ogni file sono: -\begin{itemize*} +\begin{itemize} \item il permesso di lettura (indicato con la lettera \texttt{r}, dall'inglese \textit{read}). \item il permesso di scrittura (indicato con la lettera \texttt{w}, dall'inglese \textit{write}). \item il permesso di esecuzione (indicato con la lettera \texttt{x}, dall'inglese \textit{execute}). -\end{itemize*} +\end{itemize} mentre i tre livelli su cui sono divisi i privilegi sono: -\begin{itemize*} +\begin{itemize} \item i privilegi per l'utente proprietario del file. \item i privilegi per un qualunque utente faccia parte del gruppo cui appartiene il file. \item i privilegi per tutti gli altri utenti. -\end{itemize*} +\end{itemize} L'insieme dei permessi viene espresso con un numero a 12 bit; di questi i nove meno significativi sono usati a gruppi di tre per indicare i permessi base di lettura, scrittura ed esecuzione e sono applicati rispettivamente rispettivamente al proprietario, al gruppo, a tutti gli altri. -I restanti tre bit (noti come \acr{suid}, \acr{sgid}, e \textsl{sticky}) sono -usati per indicare alcune caratteristiche più complesse del meccanismo del -controllo di accesso su cui torneremo in seguito (in -\secref{sec:file_suid_sgid} e \secref{sec:file_sticky}); lo schema di -allocazione dei bit è riportato in \figref{fig:file_perm_bit}. - \begin{figure}[htb] \centering \includegraphics[width=6cm]{img/fileperm} @@ -1535,6 +1529,12 @@ allocazione dei bit \label{fig:file_perm_bit} \end{figure} +I restanti tre bit (noti come \acr{suid}, \acr{sgid}, e \textsl{sticky}) sono +usati per indicare alcune caratteristiche più complesse del meccanismo del +controllo di accesso su cui torneremo in seguito (in +\secref{sec:file_suid_sgid} e \secref{sec:file_sticky}); lo schema di +allocazione dei bit è riportato in \figref{fig:file_perm_bit}. + Anche i permessi, come tutte le altre informazioni pertinenti al file, sono memorizzati nell'inode\index{inode}; in particolare essi sono contenuti in alcuni bit del campo \var{st\_mode} della struttura \struct{stat} (si veda di @@ -1589,6 +1589,7 @@ la quale appunto serve il diritto di esecuzione). Per una directory infatti il permesso di esecuzione significa che essa può essere attraversata nella risoluzione del pathname, ed è distinto dal permesso di lettura che invece implica che si può leggere il contenuto della directory. + Questo significa che se si ha il permesso di esecuzione senza permesso di lettura si potrà lo stesso aprire un file in una directory (se si hanno i permessi opportuni per il medesimo) ma non si potrà vederlo con \cmd{ls} @@ -1768,22 +1769,23 @@ invece assunto un uso importante per le directory;\footnote{lo \textsl{sticky impostato un file potrà essere rimosso dalla directory soltanto se l'utente ha il permesso di scrittura su di essa ed inoltre è vera una delle seguenti condizioni: -\begin{itemize*} +\begin{itemize} \item l'utente è proprietario del file \item l'utente è proprietario della directory \item l'utente è l'amministratore -\end{itemize*} +\end{itemize} un classico esempio di directory che ha questo bit impostato è \file{/tmp}, i -permessi infatti di solito sono impostati come: +permessi infatti di solito sono i seguenti: \begin{verbatim} $ ls -ld /tmp drwxrwxrwt 6 root root 1024 Aug 10 01:03 /tmp \end{verbatim}%$ -in questo modo chiunque può creare file in questa directory (che infatti è -normalmente utilizzata per la creazione di file temporanei), ma solo l'utente -che ha creato un certo file potrà cancellarlo o rinominarlo. In questo modo si -evita che un utente possa, più o meno consapevolmente, cancellare i file degli -altri. +quindi con lo \textsl{sticky bit} bit impostato. In questo modo qualunque +utente nel sistema può creare dei file in questa directory (che, come +suggerisce il nome, è normalmente utilizzata per la creazione di file +temporanei), ma solo l'utente che ha creato un certo file potrà cancellarlo o +rinominarlo. In questo modo si evita che un utente possa, più o meno +consapevolmente, cancellare i file temporanei creati degli altri utenti. \subsection{La titolarità di nuovi file e directory} @@ -1799,11 +1801,11 @@ per la creazione di nuove directory (procedimento descritto in Lo standard POSIX prescrive che l'\acr{uid} del nuovo file corrisponda all'userid effettivo del processo che lo crea; per il \acr{gid} invece prevede due diverse possibilità: -\begin{itemize*} +\begin{itemize} \item il \acr{gid} del file corrisponde al groupid effettivo del processo. \item il \acr{gid} del file corrisponde al \acr{gid} della directory in cui esso è creato. -\end{itemize*} +\end{itemize} in genere BSD usa sempre la seconda possibilità, che viene per questo chiamata semantica BSD. Linux invece segue quella che viene chiamata semantica SVr4; di norma cioè il nuovo file viene creato, seguendo la prima opzione, con il @@ -1812,13 +1814,14 @@ bit \acr{sgid} impostato allora viene usata la seconda opzione. Usare la semantica BSD ha il vantaggio che il \acr{gid} viene sempre automaticamente propagato, restando coerente a quello della directory di -partenza, in tutte le sottodirectory. La semantica SVr4 offre la possibilità -di scegliere, ma per ottenere lo stesso risultato di coerenza che si ha con -BSD necessita che per le nuove directory venga anche propagato anche il bit -\acr{sgid}. Questo è il comportamento predefinito di \cmd{mkdir}, ed è in -questo modo ad esempio che Debian assicura che le sottodirectory create nella -home di un utente restino sempre con il \acr{gid} del gruppo primario dello -stesso. +partenza, in tutte le sottodirectory. + +La semantica SVr4 offre la possibilità di scegliere, ma per ottenere lo stesso +risultato di coerenza che si ha con BSD necessita che per le nuove directory +venga anche propagato anche il bit \acr{sgid}. Questo è il comportamento +predefinito del comando \cmd{mkdir}, ed è in questo modo ad esempio che Debian +assicura che le sottodirectory create nella home di un utente restino sempre +con il \acr{gid} del gruppo primario dello stesso. \subsection{La funzione \func{access}} @@ -1830,13 +1833,13 @@ sono casi per ed il groupid reale, vale a dire usando i valori di \acr{uid} e \acr{gid} relativi all'utente che ha lanciato il programma, e che, come accennato in \secref{sec:file_suid_sgid} e spiegato in dettaglio in -\secref{sec:proc_perms}, non è detto siano uguali a quelli effettivi. Per far -questo si può usare la funzione \func{access}, il cui prototipo è: +\secref{sec:proc_perms}, non è detto siano uguali a quelli effettivi. + +Per far questo si può usare la funzione \funcd{access}, il cui prototipo è: \begin{prototype}{unistd.h} {int access(const char *pathname, int mode)} -Verifica i permessi di accesso, indicati da \param{mode}, per il file indicato -da \param{pathname}. +Verifica i permessi di accesso. \bodydesc{La funzione ritorna 0 se l'accesso è consentito, -1 se l'accesso non è consentito ed in caso di errore; nel qual caso la variabile \var{errno} @@ -1852,14 +1855,15 @@ da \param{pathname}. \errval{ENOTDIR}, \errval{ELOOP}, \errval{EIO}.} \end{prototype} -I valori possibili per l'argomento \param{mode} sono esprimibili come -combinazione delle costanti numeriche riportate in -\tabref{tab:file_access_mode_val} (attraverso un OR binario delle stesse). I -primi tre valori implicano anche la verifica dell'esistenza del file, se si -vuole verificare solo quest'ultima si può usare \const{F\_OK}, o anche -direttamente \func{stat}. Nel caso in cui \param{pathname} si riferisca ad un -link simbolico, questo viene seguito ed il controllo è fatto sul file a cui -esso fa riferimento. +La funzione verifica i permessi di accesso, indicati da \param{mode}, per il +file indicato da \param{pathname}. I valori possibili per l'argomento +\param{mode} sono esprimibili come combinazione delle costanti numeriche +riportate in \tabref{tab:file_access_mode_val} (attraverso un OR binario delle +stesse). I primi tre valori implicano anche la verifica dell'esistenza del +file, se si vuole verificare solo quest'ultima si può usare \const{F\_OK}, o +anche direttamente \func{stat}. Nel caso in cui \param{pathname} si riferisca +ad un link simbolico, questo viene seguito ed il controllo è fatto sul file a +cui esso fa riferimento. La funzione controlla solo i bit dei permessi di accesso, si ricordi che il fatto che una directory abbia permesso di scrittura non significa che ci si @@ -2011,7 +2015,7 @@ perdita di questo privilegio. Oltre che dai valori indicati in sede di creazione, i permessi assegnati ai nuovi file sono controllati anche da una maschera di bit impostata con la -funzione \func{umask}, il cui prototipo è: +funzione \funcd{umask}, il cui prototipo è: \begin{prototype}{stat.h} {mode\_t umask(mode\_t mask)} @@ -2220,7 +2224,7 @@ processo figlio, e quindi di norma coincide con la \file{/} del sistema. In certe situazioni però per motivi di sicurezza non si vuole che un processo possa accedere a tutto il filesystem; per questo si può cambiare la directory -radice con la funzione \func{chroot}, il cui prototipo è: +radice con la funzione \funcd{chroot}, il cui prototipo è: \begin{prototype}{unistd.h}{int chroot(const char *path)} Cambia la directory radice del processo a quella specificata da \param{path}. diff --git a/filestd.tex b/filestd.tex index aed8add..5bf7cf4 100644 --- a/filestd.tex +++ b/filestd.tex @@ -46,7 +46,8 @@ dimensioni del blocco di dati (il parametro \param{buf} di \func{read} e \func{write}) nell'efficienza nelle operazioni di I/O con i file descriptor, evidenziando come le prestazioni ottimali si ottengano a partire da dimensioni del buffer dei dati pari a quelle dei blocchi del filesystem (il valore dato -dal campo \var{st\_blksize} di \struct{stat}). +dal campo \var{st\_blksize} di \struct{stat}), che di norma corrispondono alle +dimensioni dei settori fisici in cui è suddiviso il disco. Se il programmatore non si cura di effettuare le operazioni in blocchi di dimensioni adeguate, le prestazioni sono inferiori. La caratteristica @@ -136,21 +137,24 @@ funzionalit uno degli aspetti più comunemente fraintesi, in particolare per quello che riguarda l'aspetto della scrittura dei dati sul file. -I caratteri che vengono scritti su uno stream normalmente vengono accumulati -in un buffer e poi trasmessi in blocco in maniera asincrona rispetto alla -scrittura (quello che viene chiamato lo \textsl{scarico} dei dati, -dall'inglese \textit{flush}) tutte le volte che il buffer viene riempito. Un -comportamento analogo avviene anche in lettura (cioè dal file viene letto un -blocco di dati, anche se ne sono richiesti una quantità inferiore), ma la cosa -ovviamente ha rilevanza inferiore, dato che i dati letti sono sempre gli -stessi; in caso di scrittura invece, quando si ha un accesso contemporaneo -allo stesso file (ad esempio da parte di un altro processo) si potranno vedere -solo le parti effettivamente scritte, e non quelle ancora presenti nel buffer. - -Allo stesso modo, se si sta facendo dell'input/output interattivo -bisognerà tenere presente le caratteristiche delle operazioni di scarico -dei dati, poiché non è detto che ad una scrittura sullo stream -corrisponda una immediata scrittura sul dispositivo. +I caratteri che vengono scritti su di uno stream normalmente vengono +accumulati in un buffer e poi trasmessi in blocco\footnote{qiesta operazione + viene usualmente chiamata \textsl{scaricamento} dei dati, dal termine + inglese \textit{flush}.} tutte le volte che il buffer viene riempito, in +maniera asincrona rispetto alla scrittura. Un comportamento analogo avviene +anche in lettura (cioè dal file viene letto un blocco di dati, anche se ne +sono richiesti una quantità inferiore), ma la cosa ovviamente ha rilevanza +inferiore, dato che i dati letti sono sempre gli stessi. In caso di scrittura +invece, quando si ha un accesso contemporaneo allo stesso file (ad esempio da +parte di un altro processo) si potranno vedere solo le parti effettivamente +scritte, e non quelle ancora presenti nel buffer. + +Per lo stesso motivo, in tutte le situazioni in cui si sta facendo +dell'input/output interattivo, bisognerà tenere presente le caratteristiche +delle operazioni di scaricamento dei dati, poiché non è detto che ad una +scrittura sullo stream corrisponda una immediata scrittura sul dispositivo (la +cosa è particolaemente evidente quando con le operazioni di input/output su +terminale). Per rispondere ad esigenze diverse, lo standard definisce tre distinte modalità in cui può essere eseguita la bufferizzazione, delle quali @@ -219,7 +223,7 @@ corrente in uno stream. \label{sec:file_fopen} Le funzioni che si possono usare per aprire uno stream sono solo tre: -\func{fopen}, \func{fdopen} e \func{freopen},\footnote{\func{fopen} e +\funcd{fopen}, \funcd{fdopen} e \funcd{freopen},\footnote{\func{fopen} e \func{freopen} fanno parte dello standard ANSI C, \func{fdopen} è parte dello standard POSIX.1.} i loro prototipi sono: \begin{functions} @@ -348,7 +352,7 @@ Una volta aperto lo stream, si pu (si veda \secref{sec:file_buffering_ctrl}) fintanto che non si è effettuato alcuna operazione di I/O sul file. -Uno stream viene chiuso con la funzione \func{fclose} il cui prototipo è: +Uno stream viene chiuso con la funzione \funcd{fclose} il cui prototipo è: \begin{prototype}{stdio.h}{int fclose(FILE *stream)} Chiude lo stream \param{stream}. @@ -366,8 +370,8 @@ dati presenti nei buffer in user space usati dalle \acr{glibc}; se si vuole essere sicuri che il kernel forzi la scrittura su disco occorrerà effettuare una \func{sync} (vedi \secref{sec:file_sync}). -Linux supporta anche una altra funzione, \func{fcloseall}, come estensione GNU -implementata dalle \acr{glibc}, accessibile avendo definito +Linux supporta anche una altra funzione, \funcd{fcloseall}, come estensione +GNU implementata dalle \acr{glibc}, accessibile avendo definito \macro{\_GNU\_SOURCE}, il suo prototipo è: \begin{prototype}{stdio.h}{int fcloseall(void)} Chiude tutti gli stream. @@ -425,7 +429,8 @@ mantengono per ogni stream almeno due flag all'interno dell'oggetto \ctyp{FILE}, il flag di \textit{end-of-file}, che segnala che si è raggiunta la fine del file in lettura, e quello di errore, che segnala la presenza di un qualche errore nelle operazioni di input/output; -questi due flag possono essere riletti dalle funzioni: +questi due flag possono essere riletti dalle funzioni \funcd{feof} e +\funcd{ferror}, i cui prototipi sono: \begin{functions} \headdecl{stdio.h} \funcdecl{int feof(FILE *stream)} @@ -442,7 +447,7 @@ qualunque operazione sullo stream, il controllo quindi deve essere effettuato ogni volta che si chiama una funzione di libreria. Entrambi i flag (di errore e di end-of-file) possono essere cancellati usando -la funzione \func{clearerr}, il cui prototipo è: +la funzione \funcd{clearerr}, il cui prototipo è: \begin{prototype}{stdio.h}{void clearerr(FILE *stream)} Cancella i flag di errore ed end-of-file di \param{stream}. \end{prototype} @@ -457,10 +462,11 @@ dello stream (vedi \secref{sec:file_stream_thread}). \label{sec:file_binary_io} La prima modalità di input/output non formattato ricalca quella della -interfaccia dei file descriptor, e provvede semplicemente la scrittura e -la lettura dei dati da un buffer verso un file e viceversa. In generale -questa è la modalità che si usa quando si ha a che fare con dati non -formattati. Le due funzioni che si usano per l'I/O binario sono: +interfaccia dei file descriptor, e provvede semplicemente la scrittura e la +lettura dei dati da un buffer verso un file e viceversa. In generale questa è +la modalità che si usa quando si ha a che fare con dati non formattati. Le due +funzioni che si usano per l'I/O binario sono \funcd{fread} ed \funcd{fwrite}; +i loro prototipi sono: \begin{functions} \headdecl{stdio.h} @@ -558,10 +564,11 @@ permetta di recuperare l'informazione completa), per assicurarsi che versioni diverse del programma siano in grado di rileggere i dati tenendo conto delle eventuali differenze. -Le \acr{glibc} definiscono altre due funzioni per l'I/O binario, che -evitano il lock implicito dello stream, usato per dalla librerie per la -gestione delle applicazioni multi-thread (si veda -\secref{sec:file_stream_thread} per i dettagli): +Le \acr{glibc} definiscono altre due funzioni per l'I/O binario, +\funcd{fread\_unlocked} e \funcd{fwrite\_unlocked} che evitano il lock +implicito dello stream, usato per dalla librerie per la gestione delle +applicazioni multi-thread (si veda \secref{sec:file_stream_thread} per i +dettagli), i loro prototipi sono: \begin{functions} \headdecl{stdio.h} @@ -583,7 +590,7 @@ gestione delle applicazioni multi-thread (si veda La seconda modalità di input/output è quella a caratteri, in cui si trasferisce un carattere alla volta. Le funzioni per la lettura a -caratteri sono tre, \func{fgetc}, \func{getc} e \func{getchar}, i +caratteri sono tre, \funcd{fgetc}, \funcd{getc} e \funcd{getchar}, i rispettivi prototipi sono: \begin{functions} \headdecl{stdio.h} @@ -614,7 +621,7 @@ Invece \func{fgetc} motivo la sua esecuzione normalmente è più lenta per via dell'overhead della chiamata, ma è altresì possibile ricavarne l'indirizzo, che può essere passato come parametro ad un altra funzione (e non si hanno i -problemi accennati in precedenza con \param{stream}). +problemi accennati in precedenza nel tipo di argomento). Le tre funzioni restituiscono tutte un \ctyp{unsigned char} convertito ad \ctyp{int} (si usa \ctyp{unsigned char} in modo da evitare @@ -622,9 +629,10 @@ l'espansione del segno). In questo modo il valore di ritorno positivo, tranne in caso di errore o fine del file. Nelle estensioni GNU che provvedono la localizzazione sono definite tre -funzioni equivalenti alle precedenti che invece di un carattere di un -byte restituiscono un carattere in formato esteso (cioè di tipo -\ctyp{wint\_t}), il loro prototipo è: +funzioni equivalenti alle precedenti, \funcd{getwc}, \funcd{fgetwc} e +\funcd{getwchar}, che invece di un carattere di un byte restituiscono un +carattere in formato esteso (cioè di tipo \ctyp{wint\_t}), il loro prototipo +è: \begin{functions} \headdecl{stdio.h} \headdecl{wchar.h} @@ -641,9 +649,9 @@ byte restituiscono un carattere in formato esteso (cio caso di errore o fine del file il valore di ritorno è \const{WEOF}.} \end{functions} -Per scrivere un carattere si possono usare tre funzioni analoghe alle -precedenti usate per leggere: \func{putc}, \func{fputc} e -\func{putchar}; i loro prototipi sono: +Per scrivere un carattere si possono usare tre funzioni, analoghe alle +precedenti usate per leggere: \funcd{putc}, \funcd{fputc} e \funcd{putchar}; i +loro prototipi sono: \begin{functions} \headdecl{stdio.h} @@ -666,15 +674,15 @@ con un cast da un \ctyp{unsigned char}). Anche il valore di ritorno sempre un intero; in caso di errore o fine del file il valore di ritorno è \val{EOF}. -Come nel caso dell'I/O binario le \acr{glibc} provvedono per ciascuna -delle funzioni precedenti, come estensione GNU, una seconda funzione, il -cui nome è ottenuto aggiungendo un \code{\_unlocked}, che esegue -esattamente le stesse operazioni evitando però il lock implicito dello -stream. +Come nel caso dell'I/O binario con \func{fread} e \func{fwrite} le \acr{glibc} +provvedono come estensione, per ciascuna delle funzioni precedenti, +un'ulteriore funzione, il cui nome è ottenuto aggiungendo un +\code{\_unlocked}, che esegue esattamente le stesse operazioni, evitando però +il lock implicito dello stream. -Per compatibilità con SVID sono provviste anche due funzioni per leggere -e scrivere una \textit{word} (che è sempre definita come \ctyp{int}); i -loro prototipi sono: +Per compatibilità con SVID sono inoltre provviste anche due funzioni, +\funcd{getw} e \funcd{putw}, da usare per leggere e scrivere una \textit{word} +(cioè due byte in una volta); i loro prototipi sono: \begin{functions} \headdecl{stdio.h} @@ -685,8 +693,10 @@ loro prototipi sono: \bodydesc{Le funzioni restituiscono la parola \param{w}, o \val{EOF} in caso di errore o di fine del file.} \end{functions} -\noindent l'uso di queste funzioni è deprecato in favore dell'uso di -\func{fread} e \func{fwrite}, in quanto non è possibile distinguere il + +Le funzioni leggono e scrivono una \textit{word} di due byte, usando comunque +una variabile di tipo \ctyp{int}; il loro uso è deprecato in favore dell'uso +di \func{fread} e \func{fwrite}, in quanto non è possibile distinguere il valore -1 da una condizione di errore che restituisce \val{EOF}. Uno degli usi più frequenti dell'input/output a caratteri è nei programmi di @@ -699,7 +709,7 @@ viene dopo. Nel nostro caso questo tipo di comportamento può essere realizzato prima leggendo il carattere, e poi rimandandolo indietro, cosicché ridiventi disponibile per una lettura successiva; la funzione che inverte la -lettura si chiama \func{ungetc} ed il suo prototipo è: +lettura si chiama \funcd{ungetc} ed il suo prototipo è: \begin{prototype}{stdio.h}{int ungetc(int c, FILE *stream)} Rimanda indietro il carattere \param{c}, con un cast a \ctyp{unsigned char}, sullo stream \param{stream}. @@ -739,11 +749,11 @@ scartati. La terza ed ultima modalità di input/output non formattato è quella di linea, in cui si legge o si scrive una riga alla volta; questa è una modalità molto -usata per l'I/O da terminale, ma che presenta le caratteristiche più -controverse. +usata per l'I/O da terminale, ma è anche quella che presenta le +caratteristiche più controverse. Le funzioni previste dallo standard ANSI C per leggere una linea sono -sostanzialmente due, \func{gets} e \func{fgets}, i cui rispettivi +sostanzialmente due, \funcd{gets} e \funcd{fgets}, i cui rispettivi prototipi sono: \begin{functions} \headdecl{stdio.h} @@ -793,7 +803,7 @@ finale; sar successiva. Per la scrittura di una linea lo standard ANSI C prevede altre due -funzioni, \func{fputs} e \func{puts}, analoghe a quelle di lettura, i +funzioni, \funcd{fputs} e \funcd{puts}, analoghe a quelle di lettura, i rispettivi prototipi sono: \begin{functions} \headdecl{stdio.h} @@ -816,8 +826,10 @@ uno zero ed aggiunge automaticamente il ritorno a capo. La differenza con \var{stdout}) è che quest'ultima non aggiunge il newline, che deve essere previsto esplicitamente. -Come per le funzioni di input/output a caratteri esistono le estensioni -per leggere e scrivere caratteri estesi, i loro prototipi sono: +Come per le analoghe funzioni di input/output a caratteri, anche per l'I/O di +linea esistono delle estensioni per leggere e scrivere linee di caratteri +estesi, le funzioni in questione sono \funcd{fgetws} e \funcd{fputws} ed i +loro prototipi sono: \begin{functions} \headdecl{wchar.h} \funcdecl{wchar\_t *fgetws(wchar\_t *ws, int n, FILE *stream)} @@ -831,17 +843,19 @@ per leggere e scrivere caratteri estesi, i loro prototipi sono: non negativo in caso di successo e \val{NULL} o \val{EOF} in caso di errore o fine del file.} \end{functions} -\noindent il cui comportamento è identico a quello di \func{fgets} e -\func{fputs} a parte il fatto che tutto (numero di caratteri massimo, + +Il comportamento di queste due funzioni è identico a quello di \func{fgets} e +\func{fputs}, a parte il fatto che tutto (numero di caratteri massimo, terminatore della stringa, newline) è espresso in termini di caratteri estesi -anziché di caratteri ASCII. +anziché di normali caratteri ASCII. -Come nel caso dell'I/O binario e a caratteri nelle \acr{glibc} sono -previste una serie di altre funzioni, estensione di tutte quelle -illustrate finora (eccetto \func{gets} e \func{puts}), il cui nome si -ottiene aggiungendo un \code{\_unlocked}, e che eseguono esattamente le -stesse operazioni delle loro equivalenti, evitando però il lock -implicito dello stream (vedi \secref{sec:file_stream_thread}). +Come per l'I/O binario e quello a caratteri, anche per l'I/O di linea le +\acr{glibc} supportano una serie di altre funzioni, estensioni di tutte quelle +illustrate finora (eccetto \func{gets} e \func{puts}), che eseguono +esattamente le stesse operazioni delle loro equivalenti, evitando però il lock +implicito dello stream (vedi \secref{sec:file_stream_thread}). Come per le +altre forma di I/O, dette funzioni hanno lo stesso nome della loro analoga +normale, con l'aggiuta dell'estensione \code{\_unlocked}. Come abbiamo visto, le funzioni di lettura per l'input/output di linea previste dallo standard ANSI C presentano svariati inconvenienti. Benché @@ -855,13 +869,12 @@ buffer), ma a costo di una complicazione ulteriore della logica del programma. Lo stesso dicasi quando si deve gestire il caso di stringa che eccede le dimensioni del buffer. -Per questo motivo le \acr{glibc} prevedono, come estensione GNU, due -nuove funzioni per la gestione dell'input/output di linea, il cui uso -permette di risolvere questi problemi. L'uso di queste funzioni deve -essere attivato definendo la macro \macro{\_GNU\_SOURCE} prima di -includere \file{stdio.h}. La prima delle due, \func{getline}, serve per -leggere una linea terminata da un newline esattamente allo stesso modo -di \func{fgets}, il suo prototipo è: +Per questo motivo le \acr{glibc} prevedono, come estensione GNU, due nuove +funzioni per la gestione dell'input/output di linea, il cui uso permette di +risolvere questi problemi. L'uso di queste funzioni deve essere attivato +definendo la macro \macro{\_GNU\_SOURCE} prima di includere \file{stdio.h}. La +prima delle due, \funcd{getline}, serve per leggere una linea terminata da un +newline, esattamente allo stesso modo di \func{fgets}, il suo prototipo è: \begin{prototype}{stdio.h} {ssize\_t getline(char **buffer, size\_t *n, FILE *stream)} Legge una linea dal file \param{stream} copiandola sul buffer indicato da \param{buffer} @@ -914,7 +927,7 @@ un errore la funzione restituisce -1. La seconda estensione GNU è una generalizzazione di \func{getline} per poter usare come separatore un carattere qualsiasi, la funzione si -chiama \func{getdelim} ed il suo prototipo è: +chiama \funcd{getdelim} ed il suo prototipo è: \begin{prototype}{stdio.h} {ssize\_t getdelim(char **buffer, size\_t *n, int delim, FILE *stream)} Identica a \func{getline} solo che usa \param{delim} al posto del @@ -935,7 +948,8 @@ caratteristiche pi permette di stampare in maniera facile e veloce dati, tabelle e messaggi. L'output formattato viene eseguito con una delle 13 funzioni della famiglia -\func{printf}; le tre più usate sono le seguenti: +\func{printf}; le tre più usate sono \funcd{printf}, \funcd{fprintf} e +\funcd{sprintf}, i cui prototipi sono: \begin{functions} \headdecl{stdio.h} \funcdecl{int printf(const char *format, ...)} Stampa su \file{stdout} @@ -955,18 +969,21 @@ L'output formattato viene eseguito con una delle 13 funzioni della famiglia o quello specificato) la terza permette di stampare su una stringa, in genere l'uso di \func{sprintf} è sconsigliato in quanto è possibile, se non si ha la sicurezza assoluta sulle dimensioni del risultato della stampa, eccedere le -dimensioni di \param{str} con conseguente sovrascrittura di altre variabili e -possibili buffer overflow; per questo motivo si consiglia l'uso -dell'alternativa: +dimensioni di \param{str}, con conseguente sovrascrittura di altre variabili e +possibili \textit{buffer overflow}\index{buffer overflow}; per questo motivo +si consiglia l'uso dell'alternativa \funcd{snprintf}, il cui prototipo è: \begin{prototype}{stdio.h} {snprintf(char *str, size\_t size, const char *format, ...)} Identica a \func{sprintf}, ma non scrive su \param{str} più di \param{size} caratteri. \end{prototype} -La parte più complessa di queste funzioni è il formato della stringa -\param{format} che indica le conversioni da fare, da cui poi deriva il numero -dei parametri che dovranno essere passati a seguire. +La parte più complessa delle funzioni di scrittura formattata è il formato +della stringa \param{format} che indica le conversioni da fare, e da cui +deriva anche il numero dei parametri che dovranno essere passati a seguire (si +noti come tutte queste funzioni siano \textit{variadic}\index{variadic}, +prendendo un numero di argomenti variabile che dipende appunto da quello che +si è specificato in \param{format}). \begin{table}[htb] \centering @@ -1103,7 +1120,8 @@ manuale di \func{printf} e nella documentazione delle \acr{glibc}. Una versione alternativa delle funzioni di output formattato, che permettono di usare il puntatore ad una lista di argomenti (vedi -\secref{sec:proc_variadic}), sono le seguenti: +\secref{sec:proc_variadic}), sono \funcd{vprintf}, \funcd{vfprintf} e +\funcd{vsprintf}, i cui prototipi sono: \begin{functions} \headdecl{stdio.h} @@ -1130,20 +1148,21 @@ parametri dovr \code{va\_end(ap)} ma in Linux questo non è necessario). Come per \func{sprintf} anche per \func{vsprintf} esiste una analoga -\func{vsnprintf} che pone un limite sul numero di caratteri che vengono +\funcd{vsnprintf} che pone un limite sul numero di caratteri che vengono scritti sulla stringa di destinazione: \begin{prototype}{stdio.h} {vsnprintf(char *str, size\_t size, const char *format, va\_list ap)} Identica a \func{vsprintf}, ma non scrive su \param{str} più di \param{size} caratteri. \end{prototype} -\noindent in modo da evitare possibili buffer overflow. +\noindent in modo da evitare possibili buffer overflow\index{buffer overflow}. Per eliminare alla radice questi problemi, le \acr{glibc} supportano una specifica estensione GNU che alloca dinamicamente tutto lo spazio necessario; l'estensione si attiva al solito definendo \macro{\_GNU\_SOURCE}, le due -funzioni sono: +funzioni sono \funcd{asprintf} e \funcd{vasprintf}, ed i rispettivi prototipi +sono: \begin{functions} \headdecl{stdio.h} @@ -1175,7 +1194,8 @@ davanti a \texttt{print}, sono trattate in dettaglio nella documentazione delle In corrispondenza alla famiglia di funzioni \func{printf} che si usano per l'output formattato, l'input formattato viene eseguito con le funzioni della -famiglia \func{scanf}; fra queste le tre più importanti sono: +famiglia \func{scanf}; fra queste le tre più importanti sono \funcd{scanf}, +\funcd{fscanf} e \funcd{sscanf}, i cui proprotipi sono: \begin{functions} \headdecl{stdio.h} \funcdecl{int scanf(const char *format, ...)} Esegue una scansione di \file{stdin} cercando una corrispondenza di quanto letto con il @@ -1259,9 +1279,9 @@ esempio in VMS pu rispetto al record corrente). Tutto questo comporta la presenza di diverse funzioni che eseguono -sostanzialmente le stesse operazioni, ma usano parametri di tipo -diverso. Le funzioni tradizionali usate per il riposizionamento della -posizione in uno stream sono: +sostanzialmente le stesse operazioni, ma usano parametri di tipo diverso. Le +funzioni tradizionali usate per il riposizionamento della posizione in uno +stream sono \funcd{fseek} e \funcd{rewind} i cui prototipi sono: \begin{functions} \headdecl{stdio.h} @@ -1282,7 +1302,7 @@ posizione corrente all'inizio dello stream, ma non esattamente equivalente ad una \code{fseek(stream, 0L, SEEK\_SET)} in quanto vengono cancellati anche i flag di errore e fine del file. -Per ottenere la posizione corrente si usa invece la funzione \func{ftell}, il +Per ottenere la posizione corrente si usa invece la funzione \funcd{ftell}, il cui prototipo è: \begin{prototype}{stdio.h}{long ftell(FILE *stream)} Legge la posizione attuale nello stream \param{stream}. @@ -1298,7 +1318,7 @@ dall'inizio dello stream. Queste funzioni esprimono tutte la posizione nel file come un \ctyp{long int}. Dato che (ad esempio quando si usa un filesystem indicizzato a 64 bit) questo può non essere possibile lo standard POSIX ha introdotto le nuove funzioni -\func{fgetpos} e \func{fsetpos}, che invece usano il nuovo tipo +\funcd{fgetpos} e \funcd{fsetpos}, che invece usano il nuovo tipo \type{fpos\_t}, ed i cui prototipi sono: \begin{functions} \headdecl{stdio.h} @@ -1335,7 +1355,7 @@ impliciti per la programmazione multi thread. Al contrario di quanto avviene con i file descriptor, le librerie standard del C non prevedono nessuna funzione come la \func{fcntl} per il controllo degli attributi dei file. Però, dato che ogni stream si appoggia ad un file -descriptor, si può usare la funzione \func{fileno} per ottenere quest'ultimo, +descriptor, si può usare la funzione \funcd{fileno} per ottenere quest'ultimo, il prototipo della funzione è: \begin{prototype}{stdio.h}{int fileno(FILE *stream)} Legge il file descriptor sottostante lo stream \param{stream}. @@ -1357,7 +1377,7 @@ disponibile, e si deve ricordare come il file essere complessa se le operazioni vengono effettuate in una subroutine, che a questo punto necessiterà di informazioni aggiuntive rispetto al semplice puntatore allo stream; questo può essere evitato con le due funzioni -\func{\_\_freadable} e \func{\_\_fwritable} i cui prototipi sono: +\funcd{\_\_freadable} e \funcd{\_\_fwritable} i cui prototipi sono: \begin{functions} \headdecl{stdio\_ext.h} \funcdecl{int \_\_freadable(FILE *stream)} @@ -1371,7 +1391,7 @@ puntatore allo stream; questo pu La conoscenza dell'ultima operazione effettuata su uno stream aperto è utile in quanto permette di trarre conclusioni sullo stato del buffer e del suo -contenuto. Altre due funzioni, \func{\_\_freading} e \func{\_\_fwriting} +contenuto. Altre due funzioni, \funcd{\_\_freading} e \funcd{\_\_fwriting} servono a tale scopo, il loro prototipo è: \begin{functions} \headdecl{stdio\_ext.h} @@ -1403,7 +1423,7 @@ allocati automaticamente. Però una volta che si sia aperto lo stream (ma prima di aver compiuto operazioni su di esso) è possibile intervenire sulle modalità di buffering; la -funzione che permette di controllare la bufferizzazione è \func{setvbuf}, il +funzione che permette di controllare la bufferizzazione è \funcd{setvbuf}, il suo prototipo è: \begin{prototype}{stdio.h}{int setvbuf(FILE *stream, char *buf, int mode, size\_t size)} @@ -1467,8 +1487,8 @@ specifichi la modalit vengono sempre ignorati. Oltre a \func{setvbuf} le \acr{glibc} definiscono altre tre funzioni per la -gestione della bufferizzazione di uno stream: \func{setbuf}, \func{setbuffer} -e \func{setlinebuf}; i loro prototipi sono: +gestione della bufferizzazione di uno stream: \funcd{setbuf}, \funcd{setbuffer} +e \funcd{setlinebuf}; i loro prototipi sono: \begin{functions} \headdecl{stdio.h} @@ -1486,8 +1506,8 @@ e \func{setlinebuf}; i loro prototipi sono: \noindent tutte queste funzioni sono realizzate con opportune chiamate a \func{setvbuf} e sono definite solo per compatibilità con le vecchie librerie BSD. Infine le \acr{glibc} provvedono le funzioni non standard\footnote{anche - queste funzioni sono originarie di Solaris.} \func{\_\_flbf} e -\func{\_\_fbufsize} che permettono di leggere le proprietà di bufferizzazione + queste funzioni sono originarie di Solaris.} \funcd{\_\_flbf} e +\funcd{\_\_fbufsize} che permettono di leggere le proprietà di bufferizzazione di uno stream; i cui prototipi sono: \begin{functions} \headdecl{stdio\_ext.h} @@ -1501,7 +1521,7 @@ di uno stream; i cui prototipi sono: Come già accennato, indipendentemente dalla modalità di bufferizzazione scelta, si può forzare lo scarico dei dati sul file con la funzione -\func{fflush}, il suo prototipo è: +\funcd{fflush}, il suo prototipo è: \begin{prototype}{stdio.h}{int fflush(FILE *stream)} Forza la scrittura di tutti i dati bufferizzati dello stream \param{stream}. @@ -1521,7 +1541,7 @@ stream aperti. Esistono per sicuri che sia stato eseguito tutto l'output su terminale, in cui serve poter effettuare lo scarico dei dati solo per gli stream in modalità line buffered; per questo motivo le \acr{glibc} supportano una estensione di Solaris, la -funzione \func{\_flushlbf}, il cui prototipo è: +funzione \funcd{\_flushlbf}, il cui prototipo è: \begin{prototype}{stdio-ext.h}{void \_flushlbf(void)} Forza la scrittura di tutti i dati bufferizzati degli stream in modalità line buffered. @@ -1533,7 +1553,7 @@ kernel dia effettivamente avvio alle operazioni di scrittura su disco occorre usare \func{sync} o \func{fsync} (si veda~\secref{sec:file_sync}). Infine esistono anche circostanze in cui si vuole scartare tutto l'output -pendente; per questo si può usare \func{fpurge}, il cui prototipo è: +pendente; per questo si può usare \funcd{fpurge}, il cui prototipo è: \begin{prototype}{stdio.h}{int fpurge(FILE *stream)} Cancella i buffer di input e di output dello stream \param{stream}. @@ -1566,9 +1586,10 @@ 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 che permettono la -gestione esplicita dei blocchi sugli stream; queste funzioni sono disponibili -definendo \macro{\_POSIX\_THREAD\_SAFE\_FUNCTIONS} ed i loro prototipi sono: +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} @@ -1603,7 +1624,7 @@ La sostituzione di tutte le funzioni di I/O con le relative versioni abbastanza noioso; per questo motivo le \acr{glibc} provvedono 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 \func{\_\_fsetlocking}, il cui +locking degli stream: l'uso della funzione \funcd{\_\_fsetlocking}, il cui prototipo è: \begin{prototype}{stdio\_ext.h}{int \_\_fsetlocking (FILE *stream, int type)} Specifica o richiede a seconda del valore di \param{type} la modalità in cui diff --git a/fileunix.tex b/fileunix.tex index b4e7b57..0863017 100644 --- a/fileunix.tex +++ b/fileunix.tex @@ -186,7 +186,7 @@ system call del kernel. \subsection{La funzione \func{open}} \label{sec:file_open} -La funzione \func{open} è la funzione fondamentale per accedere ai file, ed è +La funzione \funcd{open} è la funzione fondamentale per accedere ai file, ed è quella che crea l'associazione fra un pathname ed un file descriptor, il suo prototipo è: \begin{functions} @@ -387,7 +387,7 @@ estensioni specifiche di Linux, e deve essere definita la macro Nelle prime versioni di Unix i valori di \param{flag} specificabili per \func{open} erano solo quelli relativi alle modalità di accesso del file. Per questo motivo per creare un nuovo file c'era una system call apposita, -\func{creat}, il cui prototipo è: +\funcd{creat}, il cui prototipo è: \begin{prototype}{fcntl.h} {int creat(const char *pathname, mode\_t mode)} Crea un nuovo file vuoto, con i permessi specificati da \param{mode}. È del @@ -400,7 +400,7 @@ programmi. \subsection{La funzione \func{close}} \label{sec:file_close} -La funzione \func{close} permette di chiudere un file, in questo modo il file +La funzione \funcd{close} permette di chiudere un file, in questo modo il file descriptor ritorna disponibile; il suo prototipo è: \begin{prototype}{unistd.h}{int close(int fd)} Chiude il descrittore \param{fd}. @@ -454,7 +454,7 @@ automaticamente spostata in avanti del numero di byte letti o scritti. In genere (a meno di non avere richiesto la modalità \const{O\_APPEND}) questa posizione viene impostata a zero all'apertura del file. È possibile impostarla -ad un valore qualsiasi con la funzione \func{lseek}, il cui prototipo è: +ad un valore qualsiasi con la funzione \funcd{lseek}, il cui prototipo è: \begin{functions} \headdecl{sys/types.h} \headdecl{unistd.h} @@ -522,7 +522,7 @@ indefinito. Una volta che un file è stato aperto (con il permesso in lettura) su possono -leggere i dati che contiene utilizzando la funzione \func{read}, il cui +leggere i dati che contiene utilizzando la funzione \funcd{read}, il cui prototipo è: \begin{prototype}{unistd.h}{ssize\_t read(int fd, void * buf, size\_t count)} @@ -599,7 +599,7 @@ dagli albori di Unix, ma nella seconda versione delle \textit{Single Unix aggiunto con la versione 2.1, in versioni precedenti sia del kernel che delle librerie la funzione non è disponibile.} (quello che viene chiamato normalmente Unix98, vedi \secref{sec:intro_opengroup}) è stata introdotta la -definizione di un'altra funzione di lettura, \func{pread}, il cui prototipo è: +definizione di un'altra funzione di lettura, \funcd{pread}, il cui prototipo è: \begin{prototype}{unistd.h} {ssize\_t pread(int fd, void * buf, size\_t count, off\_t offset)} @@ -628,7 +628,7 @@ condivisa da processi diversi (vedi \secref{sec:file_sharing}). Il valore di \label{sec:file_write} Una volta che un file è stato aperto (con il permesso in scrittura) su può -scrivere su di esso utilizzando la funzione \func{write}, il cui prototipo è: +scrivere su di esso utilizzando la funzione \funcd{write}, il cui prototipo è: \begin{prototype}{unistd.h}{ssize\_t write(int fd, void * buf, size\_t count)} Scrive \param{count} byte dal buffer \param{buf} sul file \param{fd}. @@ -669,7 +669,7 @@ Per i file ordinari il numero di byte scritti indicato da \param{count}, a meno di un errore. Negli altri casi si ha lo stesso comportamento di \func{read}. -Anche per \func{write} lo standard Unix98 definisce un'analoga \func{pwrite} +Anche per \func{write} lo standard Unix98 definisce un'analoga \funcd{pwrite} per scrivere alla posizione indicata senza modificare la posizione corrente nel file, il suo prototipo è: \begin{prototype}{unistd.h} @@ -840,7 +840,7 @@ scarico dei dati dai buffer del kernel.\footnote{come gi questo dà la garanzia assoluta che i dati siano integri dopo la chiamata, l'hardware dei dischi è in genere dotato di un suo meccanismo interno di ottimizzazione per l'accesso al disco che può ritardare ulteriormente la - scrittura effettiva.} La prima di queste funzioni è \func{sync} il cui + scrittura effettiva.} La prima di queste funzioni è \funcd{sync} il cui prototipo è: \begin{prototype}{unistd.h}{int sync(void)} @@ -866,7 +866,7 @@ significato dei valori si pu Quando si vogliono scaricare soltanto i dati di un file (ad esempio essere sicuri che i dati di un database sono stati registrati su disco) si possono -usare le due funzioni \func{fsync} e \func{fdatasync}, i cui prototipi sono: +usare le due funzioni \funcd{fsync} e \funcd{fdatasync}, i cui prototipi sono: \begin{functions} \headdecl{unistd.h} \funcdecl{int fsync(int fd)} @@ -904,7 +904,7 @@ disco) che deve essere effettuata esplicitamente.\footnote{in realt Abbiamo già visto in \secref{sec:file_sharing} come un processo figlio condivida gli stessi file descriptor del padre; è possibile però ottenere un comportamento analogo all'interno di uno stesso processo \textit{duplicando} -un file descriptor. Per far questo si usa la funzione \func{dup} il cui +un file descriptor. Per far questo si usa la funzione \funcd{dup} il cui prototipo è: \begin{prototype}{unistd.h}{int dup(int oldfd)} Crea una copia del file descriptor \param{oldfd}. @@ -956,8 +956,8 @@ restituito alla chiamata di \func{dup}, come primo file descriptor disponibile. Dato che questa è l'operazione più comune, è prevista una diversa versione -della funzione, \func{dup2}, che permette di specificare esplicitamente qual'è -il valore di file descriptor che si vuole avere come duplicato; il suo +della funzione, \funcd{dup2}, che permette di specificare esplicitamente +qual'è il valore di file descriptor che si vuole avere come duplicato; il suo prototipo è: \begin{prototype}{unistd.h}{int dup2(int oldfd, int newfd)} @@ -1004,7 +1004,7 @@ funzionalit (vedi \secref{sec:file_locking}).} Per queste operazioni di manipolazione e di controllo su proprietà e -caratteristiche un file descriptor, viene usata la funzione \func{fcntl}, il +caratteristiche un file descriptor, viene usata la funzione \funcd{fcntl}, il cui prototipo è: \begin{functions} \headdecl{unistd.h} @@ -1093,9 +1093,9 @@ valori valore zero indica di usare il segnale predefinito, \const{SIGIO}. Un altro valore (compreso lo stesso \const{SIGIO}) specifica il segnale voluto; l'uso di un valore diverso da zero permette inoltre, se si è installato il - manipolatore del segnale come \var{sa\_sigaction} usando + gestore del segnale come \var{sa\_sigaction} usando \const{SA\_SIGINFO}, (vedi \secref{sec:sig_sigaction}), di rendere - disponibili al manipolatore informazioni ulteriori informazioni riguardo il + disponibili al gestore informazioni ulteriori informazioni riguardo il file che ha generato il segnale attraverso i valori restituiti in \struct{siginfo\_t} (come vedremo in \secref{sec:file_asyncronous_io}).\footnote{i due comandi \const{F\_SETSIG} @@ -1137,7 +1137,7 @@ interfaccia astratta (un caso tipico porta seriale, o le dimensioni di un framebuffer). Per questo motivo nell'architettura del sistema è stata prevista l'esistenza -di una funzione apposita, \func{ioctl}, con cui poter compiere le operazioni +di una funzione apposita, \funcd{ioctl}, con cui poter compiere le operazioni specifiche di ogni dispositivo particolare, usando come riferimento il solito file descriptor. Il prototipo di questa funzione è: \begin{prototype}{sys/ioctl.h}{int ioctl(int fd, int request, ...)} diff --git a/ipc.tex b/ipc.tex index e2052c8..c7f2c4a 100644 --- a/ipc.tex +++ b/ipc.tex @@ -49,7 +49,7 @@ due file descriptor, nella forma di un \textsl{tubo} (da cui il nome) attraverso cui fluiscono i dati. La funzione che permette di creare questa speciale coppia di file descriptor -associati ad una \textit{pipe} è appunto \func{pipe}, ed il suo prototipo è: +associati ad una \textit{pipe} è appunto \funcd{pipe}, ed il suo prototipo è: \begin{prototype}{unistd.h} {int pipe(int filedes[2])} @@ -113,8 +113,8 @@ pipe il cui capo in scrittura (vale a dire che la funzione \func{read} ritornerà restituendo 0). Se invece si esegue una scrittura su una pipe il cui capo in lettura non è aperto il processo riceverà il segnale \errcode{EPIPE}, e la funzione di scrittura -restituirà un errore di \errcode{EPIPE} (al ritorno del manipolatore, o qualora -il segnale sia ignorato o bloccato). +restituirà un errore di \errcode{EPIPE} (al ritorno del gestore, o qualora il +segnale sia ignorato o bloccato). La dimensione del buffer della pipe (\const{PIPE\_BUF}) ci dà inoltre un'altra importante informazione riguardo il comportamento delle operazioni di lettura @@ -322,7 +322,7 @@ Come si utilizzarla per fare da tramite fra output ed input di due programmi invocati in sequenza; per questo motivo lo standard POSIX.2 ha introdotto due funzioni che permettono di sintetizzare queste operazioni. La prima di esse si chiama -\func{popen} ed il suo prototipo è: +\funcd{popen} ed il suo prototipo è: \begin{prototype}{stdio.h} {FILE *popen(const char *command, const char *type)} @@ -352,7 +352,7 @@ stream visti in \capref{cha:files_std_interface}, anche se pipe e non ad un inode\index{inode}, e viene sempre aperto in modalità \textit{fully-buffered} (vedi \secref{sec:file_buffering}); l'unica differenza con gli usuali stream è che dovrà essere chiuso dalla seconda delle due nuove -funzioni, \func{pclose}, il cui prototipo è: +funzioni, \funcd{pclose}, il cui prototipo è: \begin{prototype}{stdio.h} {int pclose(FILE *stream)} @@ -836,7 +836,7 @@ una modalit che fornisca l'interfaccia dei socket.} che li rende sostanzialmente identici ad una pipe bidirezionale. -La funzione \func{socketpair} infatti consente di creare una coppia di file +La funzione \funcd{socketpair} infatti consente di creare una coppia di file descriptor connessi fra di loro (tramite un socket\index{socket}, appunto), senza dover ricorrere ad un file speciale sul filesystem, i descrittori sono del tutto analoghi a quelli che si avrebbero con una chiamata a \func{pipe}, @@ -977,9 +977,9 @@ alternativa pi la chiave (che ad esempio può essere dichiarato in un header comune), ma c'è sempre il rischio che questa chiave possa essere stata già utilizzata da qualcun altro. Dato che non esiste una convenzione su come assegnare queste -chiavi in maniera univoca l'interfaccia mette a disposizione una funzione, -\func{ftok}, che permette di ottenere una chiave specificando il nome di un -file ed un numero di versione; il suo prototipo è: +chiavi in maniera univoca l'interfaccia mette a disposizione una funzione +apposita, \funcd{ftok}, che permette di ottenere una chiave specificando il +nome di un file ed un numero di versione; il suo prototipo è: \begin{functions} \headdecl{sys/types.h} \headdecl{sys/ipc.h} @@ -1236,8 +1236,8 @@ anche se la loro struttura quello di permettere a processi diversi di scambiarsi dei dati. La funzione che permette di richiedere al sistema l'identificatore di una coda -di messaggi esistente (o di crearne una se questa non esiste) è \func{msgget}; -il suo prototipo è: +di messaggi esistente (o di crearne una se questa non esiste) è +\funcd{msgget}; il suo prototipo è: \begin{functions} \headdecl{sys/types.h} \headdecl{sys/ipc.h} @@ -1416,7 +1416,7 @@ gli altri campi invece: \end{itemize} Una volta creata una coda di messaggi le operazioni di controllo vengono -effettuate con la funzione \func{msgctl}, che (come le analoghe \func{semctl} +effettuate con la funzione \funcd{msgctl}, che (come le analoghe \func{semctl} e \func{shmctl}) fa le veci di quello che \func{ioctl} è per i file; il suo prototipo è: \begin{functions} @@ -1471,7 +1471,7 @@ eseguire; i valori possibili sono: Una volta che si abbia a disposizione l'identificatore, per inviare un -messaggio su una coda si utilizza la funzione \func{msgsnd}; il suo prototipo +messaggio su una coda si utilizza la funzione \funcd{msgsnd}; il suo prototipo è: \begin{functions} \headdecl{sys/types.h} @@ -1584,7 +1584,7 @@ vengono modificati: \end{itemize*} La funzione che viene utilizzata per estrarre un messaggio da una coda è -\func{msgrcv}; il suo prototipo è: +\funcd{msgrcv}; il suo prototipo è: \begin{functions} \headdecl{sys/types.h} \headdecl{sys/ipc.h} @@ -1770,11 +1770,11 @@ con \var{msgbuf\_write} (\texttt{\small 12--15}) vengono restituite le frasi. La gestione delle opzioni si è al solito omessa, essa si curerà di impostare in \var{n} il numero di frasi da leggere specificato a linea di comando ed in \var{fortunefilename} il file da cui leggerle; dopo aver installato -(\texttt{\small 19--21}) dei manipolatori per gestire l'uscita dal server, -viene prima controllato (\texttt{\small 22}) il numero di frasi richieste -abbia senso (cioè sia maggiore di zero), le quali poi (\texttt{\small 23}) -vengono lette nel vettore in memoria con la stessa funzione -\code{FortuneParse()} usata anche per il server basato sulle fifo. +(\texttt{\small 19--21}) i gestori dei segnali per trattare l'uscita dal +server, viene prima controllato (\texttt{\small 22}) il numero di frasi +richieste abbia senso (cioè sia maggiore di zero), le quali poi +(\texttt{\small 23}) vengono lette nel vettore in memoria con la stessa +funzione \code{FortuneParse()} usata anche per il server basato sulle fifo. Una volta inizializzato il vettore di stringhe coi messaggi presi dal file delle \textit{fortune} si procede (\texttt{\small 25}) con la generazione di @@ -1808,7 +1808,7 @@ messaggio di risposta. Si tenga conto che se la coda funzione potrà bloccarsi fintanto che non venga liberato dello spazio. Si noti che il programma può terminare solo grazie ad una interruzione da -parte di un segnale; in tal caso verrà eseguito il manipolatore +parte di un segnale; in tal caso verrà eseguito il gestore \code{HandSIGTERM}, che semplicemente si limita a cancellare la coda (\texttt{\small 44}) ed ad uscire (\texttt{\small 45}). @@ -1926,7 +1926,7 @@ Il sistema di comunicazione interprocesso di \textit{SysV IPC} prevede anche i semafori, ma gli oggetti utilizzati non sono semafori singoli, ma gruppi di semafori detti \textsl{insiemi} (o \textit{semaphore set}); la funzione che permette di creare o ottenere l'identificatore di un insieme di semafori è -\func{semget}, ed il suo prototipo è: +\funcd{semget}, ed il suo prototipo è: \begin{functions} \headdecl{sys/types.h} \headdecl{sys/ipc.h} @@ -2096,7 +2096,7 @@ direttamente nel file \file{/proc/sys/kernel/sem}. La funzione che permette di effettuare le varie operazioni di controllo sui semafori (fra le quali, come accennato, è impropriamente compresa anche la -loro inizializzazione) è \func{semctl}; il suo prototipo è: +loro inizializzazione) è \funcd{semctl}; il suo prototipo è: \begin{functions} \headdecl{sys/types.h} \headdecl{sys/ipc.h} @@ -2245,7 +2245,7 @@ colonna della tabella. Le operazioni ordinarie sui semafori, come l'acquisizione o il rilascio degli stessi (in sostanza tutte quelle non comprese nell'uso di \func{semctl}) -vengono effettuate con la funzione \func{semop}, il cui prototipo è: +vengono effettuate con la funzione \funcd{semop}, il cui prototipo è: \begin{functions} \headdecl{sys/types.h} \headdecl{sys/ipc.h} @@ -2593,7 +2593,7 @@ analoga senza questo problemi usando il file locking\index{file!locking}. \label{sec:ipc_sysv_shm} Il terzo oggetto introdotto dal \textit{SysV IPC} è quello dei segmenti di -memoria condivisa. La funzione che permette di ottenerne uno è \func{shmget}, +memoria condivisa. La funzione che permette di ottenerne uno è \funcd{shmget}, ed il suo prototipo è: \begin{functions} \headdecl{sys/types.h} @@ -2738,7 +2738,7 @@ che permettono di cambiarne il valore. \end{table} Al solito la funzione che permette di effettuare le operazioni di controllo su -un segmento di memoria condivisa è \func{shmctl}; il suo prototipo è: +un segmento di memoria condivisa è \funcd{shmctl}; il suo prototipo è: \begin{functions} \headdecl{sys/ipc.h} \headdecl{sys/shm.h} @@ -2792,7 +2792,7 @@ i primi tre comandi sono gli stessi gi gli ultimi due sono delle estensioni previste da Linux. Per utilizzare i segmenti di memoria condivisa l'interfaccia prevede due -funzioni, la prima è \func{shmat}, che serve ad agganciare un segmento al +funzioni, la prima è \funcd{shmat}, che serve ad agganciare un segmento al processo chiamante, in modo che quest'ultimo possa vederlo nel suo spazio di indirizzi; il suo prototipo è: \begin{functions} @@ -2894,7 +2894,7 @@ attraverso una \func{exit}. Una volta che un segmento di memoria condivisa non serve più, si può sganciarlo esplicitamente dal processo usando l'altra funzione -dell'interfaccia, \func{shmdt}, il cui prototipo è: +dell'interfaccia, \funcd{shmdt}, il cui prototipo è: \begin{functions} \headdecl{sys/types.h} \headdecl{sys/shm.h} diff --git a/process.tex b/process.tex index 5a3e630..8bde54c 100644 --- a/process.tex +++ b/process.tex @@ -815,10 +815,10 @@ prototipi sono: \end{functions} Le due funzioni permettono rispettivamente di bloccare e sbloccare la -paginazione per l'intervallo di memoria specificato dagli argomenti, che ne -indicano nell'ordine l'indirizzo iniziale e la lunghezza. Tutte le pagine che -contengono una parte dell'intervallo bloccato sono mantenute in RAM per tutta -la durata del blocco. +paginazione\index{paginazione} per l'intervallo di memoria specificato dagli +argomenti, che ne indicano nell'ordine l'indirizzo iniziale e la lunghezza. +Tutte le pagine che contengono una parte dell'intervallo bloccato sono +mantenute in RAM per tutta la durata del blocco. Altre due funzioni, \funcd{mlockall} e \funcd{munlockall}, consentono di bloccare genericamente la paginazione\index{paginazione} per l'intero spazio @@ -1330,11 +1330,11 @@ viene usato questo meccanismo. Come vedremo nei capitoli successivi, non sempre è possibile specificare un numero fisso di parametri per una funzione. Lo standard ISO C prevede nella -sua sintassi la possibilità di definire delle \textit{variadic function} che -abbiano un numero variabile di argomenti, attraverso l'uso della -\textit{ellipsis} \code{...} nella dichiarazione della funzione; ma non -provvede a livello di linguaggio alcun meccanismo con cui dette funzioni -possono accedere ai loro argomenti. +sua sintassi la possibilità di definire delle \textit{variadic + function}\index{variadic} che abbiano un numero variabile di argomenti, +attraverso l'uso della \textit{ellipsis} \code{...} nella dichiarazione della +funzione; ma non provvede a livello di linguaggio alcun meccanismo con cui +dette funzioni possono accedere ai loro argomenti. L'accesso viene invece realizzato dalle librerie standard che provvedono gli strumenti adeguati. L'uso delle \textit{variadic function} prevede tre punti: @@ -1348,10 +1348,10 @@ strumenti adeguati. L'uso delle \textit{variadic function} prevede tre punti: a seguire gli addizionali. \end{itemize*} -Lo standard ISO C prevede che una \textit{variadic function} abbia sempre -almeno un argomento fisso; prima di effettuare la dichiarazione deve essere -incluso l'apposito header file \file{stdarg.h}; un esempio di dichiarazione è -il prototipo della funzione \func{execl} che vedremo in +Lo standard ISO C prevede che una \textit{variadic function}\index{variadic} +abbia sempre almeno un argomento fisso; prima di effettuare la dichiarazione +deve essere incluso l'apposito header file \file{stdarg.h}; un esempio di +dichiarazione è il prototipo della funzione \func{execl} che vedremo in \secref{sec:proc_exec}: \begin{lstlisting}[labelstep=0,frame=,indent=1cm]{} int execl(const char *path, const char *arg, ...); diff --git a/prochand.tex b/prochand.tex index a1b36fc..9321232 100644 --- a/prochand.tex +++ b/prochand.tex @@ -1430,7 +1430,7 @@ programmi in cui ci sia necessit privilegi o permessi di un'altro (o dell'amministratore). Come nel caso del \acr{pid} e del \acr{ppid}, anche tutti questi -identificatori possono essere letti attraverso le opportune funzioni: +identificatori possono essere letti attraverso le rispettive funzioni: \funcd{getuid}, \funcd{geteuid}, \funcd{getgid} e \funcd{getegid}, i loro prototipi sono: \begin{functions} @@ -1585,7 +1585,7 @@ l'\textsl{userid effettivo} del processo per cedere i privilegi occorre ricorrere ad altre funzioni (si veda ad esempio \secref{sec:proc_seteuid}). -\subsection{Le funzioni \funcd{setreuid} e \funcd{setresuid}} +\subsection{Le funzioni \func{setreuid} e \func{setresuid}} \label{sec:proc_setreuid} Queste due funzioni derivano da BSD che, non supportando\footnote{almeno fino @@ -2524,7 +2524,7 @@ 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 manipolatori dei segnali. +delle funzioni all'interno dei gestori dei segnali. Fintanto che una funzione opera soltanto con le variabili locali è rientrante; queste infatti vengono allocate nello stack, e un'altra invocazione non fa diff --git a/session.tex b/session.tex index ee8b2d8..9bff74f 100644 --- a/session.tex +++ b/session.tex @@ -124,7 +124,7 @@ dal comando \cmd{ps} usando l'opzione \cmd{-j}. Un \textit{process group} è pertanto definito da tutti i processi che hanno lo stesso \acr{pgid}; è possibile leggere il valore di questo identificatore con -le funzioni \func{getpgid} e \func{getpgrp},\footnote{\func{getpgrp} è +le funzioni \funcd{getpgid} e \funcd{getpgrp},\footnote{\func{getpgrp} è definita nello standard POSIX.1, mentre \func{getpgid} è richiesta da SVr4.} i cui prototipi sono: \begin{functions} @@ -148,7 +148,7 @@ restituisce il \acr{pgid} del processo corrente; \func{getpgrp} equivalente a \code{getpgid(0)}. In maniera analoga l'identificatore della sessione può essere letto dalla -funzione \func{getsid}, che però nelle \acr{glibc}\footnote{la system call è +funzione \funcd{getsid}, che però nelle \acr{glibc}\footnote{la system call è stata introdotta in Linux a partire dalla versione 1.3.44, il supporto nelle librerie del C è iniziato dalla versione 5.2.19. La funzione non è prevista da POSIX.1, che parla solo di processi leader di sessione, e non di @@ -181,7 +181,7 @@ Ciascun raggruppamento di processi ha sempre un processo principale, il cosiddetto \textit{process group leader}, che è identificato dall'avere un \acr{pgid} uguale al suo \acr{pid}, in genere questo è il primo processo del raggruppamento, che si incarica di lanciare tutti gli altri. Un nuovo -raggruppamento si crea con la funzione \func{setpgrp},\footnote{questa è la +raggruppamento si crea con la funzione \funcd{setpgrp},\footnote{questa è la definizione di POSIX.1, BSD definisce una funzione con lo stesso nome, che però è identica a \func{setpgid}; nelle \acr{glibc} viene sempre usata sempre questa definizione, a meno di non richiedere esplicitamente la @@ -198,7 +198,7 @@ La funzione, assegnando al \acr{pgid} il valore del \acr{pid} processo corrente, rende questo \textit{group leader} di un nuovo raggruppamento, tutti i successivi processi da esso creati apparterranno (a meno di non cambiare di nuovo il \acr{pgid}) al nuovo raggruppamento. È possibile invece spostare un -processo da un raggruppamento ad un altro con la funzione \func{setpgid}, il +processo da un raggruppamento ad un altro con la funzione \funcd{setpgid}, il cui prototipo è: \begin{prototype}{unistd.h}{int setpgid(pid\_t pid, pid\_t pgid)} Assegna al \acr{pgid} del processo \param{pid} il valore \param{pgid}. @@ -239,7 +239,7 @@ comunque entrambe per evitare di esporsi ad una race condition. Si noti come nessuna delle funzioni esaminate finora permetta di spostare un processo da una sessione ad un altra; infatti l'unico modo di far cambiare sessione ad un processo è quello di crearne una nuova con l'uso di -\func{setsid}; il suo prototipo è: +\funcd{setsid}; il suo prototipo è: \begin{prototype}{unistd.h}{pid\_t setsid(void)} Crea una nuova sessione sul processo corrente impostandone \acr{sid} e \acr{pgid}. @@ -319,7 +319,7 @@ associato ai file standard (di input, output ed error) dei processi nella sessione, ma solo quelli che fanno parte del cosiddetto raggruppamento di \textit{foreground}, possono leggere e scrivere in certo istante. Per impostare il raggruppamento di \textit{foreground} di un terminale si usa la -funzione \func{tcsetpgrp}, il cui prototipo è: +funzione \funcd{tcsetpgrp}, il cui prototipo è: \begin{functions} \headdecl{unistd.h} \headdecl{termios.h} @@ -358,7 +358,7 @@ condizioni di errore.\footnote{la shell in genere notifica comunque un funzioni di lettura e scrittura falliranno con un errore di \errcode{EIO}. Un processo può controllare qual'è il gruppo di \textit{foreground} associato -ad un terminale con la funzione \func{tcgetpgrp}, il cui prototipo è: +ad un terminale con la funzione \funcd{tcgetpgrp}, il cui prototipo è: \begin{functions} \headdecl{unistd.h} \headdecl{termios.h} @@ -644,7 +644,7 @@ occorrer In Linux buona parte di queste azioni possono venire eseguite invocando la -funzione \func{daemon}, introdotta per la prima volta in BSD4.4; il suo +funzione \funcd{daemon}, introdotta per la prima volta in BSD4.4; il suo prototipo è: \begin{prototype}{unistd.h}{int daemon(int nochdir, int noclose)} Esegue le operazioni che distaccano il processo dal terminale di controllo e @@ -720,7 +720,7 @@ funzionano solo localmente; se si vogliono inviare i messaggi ad un'altro sistema occorre farlo esplicitamente con un socket\index{socket} UDP, o utilizzare le capacità di reinvio del servizio. -La prima funzione definita dall'interfaccia è \func{openlog}, che apre una +La prima funzione definita dall'interfaccia è \funcd{openlog}, che apre una connessione al servizio di \textit{syslog}; essa in generale non è necessaria per l'uso del servizio, ma permette di impostare alcuni valori che controllano gli effetti delle chiamate successive; il suo prototipo è: @@ -808,7 +808,7 @@ con un OR aritmetico di una qualunque delle costanti riportate in \label{tab:sess_openlog_option} \end{table} -La funzione che si usa per generare un messaggio è \func{syslog}, dato che +La funzione che si usa per generare un messaggio è \funcd{syslog}, dato che l'uso di \func{openlog} è opzionale, sarà quest'ultima a provvede a chiamare la prima qualora ciò non sia stato fatto (nel qual caso il valore di \param{ident} è nullo). Il suo prototipo è: @@ -866,7 +866,7 @@ con la maschera binaria delle costanti di \tabref{tab:sess_syslog_facility}. \label{tab:sess_syslog_priority} \end{table} -Una ulteriore funzione, \func{setlogmask}, permette di filtrare +Una ulteriore funzione, \funcd{setlogmask}, permette di filtrare preliminarmente i messaggi in base alla loro priorità; il suo prototipo è: \begin{prototype}{syslog.h}{int setlogmask(int mask)} @@ -1005,7 +1005,7 @@ Alcune di queste funzioni prendono come argomento un file descriptor (in origine molte operazioni venivano effettuate con \func{ioctl}), ma ovviamente possono essere usate solo con file che corrispondano effettivamente ad un terminale (altrimenti si otterrà un errore di \errcode{ENOTTY}); questo può -essere evitato utilizzando la funzione \func{isatty}, il cui prototipo è: +essere evitato utilizzando la funzione \funcd{isatty}, il cui prototipo è: \begin{prototype}{unistd.h}{int isatty(int desc)} Controlla se il file descriptor \param{desc} è un terminale. @@ -1014,7 +1014,7 @@ essere evitato utilizzando la funzione \func{isatty}, il cui prototipo terminale, 0 altrimenti.} \end{prototype} -Un'altra funzione che fornisce informazioni su un terminale è \func{ttyname}, +Un'altra funzione che fornisce informazioni su un terminale è \funcd{ttyname}, che permette di ottenere il nome del terminale associato ad un file descriptor; il suo prototipo è: \begin{prototype}{unistd.h}{char *ttyname(int desc)} @@ -1028,7 +1028,7 @@ descriptor; il suo prototipo Si tenga presente che la funzione restituisce un indirizzo di dati statici, che pertanto possono essere sovrascritti da successive chiamate. Una funzione -funzione analoga, anch'essa prevista da POSIX.1, è \func{ctermid}, il cui +funzione analoga, anch'essa prevista da POSIX.1, è \funcd{ctermid}, il cui prototipo è: \begin{prototype}{stdio.h}{char *ctermid(char *s)} @@ -1047,7 +1047,7 @@ precedenza ed essere lunga almeno indica la dimensione che deve avere una stringa per poter contenere il nome di un terminale.} caratteri. -Esiste infine una versione rientrante \func{ttyname\_r} della funzione +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 è: \begin{prototype}{unistd.h}{int ttyname\_r(int desc, char *buff, size\_t len)} @@ -1568,10 +1568,11 @@ esempio \const{VINTR}, \const{VSUSP}, e \const{VQUIT} richiedono sia settato settato \const{IEXTEN}. In ogni caso quando vengono attivati i caratteri vengono interpretati e non sono passati sulla coda di ingresso. -Per leggere ed scrivere tutte le impostazioni dei terminali lo standard POSIX -prevede due funzioni, \func{tcgetattr} e \func{tcsetattr}; entrambe utilizzano -come argomento un puntatore ad struttura \struct{termios} che sarà quella in -cui andranno immagazzinate le impostazioni, il loro prototipo è: +Per leggere ed scrivere tutte le varie impostazioni dei terminali viste finora +lo standard POSIX prevede due funzioni che utilizzano come argomento un +puntatore ad una struttura \struct{termios} che sarà quella in cui andranno +immagazzinate le impostazioni. Le funzioni sono \funcd{tcgetattr} e +\funcd{tcsetattr} ed il loro prototipo è: \begin{functions} \headdecl{unistd.h} \headdecl{termios.h} @@ -1741,8 +1742,8 @@ devono essere acceduti direttamente ma solo attraverso le apposite funzioni di interfaccia provviste da POSIX.1. Lo standard prevede due funzioni per scrivere la velocità delle linee seriali, -\func{cfsetispeed} per la velocità della linea di ingresso e -\func{cfsetospeed} per la velocità della linea di uscita; i loro prototipi +\funcd{cfsetispeed} per la velocità della linea di ingresso e +\funcd{cfsetospeed} per la velocità della linea di uscita; i loro prototipi sono: \begin{functions} \headdecl{unistd.h} @@ -1770,9 +1771,12 @@ altre versioni di librerie possono utilizzare dei valori diversi; per questo POSIX.1 prevede una serie di costanti che però servono solo per specificare le velocità tipiche delle linee seriali: \begin{verbatim} - B0 B50 B75 B110 B134 B150 - B200 B300 B600 B1200 B1800 B2400 - B4800 B9600 B19200 B38400 B57600 B115200 + B0 B50 B75 + B110 B134 B150 + B200 B300 B600 + B1200 B1800 B2400 + B4800 B9600 B19200 + B38400 B57600 B115200 B230400 B460800 \end{verbatim} @@ -1835,7 +1839,7 @@ illustrato in \secref{sec:sess_ctrl_term}.\footnote{con la stessa eccezione, processo chiamante.} Una prima funzione, che è efficace solo in caso di terminali seriali asincroni -(non fa niente per tutti gli altri terminali), è \func{tcsendbreak}; il suo +(non fa niente per tutti gli altri terminali), è \funcd{tcsendbreak}; il suo prototipo è: \begin{functions} \headdecl{unistd.h} @@ -1859,7 +1863,7 @@ compreso fra 0.25 e 0.5.\footnote{POSIX specifica il comportamento solo nel Le altre funzioni previste da POSIX servono a controllare il comportamento dell'interazione fra le code associate al terminale e l'utente; la prima è -\func{tcdrain}, il cui prototipo è: +\funcd{tcdrain}, il cui prototipo è: \begin{functions} \headdecl{unistd.h} \headdecl{termios.h} @@ -1878,7 +1882,7 @@ di uscita non % chiamate devono essere protette con dei % gestori di cancellazione. -Una seconda funzione, \func{tcflush}, permette svuotare immediatamente le code +Una seconda funzione, \funcd{tcflush}, permette svuotare immediatamente le code di cancellando tutti i dati presenti al loro interno; il suo prototipo è: \begin{functions} \headdecl{unistd.h} \headdecl{termios.h} @@ -1918,7 +1922,7 @@ di uscita canceller L'ultima funzione dell'interfaccia che interviene sulla disciplina di linea è -\func{tcflow}, che viene usata per sospendere la trasmissione e la ricezione +\funcd{tcflow}, che viene usata per sospendere la trasmissione e la ricezione dei dati sul terminale; il suo prototipo è: \begin{functions} \headdecl{unistd.h} diff --git a/signal.tex b/signal.tex index a5363ec..9b90669 100644 --- a/signal.tex +++ b/signal.tex @@ -711,13 +711,13 @@ classificabili in maniera omogenea. Questi segnali sono: \subsection{Le funzioni \func{strsignal} e \func{psignal}} \label{sec:sig_strsignal} -Per la descrizione dei segnali il sistema mette a disposizione due funzioni, -\func{strsignal} e \func{psignal}, che stampano un messaggio di descrizione -dato il numero. In genere si usano quando si vuole notificare all'utente il -segnale avvenuto (nel caso di terminazione di un processo figlio o di un -gestore che gestisce più segnali); la prima funzione è una estensione -GNU, accessibile avendo definito \macro{\_GNU\_SOURCE}, ed è analoga alla -funzione \func{strerror} (si veda \secref{sec:sys_strerror}) per gli errori: +Per la descrizione dei segnali il sistema mette a disposizione due funzioni +che stampano un messaggio di descrizione dato il numero. In genere si usano +quando si vuole notificare all'utente il segnale ricevuto (nel caso di +terminazione di un processo figlio o di un gestore che gestisce più segnali); +la prima funzione, \funcd{strsignal}, è una estensione GNU, accessibile avendo +definito \macro{\_GNU\_SOURCE}, ed è analoga alla funzione \func{strerror} (si +veda \secref{sec:sys_strerror}) per gli errori: \begin{prototype}{string.h}{char *strsignal(int signum)} Ritorna il puntatore ad una stringa che contiene la descrizione del segnale \param{signum}. @@ -727,8 +727,9 @@ modificare il contenuto, che resta valido solo fino alla successiva chiamata di \func{strsignal}. Nel caso si debba mantenere traccia del messaggio sarà necessario copiarlo. -La seconda funzione deriva da BSD ed è analoga alla funzione \func{perror} -descritta sempre in \secref{sec:sys_strerror}; il suo prototipo è: +La seconda funzione, \funcd{psignal}, deriva da BSD ed è analoga alla funzione +\func{perror} descritta sempre in \secref{sec:sys_strerror}; il suo prototipo +è: \begin{prototype}{signal.h}{void psignal(int sig, const char *s)} Stampa sullo standard error un messaggio costituito dalla stringa \param{s}, seguita da due punti ed una descrizione del segnale indicato da \param{sig}. @@ -807,7 +808,7 @@ attendere la conclusione della sistem call, perch impossibile una risposta pronta al segnale, per cui il gestore viene eseguito prima che la system call sia ritornata. Un elenco dei casi in cui si presenta questa situazione è il seguente: -\begin{itemize} +\begin{itemize*} \item la lettura da file che possono bloccarsi in attesa di dati non ancora presenti (come per certi file di dispositivo\index{file!di dispositivo}, i socket\index{socket} o le pipe). @@ -822,7 +823,7 @@ presenta questa situazione \item la funzione \func{pause} (usata appunto per attendere l'arrivo di un segnale). \item la funzione \func{wait} (se nessun processo figlio è ancora terminato). -\end{itemize} +\end{itemize*} In questo caso si pone il problema di cosa fare una volta che il gestore sia ritornato. La scelta originaria dei primi Unix era quella di far ritornare @@ -854,7 +855,7 @@ ritornano sempre indicando i byte trasferiti. \label{sec:sig_signal} L'interfaccia più semplice per la gestione dei segnali è costituita dalla -funzione \func{signal} che è definita fin dallo standard ANSI C. Quest'ultimo +funzione \funcd{signal} che è definita fin dallo standard ANSI C. Quest'ultimo però non considera sistemi multitasking, per cui la definizione è tanto vaga da essere del tutto inutile in un sistema Unix; è questo il motivo per cui ogni implementazione successiva ne ha modificato e ridefinito il @@ -874,20 +875,19 @@ comportamento, pur mantenendone immutato il prototipo\footnote{in realt \end{prototype} In questa definizione si è usato un tipo di dato, \type{sighandler\_t}, che è -una estensione GNU, definita dalle \acr{glibc}, esso permette di riscrivere il -prototipo di \func{signal} nella forma appena vista, che risulta molto più -leggibile di quanto non sia la versione originaria che di norma è definita -come: -\begin{verbatim} +una estensione GNU, definita dalle \acr{glibc}, che permette di riscrivere il +prototipo di \func{signal} nella forma appena vista, molto più leggibile di +quanto non sia la versione originaria, che di norma è definita come: +\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{} void (*signal(int signum, void (*handler)(int)))int) -\end{verbatim} +\end{lstlisting} questa infatti, per la poca chiarezza della sintassi del C quando si vanno a trattare puntatori a funzioni, è molto meno comprensibile. Da un confronto con il precedente prototipo si può dedurre la definizione di \type{sighandler\_t} che è: -\begin{verbatim} +\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{} typedef void (* sighandler_t)(int) -\end{verbatim} +\end{lstlisting} e cioè un puntatore ad una funzione \ctyp{void} (cioè senza valore di ritorno) e che prende un argomento di tipo \ctyp{int}.\footnote{si devono usare le parentesi intorno al nome della funzione per via delle precedenze degli @@ -904,7 +904,8 @@ all'occorrenza del segnale, pu \const{SIG\_IGN} con cui si dice ignorare il segnale e \const{SIG\_DFL} per reinstallare l'azione predefinita.\footnote{si ricordi però che i due segnali \const{SIGKILL} e \const{SIGSTOP} non possono essere ignorati né - intercettati.} + intercettati; l'uso di \const{SIG\_IGN} per questi segnali non ha alcun + effetto.} La funzione restituisce l'indirizzo dell'azione precedente, che può essere salvato per poterlo ripristinare (con un'altra chiamata a \func{signal}) in un @@ -938,9 +939,16 @@ un ciclo infinito. \label{sec:sig_kill_raise} Come accennato in \secref{sec:sig_types}, un segnale può essere generato -direttamente da un processo. L'invio di un segnale generico può essere -effettuato attraverso delle funzioni \func{kill} e \func{raise}. La prima -serve per inviare un segnale al processo corrente, ed il suo prototipo è: +direttamente da un processo attraverso una opportuna system call. Le funzioni +che si usano di solito per invare un segnale generico sono due, \func{raise} e +\func{kill}. + +La prima funzione è \funcd{raise}, che è definita dallo standard ANSI C, e +serve per inviare un segnale al processo corrente,\footnote{non prevedendo la + presenza di un sistema multiutente lo standard ANSI C non poteva che + definire una funzione che invia il segnale al programma in esecuzione. Nel + caso di Linux questa viene implementata come funzione di compatibilità.} il +suo prototipo è: \begin{prototype}{signal.h}{int raise(int sig)} Invia il segnale \param{sig} al processo corrente. @@ -954,10 +962,13 @@ essere specificato con una delle macro definite in \secref{sec:sig_classification}. In genere questa funzione viene usata per riprodurre il comportamento predefinito di un segnale che sia stato intercettato. In questo caso, una volta eseguite le operazioni volute, il -gestore potrà reinstallare l'azione predefinita, e attivarla con \func{raise}. +gestore dovrà prima reinstallare l'azione predefinita, per poi attivarla +chiamando \func{raise}. -Se invece si vuole inviare un segnale ad un altro processo occorre utilizzare -la funzione \func{kill}; il cui prototipo è: +Mentre \func{raise} è una funzione di libreria, quando si vuole inviare un +segnale generico ad un processo occorre utilizzare la apposita system call, +questa può essere chiamata attraverso la funzione \funcd{kill}, il cui +prototipo è: \begin{functions} \headdecl{sys/types.h} \headdecl{signal.h} @@ -975,12 +986,12 @@ la funzione \func{kill}; il cui prototipo \end{functions} Lo standard POSIX prevede che il valore 0 per \param{sig} sia usato per -specificare il segnale nullo. Se le funzioni vengono chiamate con questo -valore non viene inviato nessun segnale, ma viene eseguito il controllo degli -errori, in tal caso si otterrà un errore \errcode{EPERM} se non si hanno i -permessi necessari ed un errore \errcode{ESRCH} se il processo specificato non -esiste. Si tenga conto però che il sistema ricicla i \acr{pid} (come accennato -in \secref{sec:proc_pid}) per cui l'esistenza di un processo non significa che +specificare il segnale nullo. Se la funzione viene chiamata con questo valore +non viene inviato nessun segnale, ma viene eseguito il controllo degli errori, +in tal caso si otterrà un errore \errcode{EPERM} se non si hanno i permessi +necessari ed un errore \errcode{ESRCH} se il processo specificato non esiste. +Si tenga conto però che il sistema ricicla i \acr{pid} (come accennato in +\secref{sec:proc_pid}) per cui l'esistenza di un processo non significa che esso sia realmente quello a cui si intendeva mandare il segnale. Il valore dell'argomento \param{pid} specifica il processo (o i processi) di @@ -1014,7 +1025,7 @@ standard ISO C, non esiste in alcune vecchie versioni di Unix, in generale l'uso di \func{kill} finisce per essere più portabile. Una seconda funzione che può essere definita in termini di \func{kill} è -\func{killpg}, che è sostanzialmente equivalente a +\funcd{killpg}, che è sostanzialmente equivalente a \code{kill(-pidgrp, signal)}; il suo prototipo è: \begin{prototype}{signal.h}{int killpg(pid\_t pidgrp, int signal)} @@ -1049,7 +1060,7 @@ segnale al processo che ha effettuato la chiamata. Un caso particolare di segnali generati a richiesta è quello che riguarda i vari segnali di temporizzazione e \const{SIGABRT}, per ciascuno di questi segnali sono previste funzioni specifiche che ne effettuino l'invio. La più -comune delle funzioni usate per la temporizzazione è \func{alarm} il cui +comune delle funzioni usate per la temporizzazione è \funcd{alarm} il cui prototipo è: \begin{prototype}{unistd.h}{unsigned int alarm(unsigned int seconds)} Predispone l'invio di \const{SIGALRM} dopo \param{seconds} secondi. @@ -1098,7 +1109,7 @@ questo presenta numerosi limiti: non consente di usare gli altri timer, non può specificare intervalli di tempo con precisione maggiore del secondo e genera il segnale una sola volta. -Per ovviare a questi limiti Linux deriva da BSD la funzione \func{setitimer} +Per ovviare a questi limiti Linux deriva da BSD la funzione \funcd{setitimer} che permette di usare un timer qualunque e l'invio di segnali periodici, al costo però di una maggiore complessità d'uso e di una minore portabilità. Il suo prototipo è: @@ -1219,7 +1230,7 @@ in \secref{sec:sig_sigchld}, un solo segnale sar Dato che sia \func{alarm} che \func{setitimer} non consentono di leggere il valore corrente di un timer senza modificarlo, è possibile usare la funzione -\func{getitimer}, il cui prototipo è: +\funcd{getitimer}, il cui prototipo è: \begin{prototype}{sys/time.h}{int getitimer(int which, struct itimerval *value)} @@ -1232,8 +1243,8 @@ valore corrente di un timer senza modificarlo, \func{setitimer}. -L'ultima funzione che permette l'invio diretto di un segnale è \func{abort}; -che, come accennato in \ref{sec:proc_termination}, permette di abortire +L'ultima funzione che permette l'invio diretto di un segnale è \funcd{abort}; +che, come accennato in \secref{sec:proc_termination}, permette di abortire l'esecuzione di un programma tramite l'invio di \const{SIGABRT}. Il suo prototipo è: \begin{prototype}{stdlib.h}{void abort(void)} @@ -1258,13 +1269,20 @@ saranno chiusi ed i buffer scaricati su disco. Non verranno invece eseguite le eventuali funzioni registrate con \func{at\_exit} e \func{on\_exit}. -\subsection{Le funzioni \func{pause} e \func{sleep}} +\subsection{Le funzioni di pausa e attesa} \label{sec:sig_pause_sleep} -Il metodo tradizionale per fare attendere\footnote{cioè di porre - temporaneamente il processo in stato di \textit{sleep}, vedi - \ref{sec:proc_sched}.} ad un processo fino all'arrivo di un segnale è -quello di usare la funzione \func{pause}, il cui prototipo è: +Sono parecchie le occasioni in cui si può avere necessità di sospendere +temporaneamente l'esecuzione di un processo. Nei sistemi più elementari in +genere questo veniva fatto con un opportuno loop di attesa, ma in un sistema +multitasking un loop di attesa è solo un inutile spreco di CPU, per questo ci +sono apposite funzioni che permettono di mettere un processo in stato di +attesa.\footnote{si tratta in sostanza di funzioni che permettono di portare + esplicitamente il processo in stato di \textit{sleep}, vedi + \secref{sec:proc_sched}.} + +Il metodo tradizionale per fare attendere ad un processo fino all'arrivo di un +segnale è quello di usare la funzione \funcd{pause}, il cui prototipo è: \begin{prototype}{unistd.h}{int pause(void)} Pone il processo in stato di sleep fino al ritorno di un gestore. @@ -1277,12 +1295,13 @@ quello di usare la funzione \func{pause}, il cui prototipo La funzione segnala sempre una condizione di errore (il successo sarebbe quello di aspettare indefinitamente). In genere si usa questa funzione quando si vuole mettere un processo in attesa di un qualche evento specifico che non -è sotto il suo diretto controllo (ad esempio la si può usare per far reagire -il processo ad un segnale inviato da un altro processo). +è sotto il suo diretto controllo (ad esempio la si può usare per interrompere +l'esecuzione del processo fino all'arrivo di un segnale inviato da un altro +processo). -Se invece si vuole fare attendere un processo per un determinato intervallo di -tempo nello standard POSIX.1 viene definita la funzione \func{sleep}, il cui -prototipo è: +Quando invece si vuole fare attendere un processo per un intervallo di tempo +già noto nello standard POSIX.1 viene definita la funzione \funcd{sleep}, il +cui prototipo è: \begin{prototype}{unistd.h}{unsigned int sleep(unsigned int seconds)} Pone il processo in stato di sleep per \param{seconds} secondi. @@ -1309,9 +1328,9 @@ vedremo in \secref{sec:sig_example}). In tal caso mescolare chiamata di causare risultati indefiniti. Nel caso delle \acr{glibc} è stata usata una implementazione completamente indipendente e questi problemi non ci sono. -La granularità di \func{sleep} permette di specificare attese in secondi, per -questo sia sotto BSD4.3 che in SUSv2 è stata definita la funzione -\func{usleep} (dove la \texttt{u} è intesa come sostituzione di $\mu$); i due +La granularità di \func{sleep} permette di specificare attese soltanto in +secondi, per questo sia sotto BSD4.3 che in SUSv2 è stata definita la funzione +\funcd{usleep} (dove la \texttt{u} è intesa come sostituzione di $\mu$); i due standard hanno delle definizioni diverse, ma le \acr{glibc} seguono\footnote{secondo la pagina di manuale almeno dalla versione 2.2.2.} seguono quella di SUSv2 che prevede il seguente prototipo: @@ -1327,7 +1346,7 @@ seguono quella di SUSv2 che prevede il seguente prototipo: Anche questa funzione, a seconda delle implementazioni, può presentare problemi nell'interazione con \func{alarm} e \const{SIGALRM}. È pertanto -deprecata in favore della funzione \func{nanosleep}, definita dallo standard +deprecata in favore della funzione \funcd{nanosleep}, definita dallo standard POSIX1.b, il cui prototipo è: \begin{prototype}{unistd.h}{int nanosleep(const struct timespec *req, struct timespec *rem)} @@ -1694,8 +1713,9 @@ della macchina\footnote{nel caso dei PC questo comporta un massimo di 32 associato ad uno specifico segnale; in questo modo è di solito possibile implementare le operazioni direttamente con istruzioni elementari del processore; lo standard POSIX.1 definisce cinque funzioni per la manipolazione -degli insiemi di segnali: \func{sigemptyset}, \func{sigfillset}, -\func{sigaddset}, \func{sigdelset} e \func{sigismember}, i cui prototipi sono: +degli insiemi di segnali: \funcd{sigemptyset}, \funcd{sigfillset}, +\funcd{sigaddset}, \funcd{sigdelset} e \funcd{sigismember}, i cui prototipi +sono: \begin{functions} \headdecl{signal.h} @@ -1740,8 +1760,13 @@ insieme. \subsection{La funzione \func{sigaction}} \label{sec:sig_sigaction} -La funzione principale dell'interfaccia standard POSIX.1 per i segnali è -\func{sigaction}, essa ha sostanzialemente lo stesso uso di \func{signal}, +Abbiamo già accennato in \secref{sec:sig_signal} i problemi di compatibilità +relativi all'uso di \func{signal}. Per ovviare a tutto questo lo standard +POSIX.1 ha ridefinito completamente l'interfaccia per la gestione dei segnali, +rendendola molto più flessibile e robusta, anche se leggermente più complessa. + +La funzione principale dell'interfaccia POSIX.1 per i segnali è +\funcd{sigaction}. Essa ha sostanzialemente lo stesso uso di \func{signal}, permette cioè di specificare le modalità con cui un segnale può essere gestito da un processo. Il suo prototipo è: \begin{prototype}{signal.h}{int sigaction(int signum, const struct sigaction @@ -2025,7 +2050,7 @@ che essi siano eseguiti senza interruzioni. Le operazioni più semplici, come l'assegnazione o il controllo di una variabile (per essere sicuri si può usare il tipo \type{sig\_atomic\_t}) di norma sono atomiche, quando occorrono operazioni più complesse si può invece -usare la funzione \func{sigprocmask} che permette di bloccare uno o più +usare la funzione \funcd{sigprocmask} che permette di bloccare uno o più segnali; il suo prototipo è: \begin{prototype}{signal.h} {int sigprocmask(int how, const sigset\_t *set, sigset\_t *oldset)} @@ -2089,7 +2114,7 @@ uscire dallo stato di attesa invocato con \func{pause} immediatamente prima dell'esecuzione di quest'ultima. Per poter effettuare atomicamente la modifica della maschera dei segnali (di solito attivandone uno specifico) insieme alla sospensione del processo lo standard POSIX ha previsto la funzione -\func{sigsuspend}, il cui prototipo è: +\funcd{sigsuspend}, il cui prototipo è: \begin{prototype}{signal.h} {int sigsuspend(const sigset\_t *mask)} @@ -2174,13 +2199,13 @@ dato che \const{SIGALRM} viene disabilitato con \func{sigprocmask} fino alla chiamata di \func{sigsuspend}. Questo metodo è assolutamente generale e può essere applicato a qualunque altra situazione in cui si deve attendere per un segnale, i passi sono sempre i seguenti: -\begin{enumerate*} +\begin{enumerate} \item Leggere la maschera dei segnali corrente e bloccare il segnale voluto con \func{sigprocmask}. \item Mandare il processo in attesa con \func{sigsuspend} abilitando la ricezione del segnale voluto. \item Ripristinare la maschera dei segnali originaria. -\end{enumerate*} +\end{enumerate} Per quanto possa sembrare strano bloccare la ricezione di un segnale per poi riabilitarla immediatamente dopo, in questo modo si evita il deadlock\index{deadlock} dovuto all'arrivo del segnale prima dell'esecuzione @@ -2190,10 +2215,12 @@ di \func{sigsuspend}. \subsection{Ulteriori funzioni di gestione} \label{sec:sig_specific_features} -In questa ultimo paragrafo esamineremo varie funzioni di gestione dei segnali -non descritte finora, relative agli aspetti meno utilizzati. La prima di esse -è \func{sigpending}, anch'essa introdotta dallo standard POSIX.1; il suo -prototipo è: +In questo ultimo paragrafo esamineremo le rimanenti funzioni di gestione dei +segnali non descritte finora, relative agli aspetti meno utilizzati e più +``\textsl{esoterici}'' della interfaccia. + +La prima di queste funzioni è \funcd{sigpending}, anch'essa introdotta dallo +standard POSIX.1; il suo prototipo è: \begin{prototype}{signal.h} {int sigpending(sigset\_t *set)} @@ -2240,7 +2267,7 @@ conosce esattamente quanto aggiungere questo valore per allocare uno stack di dimensione sufficiente. Come accennato per poter essere usato lo stack per i segnali deve essere -indicato al sistema attraverso la funzione \func{sigaltstack}; il suo +indicato al sistema attraverso la funzione \funcd{sigaltstack}; il suo prototipo è: \begin{prototype}{signal.h} {int sigaltstack(const stack\_t *ss, stack\_t *oss)} @@ -2450,7 +2477,7 @@ union sigval { A causa di queste loro caratteristiche, la funzione \func{kill} non è adatta ad inviare un segnale real time, in quanto non è in grado di fornire alcun valore per \struct{sigval}; per questo motivo lo standard ha previsto una -nuova funzione, \func{sigqueue}, il cui prototipo è: +nuova funzione, \funcd{sigqueue}, il cui prototipo è: \begin{prototype}{signal.h} {int sigqueue(pid\_t pid, int signo, const union sigval value)} @@ -2493,7 +2520,7 @@ 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 è -\func{sigwait}, il cui prototipo è: +\funcd{sigwait}, il cui prototipo è: \begin{prototype}{signal.h} {int sigwait(const sigset\_t *set, int *sig)} @@ -2527,7 +2554,7 @@ consegnato che essere ricevuto da \func{sigwait}, il tutto in maniera non prevedibile. Lo standard POSIX.1b definisce altre due funzioni, anch'esse usate -prevalentemente con i thread; \func{sigwaitinfo} e \func{sigtimedwait}, i +prevalentemente con i thread; \funcd{sigwaitinfo} e \funcd{sigtimedwait}, i relativi prototipi sono: \begin{functions} \headdecl{signal.h} diff --git a/simpltcp.tex b/simpltcp.tex index d723e30..93a66e1 100644 --- a/simpltcp.tex +++ b/simpltcp.tex @@ -408,7 +408,7 @@ Tutto questo riguarda la connessione, c' del procedimento di chiusura del processo figlio nel server (si veda quanto esaminato in \secref{sec:proc_termination}). In questo caso avremo l'invio del segnale \const{SIGCHLD} al padre, ma dato che non si è installato un -manipolatore e che l'azione predefinita per questo segnale è quella di essere +gestore e che l'azione predefinita per questo segnale è quella di essere ignorato, non avendo predisposto la ricezione dello stato di terminazione, otterremo che il processo figlio entrerà nello stato di zombie\index{zombie} (si riveda quanto illustrato in \secref{sec:sig_sigchld}), come risulterà @@ -425,9 +425,9 @@ del processo (si veda \secref{sec:proc_wait}), cosa che faremo utilizzando \const{SIGCHLD} secondo quanto illustrato in \secref{sec:sig_sigchld}. La prima modifica al nostro server è pertanto quella di inserire la gestione -della terminazione dei processi figli attraverso l'uso di un manipolatore. +della terminazione dei processi figli attraverso l'uso di un gestore. Per questo useremo la funzione \code{Signal}, illustrata in -\figref{fig:sig_Signal_code}, per installare il semplice manipolatore che +\figref{fig:sig_Signal_code}, per installare il semplice gestore che riceve i segnali dei processi figli terminati già visto in \figref{fig:sig_sigchld_handl}; aggiungendo il seguente codice: \begin{lstlisting}{} diff --git a/socket.tex b/socket.tex index e024bd7..43c4905 100644 --- a/socket.tex +++ b/socket.tex @@ -110,7 +110,7 @@ il tipo di comunicazione che esso deve utilizzare. \label{sec:sock_socket} La creazione di un socket avviene attraverso l'uso della funzione -\func{socket}; questa restituisce un \textit{file descriptor}\footnote{del +\funcd{socket}; questa restituisce un \textit{file descriptor}\footnote{del tutto analogo a quelli che si ottengono per i file di dati e le pipe, descritti in \secref{sec:file_fd}.} che serve come riferimento al socket; il suo protototipo è: @@ -606,10 +606,11 @@ con i due byte in cui invertito l'ordine di lettura per cui, per riavere il valore originale dovranno essere rovesciati. -Per questo motivo si usano le seguenti funzioni di conversione che servono a -tener conto automaticamente della possibile differenza fra l'ordinamento usato -sul computer e quello che viene usato nelle trasmissione sulla rete; queste -funzioni sono: +Per questo motivo si usano delle funzioni di conversione che servono a tener +conto automaticamente della possibile differenza fra l'ordinamento usato sul +computer e quello che viene usato nelle trasmissione sulla rete; queste +funzioni sono \funcd{htonl}, \funcd{htons}, \funcd{ntonl} e \funcd{ntons} ed i +rispettivi prototipi sono: \begin{functions} \headdecl{netinet/in.h} \funcdecl{unsigned long int htonl(unsigned long int hostlong)} @@ -659,7 +660,8 @@ indirizzi IPv4 da una stringa in cui il numero di IP cosiddetta notazione \textit{dotted-decimal}, (cioè nella forma \texttt{192.160.0.1}) al formato binario (direttamente in \textit{network order}) e viceversa; in questo caso si usa la lettera \texttt{a} come -mnemonico per indicare la stringa. Dette funzioni sono: +mnemonico per indicare la stringa. Dette funzioni sono \funcd{inet\_addr}, +\funcd{inet\_aton} e \funcd{inet\_ntoa}, ed i rispettivi prototipi sono: \begin{functions} \headdecl{arpa/inet.h} @@ -720,8 +722,9 @@ e \textit{numeric}. % \end{figure} Entrambe le funzioni accettano l'argomento \param{af} che indica il tipo di -indirizzo e può essere soltanto \const{AF\_INET} o \const{AF\_INET6}. I -prototipi delle suddette funzioni sono i seguenti: +indirizzo e può essere soltanto \const{AF\_INET} o \const{AF\_INET6}. La prima +funzione è \funcd{inet\_pton}, che serve a convertire una stringa in un +indirizzo, il suo prototipo è: \begin{prototype}{sys/socket.h} {int inet\_pton(int af, const char *src, void *addr\_ptr)} @@ -740,7 +743,8 @@ un valore positivo in caso di successo, e zero se la stringa non rappresenta un indirizzo valido, e negativo se \param{af} specifica una famiglia di indirizzi non valida. - +La sedonda funzione è \funcd{inet\_ntop} che converte un indirizzo in una +stringa; il suo prototipo è: \begin{prototype}{sys/socket.h} {char *inet\_ntop(int af, const void *addr\_ptr, char *dest, size\_t len)} Converte l'indirizzo dalla relativa struttura in una stringa simbolica. diff --git a/system.tex b/system.tex index 69d6036..03d1bed 100644 --- a/system.tex +++ b/system.tex @@ -8,7 +8,7 @@ %% license is included in the section entitled "GNU Free Documentation %% License". %% -\chapter{La gestione del sistema, delle risorse, e degli errori} +\chapter{La gestione del sistema, del tempo e degli errori} \label{cha:system} In questo capitolo tratteremo varie interfacce che attengono agli aspetti più @@ -292,7 +292,7 @@ Come accennato in \secref{sec:sys_limits} quando uno dei limiti o delle caratteristiche del sistema può variare, per non dover essere costretti a ricompilare un programma tutte le volte che si cambiano le opzioni con cui è compilato il kernel, o alcuni dei parametri modificabili a run time, è -necessario ottenerne il valore attraverso la funzione \func{sysconf}. Il +necessario ottenerne il valore attraverso la funzione \funcd{sysconf}. Il prototipo di questa funzione è: \begin{prototype}{unistd.h}{long sysconf(int name)} Restituisce il valore del parametro di sistema \param{name}. @@ -464,7 +464,7 @@ In generale i limiti per i file sono molto pi rispetto ai limiti generali del sistema; ad esempio parametri come la lunghezza del nome del file o il numero di link possono variare da filesystem a filesystem; per questo motivo questi limiti devono essere sempre controllati -con la funzione \func{pathconf}, il cui prototipo è: +con la funzione \funcd{pathconf}, il cui prototipo è: \begin{prototype}{unistd.h}{long pathconf(char *path, int name)} Restituisce il valore del parametro \param{name} per il file \param{path}. @@ -476,7 +476,7 @@ con la funzione \func{pathconf}, il cui prototipo E si noti come la funzione in questo caso richieda un parametro che specifichi a quale file si fa riferimento, dato che il valore del limite cercato può variare a seconda del filesystem. Una seconda versione della funzione, -\func{fpathconf}, opera su un file descriptor invece che su un pathname. Il +\funcd{fpathconf}, opera su un file descriptor invece che su un pathname. Il suo prototipo è: \begin{prototype}{unistd.h}{long fpathconf(int fd, int name)} Restituisce il valore del parametro \param{name} per il file \param{fd}. @@ -492,8 +492,8 @@ suo prototipo \label{sec:sys_uname} Un'altra funzione che si può utilizzare per raccogliere informazioni sia -riguardo al sistema che al computer su cui esso sta girando è \func{uname}; il -suo prototipo è: +riguardo al sistema che al computer su cui esso sta girando è \funcd{uname}; +il suo prototipo è: \begin{prototype}{sys/utsname.h}{int uname(struct utsname *info)} Restituisce informazioni sul sistema nella struttura \param{info}. @@ -575,7 +575,7 @@ sistema, come quelle per la gestione dei filesystem e di utenti e gruppi. \label{sec:sys_sysctl} La funzione che permette la lettura ed l'impostazione dei parametri del -sistema è \func{sysctl}; è una funzione derivata da BSD4.4, ma +sistema è \funcd{sysctl}; è una funzione derivata da BSD4.4, ma l'implementazione è specifica di Linux; il suo prototipo è: \begin{functions} \headdecl{unistd.h} @@ -639,14 +639,14 @@ sistema) e in genere i loro nomi possono variare da una versione di kernel all'altra; per questo è sempre il caso di evitare l'uso di \func{sysctl} quando esistono modalità alternative per ottenere le stesse informazioni. Alcuni esempi di parametri ottenibili sono: -\begin{itemize*} +\begin{itemize} \item il nome di dominio \item i parametri del meccanismo di \textit{paging}. \item il filesystem montato come radice \item la data di compilazione del kernel \item i parametri dello stack TCP \item il numero massimo di file aperti -\end{itemize*} +\end{itemize} Come accennato in Linux si ha una modalità alternativa per accedere alle stesse informazioni di \func{sysctl} attraverso l'uso del filesystem @@ -685,8 +685,8 @@ Come accennato in \secref{sec:file_organization} per poter accedere ai file occorre prima rendere disponibile al sistema il filesystem su cui essi sono memorizzati; l'operazione di attivazione del filesystem è chiamata \textsl{montaggio}, per far questo in Linux\footnote{la funzione è specifica - di Linux e non è portabile.} si usa la funzione \func{mount} il cui prototipo -è: + di Linux e non è portabile.} si usa la funzione \funcd{mount} il cui +prototipo è: \begin{prototype}{sys/mount.h} {mount(const char *source, const char *target, const char *filesystemtype, unsigned long mountflags, const void *data)} @@ -813,7 +813,7 @@ specificate dagli altri bit), anche in questo caso il valore di \param{source} viene ignorato. Una volta che non si voglia più utilizzare un certo filesystem è possibile -\textsl{smontarlo} usando la funzione \func{umount}, il cui prototipo è: +\textsl{smontarlo} usando la funzione \funcd{umount}, il cui prototipo è: \begin{prototype}{sys/mount.h}{umount(const char *target)} Smonta il filesystem montato sulla directory \param{target}. @@ -843,7 +843,7 @@ filesystem, se questo contiene la directory di lavoro corrente di un qualunque processo o il mount point di un altro filesystem; in questo caso l'errore restituito è \errcode{EBUSY}. -Linux provvede inoltre una seconda funzione, \func{umount2}, che in alcuni +Linux provvede inoltre una seconda funzione, \funcd{umount2}, che in alcuni casi permette di forzare lo smontaggio di un filesystem, anche quando questo risulti occupato; il suo prototipo è: \begin{prototype}{sys/mount.h}{umount2(const char *target, int flags)} @@ -863,7 +863,7 @@ viene eseguita una sincronizzazione dei dati. Altre due funzioni specifiche di Linux,\footnote{esse si trovano anche su BSD, ma con una struttura diversa.} utili per ottenere in maniera diretta informazioni riguardo al filesystem su cui si trova un certo file, sono -\func{statfs} e \func{fstatfs}, i cui prototipi sono: +\funcd{statfs} e \funcd{fstatfs}, i cui prototipi sono: \begin{functions} \headdecl{sys/vfs.h} \funcdecl{int statfs(const char *path, struct statfs *buf)} @@ -956,7 +956,7 @@ citati, il cui formato \cmd{man 5 passwd} e \cmd{man 5 group}). Per leggere le informazioni relative ad un utente si possono usare due -funzioni, \func{getpwuid} e \func{getpwnam}, i cui prototipi sono: +funzioni, \funcd{getpwuid} e \funcd{getpwnam}, i cui prototipi sono: \begin{functions} \headdecl{pwd.h} \headdecl{sys/types.h} @@ -967,7 +967,7 @@ funzioni, \func{getpwuid} e \func{getpwnam}, i cui prototipi sono: Restituiscono le informazioni relative all'utente specificato. \bodydesc{Le funzioni ritornano il puntatore alla struttura contenente le - informazioni in caso di successo e \val{null} nel caso non sia stato + informazioni in caso di successo e \val{NULL} nel caso non sia stato trovato nessun utente corrispondente a quanto specificato.} \end{functions} @@ -1031,13 +1031,13 @@ della struttura \struct{passwd} saranno restituiti all'indirizzo un massimo di \param{buflen} byte, sarà utilizzata per contenere le stringhe puntate dai campi di \param{password}. Infine all'indirizzo puntato da \param{result} viene restituito il puntatore ai dati ottenuti, cioè -\param{buffer} nel caso l'utente esista, o \val{null} altrimenti. Qualora i +\param{buffer} nel caso l'utente esista, o \val{NULL} altrimenti. Qualora i dati non possano essere contenuti nei byte specificati da \param{buflen}, la funzione fallirà restituendo \errcode{ERANGE} (e \param{result} sarà comunque -impostato a \val{null}). +impostato a \val{NULL}). -Del tutto analoghe alle precedenti sono le funzioni \func{getgrnam} e -\func{getgrgid} (e le relative analoghe rientranti con la stessa estensione +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: \begin{functions} @@ -1175,7 +1175,7 @@ libreria. Queste sono analoghe alle precedenti (vedi solo che in questo caso la struttura del database di accounting è molto più complessa, dato che contiene diversi tipi di informazione. -Le prime tre funzioni, \func{setutent}, \func{endutent} e \func{utmpname} +Le prime tre funzioni, \funcd{setutent}, \funcd{endutent} e \funcd{utmpname} servono rispettivamente a aprire e a chiudere il file che contiene il database, e a specificare su quale file esso viene mantenuto. I loro prototipi sono: @@ -1207,8 +1207,8 @@ corrispondenti ai file \file{/var/run/utmp} e \file{/var/log/wtmp} visti in precedenza. Una volta aperto il file si può eseguire una scansione leggendo o scrivendo -una voce con le funzioni \func{getutent}, \func{getutid}, \func{getutline} e -\func{pututline}, i cui prototipi sono: +una voce con le funzioni \funcd{getutent}, \funcd{getutid}, \funcd{getutline} +e \funcd{pututline}, i cui prototipi sono: \begin{functions} \headdecl{utmp.h} @@ -1332,7 +1332,7 @@ il risultato all'indirizzo specificato dal primo argomento aggiuntivo (di tipo **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, \func{updwtmp} e \func{logwtmp}, i cui +in \file{wmtp} altre due funzioni, \funcd{updwtmp} e \funcd{logwtmp}, i cui prototipi sono: \begin{functions} \headdecl{utmp.h} @@ -1404,12 +1404,12 @@ struct rusage { \label{fig:sys_rusage_struct} \end{figure} -La struttura è ripresa da BSD 4.3, ma attualmente (con i kernel della serie -2.4.x) i soli campi che sono mantenuti sono: \var{ru\_utime}, \var{ru\_stime}, -\var{ru\_minflt}, \var{ru\_majflt}, e \var{ru\_nswap}. I primi due indicano -rispettivamente il tempo impiegato dal processo nell'eseguire le istruzioni in -user space, e quello impiegato dal kernel nelle system call eseguite per conto -del processo. +La definizione della struttura in \figref{fig:sys_rusage_struct} è ripresa da +BSD 4.3, ma attualmente (con i kernel della serie 2.4.x) i soli campi che sono +mantenuti sono: \var{ru\_utime}, \var{ru\_stime}, \var{ru\_minflt}, +\var{ru\_majflt}, e \var{ru\_nswap}. I primi due indicano rispettivamente il +tempo impiegato dal processo nell'eseguire le istruzioni in user space, e +quello impiegato dal kernel nelle system call eseguite per conto del processo. Gli altri tre campi servono a quantificare l'uso della memoria virtuale\index{memoria virtuale} e corrispondono rispettivamente al numero di @@ -1419,16 +1419,17 @@ quelli che invece han richiesto I/O (detti invece \textit{major page fault}) ed al numero di volte che il processo è stato completamente tolto dalla memoria per essere inserito nello swap. -In genere includere esplicitamente \file{} non è più necessario, -ma aumenta la portabilità, e serve comunque quando, come nella maggior parte -dei casi, si debba accedere ai campi di \struct{rusage} relativi ai tempi di -utilizzo del processore, che sono definiti come strutture \struct{timeval}. +In genere includere esplicitamente \file{} non è più strettamente +necessario, ma aumenta la portabilità, e serve comunque quando, come nella +maggior parte dei casi, si debba accedere ai campi di \struct{rusage} relativi +ai tempi di utilizzo del processore, che sono definiti come strutture +\struct{timeval}. - -Questa è la stessa struttura utilizzata da \func{wait4} per ricavare la -quantità di risorse impiegato dal processo di cui si è letto lo stato di -terminazione, ma essa può anche essere letta direttamente utilizzando la -funzione \func{getrusage}, il cui prototipo è: +Questa è la stessa struttura utilizzata da \func{wait4} (si ricordi quando +visto in \secref{sec:proc_wait4}) per ricavare la quantità di risorse +impiegate dal processo di cui si è letto lo stato di terminazione, ma essa può +anche essere letta direttamente utilizzando la funzione \funcd{getrusage}, il +cui prototipo è: \begin{functions} \headdecl{sys/time.h} \headdecl{sys/resource.h} @@ -1486,9 +1487,9 @@ struct rlimit { \end{figure} In genere il superamento di un limite comporta o l'emissione di un segnale o -il fallimento della system call che lo ha provocato; per far leggere o -impostare i limiti di utilizzo delle risorse da parte di un processo le -\acr{glibc} prevedono due funzioni, \func{getrlimit} e \func{setrlimit}, i cui +il fallimento della system call che lo ha provocato; per permettere di leggere +e di impostare i limiti di utilizzo delle risorse da parte di un processo +Linux prevede due funzioni, \funcd{getrlimit} e \funcd{setrlimit}, i cui prototipi sono: \begin{functions} \headdecl{sys/time.h} @@ -1513,10 +1514,12 @@ prototipi sono: ed \errval{EFAULT}.} \end{functions} -Entrambe le funzioni permettono di specificare su quale risorsa si vuole -operare attraverso \param{resource}, i cui possibili valori sono elencati in -\secref{tab:sys_rlimit_values}, e utilizzano una struttura \struct{rlimit} per -specificarne i valori. +Entrambe le funzioni permettono di specificare, attraverso l'argomento +\param{resource}, su quale risorsa si vuole operare: i possibili valori di +questo argomento sono elencati in \secref{tab:sys_rlimit_values}. L'acceso +(rispettivamente in lettura e scrittura) ai valori effettivi dei limiti viene +poi effettuato attraverso la struttura \struct{rlimit} puntata da +\param{rlim}. \begin{table}[htb] \footnotesize @@ -1557,7 +1560,9 @@ specificarne i valori. aprire. L'apertura di un ulteriore file fallirà con un errore \errcode{EMFILE}.\\ \const{RLIMIT\_MEMLOCK}& L'ammontare massimo di memoria che può essere - bloccata (vedi \secref{sec:proc_mem_lock}).\\ + bloccata in RAM senza + paginazione\index{paginazione} (vedi + \secref{sec:proc_mem_lock}).\\ \const{RLIMIT\_AS} & La dimensione massima di tutta la memoria che il processo può ottenere. Se il processo tenta di allocarne di più funzioni come \func{brk}, @@ -1570,14 +1575,17 @@ specificarne i valori. \end{table} \footnotetext{Impostare questo limite a zero è la maniera più semplice per - evitare la creazione di \file{core} file.} + evitare la creazione di \file{core} file (al proposito si veda + \secref{sec:sig_prog_error}).} -È inoltre definita la costante \const{RLIM\_INFINITY} che permette di -sbloccare l'uso di una risorsa, ma solo un processo con i privilegi di -amministratore può innalzare un limite al di sopra del valore corrente del -limite massimo. Si tenga conto infine che tutti i limiti vengono ereditati dal -processo padre attraverso una \func{fork} (vedi \secref{sec:proc_fork}) e -mantenuti attraverso una \func{exec} (vedi \secref{sec:proc_exec}). +Nello specificare un limite, oltre a dei valori specifici, si può anche usare +la costante \const{RLIM\_INFINITY} che permette di sbloccare l'uso di una +risorsa; ma si ricordi che solo un processo con i privilegi di amministratore +può innalzare un limite al di sopra del valore corrente del limite massimo. Si +tenga conto infine che tutti i limiti vengono ereditati dal processo padre +attraverso una \func{fork} (vedi \secref{sec:proc_fork}) e mantenuti per gli +altri programmi eseguiti attraverso una \func{exec} (vedi +\secref{sec:proc_exec}). \subsection{Le risorse di memoria e processore} @@ -1588,23 +1596,24 @@ La gestione della memoria meccanismo della memoria virtuale\index{memoria virtuale} attraverso la divisione della memoria fisica in pagine. -In genere questo è del tutto trasparente al singolo processo, ma in certi +In genere tutto ciò è del tutto trasparente al singolo processo, ma in certi casi, come per l'I/O mappato in memoria (vedi \secref{sec:file_memory_map}) che usa lo stesso meccanismo per accedere ai file, è necessario conoscere le dimensioni delle pagine usate dal kernel. Lo stesso vale quando si vuole -gestire in maniera ottimale l'interazione della memoria allocata con il -meccanismo della paginazione. +gestire in maniera ottimale l'interazione della memoria che si sta allocando +con il meccanismo della paginazione\index{paginazione}. Di solito la dimensione delle pagine di memoria è fissata dall'architettura -hardware, per cui in genere la dimensione delle pagine di memoria era una -costante definita in fase di compilazione, ma oggi alcune architetture (ad -esempio su Sun Sparc) permettono di variare questa dimensione, e non volendo -dover fornire binari diversi per ogni possibile modello, è necessario poter -utilizzare una funzione. - -In genere questa dimensione può essere ottenuta attraverso una chiamata a -\func{sysconf} come \code{sysconf(\_SC\_PAGESIZE)}, ma in BSD 4.2 è stata -introdotta una apposita funzione, \func{getpagesize}, che restituisce la +hardware, per cui il suo valore di norma veniva mantenuto in una costante che +bastava utilizzare in fase di compilazione, ma oggi, con la presenza di alcune +architetture (ad esempio Sun Sparc) che permettono di variare questa +dimensione, per non dover ricompilare i programmi per ogni possibile modello e +scelta di dimensioni, è necessario poter utilizzare una funzione. + +Dato che si tratta di una caratteristica generale del sistema, questa +dimensione può essere ottenuta come tutte le altre attraverso una chiamata a +\func{sysconf} (nel caso \code{sysconf(\_SC\_PAGESIZE)}, ma in BSD 4.2 è stata +introdotta una apposita funzione, \funcd{getpagesize}, che restituisce la dimensione delle pagine di memoria; il suo prototipo è: \begin{prototype}{unistd.h}{int getpagesize(void)} Legge le dimensioni delle pagine di memoria. @@ -1622,8 +1631,8 @@ precedenti le \acr{glibc} 2.1 implementavano questa funzione restituendo sempre un valore statico. Le \acr{glibc} forniscono, come specifica estensione GNU, altre due funzioni, -\func{get\_phys\_pages} e \func{get\_avphys\_pages} che permettono di ottenere -informazioni riguardo la memoria; i loro prototipi sono: +\funcd{get\_phys\_pages} e \funcd{get\_avphys\_pages} che permettono di +ottenere informazioni riguardo la memoria; i loro prototipi sono: \begin{functions} \headdecl{sys/sysinfo.h} @@ -1650,7 +1659,7 @@ attivi); anche queste sono informazioni comunque ottenibili attraverso \func{sysconf} utilizzando rispettivamente i parametri \const{\_SC\_NPROCESSORS\_CONF} e \const{\_SC\_NPROCESSORS\_ONLN}. -Infine le \acr{glibc} riprendono da BSD la funzione \func{getloadavg} che +Infine le \acr{glibc} riprendono da BSD la funzione \funcd{getloadavg} che permette di ottenere il carico di processore della macchina, in questo modo è possibile prendere decisioni su quando far partire eventuali nuovi processi. Il suo prototipo è: @@ -1729,7 +1738,7 @@ una precisione ovviamente superiore al \textit{calendar time} (che dal sistema con una granularità di un secondo) e viene usato per tenere conto dei tempi di esecuzione dei processi. Per ciascun processo il kernel calcola tre tempi diversi: -\begin{description*} +\begin{description} \item[\textit{clock time}]: il tempo \textsl{reale} (viene chiamato anche \textit{wall clock time}) passato dall'avvio del processo. Chiaramente tale tempo dipende anche dal carico del sistema e da quanti altri processi @@ -1738,7 +1747,7 @@ tre tempi diversi: delle istruzioni del processo in user space. \item[\textit{system time}]: il tempo che la CPU ha impiegato nel kernel per eseguire delle system call per conto del processo. -\end{description*} +\end{description} In genere la somma di \textit{user time} e \textit{system time} indica il tempo di processore totale in cui il sistema è stato effettivamente impegnato @@ -1759,7 +1768,7 @@ un altro processo era in esecuzione o in attesa del risultato di una operazione di I/O. La funzione più semplice per leggere il \textit{process time} di un processo è -\func{clock}, che da una valutazione approssimativa del tempo di CPU +\funcd{clock}, che da una valutazione approssimativa del tempo di CPU utilizzato dallo stesso; il suo prototipo è: \begin{prototype}{time.h}{clock\_t clock(void)} Legge il valore corrente del tempo di CPU. @@ -1780,7 +1789,7 @@ riprender Come accennato in \secref{sec:sys_unix_time} il tempo di CPU è la somma di altri due tempi, l'\textit{user time} ed il \textit{system time} che sono quelli effettivamente mantenuti dal kernel per ciascun processo. Questi -possono essere letti attraverso la funzione \func{times}, il cui prototipo è: +possono essere letti attraverso la funzione \funcd{times}, il cui prototipo è: \begin{prototype}{sys/times.h}{clock\_t times(struct tms *buf)} Legge in \param{buf} il valore corrente dei tempi di processore. @@ -1835,7 +1844,7 @@ Come anticipato in \secref{sec:sys_unix_time} il \textit{calendar time} mantenuto dal kernel in una variabile di tipo \type{time\_t}, che usualmente corrisponde ad un tipo nativo (in Linux è un intero a 32 bit). Il valore corrente del \textit{calendar time}, che indicheremo come \textsl{tempo di - sistema}, può essere ottenuto con la funzione \func{time} che lo restituisce + sistema}, può essere ottenuto con la funzione \funcd{time} che lo restituisce in nel suddetto formato; il suo prototipo è: \begin{prototype}{time.h}{time\_t time(time\_t *t)} Legge il valore corrente del \textit{calendar time}. @@ -1846,7 +1855,7 @@ in nel suddetto formato; il suo prototipo \noindent dove \param{t}, se non nullo, deve essere l'indirizzo di una variabile su cui duplicare il valore di ritorno. -Analoga a \func{time} è la funzione \func{stime} che serve per effettuare +Analoga a \func{time} è la funzione \funcd{stime} che serve per effettuare l'operazione inversa, e cioè per impostare il tempo di sistema qualora questo sia necessario; il suo prototipo è: \begin{prototype}{time.h}{int stime(time\_t *t)} @@ -1863,7 +1872,7 @@ altrimenti la chiamata fallir Data la scarsa precisione nell'uso di \type{time\_t} (che ha una risoluzione massima di un secondo) quando si devono effettuare operazioni sui tempi di norma l'uso delle funzioni precedenti è sconsigliato, ed esse sono di solito -sostituite da \func{gettimeofday} e \func{settimeofday},\footnote{le due +sostituite da \funcd{gettimeofday} e \funcd{settimeofday},\footnote{le due funzioni \func{time} e \func{stime} sono più antiche e derivano da SVr4, \func{gettimeofday} e \func{settimeofday} sono state introdotte da BSD, ed in BSD4.3 sono indicate come sostitute delle precedenti.} i cui prototipi @@ -1917,24 +1926,30 @@ struct timespec { \label{fig:sys_timeval_struct} \end{figure} -Come nel caso di \func{stime} anche \func{settimeofday} (e qualunque funzione -vada a modificare l'orologio di sistema, come quelle che tratteremo in -seguito) può essere utilizzata solo da un processo coi privilegi di -amministratore. Il secondo parametro di entrambe le funzioni è una struttura +Come nel caso di \func{stime} anche \func{settimeofday} (la cosa continua a +valere per qualunque funzione che vada a modificare l'orologio di sistema, +quindi anche per quelle che tratteremo in seguito) può essere utilizzata solo +da un processo coi privilegi di amministratore. + +Il secondo parametro di entrambe le funzioni è una struttura \struct{timezone}, che storicamente veniva utilizzata per specificare appunto la \textit{time zone}, cioè l'insieme del fuso orario e delle convenzioni per l'ora legale che permettevano il passaggio dal tempo universale all'ora -locale. Questo parametro è obsoleto e in Linux non è mai stato utilizzato e -non è supportato né dalle vecchie \textsl{libc5}, né dalle \textsl{glibc}: -pertanto deve essere sempre impostato a \val{null}. +locale. Questo parametro oggi è obsoleto ed in Linux non è mai stato +utilizzato; esso non è supportato né dalle vecchie \textsl{libc5}, né dalle +\textsl{glibc}: pertanto quando si chiama questa funzione deve essere sempre +impostato a \val{NULL}. Modificare l'orologio di sistema con queste funzioni è comunque problematico, in quanto esse effettuano un cambiamento immediato. Questo può creare dei buchi o delle ripetizioni nello scorrere dell'orologio di sistema, con -conseguenze indesiderate; ad esempio se si porta avanti l'orologio si possono +conseguenze indesiderate. Ad esempio se si porta avanti l'orologio si possono perdere delle esecuzioni di \cmd{cron} programmate nell'intervallo che si è -saltato. Per questo motivo la modalità più corretta per impostare l'ora è -quella di usare la funzione \func{adjtime}, il cui prototipo è: +saltato. Oppure se si porta indietro l'orologio si possono eseguire due volte +delle operazioni previste nell'intervallo di tempo che viene ripetuto. + +Per questo motivo la modalità più corretta per impostare l'ora è quella di +usare la funzione \funcd{adjtime}, il cui prototipo è: \begin{prototype}{sys/time.h} {int adjtime(const struct timeval *delta, struct timeval *olddelta)} @@ -1952,27 +1967,6 @@ il tempo richiesto, altrimenti sar usato, se non nullo, per ricevere il valore dell'ultimo aggiustamento effettuato. -Linux poi prevede un'altra funzione, \func{adjtimex}, che consente un -aggiustamento molto più dettagliato, permettendo ad esempio anche di -modificare anche la velocità dell'orologio di sistema. Il suo prototipo è: -\begin{prototype}{sys/timex.h} -{int adjtimex(struct timex *buf)} - - Aggiusta del valore \param{delta} l'orologio di sistema. - - \bodydesc{La funzione restituisce lo stato dell'orologio (un valore $>0$) in - caso di successo e -1 in caso di errore, nel qual caso \var{errno} - assumerà i valori \errval{EFAULT}, \errval{EINVAL} ed \errval{EPERM}.} -\end{prototype} - -La funzione richiede una struttura di tipo \struct{timex}, la cui definizione, -così come effettuata in \file{sys/timex.h}, è riportata in -\figref{fig:sys_timex_struct}. L'azione della funzione dipende dal valore del -campo \var{mode}, che specifica quale parametro dell'orologio di sistema, -specificato in un opportuno campo di \struct{timex}, deve essere impostato. Un -valore nullo serve per leggere i parametri correnti; i valori diversi da zero -devono essere specificati come OR binario delle costanti riportate in -\secref{tab:sys_timex_mode}. \begin{figure}[!htb] \footnotesize \centering @@ -2007,6 +2001,29 @@ struct timex { \label{fig:sys_timex_struct} \end{figure} +Linux poi prevede un'altra funzione, che consente un aggiustamento molto più +dettagliato del tempo, permettendo ad esempio anche di modificare anche la +velocità dell'orologio di sistema. La funzione è \funcd{adjtimex} ed il suo +prototipo è: +\begin{prototype}{sys/timex.h} +{int adjtimex(struct timex *buf)} + + Aggiusta del valore \param{delta} l'orologio di sistema. + + \bodydesc{La funzione restituisce lo stato dell'orologio (un valore $>0$) in + caso di successo e -1 in caso di errore, nel qual caso \var{errno} + assumerà i valori \errval{EFAULT}, \errval{EINVAL} ed \errval{EPERM}.} +\end{prototype} + +La funzione richiede una struttura di tipo \struct{timex}, la cui definizione, +così come effettuata in \file{sys/timex.h}, è riportata in +\figref{fig:sys_timex_struct}. L'azione della funzione dipende dal valore del +campo \var{mode}, che specifica quale parametro dell'orologio di sistema, +specificato in un opportuno campo di \struct{timex}, deve essere impostato. Un +valore nullo serve per leggere i parametri correnti; i valori diversi da zero +devono essere specificati come OR binario delle costanti riportate in +\secref{tab:sys_timex_mode}. + La funzione utilizza il meccanismo di David L. Mills, descritto nell'RFC~1305, che è alla base del protocollo NTP; la funzione è specifica di Linux e non deve essere usata se la portabilità è un requisito, le \acr{glibc} provvedono @@ -2020,7 +2037,7 @@ essere ritrovato in \cite{glibc}. \begin{table}[htb] \footnotesize \centering - \begin{tabular}[c]{|l|c| p{10cm}|} + \begin{tabular}[c]{|l|c| p{9cm}|} \hline \textbf{Nome} & \textbf{Valore} & \textbf{Significato}\\ \hline @@ -2171,7 +2188,7 @@ tempo in una stringa contenente data ed ora, i loro prototipi sono: Converte il \textit{broken-down time} in formato \type{time\_t}. \bodydesc{Tutte le funzioni restituiscono un puntatore al risultato in caso - di successo e \val{null} in caso di errore, tranne che \func{mktime} che + di successo e \val{NULL} in caso di errore, tranne che \func{mktime} che restituisce direttamente il valore o -1 in caso di errore.} \end{functions} @@ -2247,8 +2264,8 @@ solare, la seconda per l'ora legale.\footnote{anche se sono indicati come Benché la funzione \func{asctime} fornisca la modalità più immediata per stampare un tempo o una data, la flessibilità non fa parte delle sue caratteristiche; quando si vuole poter stampare solo una parte (l'ora, o il -gionrno) di un tempo si può ricorrere alla più sofisticata \func{strftime}, il -cui prototipo è: +gionrno) di un tempo si può ricorrere alla più sofisticata \funcd{strftime}, +il cui prototipo è: \begin{prototype}{time.h} {size\_t strftime(char *s, size\_t max, const char *format, const struct tm *tm)} @@ -2349,7 +2366,7 @@ Per riportare il tipo di errore il sistema usa la variabile globale variabile è in genere definita come \direct{volatile} dato che può essere cambiata in modo asincrono da un segnale (si veda \secref{sec:sig_sigchld} per un esempio, ricordando quanto trattato in \secref{sec:proc_race_cond}), ma -dato che un manipolatore di segnale scritto bene salva e ripristina il valore +dato che un gestore di segnale scritto bene salva e ripristina il valore della variabile, di questo non è necessario preoccuparsi nella programmazione normale. @@ -2381,13 +2398,13 @@ Bench \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 è: +\funcd{strerror}, il cui prototipo è: \begin{prototype}{string.h}{char *strerror(int errnum)} Restituisce una stringa con il messaggio di errore relativo ad \param{errnum}. \bodydesc{La funzione ritorna il puntatore alla stringa col messaggio di - errore in caso di successo e \val{null} in caso di errore, nel qual caso + errore in caso di successo e \val{NULL} in caso di errore, nel qual caso \var{errno} assumerà il valore \errval{EINVAL} se si è specificato un numero di errore non valido.} \end{prototype} @@ -2429,7 +2446,7 @@ zero (il carattere NUL). Una seconda funzione usata per riportare i codici di errore in maniera automatizzata sullo standard error (vedi \secref{sec:file_std_descr}) è -\func{perror}, il cui prototipo è: +\funcd{perror}, il cui prototipo è: \begin{prototype}{stdio.h}{void perror(const char *message)} Stampa il messaggio di errore relativo al valore corrente di \var{errno} sullo standard error; preceduto dalla stringa \param{message}. @@ -2515,7 +2532,7 @@ messaggi con maggiore informazione; ad esempio negli standard di programmazione GNU si richiede che ogni messaggio di errore sia preceduto dal nome del programma, ed in generale si può voler stampare il contenuto di qualche variabile; per questo le \acr{glibc} definiscono la funzione -\func{error}, il cui prototipo è: +\funcd{error}, il cui prototipo è: \begin{prototype}{stdio.h} {void error(int status, int errnum, const char *format, ...)} @@ -2548,8 +2565,8 @@ un'altra variabile globale, \var{error\_message\_count}, che tiene conto di quanti errori ci sono stati. Un'altra funzione per la stampa degli errori, ancora più sofisticata, è -\func{error\_at\_line}, che prende due argomenti aggiuntivi per indicare linea -e file su cui è avvenuto l'errore; il suo prototipo è: +\funcd{error\_at\_line}, che prende due argomenti aggiuntivi per indicare +linea e file su cui è avvenuto l'errore; il suo prototipo è: \begin{prototype}{stdio.h} {void error\_at\_line(int status, int errnum, const char *fname, unsigned int lineno, const char *format, ...)}