From: Simone Piccardi Date: Sun, 6 May 2012 19:38:23 +0000 (+0000) Subject: Avanti sui segnali e qualche indicizzazione. X-Git-Url: https://gapil.gnulinux.it/gitweb/?a=commitdiff_plain;h=34acc86e5e2a1282b22de6edd59f4e05683a7b1b;p=gapil.git Avanti sui segnali e qualche indicizzazione. --- diff --git a/signal.tex b/signal.tex index 357526d..915e168 100644 --- a/signal.tex +++ b/signal.tex @@ -365,7 +365,7 @@ esse sono definite nell'header di sistema \headfile{signal.h}. \signal{SIGXCPU} &BS& C & Ecceduto il limite sul tempo di CPU.\\ \signal{SIGXFSZ} &BS& C & Ecceduto il limite sulla dimensione dei file.\\ \signal{SIGVTALRM}&BS& T& Timer di esecuzione scaduto.\\ - \signal{SIGPROF} &BS& T & Timer del profiling scaduto.\\ + \signal{SIGPROF} &BS& T & Timer del \textit{profiling} scaduto.\\ \signal{SIGWINCH}&B & I & Finestra ridimensionata (4.3BSD, Sun).\\ \signal{SIGIO} &B & T & L'I/O è possibile.\\ \signal{SIGPOLL} &VS& T & \textit{Pollable event}, sinonimo di @@ -1183,7 +1183,7 @@ con \param{pid} non esistono. \begin{table}[htb] \footnotesize \centering - \begin{tabular}[c]{|r|l|} + \begin{tabular}[c]{|r|p{8cm}|} \hline \textbf{Valore} & \textbf{Significato} \\ \hline @@ -1212,6 +1212,23 @@ per questo argomento. Si tenga conto però che il sistema ricicla i \ids{PID} non significa che esso sia realmente quello a cui si intendeva mandare il segnale. +Indipendentemente dalla funzione specifica che viene usata solo +l'amministratore può inviare un segnale ad un processo qualunque, in tutti gli +altri casi l'\ids{UID} reale o l'\ids{UID} effettivo del processo chiamante +devono corrispondere all'\ids{UID} reale o all'\ids{UID} salvato della +destinazione. Fa eccezione il caso in cui il segnale inviato sia +\signal{SIGCONT}, nel quale occorre anche che entrambi i processi appartengano +alla stessa sessione. + +Si tenga presente che, per il ruolo fondamentale che riveste nel sistema, non +è possibile inviare al processo 1 (cioè a \cmd{init}) segnali per i quali esso +non abbia un gestore installato. Infine, seguendo le specifiche POSIX +1003.1-2001, l'uso della chiamata \code{kill(-1, sig)} comporta che il segnale +sia inviato (con la solita eccezione di \cmd{init}) a tutti i processi per i +quali i permessi lo consentano. Lo standard permette comunque alle varie +implementazioni di escludere alcuni processi specifici: nel caso in questione +Linux non invia il segnale al processo che ha effettuato la chiamata. + Si noti pertanto che la funzione \code{raise(sig)} può essere definita in termini di \func{kill}, ed è sostanzialmente equivalente ad una \code{kill(getpid(), sig)}. Siccome \func{raise}, che è definita nello @@ -1227,45 +1244,62 @@ prototipo è: } { La funzione ritorna $0$ in caso di successo e $-1$ per un errore, e gli - errori sono gli stessi di \func{kill}. } + errori sono gli stessi di \func{kill}. +} \end{funcproto} La funzione invia il segnale \param{signal} al \itindex{process~group} -\textit{process group} \param{pidgrp} ed è è sostanzialmente equivalente -all'esecuzione di \code{kill(-pidgrp, signal)}. - -Oltre a queste funzioni di base vedremo più avanti che esistono altre funzioni -per inviare segnali, come \func{sigqueue} per i segnali \textit{real-time} -(vedi sez.~\ref{sec:sig_real_time}) e le specifiche funzioni per i -\textit{thread} che tratteremo in sez.~\ref{sec:thread_signal}. - -Ma indipendentemente dalla funzione usata solo l'amministratore può inviare un -segnale ad un processo qualunque, in tutti gli altri casi l'\ids{UID} reale o -l'\ids{UID} effettivo del processo chiamante devono corrispondere -all'\ids{UID} reale o all'\ids{UID} salvato della destinazione. Fa eccezione -il caso in cui il segnale inviato sia \signal{SIGCONT}, nel quale occorre che -entrambi i processi appartengano alla stessa sessione. Inoltre, dato il ruolo -fondamentale che riveste nel sistema (si ricordi quanto visto in -sez.~\ref{sec:sig_termination}), non è possibile inviare al processo 1 (cioè a -\cmd{init}) segnali per i quali esso non abbia un gestore installato. - -Infine, seguendo le specifiche POSIX 1003.1-2001, l'uso della chiamata -\code{kill(-1, sig)} comporta che il segnale sia inviato (con la solita -eccezione di \cmd{init}) a tutti i processi per i quali i permessi lo -consentano. Lo standard permette comunque alle varie implementazioni di -escludere alcuni processi specifici: nel caso in questione Linux non invia il -segnale al processo che ha effettuato la chiamata. - - -\subsection{Le funzioni di allarme ed interruzione ed i \textit{timer}} +\textit{process group} il cui \acr{PGID} (vedi sez.~\ref{sec:sess_proc_group}) +è indicato dall'argomento \param{pidgrp}, che deve essere un intero +positivo. Il suo utilizzo è sostanzialmente equivalente all'esecuzione di +\code{kill(-pidgrp, signal)}. + +Oltre alle precedenti funzioni di base, vedremo più avanti che esistono altre +funzioni per inviare segnali generici, come \func{sigqueue} per i segnali +\textit{real-time} (vedi sez.~\ref{sec:sig_real_time}) e le specifiche +funzioni per i \textit{thread} che tratteremo in sez.~\ref{sec:thread_signal}. + +Esiste però un'ultima funzione che permette l'invio diretto di un segnale che +vale la pena di trattare a parte per le sue peculiarità. La funzione in +questione è \funcd{abort} che, come accennato in +sez.~\ref{sec:proc_termination}, permette di abortire l'esecuzione di un +programma tramite l'invio del segnale \signal{SIGABRT}. Il suo prototipo è: + +\begin{funcproto}{ +\fhead{stdlib.h} +\fdecl{void abort(void)} +\fdesc{Abortisce il processo corrente.} +} + +{La funzione non ritorna, il processo viene terminato.} +\end{funcproto} + +La differenza fra questa funzione e l'uso di \func{raise} o di un'altra +funzione per l'invio di \signal{SIGABRT} è che anche se il segnale è bloccato +o ignorato, la funzione ha effetto lo stesso. Il segnale può però essere +intercettato per effettuare eventuali operazioni di chiusura prima della +terminazione del processo. + +Lo standard ANSI C richiede inoltre che anche se il gestore ritorna, la +funzione non ritorni comunque. Lo standard POSIX.1 va oltre e richiede che se +il processo non viene terminato direttamente dal gestore sia la stessa +\func{abort} a farlo al ritorno dello stesso. Inoltre, sempre seguendo lo +standard POSIX, prima della terminazione tutti i file aperti e gli stream +saranno chiusi ed i buffer scaricati su disco. Non verranno invece eseguite le +eventuali funzioni registrate con \func{atexit} e \func{on\_exit}. + + + + +\subsection{Le funzioni di allarme ed i \textit{timer}} \label{sec:sig_alarm_abort} Un caso particolare di segnali generati a richiesta è quello che riguarda i -vari segnali di temporizzazione e \signal{SIGABRT}, per ciascuno di questi -segnali sono previste funzioni specifiche che ne effettuino l'invio. La più -comune delle funzioni usate per la temporizzazione è \funcd{alarm} il cui -prototipo è: +vari segnali usati per la temporizzazione, per ciascuno di essi infatti sono +previste delle funzioni specifiche che ne effettuino l'invio. La più comune, e +la più semplice, delle funzioni usate per la temporizzazione è la funzione di +sistema \funcd{alarm}, il cui prototipo è: \begin{funcproto}{ \fhead{unistd.h} @@ -1306,7 +1340,7 @@ processo tre diversi timer: \item un \textit{profiling timer} che calcola la somma dei tempi di processore utilizzati direttamente dal processo in user space, e dal kernel nelle \textit{system call} ad esso relative (che corrisponde a quello che in - sez.~\ref{sec:sys_unix_time} abbiamo chiamato \textit{CPU time}). La + sez.~\ref{sec:sys_unix_time} abbiamo chiamato \textit{processor time}). La scadenza di questo timer provoca l'emissione di \signal{SIGPROF}. \end{itemize*} @@ -1320,18 +1354,24 @@ 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 è: -\begin{prototype}{sys/time.h}{int setitimer(int which, const struct - itimerval *value, struct itimerval *ovalue)} - - Predispone l'invio di un segnale di allarme alla scadenza dell'intervallo - \param{value} sul timer specificato da \param{which}. + +\begin{funcproto}{ +\fhead{sys/time.h} +\fdecl{int setitimer(int which, const struct itimerval *value, struct + itimerval *ovalue)} - \bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di - errore, nel qual caso \var{errno} assumerà uno dei valori \errval{EINVAL} o - \errval{EFAULT}.} -\end{prototype} +\fdesc{Predispone l'invio di un segnale di allarme.} +} + +{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual + caso \var{errno} assumerà uno dei valori \errval{EINVAL} o \errval{EFAULT} + nel loro significato generico.} +\end{funcproto} -Il valore di \param{which} permette di specificare quale dei tre timer + +La funzione predispone l'invio di un segnale di allarme alla scadenza +dell'intervallo indicato dall'argomento \param{value}. Il valore +dell'argomento \param{which} permette di specificare quale dei tre timer illustrati in precedenza usare; i possibili valori sono riportati in tab.~\ref{tab:sig_setitimer_values}. \begin{table}[htb] @@ -1369,7 +1409,7 @@ questo modo il ciclo verrà ripetuto; se invece il valore di \var{it\_interval} \begin{figure}[!htb] \footnotesize \centering - \begin{minipage}[c]{\textwidth} + \begin{minipage}[c]{0.8\textwidth} \includestruct{listati/itimerval.h} \end{minipage} \normalsize @@ -1388,7 +1428,7 @@ fig.~\ref{fig:sig_alarm_def}.\footnote{questo comporta anche che non è il caso \begin{figure}[!htb] \footnotesize \centering - \begin{minipage}[c]{\textwidth} + \begin{minipage}[c]{0.8\textwidth} \includestruct{listati/alarm_def.c} \end{minipage} \normalsize @@ -1397,20 +1437,21 @@ fig.~\ref{fig:sig_alarm_def}.\footnote{questo comporta anche che non è il caso \end{figure} Si deve comunque tenere presente che fino al kernel 2.6.16 la precisione di -queste funzioni era limitata dalla frequenza del timer di sistema,\footnote{il - valore della costante \texttt{HZ}, di cui abbiamo già parlato in - sez.~\ref{sec:proc_hierarchy}.} in quanto le temporizzazioni erano calcolate -in numero di interruzioni del timer (i cosiddetti \itindex{jiffies} +queste funzioni era limitata dalla frequenza del timer di sistema, determinato +dal valore della costante \texttt{HZ} di cui abbiamo già parlato in +sez.~\ref{sec:proc_hierarchy}, in quanto le temporizzazioni erano calcolate in +numero di interruzioni del timer (i cosiddetti \itindex{jiffies} ``\textit{jiffies}''), ed era assicurato soltanto che il segnale non sarebbe stato mai generato prima della scadenza programmata (l'arrotondamento cioè era effettuato per eccesso).\footnote{questo in realtà non è del tutto vero a causa di un bug, presente fino al kernel 2.6.12, che in certe circostanze - causava l'emissione del segnale con un arrotondamento per difetto.} L'uso -del contatore dei \itindex{jiffies} \textit{jiffies}, un intero a 32 bit, -comportava inoltre l'impossibilità di specificare tempi molto -lunghi.\footnote{superiori al valore della costante - \const{MAX\_SEC\_IN\_JIFFIES}, pari, nel caso di default di un valore di - \const{HZ} di 250, a circa 99 giorni e mezzo.} Con il cambiamento della + causava l'emissione del segnale con un arrotondamento per difetto.} + +L'uso del contatore dei \itindex{jiffies} \textit{jiffies}, un intero a 32 bit +nella maggior parte dei casi, comportava inoltre l'impossibilità di +specificare tempi molto lunghi. superiori al valore della costante +\const{MAX\_SEC\_IN\_JIFFIES}, pari, nel caso di default di un valore di +\const{HZ} di 250, a circa 99 giorni e mezzo. Con il cambiamento della rappresentazione effettuato nel kernel 2.6.16 questo problema è scomparso e con l'introduzione dei timer ad alta risoluzione (vedi sez.~\ref{sec:sig_timer_adv}) nel kernel 2.6.21 la precisione è diventata @@ -1425,50 +1466,30 @@ seconda del carico del sistema. Questo ha una conseguenza che può indurre ad errori molto subdoli, si tenga conto poi che in caso di sistema molto carico, si può avere il caso patologico in cui un timer scade prima che il segnale di una precedente scadenza sia -stato consegnato; in questo caso, per il comportamento dei segnali descritto +stato consegnato. In questo caso, per il comportamento dei segnali descritto in sez.~\ref{sec:sig_sigchld}, un solo segnale sarà consegnato. Per questo -oggi l'uso di questa funzione è deprecato a favore dei \textit{POSIX timer} -che tratteremo in sez.~\ref{sec:sig_timer_adv}. +oggi l'uso di questa funzione è deprecato a favore degli +\index{High~Resolution~Timer~(HRT)} \textit{high-resolution timer} e della +cosiddetta \itindex{POSIX~Timer~API} \textit{POSIX Timer API}, che tratteremo +in sez.~\ref{sec:sig_timer_adv}. Dato che sia \func{alarm} che \func{setitimer} non consentono di leggere il valore corrente di un timer senza modificarlo, è possibile usare la funzione \funcd{getitimer}, il cui prototipo è: -\begin{prototype}{sys/time.h}{int getitimer(int which, struct - itimerval *value)} - - Legge in \param{value} il valore del timer specificato da \param{which}. - - \bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di - errore e restituisce gli stessi errori di \func{getitimer}.} -\end{prototype} -\noindent i cui argomenti hanno lo stesso significato e formato di quelli di -\func{setitimer}. - -L'ultima funzione che permette l'invio diretto di un segnale è \funcd{abort}, -che, come accennato in sez.~\ref{sec:proc_termination}, permette di abortire -l'esecuzione di un programma tramite l'invio di \signal{SIGABRT}. Il suo -prototipo è: -\begin{prototype}{stdlib.h}{void abort(void)} - - Abortisce il processo corrente. - - \bodydesc{La funzione non ritorna, il processo è terminato inviando il - segnale di \signal{SIGABRT}.} -\end{prototype} +\begin{funcproto}{ +\fhead{sys/time.h} +\fdecl{int getitimer(int which, struct itimerval *value)} +\fdesc{Legge il valore di un timer.} +} -La differenza fra questa funzione e l'uso di \func{raise} è che anche se il -segnale è bloccato o ignorato, la funzione ha effetto lo stesso. Il segnale -può però essere intercettato per effettuare eventuali operazioni di chiusura -prima della terminazione del processo. +{ La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual + caso \var{errno} assumerà gli stessi valori di \func{getitimer}. } +\end{funcproto} -Lo standard ANSI C richiede inoltre che anche se il gestore ritorna, la -funzione non ritorni comunque. Lo standard POSIX.1 va oltre e richiede che se -il processo non viene terminato direttamente dal gestore sia la stessa -\func{abort} a farlo al ritorno dello stesso. Inoltre, sempre seguendo lo -standard POSIX, prima della terminazione tutti i file aperti e gli stream -saranno chiusi ed i buffer scaricati su disco. Non verranno invece eseguite le -eventuali funzioni registrate con \func{atexit} e \func{on\_exit}. +La funzione legge nella struttura \struct{itimerval} puntata da \param{value} +il valore del timer specificato da \param{which} ed i suoi argomenti hanno lo +stesso significato e formato di quelli di \func{setitimer}. \subsection{Le funzioni di pausa e attesa} @@ -1476,102 +1497,137 @@ eventuali funzioni registrate con \func{atexit} e \func{on\_exit}. 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 - sez.~\ref{sec:proc_sched}.} - -Il metodo tradizionale per fare attendere ad un processo fino all'arrivo di un -segnale è quello di usare la funzione \funcd{pause}, il cui prototipo è: -\begin{prototype}{unistd.h}{int pause(void)} - - Pone il processo in stato di sleep fino al ritorno di un gestore. - - \bodydesc{La funzione ritorna solo dopo che un segnale è stato ricevuto ed - il relativo gestore è ritornato, nel qual caso restituisce $-1$ e - \var{errno} assumerà il valore \errval{EINTR}.} -\end{prototype} +genere questo veniva fatto con un ciclo di attesa in cui il programma ripete +una operazione un numero sufficiente di volte per far passare il tempo +richiesto. + +Ma in un sistema multitasking un ciclo di attesa è solo un inutile spreco di +tempo di processore, dato che altri programmi possono essere eseguiti nel +frattempo, per questo ci sono delle apposite funzioni che permettono di +mantenere un processo in attesa per il tempo voluto, senza impegnare il +processore. In pratica si tratta di funzioni che permettono di portare +esplicitamente il processo nello stato di \textit{sleep} (si ricordi quanto +illustrato in tab.~\ref{tab:proc_proc_states}) per un certo periodo di tempo. + +La prima di queste è la funzione di sistema \funcd{pause}, che viene usata per +mettere un processo in attesa per un periodo di tempo indefinito, fino +all'arrivo di un segnale, il suo 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 interrompere -l'esecuzione del processo fino all'arrivo di un segnale inviato da un altro -processo). +\begin{funcproto}{ +\fhead{unistd.h} +\fdecl{int pause(void)} +\fdesc{Pone il processo in pausa fino al ricevimento di un segnale.} +} + +{La funzione ritorna solo dopo che un segnale è stato ricevuto ed il relativo + gestore è ritornato, nel qual caso restituisce $-1$ e \var{errno} assume il + valore \errval{EINTR}.} +\end{funcproto} + +La funzione ritorna sempre con una condizione di errore, dato che il successo +sarebbe quello di continuare ad 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 interrompere l'esecuzione del processo fino all'arrivo di un +segnale inviato da un altro processo. 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. - - \bodydesc{La funzione restituisce zero se l'attesa viene completata, o il - numero di secondi restanti se viene interrotta da un segnale.} -\end{prototype} +già noto in partenza, lo standard POSIX.1 prevede una funzione di attesa +specifica, \funcd{sleep}, il cui prototipo è: + +\begin{funcproto}{ -La funzione attende per il tempo specificato, a meno di non essere interrotta -da un segnale. In questo caso non è una buona idea ripetere la chiamata per il -tempo rimanente, in quanto la riattivazione del processo può avvenire in un -qualunque momento, ma il valore restituito sarà sempre arrotondato al secondo, -con la conseguenza che, se la successione dei segnali è particolarmente -sfortunata e le differenze si accumulano, si potranno avere ritardi anche di -parecchi secondi. In genere la scelta più sicura è quella di stabilire un -termine per l'attesa, e ricalcolare tutte le volte il numero di secondi da -aspettare. - -In alcune implementazioni inoltre l'uso di \func{sleep} può avere conflitti -con quello di \signal{SIGALRM}, dato che la funzione può essere realizzata con -l'uso di \func{pause} e \func{alarm} (in maniera analoga all'esempio che -vedremo in sez.~\ref{sec:sig_example}). In tal caso mescolare chiamata di -\func{alarm} e \func{sleep} o modificare l'azione di \signal{SIGALRM}, può -causare risultati indefiniti. Nel caso delle \acr{glibc} è stata usata una -implementazione completamente indipendente e questi problemi non ci sono. +\fhead{unistd.h} +\fdecl{unsigned int sleep(unsigned int seconds)} +\fdesc{Pone il processo in pausa per un tempo in secondi.} +} + +{La funzione ritorna $0$ se l'attesa viene completata o il + numero di secondi restanti se viene interrotta da un segnale, non sono + previsti codici di errore.} +\end{funcproto} + +La funzione pone il processo in stato di \textit{sleep} per il numero di +secondi specificato dall'argomento \param{seconds}, a meno di non essere +interrotta da un segnale. Alla terminazione del periodo di tempo indicato la +funzione ritorna riportando il processo in stato \textit{runnable} così che +questo possa riprendere l'esecuzione. + +In caso di interruzione della funzione non è una buona idea ripetere la +chiamata per il tempo rimanente restituito dalla stessa, in quanto la +riattivazione del processo può avvenire in un qualunque momento, ma il valore +restituito sarà sempre arrotondato al secondo. Questo può avere la conseguenza +che se la successione dei segnali è particolarmente sfortunata e le differenze +si accumulano, si possono avere ritardi anche di parecchi secondi rispetto a +quanto programmato inizialmente. In genere la scelta più sicura in questo caso +è quella di stabilire un termine per l'attesa, e ricalcolare tutte le volte il +numero di secondi che restano da aspettare. + +Si tenga presente che alcune implementazioni l'uso di \func{sleep} può avere +conflitti con quello di \signal{SIGALRM}, dato che la funzione può essere +realizzata con l'uso di \func{pause} e \func{alarm}, in una maniera analoga a +quella dell'esempio che vedremo in sez.~\ref{sec:sig_example}. In tal caso +mescolare chiamate di \func{alarm} e \func{sleep} o modificare l'azione +associata \signal{SIGALRM}, può portare a dei risultati indefiniti. Nel caso +delle \acr{glibc} è stata usata una implementazione completamente indipendente +e questi problemi non ci sono, ma un programma portabile non può fare questa +assunzione. 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: -\begin{prototype}{unistd.h}{int usleep(unsigned long usec)} - - Pone il processo in stato di sleep per \param{usec} microsecondi. - - \bodydesc{La funzione restituisce zero se l'attesa viene completata, o $-1$ - in caso di errore, nel qual caso \var{errno} assumerà il valore - \errval{EINTR}.} +secondi, per questo sia sotto BSD4.3 che in SUSv2 è stata definita un'altra +funzione con una precisione teorica del microsecondo. I due standard hanno +delle definizioni diverse, ma le \acr{glibc} seguono (secondo la pagina di +manuale almeno dalla versione 2.2.2) seguono quella di SUSv2 per cui la +funzione \funcd{usleep} (dove la \texttt{u} è intesa come sostituzione di +$\mu$), ha il seguente prototipo: -\end{prototype} +\begin{funcproto}{ +\fhead{unistd.h} +\fdecl{int usleep(unsigned long usec)} +\fdesc{Pone il processo in pausa per un tempo in microsecondi.} +} + +{La funzione ritorna $0$ se l'attesa viene completata e $-1$ per un errore, + nel qual caso \var{errno} assumerà uno dei valori: + \begin{errlist} + \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale. + \item[\errcode{EINVAL}] si è indicato un valore di \param{usec} maggiore di + 1000000. + \end{errlist} +} +\end{funcproto} Anche questa funzione, a seconda delle implementazioni, può presentare -problemi nell'interazione con \func{alarm} e \signal{SIGALRM}. È pertanto -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)} - - Pone il processo in stato di sleep per il tempo specificato da \param{req}. - In caso di interruzione restituisce il tempo restante in \param{rem}. - - \bodydesc{La funzione restituisce zero se l'attesa viene completata, o $-1$ - in caso di errore, nel qual caso \var{errno} assumerà uno dei valori: - \begin{errlist} +problemi nell'interazione con \func{alarm} e \signal{SIGALRM}, per questo +motivo, pur essendovi citata, nello standard POSIX.1-2001 viene deprecata in +favore della nuova funzione di sistema \funcd{nanosleep}, il cui prototipo è: + +\begin{funcproto}{ +\fhead{unistd.h} +\fdecl{int nanosleep(const struct timespec *req, struct timespec *rem)} +\fdesc{Pone il processo in pausa per un periodo di tempo.} +} + +{La funzione ritorna $0$ se l'attesa viene completata e $-1$ per un errore, + nel qual caso \var{errno} assumerà uno dei valori: + \begin{errlist} \item[\errcode{EINVAL}] si è specificato un numero di secondi negativo o un numero di nanosecondi maggiore di 999.999.999. \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale. - \end{errlist}} -\end{prototype} + \end{errlist} +} +\end{funcproto} -Lo standard richiede che la funzione sia implementata in maniera del tutto -indipendente da \func{alarm}\footnote{nel caso di Linux questo è fatto - utilizzando direttamente il timer del kernel.} e sia utilizzabile senza -interferenze con l'uso di \signal{SIGALRM}. La funzione prende come argomenti -delle strutture di tipo \struct{timespec}, la cui definizione è riportata in -fig.~\ref{fig:sys_timespec_struct}, che permette di specificare un tempo con -una precisione fino al nanosecondo. +La funzione pone il processo in pausa portandolo nello stato di \textit{sleep} +per il tempo specificato dall'argomento \param{req}, ed in caso di +interruzione restituisce il tempo restante nell'argomento \param{rem}. Lo +standard richiede che la funzione sia implementata in maniera del tutto +indipendente da \func{alarm}, e nel caso di Linux questo è fatto utilizzando +direttamente il timer del kernel. Lo standard richiede inoltre che la funzione +sia utilizzabile senza interferenze con l'uso di \signal{SIGALRM}. La funzione +prende come argomenti delle strutture di tipo \struct{timespec}, la cui +definizione è riportata in fig.~\ref{fig:sys_timespec_struct}, il che permette +di specificare un tempo con una precisione teorica fino al nanosecondo. La funzione risolve anche il problema di proseguire l'attesa dopo l'interruzione dovuta ad un segnale; infatti in tal caso in \param{rem} viene @@ -1580,12 +1636,13 @@ inizialmente,\footnote{con l'eccezione, valida solo nei kernel della serie 2.4, in cui, per i processi riavviati dopo essere stati fermati da un segnale, il tempo passato in stato \texttt{T} non viene considerato nel calcolo della rimanenza.} e basta richiamare la funzione per completare -l'attesa.\footnote{anche qui però occorre tenere presente che i tempi sono - arrotondati, per cui la precisione, per quanto migliore di quella ottenibile - con \func{sleep}, è relativa e in caso di molte interruzioni si può avere - una deriva, per questo esiste la funzione \func{clock\_nanosleep} (vedi - sez.~\ref{sec:sig_timer_adv}) che permette di specificare un tempo assoluto - anziché un tempo relativo.} +l'attesa. + +Anche qui però occorre tenere presente che i tempi sono arrotondati, per cui +la precisione, per quanto migliore di quella ottenibile con \func{sleep}, è +relativa e in caso di molte interruzioni si può avere una deriva, per questo +esiste la funzione \func{clock\_nanosleep} (vedi sez.~\ref{sec:sig_timer_adv}) +che permette di specificare un tempo assoluto anziché un tempo relativo. Chiaramente, anche se il tempo può essere specificato con risoluzioni fino al nanosecondo, la precisione di \func{nanosleep} è determinata dalla risoluzione @@ -1615,21 +1672,18 @@ precisione disponibile sull'hardware della propria macchina. Un semplice esempio per illustrare il funzionamento di un gestore di segnale è quello della gestione di \signal{SIGCHLD}. Abbiamo visto in sez.~\ref{sec:proc_termination} che una delle azioni eseguite dal kernel alla -conclusione di un processo è quella di inviare questo segnale al -padre.\footnote{in realtà in SVr4 eredita la semantica di System V, in cui il - segnale si chiama \signal{SIGCLD} e viene trattato in maniera speciale; in - System V infatti se si imposta esplicitamente l'azione a \const{SIG\_IGN} il - segnale non viene generato ed il sistema non genera \itindex{zombie} - \textit{zombie} (lo stato di terminazione viene scartato senza dover - chiamare una \func{wait}). L'azione predefinita è sempre quella di ignorare - il segnale, ma non attiva questo comportamento. Linux, come BSD e POSIX, non - supporta questa semantica ed usa il nome di \signal{SIGCLD} come sinonimo di - \signal{SIGCHLD}.} In generale dunque, quando non interessa elaborare lo -stato di uscita di un processo, si può completare la gestione della -terminazione installando un gestore per \signal{SIGCHLD} il cui unico compito -sia quello di chiamare \func{waitpid} per completare la procedura di -terminazione in modo da evitare la formazione di \itindex{zombie} -\textit{zombie}. +conclusione di un processo è quella di inviare questo segnale al padre. In +generale dunque, quando non interessa elaborare lo stato di uscita di un +processo, si può completare la gestione della terminazione installando un +gestore per \signal{SIGCHLD} il cui unico compito sia quello di chiamare +\func{waitpid} per completare la procedura di terminazione in modo da evitare +la formazione di \itindex{zombie} \textit{zombie}.\footnote{si ricordi + comunque che dal kernel 2.6 seguendo lo standard POSIX.1-2001 per evitare di + dover ricevere gli stati di uscita che non interessano basta impostare come + azione predefinita quella di ignorare \signal{SIGCHLD}, nel qual caso viene + assunta la semantica di System V, in cui il segnale non viene inviato, il + sistema non genera \itindex{zombie} \textit{zombie} e lo stato di + terminazione viene scartato senza dover chiamare una \func{wait}.} In fig.~\ref{fig:sig_sigchld_handl} è mostrato il codice contenente una implementazione generica di una funzione di gestione per \signal{SIGCHLD}, @@ -1650,13 +1704,14 @@ più la creazione di \itindex{zombie} \textit{zombie}. \label{fig:sig_sigchld_handl} \end{figure} -Il codice del gestore è di lettura immediata; come buona norma di +Il codice del gestore è di lettura immediata, come buona norma di programmazione (si ricordi quanto accennato sez.~\ref{sec:sys_errno}) si comincia (\texttt{\small 6--7}) con il salvare lo stato corrente di \var{errno}, in modo da poterlo ripristinare prima del ritorno del gestore (\texttt{\small 16--17}). In questo modo si preserva il valore della variabile visto dal corso di esecuzione principale del processo, che altrimenti sarebbe -sovrascritto dal valore restituito nella successiva chiamata di \func{waitpid}. +sovrascritto dal valore restituito nella successiva chiamata di +\func{waitpid}. Il compito principale del gestore è quello di ricevere lo stato di terminazione del processo, cosa che viene eseguita nel ciclo in @@ -1714,7 +1769,7 @@ questo può sembrare di implementazione immediata; ad esempio una semplice versione di \func{sleep} potrebbe essere quella illustrata in fig.~\ref{fig:sig_sleep_wrong}. -\begin{figure}[!htbp] +\begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{\codesamplewidth} \includecodesample{listati/sleep_danger.c} @@ -1751,7 +1806,7 @@ uscire dal gestore; in questo modo, con una condizione sullo stato di uscita di quest'ultima, si può evitare la chiamata a \func{pause}, usando un codice del tipo di quello riportato in fig.~\ref{fig:sig_sleep_incomplete}. -\begin{figure}[!htbp] +\begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{\codesamplewidth} \includecodesample{listati/sleep_defect.c} @@ -2071,8 +2126,8 @@ altre informazioni specifiche. \const{SI\_KERNEL} & Inviato dal kernel.\\ \const{SI\_QUEUE} & Inviato con \func{sigqueue} (vedi sez.~\ref{sec:sig_real_time}).\\ - \const{SI\_TIMER} & Scadenza di un POSIX timer - (vedi sez.~\ref{sec:sig_timer_adv}).\\ + \const{SI\_TIMER} & Scadenza di un\itindex{POSIX~Timer~API} \textit{POSIX + timer} (vedi sez.~\ref{sec:sig_timer_adv}).\\ \const{SI\_MESGQ} & Inviato al cambiamento di stato di una coda di messaggi POSIX (vedi sez.~\ref{sec:ipc_posix_mq}).\footnotemark\\ @@ -2162,21 +2217,22 @@ cui si sono appena citati i rispettivi segnali.\footnote{il prefisso del nome \label{tab:sig_si_code_special} \end{table} -Il resto della struttura \struct{siginfo\_t} è definito come \direct{union} ed i -valori eventualmente presenti dipendono dal segnale, così \signal{SIGCHLD} ed i -segnali \textit{real-time} (vedi sez.~\ref{sec:sig_real_time}) inviati tramite -\func{kill} avvalorano \var{si\_pid} e \var{si\_uid} coi valori corrispondenti -al processo che ha emesso il segnale, \signal{SIGCHLD} avvalora anche i campi -\var{si\_status}, \var{si\_utime} e \var{si\_stime} che indicano +Il resto della struttura \struct{siginfo\_t} è definito come \direct{union} ed +i valori eventualmente presenti dipendono dal segnale, così \signal{SIGCHLD} +ed i segnali \textit{real-time} (vedi sez.~\ref{sec:sig_real_time}) inviati +tramite \func{kill} avvalorano \var{si\_pid} e \var{si\_uid} coi valori +corrispondenti al processo che ha emesso il segnale, \signal{SIGCHLD} avvalora +anche i campi \var{si\_status}, \var{si\_utime} e \var{si\_stime} che indicano rispettivamente lo stato di uscita, l'\textit{user time} e il \textit{system time} (vedi sez.~\ref{sec:sys_cpu_times}) usati dal processo; -\signal{SIGILL}, \signal{SIGFPE}, \signal{SIGSEGV} e \signal{SIGBUS} avvalorano -\var{si\_addr} con l'indirizzo in cui è avvenuto l'errore, \signal{SIGIO} (vedi -sez.~\ref{sec:file_asyncronous_io}) avvalora \var{si\_fd} con il numero del -file descriptor e \var{si\_band} per i \itindex{out-of-band} dati urgenti -(vedi sez.~\ref{sec:TCP_urgent_data}) su un socket, il segnale inviato alla -scadenza di un timer POSIX (vedi sez.~\ref{sec:sig_timer_adv}) avvalora i -campi \var{si\_timerid} e \var{si\_overrun}. +\signal{SIGILL}, \signal{SIGFPE}, \signal{SIGSEGV} e \signal{SIGBUS} +avvalorano \var{si\_addr} con l'indirizzo in cui è avvenuto l'errore, +\signal{SIGIO} (vedi sez.~\ref{sec:file_asyncronous_io}) avvalora \var{si\_fd} +con il numero del file descriptor e \var{si\_band} per i \itindex{out-of-band} +dati urgenti (vedi sez.~\ref{sec:TCP_urgent_data}) su un socket, il segnale +inviato alla scadenza di un \itindex{POSIX~Timer~API} POSIX timer (vedi +sez.~\ref{sec:sig_timer_adv}) avvalora i campi \var{si\_timerid} e +\var{si\_overrun}. Benché sia possibile usare nello stesso programma sia \func{sigaction} che \func{signal} occorre molta attenzione, in quanto le due funzioni possono @@ -2624,11 +2680,12 @@ se usata nella forma \var{sival\_int}, o un indirizzo, se usata nella forma vari meccanismi di notifica\footnote{un campo di tipo \type{sigval\_t} è presente anche nella struttura \struct{sigevent} (definita in fig.~\ref{fig:struct_sigevent}) che viene usata dai meccanismi di notifica - come quelli per i timer POSIX (vedi sez.~\ref{sec:sig_timer_adv}), l'I/O - asincrono (vedi sez.~\ref{sec:file_asyncronous_io}) o le code di messaggi - POSIX (vedi sez.~\ref{sec:ipc_posix_mq}).} per restituire dati al gestore -del segnale; in alcune definizioni essa viene identificata anche con -l'abbreviazione \type{sigval\_t}. + come quelli per \itindex{POSIX~Timer~API} i timer POSIX (vedi + sez.~\ref{sec:sig_timer_adv}), l'I/O asincrono (vedi + sez.~\ref{sec:file_asyncronous_io}) o le code di messaggi POSIX (vedi + sez.~\ref{sec:ipc_posix_mq}).} per restituire dati al gestore del segnale; +in alcune definizioni essa viene identificata anche con l'abbreviazione +\type{sigval\_t}. A causa delle loro caratteristiche, la funzione \func{kill} non è adatta ad inviare segnali \textit{real-time}, poiché non è in grado di fornire alcun @@ -2780,6 +2837,9 @@ riceverlo fra due chiamate successive. \subsection{La gestione avanzata delle temporizzazioni} \label{sec:sig_timer_adv} +% TODO: indicizzare i termini \itindex{POSIX~Timer~API} e HRT + + Sia le funzioni per la gestione dei tempi viste in sez.~\ref{sec:sys_cpu_times} che quelle per la gestione dei timer di sez.~\ref{sec:sig_alarm_abort} sono state a lungo limitate dalla risoluzione @@ -2810,10 +2870,10 @@ tempo da esse dedicato all'esecuzione di un processo. Per usare queste funzionalità ed ottenere risoluzioni temporali più accurate, occorre però un opportuno supporto da parte del kernel, ed i cosiddetti -\itindex{high~resolution~timer} \textit{high resolution timer} che consentono -di fare ciò sono stati introdotti nel kernel ufficiale solo a partire dalla -versione 2.6.21.\footnote{deve essere stata abilitata l'opzione di - compilazione \texttt{CONFIG\_HIGH\_RES\_TIMERS}, erano però disponibili +\itindex{High~Resolution~Timer~(HRT)} \textit{high resolution timer} che +consentono di fare ciò sono stati introdotti nel kernel ufficiale solo a +partire dalla versione 2.6.21.\footnote{deve essere stata abilitata l'opzione + di compilazione \texttt{CONFIG\_HIGH\_RES\_TIMERS}, erano però disponibili anche in precedenza come patch facenti parte dello sviluppo delle estensioni \textit{real-time} del kernel, per cui alcune distribuzioni possono avere questo supporto anche con versioni precedenti del kernel.} Le funzioni @@ -3072,7 +3132,7 @@ da BSD presenti delle serie limitazioni,\footnote{in particolare la possibilità di perdere un segnale sotto carico.} tanto che nello standard POSIX.1-2008 questa viene marcata come obsoleta, e ne viene fortemente consigliata la sostituzione con nuova interfaccia definita dallo standard -POSIX.1-2001 che va sotto il nome di \textit{Posix Timer API}. Questa +POSIX.1-2001 che va sotto il nome di \textit{POSIX Timer API}. Questa interfaccia è stata introdotta a partire dal kernel 2.6, anche se il supporto di varie funzionalità è stato aggiunto solo in un secondo tempo. @@ -3641,4 +3701,4 @@ parte l'uso di \type{sigjmp\_buf} per \param{env}, è assolutamente identica a %%% mode: latex %%% TeX-master: "gapil" %%% End: -% LocalWords: pwait msgrcv msgsnd semop semtimedop +% LocalWords: pwait msgrcv msgsnd semop semtimedop runnable diff --git a/system.tex b/system.tex index ac81bc7..bc4d8fb 100644 --- a/system.tex +++ b/system.tex @@ -2176,9 +2176,10 @@ maniera indipendente usando la costante del kernel \const{USER\_HZ}. Fino al kernel 2.6.21 la durata di un \textit{jiffy} costituiva la risoluzione massima ottenibile nella misura dei tempi impiegabile in una \textit{system call} (ad esempio per i timeout). Con il 2.6.21 e l'introduzione degli -\textit{high-resolution timers} (HRT) è divenuto possibile ottenere, per le -funzioni di attesa ed i timer, la massima risoluzione possibile fornita -dall'hardware. Torneremo su questo in sez.~\ref{sec:sig_timer_adv}. +\index{High~Resolution~Timer~(HRT)} \textit{high-resolution timers} (HRT) è +divenuto possibile ottenere, per le funzioni di attesa ed i timer, la massima +risoluzione possibile fornita dall'hardware. Torneremo su questo in +sez.~\ref{sec:sig_timer_adv}.