X-Git-Url: https://gapil.gnulinux.it/gitweb/?a=blobdiff_plain;f=signal.tex;h=177555d272f2a7d13a1e15019b3969916185d886;hb=0bcf5c7d8d90342067fe6cb28045993bf6c7f207;hp=83f35f1503098d93ff4ac8d86046085b31c450a6;hpb=a16489a1d394096d615743b3be598c47b994ef52;p=gapil.git diff --git a/signal.tex b/signal.tex index 83f35f1..177555d 100644 --- a/signal.tex +++ b/signal.tex @@ -865,6 +865,9 @@ sez.~\ref{sec:sig_sigaction}). interruzione nel mezzo di un trasferimento parziale di dati, le system call ritornano sempre indicando i byte trasferiti. +% TODO: alcune syscall danno EINTR anche se il segnale è installato con +% SA_RESTART, vedi signal(7) + \subsection{La funzione \func{signal}} \label{sec:sig_signal} @@ -1988,7 +1991,9 @@ rispettivamente lo stato di uscita, l'\textit{user time} e il \textit{system \var{si\_addr} con l'indirizzo in cui è avvenuto l'errore, \const{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. +(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}. Benché sia possibile usare nello stesso programma sia \func{sigaction} che \func{signal} occorre molta attenzione, in quanto le due funzioni possono @@ -2668,6 +2673,9 @@ sostituito dalla risorsa \const{RLIMIT\_SIGPENDING} associata al singolo utente, che può essere modificata con \func{setrlimit} come illustrato in sez.~\ref{sec:sys_resource_limit}. +% TODO: spostare insieme a signalfd e affini, meccanismo di notifica sincrona +% dei segnali (da capire se è il caso di farlo) + 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 \itindex{thread} \textit{thread}, in cui si possono usare i @@ -2717,7 +2725,7 @@ prevalentemente con i \itindex{thread} \textit{thread}; \funcd{sigwaitinfo} e segnale in \param{info}. \funcdecl{int sigtimedwait(const sigset\_t *set, siginfo\_t *info, const - struct timespec *timout)} + struct timespec *timeout)} Analoga a \func{sigwaitinfo}, con un la possibilità di specificare un timeout in \param{timeout}. @@ -2865,7 +2873,7 @@ tab.~\ref{tab:sig_timer_clockid_types}. Per poter utilizzare queste funzionalità le \acr{glibc} richiedono che la macro \macro{\_POSIX\_C\_SOURCE} sia definita ad un valore maggiore o uguale di \texttt{199309L} (vedi sez.~\ref{sec:intro_gcc_glibc_std}), inoltre i -programmi che le usano devono essere linkati con la libreria delle estensioni +programmi che le usano devono essere collegati con la libreria delle estensioni \textit{real-time} usando esplicitamente l'opzione \texttt{-lrt}. Si tenga presente inoltre che la disponibilità di queste funzionalità avanzate può essere controllato dalla definizione della macro \macro{\_POSIX\_TIMERS} ad un @@ -2874,10 +2882,10 @@ valore maggiore di 0, e che le ulteriori macro \macro{\_POSIX\_THREAD\_CPUTIME} indicano la presenza dei rispettivi orologi di tipo \const{CLOCK\_MONOTONIC}, \const{CLOCK\_PROCESS\_CPUTIME\_ID} e \const{CLOCK\_PROCESS\_CPUTIME\_ID}.\footnote{tutte queste macro sono definite - in \texttt{unistd.h}, che peranto deve essere incluso per poterle + in \texttt{unistd.h}, che pertanto deve essere incluso per poterle controllarle.} Infine se il kernel ha il supporto per gli \textit{high resolution timer} un elenco degli orologi e dei timer può essere ottenuto -tremite il file \procfile{/proc/timer\_list}. +tramite il file \procfile{/proc/timer\_list}. Le due funzioni che ci consentono rispettivamente di modificare o leggere il valore per uno degli orologi \textit{real-time} sono \funcd{clock\_settime} e @@ -2909,7 +2917,7 @@ tab.~\ref{tab:sig_timer_clockid_types} o con il risultato di una chiamata a \func{clock\_getcpuclockid} (che tratteremo a breve), il secondo argomento invece è sempre il puntatore \param{tp} ad una struttura \struct{timespec} (vedi fig.~\ref{fig:sys_timespec_struct}) che deve essere stata -precedentemente allocata; nel primo caso questa devrà anche essere stata +precedentemente allocata; nel primo caso questa dovrà anche essere stata inizializzata con il valore che si vuole impostare sull'orologio, mentre nel secondo verrà restituito al suo interno il valore corrente dello stesso. @@ -2946,7 +2954,7 @@ orologio, la funzione } \end{functions} -La funzione richiede come primo argomento l'indicazione dell' orologio di cui +La funzione richiede come primo argomento l'indicazione dell'orologio di cui si vuole conoscere la risoluzione (effettuata allo stesso modo delle due precedenti) e questa verrà restituita in una struttura \struct{timespec} all'indirizzo puntato dall'argomento \param{res}. @@ -3089,7 +3097,7 @@ introduce una struttura di uso generale, \struct{sigevent}, che viene utilizzata anche da altre funzioni, come quelle per l'I/O asincrono (vedi sez.~\ref{sec:file_asyncronous_io}) o le code di messaggi POSIX (vedi sez.~\ref{sec:ipc_posix_mq})) e che serve ad indicare in maniera generica un -meccanimo di notifica. +meccanismo di notifica. \begin{figure}[!htb] \footnotesize \centering @@ -3105,11 +3113,11 @@ meccanimo di notifica. La struttura \struct{sigevent} (accessibile includendo \texttt{time.h}) è riportata in fig.~\ref{fig:struct_sigevent};\footnote{la definizione effettiva dipende dall'implementazione, quella mostrata è la versione descritta nella - pagina di manule di \func{timer\_create}.} il campo \var{sigev\_notify} è il + pagina di manuale di \func{timer\_create}.} il campo \var{sigev\_notify} è il più importante essendo quello che indica le modalità della notifica, gli altri dipendono dal valore che si è specificato per \var{sigev\_notify}, si sono riportati in tab.~\ref{tab:sigevent_sigev_notify}. La scelta del meccanismo di -nnotifica viene fatta impostando uno dei valori di +notifica viene fatta impostando uno dei valori di tab.~\ref{tab:sigevent_sigev_notify} per \var{sigev\_notify}, e fornendo gli eventuali ulteriori argomenti necessari a secondo della scelta effettuata. Diventa così possibile indicare l'uso di un segnale o l'esecuzione @@ -3165,7 +3173,6 @@ utilizzato un valore equivalente all'aver specificato \const{SIGEV\_SIGNAL} per \var{sigev\_notify}, \const{SIGALRM} per \var{sigev\_signo} e l'identificatore del timer come valore per \var{sigev\_value.sival\_int}. - Il terzo argomento deve essere l'indirizzo di una variabile di tipo \type{timer\_t} dove sarà scritto l'identificativo associato al timer appena creato, da usare in tutte le successive funzioni di gestione. Una volta creato @@ -3180,11 +3187,11 @@ segnale \textit{real-time} per ciascun timer che viene creato con \func{timer\_create}; dato che ciascuno di essi richiede un posto nella coda dei segnali \textit{real-time}, il numero massimo di timer utilizzabili da un processo è limitato dalle dimensioni di detta coda, ed anche, qualora questo -sia stato impostato, dal limite \const{RLIMIT\_SIGPENDING} +sia stato impostato, dal limite \const{RLIMIT\_SIGPENDING}. Una volta creato il timer \func{timer\_create} ed ottenuto il relativo identificatore, si può attivare o disattivare un allarme (in gergo -\textsl{armare} o \textsl{disarmare} il timer) con la fuzione +\textsl{armare} o \textsl{disarmare} il timer) con la funzione \funcd{timer\_settime}, il cui prototipo è: \begin{functions} \headdecl{signal.h} @@ -3195,8 +3202,7 @@ identificatore, si pu Arma o disarma il timer POSIX. - \bodydesc{La funzione restituisce 0 in caso di successo e $-1$ - in caso di errore, nel qual caso \var{errno} assumerà + \bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno dei seguenti valori: \begin{errlist} \item[\errcode{EINVAL}] all'interno di \param{new\_value.value} si è @@ -3208,11 +3214,13 @@ identificatore, si pu } \end{functions} -La funzione richiede che si indici la scadenza del timer con +La funzione richiede che si indichi la scadenza del timer con l'argomento \param{new\_value}, che deve essere specificato come puntatore ad una struttura di tipo \struct{itimerspec}, la cui definizione è riportata in -fig.~\ref{fig:struct_itimerspec}, se \param{old\_value} è diverso da -\val{NULL} il precedente valore verrà restituito in questa struttura. +fig.~\ref{fig:struct_itimerspec}; se il puntatore \param{old\_value} è diverso +da \val{NULL} il valore corrente della scadenza verrà restituito in una +analoga struttura, ovviamente in entrambi i casi le strutture devono essere +state allocate. \begin{figure}[!htb] \footnotesize \centering @@ -3227,40 +3235,181 @@ fig.~\ref{fig:struct_itimerspec}, se \param{old\_value} Ciascuno dei due campi di \struct{itimerspec} indica un tempo, da specificare con una precisione fino al nanosecondo tramite una struttura \struct{timespec} -(la cui definizione è riportata fig.~\ref{fig:sys_timespec_struct})). Il campo +(la cui definizione è riportata fig.~\ref{fig:sys_timespec_struct}). Il campo \var{it\_value} indica la prima scadenza dell'allarme. Di default, quando il -valore di \param{flag} è nullo, questo valore viene considerato come un +valore di \param{flags} è nullo, questo valore viene considerato come un intervallo relativo al tempo corrente,\footnote{il primo allarme scatterà cioè dopo il numero di secondi e nanosecondi indicati da questo campo.} se invece -si usa per \param{flag} il valore \const{TIMER\_ABSTIME}, \var{it\_value} -viene considerato come valore assoluto rispetto al valore dell'orologio a cui -è associato il timer.\footnote{quindi a seconda dell'orologio che si usa, si - può indicare sia un tempo assoluto, se si opera rispetto all'orologio di +si usa per \param{flags} il valore \const{TIMER\_ABSTIME},\footnote{al momento + questo è l'unico valore valido per \param{flags}.} \var{it\_value} viene +considerato come un valore assoluto rispetto al valore usato dall'orologio a +cui è associato il timer.\footnote{quindi a seconda dei casi lo si potrà + indicare o come un tempo assoluto, quando si opera rispetto all'orologio di sistema (nel qual caso il valore deve essere in secondi e nanosecondi dalla - \textit{epoch}) o come un certo numero di secondi o nanosecondi rispetto - alla partenza di un orologio di CPU, } + \textit{epoch}) o come numero di secondi o nanosecondi rispetto alla + partenza di un orologio di CPU, quando si opera su uno di questi.} Infine +un valore nullo di \var{it\_value}\footnote{per nullo si intende con valori + nulli per entrambi i i campi \var{tv\_sec} e \var{tv\_nsec}.} può essere +utilizzato, indipendentemente dal tipo di orologio utilizzato, per disarmare +l'allarme. + +Il campo \var{it\_interval} di \struct{itimerspec} viene invece utilizzato per +impostare un allarme periodico. Se il suo valore è nullo (se cioè sono nulli +tutti e due i valori di detta struttura \struct{timespec}) l'allarme scatterà +una sola volta secondo quando indicato con \var{it\_value}, altrimenti il +valore specificato verrà preso come l'estensione del periodo di ripetizione +della generazione dell'allarme, che proseguirà indefinitamente fintanto che +non si disarmi il timer. + +Se il timer era già stato armato la funzione sovrascrive la precedente +impostazione, se invece si indica come prima scadenza un tempo già passato, +l'allarme verrà notificato immediatamente e al contempo verrà incrementato il +contatore dei superamenti. Questo contatore serve a fornire una indicazione al +programma che riceve l'allarme su un eventuale numero di scadenze che sono +passate prima della ricezione della notifica dell'allarme. + +É infatti possibile, qualunque sia il meccanismo di notifica scelto, che +quest'ultima venga ricevuta dopo che il timer è scaduto più di una +volta.\footnote{specialmente se si imposta un timer con una ripetizione a + frequenza elevata.} Nel caso dell'uso di un segnale infatti il sistema mette +in coda un solo segnale per timer,\footnote{questo indipendentemente che si + tratti di un segnale ordinario o \textit{real-time}; per questi ultimi + sarebbe anche possibile inviare un segnale per ogni scadenza, questo però + non viene fatto per evitare il rischio, tutt'altro che remoto, di riempire + la coda.} e se il sistema è sotto carico o se il segnale è bloccato, prima +della sua ricezione può passare un intervallo di tempo sufficientemente lungo +ad avere scadenze multiple, e lo stesso può accadere anche se si usa un +\textit{thread} di notifica. + +Per questo motivo il gestore del segnale o il \textit{thread} di notifica può +ottenere una indicazione di quante volte il timer è scaduto dall'invio della +notifica utilizzando la funzione \funcd{timer\_getoverrun}, il cui prototipo è: +\begin{functions} + \headdecl{time.h} -Se il valore di \var{it\_interval} è nullo (se cioè sono nulli tutti e due i -valori di detta struttura \struct{timespec}) l'allarme scatterà - + \funcdecl{int timer\_getoverrun(timer\_t timerid)} + + Ottiene il numero di scadenze di un timer POSIX. + + \bodydesc{La funzione restituisce il numero di scadenze di un timer in caso + di successo e $-1$ in caso di errore, nel qual caso \var{errno} assumerà + il valore: + \begin{errlist} + \item[\errcode{EINVAL}] \param{timerid} non indica un timer valido. + \end{errlist} +} +\end{functions} + +La funzione ritorna il numero delle scadenze avvenute, che può anche essere +nullo se non ve ne sono state. Come estensione specifica di Linux,\footnote{in + realtà lo standard POSIX.1-2001 prevede gli \textit{overrun} solo per i + segnali e non ne parla affatto in riferimento ai \textit{thread}.} quando +si usa un segnale come meccanismo di notifica, si può ottenere direttamente +questo valore nel campo \var{si\_overrun} della struttura \struct{siginfo\_t} +(illustrata in fig.~\ref{fig:sig_siginfo_t}) restituita al gestore del segnale +installato con \func{sigaction}; in questo modo non è più necessario eseguire +successivamente una chiamata a questa funzione per ottenere il numero delle +scadenze. Al gestore del segnale viene anche restituito, come ulteriore +informazione, l'identificativo del timer, in questo caso nel campo +\var{si\_timerid}. + +Qualora si voglia rileggere lo stato corrente di un timer, ed ottenere il +tempo mancante ad una sua eventuale scadenza, si deve utilizzare la funzione +\funcd{timer\_gettime}, il cui prototipo è: +\begin{functions} + \headdecl{time.h} + + \funcdecl{int timer\_gettime(timer\_t timerid, int flags, struct + itimerspec *curr\_value)} + + Legge lo stato di un timer POSIX. + + \bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di + errore, nel qual caso \var{errno} assumerà uno dei seguenti valori: + \begin{errlist} + \item[\errcode{EINVAL}] \param{timerid} non indica un timer valido. + \item[\errcode{EFAULT}] si è specificato un indirizzo non valido + per \param{curr\_value}. + \end{errlist} +} +\end{functions} + +La funzione restituisce nella struttura \struct{itimerspec} puntata +da \param{curr\_value} il tempo restante alla prossima scadenza nel campo +\var{it\_value}. Questo tempo viene sempre indicato in forma relativa, anche +nei casi in cui il timer era stato precedentemente impostato con +\const{TIMER\_ABSTIME} indicando un tempo assoluto. Il ritorno di un valore +nullo nel campo \var{it\_value} significa che il timer è disarmato o è +definitivamente scaduto. + +Nel campo \var{it\_interval} di \param{curr\_value} viene invece restituito, +se questo era stato impostato, il periodo di ripetizione del timer. Anche in +questo caso il ritorno di un valore nullo significa che il timer non era stato +impostato per una ripetizione e doveva operare, come suol dirsi, a colpo +singolo (in gergo \textit{one shot}). + +Infine, quando un timer non viene più utilizzato, lo si può cancellare, +rimuovendolo dal sistema e recuperando le relative risorse, effettuando in +sostanza l'operazione inversa rispetto a \funcd{timer\_create}. Per questo +compito lo standard prevede una apposita funzione \funcd{timer\_delete}, il +cui prototipo è: +\begin{functions} + \headdecl{time.h} + + \funcdecl{int timer\_delete(timer\_t timerid)} + + Cancella un timer POSIX. + + \bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di + errore, nel qual caso \var{errno} assumerà uno dei seguenti valori: + \begin{errlist} + \item[\errcode{EINVAL}] \param{timerid} non indica un timer valido. + \end{errlist} +} +\end{functions} + +La funzione elimina il timer identificato da \param{timerid}, disarmandolo se +questo era stato attivato. Nel caso, poco probabile ma comunque possibile, che +un timer venga cancellato prima della ricezione del segnale pendente per la +notifica di una scadenza, il comportamento del sistema è indefinito. -% TODO trattare i Posix timer, e le fuzioni: -% timer_getoverrun, timer_gettime, timer_settime, timer_create, timer_delete \subsection{Le interfacce per la notifica attraverso i file descriptor} \label{sec:sig_signalfd_eventfd} I segnali sono uno dei meccanismi classici, presenti da sempre nei sistemi -unix-like, per effettuare notifiche ai processi, la loro interfaccia però si è -dimostrata quasi subito poco azzeccata, in particolare per i problemi che si -vengono a creare con le funzioni di gestione dell'I/O multiplexing (vedi -sez.~\ref{sec:file_multiplexing}).\footnote{i temi trattati in questa sezione - presuppongono la conoscenza dell'I/O multiplexing si consiglia pertanto una - lettura di sez.~\ref{sec:file_multiplexing} qualora non si conosca - l'argomento. } Per questo motivo nello sviluppo del kernel si è pensato di -introdurre un meccanismo alternativo per la notifica dei segnali (ed anche di -eventi generici) basato direttamente sull'uso di file descriptor. +unix-like, per effettuare notifiche ai processi, la loro interfaccia però, +richiedendo l'esecuzione asincrona di una funzione di gestione al di fuori del +flusso di esecuzione principale del processo, si è dimostrata quasi subito +assai problematica. + +Oltre ai limiti relativi a cosa si può fare nel gestore di segnali (quelli +illustrati in sez.~\ref{sec:sig_signal_handler}), ed ai problemi relativi alla +interruzione delle system call bloccanti, c'è un problema più generale +consistente nel fatto che questa modalità di funzionamento cozza con le +interfacce di programmazione sincrona, in cui ci si aspetta che ci sia un solo +processo che gestisce gli eventi e genera delle risposte, mentre con l'arrivo +di un segnale ci si trova alla possibilità di interruzioni asincrone da +gestire e nella necessità di evitare \textit{race conditions}. + +In particolare, come vedremo in sez.~\ref{sec:file_select}, i segnali hanno +una pessima interazione con le funzioni di gestione dell'I/O multiplexing, che +costituiscono un meccanismo efficiente per gestire in maniera sincrona +l'accesso a più file o socket in cui il processo si blocca fintanto che non ci +sono dati da leggere o scrivere.\footnote{per la trattazione dettagliata del + significato e dei vantaggi dell'I/O multiplexing si rimanda a + sez.~\ref{sec:file_multiplexing}.} + +Abbiamo visto in sez.~\ref{sec:sig_real_time} che con i segnali +\textit{real-time} sono state introdotte delle interfacce di gestione sincrona +dei segnali con \func{sigwait} e affini, che consentono di gestire i segnali +in modalità sincrona, bloccando un processo fino alla ricezione di un segnale +(e disabilitando l'esecuzione asincrona di un gestore). Questo però non +risolve i problemi di interazioni con le funzioni I/O multiplexing per cui +nello sviluppo del kernel si è pensato di introdurre un meccanismo alternativo +per la notifica dei segnali (ed anche di eventi generici) basato direttamente +sull'uso di file descriptor. @@ -3326,6 +3475,9 @@ eventi generici) basato direttamente sull'uso di file descriptor. % LocalWords: openat readlinkat renameat symlinkat unlinkat utimensat utimes % LocalWords: LinuxThread NTPL Library clockid evp timerid sigev notify high % LocalWords: resolution CONFIG RES patch REALTIME MONOTONIC RAW NTP CPUTIME +% LocalWords: tick calendar The Epoch list getcpuclockid capability CAP getres +% LocalWords: ENOSYS pthread ENOENT NULL attribute itimerspec new old ABSTIME +% LocalWords: epoch multiplexing overrun %%% Local Variables: