\begin{figure}[!htb]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
+ \begin{minipage}[c]{15.6cm}
\includecodesample{listati/my_ls.c}
\end{minipage}
\caption{Esempio di codice per eseguire la lista dei file contenuti in una
\begin{figure}[!htb]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
+ \begin{minipage}[c]{15.6cm}
\includecodesample{listati/DirScan.c}
\end{minipage}
\caption{Codice della routine di scansione di una directory contenuta nel
\newcommand{\includecodesnip}[1]{\lstinputlisting[stepnumber=0,frame=]{#1}}{}
\newcommand{\includestruct}[1]{\lstinputlisting[stepnumber=0]{#1}}{}
\newcommand{\includecodesample}[1]{\lstinputlisting{#1}}{}
-
\usepackage{cite}
\usepackage{amsmath}
\usepackage{amsfonts}
--- /dev/null
+typedef void SigFunc(int);
+inline SigFunc * Signal(int signo, SigFunc *func)
+{
+ struct sigaction new_handl, old_handl;
+ new_handl.sa_handler = func;
+ /* clear signal mask: no signal blocked during execution of func */
+ if (sigemptyset(&new_handl.sa_mask)!=0){ /* initialize signal set */
+ return SIG_ERR;
+ }
+ new_handl.sa_flags=0; /* init to 0 all flags */
+ /* change action for signo signal */
+ if (sigaction(signo, &new_handl, &old_handl)){
+ return SIG_ERR;
+ }
+ return (old_handl.sa_handler);
+}
--- /dev/null
+unsigned int alarm(unsigned int seconds)
+{
+ struct itimerval old, new;
+ new.it_interval.tv_usec = 0;
+ new.it_interval.tv_sec = 0;
+ new.it_value.tv_usec = 0;
+ new.it_value.tv_sec = (long int) seconds;
+ if (setitimer(ITIMER_REAL, &new, &old) < 0) {
+ return 0;
+ }
+ else {
+ return old.it_value.tv_sec;
+ }
+}
--- /dev/null
+void HandSigCHLD(int sig)
+{
+ int errno_save;
+ int status;
+ pid_t pid;
+ /* save errno current value */
+ errno_save = errno;
+ /* loop until no */
+ do {
+ errno = 0;
+ pid = waitpid(WAIT_ANY, &status, WNOHANG);
+ if (pid > 0) {
+ debug("child %d terminated with status %x\n", pid, status);
+ }
+ } while ((pid > 0) && (errno == EINTR));
+ /* restore errno value */
+ errno = errno_save;
+ /* return */
+ return;
+}
--- /dev/null
+sig_atomic_t flag;
+int main()
+{
+ flag = 0;
+ ...
+ if (flag) { /* test if signal occurred */
+ flag = 0; /* reset flag */
+ do_response(); /* do things */
+ } else {
+ do_other(); /* do other things */
+ }
+ ...
+}
+void alarm_hand(int sig)
+{
+ /* set the flag */
+ flag = 1;
+ return;
+}
--- /dev/null
+struct sigaction
+{
+ void (*sa_handler)(int);
+ void (*sa_sigaction)(int, siginfo_t *, void *);
+ sigset_t sa_mask;
+ int sa_flags;
+ void (*sa_restorer)(void);
+}
--- /dev/null
+siginfo_t {
+ int si_signo; /* Signal number */
+ int si_errno; /* An errno value */
+ int si_code; /* Signal code */
+ pid_t si_pid; /* Sending process ID */
+ uid_t si_uid; /* Real user ID of sending process */
+ int si_status; /* Exit value or signal */
+ clock_t si_utime; /* User time consumed */
+ clock_t si_stime; /* System time consumed */
+ sigval_t si_value; /* Signal value */
+ int si_int; /* POSIX.1b signal */
+ void * si_ptr; /* POSIX.1b signal */
+ void * si_addr; /* Memory location which caused fault */
+ int si_band; /* Band event */
+ int si_fd; /* File descriptor */
+}
--- /dev/null
+union sigval_t {
+ int sival_int;
+ void *sival_ptr;
+}
--- /dev/null
+void alarm_hand(int);
+unsigned int sleep(unsigned int seconds)
+{
+ struct sigaction new_action, old_action;
+ sigset_t old_mask, stop_mask, sleep_mask;
+ /* set the signal handler */
+ sigemptyset(&new_action.sa_mask); /* no signal blocked */
+ new_action.sa_handler = alarm_hand; /* set handler */
+ new_action.sa_flags = 0; /* no flags */
+ sigaction(SIGALRM, &new_action, &old_action); /* install action */
+ /* block SIGALRM to avoid race conditions */
+ sigemptyset(&stop_mask); /* init mask to empty */
+ sigaddset(&stop_mask, SIGALRM); /* add SIGALRM */
+ sigprocmask(SIG_BLOCK, &stop_mask, &old_mask); /* add SIGALRM to blocked */
+ /* send the alarm */
+ alarm(seconds);
+ /* going to sleep enabling SIGALRM */
+ sleep_mask = old_mask; /* take mask */
+ sigdelset(&sleep_mask, SIGALRM); /* remove SIGALRM */
+ sigsuspend(&sleep_mask); /* go to sleep */
+ /* restore previous settings */
+ sigprocmask(SIG_SETMASK, &old_mask, NULL); /* reset signal mask */
+ sigaction(SIGALRM, &old_action, NULL); /* reset signal action */
+ /* return remaining time */
+ return alarm(0);
+}
+void alarm_hand(int sig)
+{
+ return; /* just return to interrupt sigsuspend */
+}
--- /dev/null
+void alarm_hand(int sig) {
+ /* check if the signal is the right one */
+ if (sig != SIGALRM) { /* if not exit with error */
+ printf("Something wrong, handler for SIGALRM\n");
+ exit(1);
+ } else { /* do nothing, just interrupt pause */
+ return;
+ }
+}
+unsigned int sleep(unsigned int seconds)
+{
+ sighandler_t prev_handler;
+ /* install and check new handler */
+ if ((prev_handler = signal(SIGALRM, alarm_hand)) == SIG_ERR) {
+ printf("Cannot set handler for alarm\n");
+ exit(-1);
+ }
+ /* set alarm and go to sleep */
+ alarm(seconds);
+ pause();
+ /* restore previous signal handler */
+ signal(SIGALRM, prev_handler);
+ /* return remaining time */
+ return alarm(0);
+}
--- /dev/null
+static jmp_buff alarm_return;
+unsigned int sleep(unsigned int seconds)
+{
+ signandler_t prev_handler;
+ if ((prev_handler = signal(SIGALRM, alarm_hand)) == SIG_ERR) {
+ printf("Cannot set handler for alarm\n");
+ exit(1);
+ }
+ if (setjmp(alarm_return) == 0) { /* if not returning from handler */
+ alarm(second); /* call alarm */
+ pause(); /* then wait */
+ }
+ /* restore previous signal handler */
+ signal(SIGALRM, prev_handler);
+ /* remove alarm, return remaining time */
+ return alarm(0);
+}
+void alarm_hand(int sig)
+{
+ /* check if the signal is the right one */
+ if (sig != SIGALRM) { /* if not exit with error */
+ printf("Something wrong, handler for SIGALRM\n");
+ exit(1);
+ } else { /* return in main after the call to pause */
+ longjump(alarm_return, 1);
+ }
+}
--- /dev/null
+typedef struct {
+ void *ss_sp; /* Base address of stack */
+ int ss_flags; /* Flags */
+ size_t ss_size; /* Number of bytes in stack */
+} stack_t;
\begin{figure}[htb]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
+ \begin{minipage}[c]{15.6cm}
\includecodesample{listati/option_code.c}
\end{minipage}
\normalsize
\begin{figure}[htb]
\centering
- \includegraphics[width=15cm]{img/exec_rel}
+ \includegraphics[width=16cm]{img/exec_rel}
\caption{La interrelazione fra le sei funzioni della famiglia \func{exec}.}
\label{fig:proc_exec_relat}
\end{figure}
\label{sec:proc_setgroups}
Le ultime funzioni che esamineremo sono quelle che permettono di operare sui
-gruppi supplementari. Ogni processo può avere fino a \const{NGROUPS\_MAX}
-gruppi supplementari in aggiunta al gruppo primario, questi vengono ereditati
-dal processo padre e possono essere cambiati con queste funzioni.
-
-La funzione che permette di leggere i gruppi supplementari è
-\funcd{getgroups}; questa funzione è definita nello standard POSIX ed il suo
-prototipo è:
+gruppi supplementari cui un utente può appartenere. Ogni processo può avere
+almeno \const{NGROUPS\_MAX} gruppi supplementari\footnote{il numero massimo di
+ gruppi secondari può essere ottenuto con \func{sysconf} (vedi
+ \secref{sec:sys_sysconf}), leggendo il parametro
+ \texttt{\_SC\_NGROUPS\_MAX}.} in aggiunta al gruppo primario; questi vengono
+ereditati dal processo padre e possono essere cambiati con queste funzioni.
+
+La funzione che permette di leggere i gruppi supplementari associati ad un
+processo è \funcd{getgroups}; questa funzione è definita nello standard
+POSIX.1, ed il suo prototipo è:
\begin{functions}
\headdecl{sys/types.h}
\headdecl{unistd.h}
\item[\errcode{EINVAL}] il valore di \param{policy} non esiste o il
relativo valore di \param{p} non è valido.
\item[\errcode{EPERM}] il processo non ha i privilegi per attivare la
- politica richiesta (vale solo per \const{SCHED\_FIFO} e
- \const{SCHED\_RR}).
+ politica richiesta.
\end{errlist}}
\end{prototype}
La funzione esegue l'impostazione per il processo specificato dall'argomento
\param{pid}; un valore nullo esegue l'impostazione per il processo corrente.
-Solo un processo con i privilegi di amministratore può impostare delle
-priorità assolute diverse da zero. La politica di scheduling è specificata
-dall'argomento \param{policy} i cui possibili valori sono riportati in
-\tabref{tab:proc_sched_policy}; un valore negativo per \param{policy} mantiene
-la politica di scheduling corrente.
+La politica di scheduling è specificata dall'argomento \param{policy} i cui
+possibili valori sono riportati in \tabref{tab:proc_sched_policy}; un valore
+negativo per \param{policy} mantiene la politica di scheduling corrente.
+Solo un processo con i privilegi di amministratore può impostare priorità
+assolute diverse da zero o politiche \const{SCHED\_FIFO} e \const{SCHED\_RR}.
\begin{table}[htb]
\centering
massimo ed uno minimo, che nel caso sono rispettivamente 1 e 99 (il valore
zero è legale, ma indica i processi normali).
-\begin{figure}[!htb]
+\begin{figure}[!bht]
\footnotesize \centering
\begin{minipage}[c]{15cm}
\includestruct{listati/sched_param.c}
\bodydesc{La funzioni ritornano il valore della priorità in caso di successo
e -1 in caso di errore, nel qual caso \var{errno} può assumere i valori:
\begin{errlist}
- \item[\errcode{EINVAL}] il valore di \param{policy} è invalido.
+ \item[\errcode{EINVAL}] il valore di \param{policy} non è valido.
\end{errlist}}
\end{functions}
\funcdecl{int sched\_setparam(pid\_t pid, const struct sched\_param *p)}
Imposta la priorità assoluta del processo \param{pid}.
-
\funcdecl{int sched\_getparam(pid\_t pid, struct sched\_param *p)}
Legge la priorità assoluta del processo \param{pid}.
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}[stepnumber=0]{}
-unsigned int alarm(unsigned int seconds)
-{
- struct itimerval old, new;
- new.it_interval.tv_usec = 0;
- new.it_interval.tv_sec = 0;
- new.it_value.tv_usec = 0;
- new.it_value.tv_sec = (long int) seconds;
- if (setitimer(ITIMER_REAL, &new, &old) < 0) {
- return 0;
- }
- else {
- return old.it_value.tv_sec;
- }
-}
- \end{lstlisting}
+ \includestruct{listati/alarm_def.c}
\end{minipage}
\normalsize
\caption{Definizione di \func{alarm} in termini di \func{setitimer}.}
% gestore per che è previsto ritornare,
\begin{figure}[!htb]
- \footnotesize
- \begin{lstlisting}{}
-void HandSigCHLD(int sig)
-{
- int errno_save;
- int status;
- pid_t pid;
- /* save errno current value */
- errno_save = errno;
- /* loop until no */
- do {
- errno = 0;
- pid = waitpid(WAIT_ANY, &status, WNOHANG);
- if (pid > 0) {
- debug("child %d terminated with status %x\n", pid, status);
- }
- } while ((pid > 0) && (errno == EINTR));
- /* restore errno value */
- errno = errno_save;
- /* return */
- return;
-}
- \end{lstlisting}
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \includecodesample{listati/hand_sigchild.c}
+ \end{minipage}
\normalsize
\caption{Codice di una funzione generica di gestione per il segnale
\texttt{SIGCHLD}.}
l'interruzione di \func{pause} venisse causata da un altro segnale.
\begin{figure}[!htb]
- \footnotesize
- \begin{lstlisting}{}
-void alarm_hand(int sig) {
- /* check if the signal is the right one */
- if (sig != SIGALRM) { /* if not exit with error */
- printf("Something wrong, handler for SIGALRM\n");
- exit(1);
- } else { /* do nothing, just interrupt pause */
- return;
- }
-}
-unsigned int sleep(unsigned int seconds)
-{
- sighandler_t prev_handler;
- /* install and check new handler */
- if ((prev_handler = signal(SIGALRM, alarm_hand)) == SIG_ERR) {
- printf("Cannot set handler for alarm\n");
- exit(-1);
- }
- /* set alarm and go to sleep */
- alarm(seconds);
- pause();
- /* restore previous signal handler */
- signal(SIGALRM, prev_handler);
- /* return remaining time */
- return alarm(0);
-}
- \end{lstlisting}
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \includecodesample{listati/sleep_danger.c}
+ \end{minipage}
\normalsize
\caption{Una implementazione pericolosa di \func{sleep}.}
\label{fig:sig_sleep_wrong}
codice del tipo di quello riportato in \figref{fig:sig_sleep_incomplete}.
\begin{figure}[!htb]
- \footnotesize
- \begin{lstlisting}{}
-static jmp_buff alarm_return;
-unsigned int sleep(unsigned int seconds)
-{
- signandler_t prev_handler;
- if ((prev_handler = signal(SIGALRM, alarm_hand)) == SIG_ERR) {
- printf("Cannot set handler for alarm\n");
- exit(1);
- }
- if (setjmp(alarm_return) == 0) { /* if not returning from handler */
- alarm(second); /* call alarm */
- pause(); /* then wait */
- }
- /* restore previous signal handler */
- signal(SIGALRM, prev_handler);
- /* remove alarm, return remaining time */
- return alarm(0);
-}
-void alarm_hand(int sig)
-{
- /* check if the signal is the right one */
- if (sig != SIGALRM) { /* if not exit with error */
- printf("Something wrong, handler for SIGALRM\n");
- exit(1);
- } else { /* return in main after the call to pause */
- longjump(alarm_return, 1);
- }
-}
- \end{lstlisting}
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \includecodesample{listati/sleep_defect.c}
+ \end{minipage}
\normalsize
\caption{Una implementazione ancora malfunzionante di \func{sleep}.}
\label{fig:sig_sleep_incomplete}
\figref{fig:sig_event_wrong}).
\begin{figure}[!htb]
- \footnotesize
- \begin{lstlisting}{}
-sig_atomic_t flag;
-int main()
-{
- flag = 0;
- ...
- if (flag) { /* test if signal occurred */
- flag = 0; /* reset flag */
- do_response(); /* do things */
- } else {
- do_other(); /* do other things */
- }
- ...
-}
-void alarm_hand(int sig)
-{
- /* set the flag
- flag = 1;
- return;
-}
- \end{lstlisting}
+ \footnotesize\centering
+ \begin{minipage}[c]{15cm}
+ \includecodesample{listati/sig_alarm.c}
+ \end{minipage}
\normalsize
\caption{Un esempio non funzionante del codice per il controllo di un
evento generato da un segnale.}
\label{sec:sig_sigset}
Come evidenziato nel paragrafo precedente, le funzioni di gestione dei segnali
-dei primi Unix, nate con la semantica inaffidabile, hanno dei limiti non
+originarie, nate con la semantica inaffidabile, hanno dei limiti non
superabili; in particolare non è prevista nessuna funzione che permetta di
gestire gestire il blocco dei segnali o di verificare lo stato dei segnali
-pendenti.
-
-Per questo motivo lo standard POSIX.1, insieme alla nuova semantica dei
-segnali ha introdotto una interfaccia di gestione completamente nuova, che
+pendenti. Per questo motivo lo standard POSIX.1, insieme alla nuova semantica
+dei segnali ha introdotto una interfaccia di gestione completamente nuova, che
permette di ottenete un controllo molto più dettagliato. In particolare lo
standard ha introdotto un nuovo tipo di dato \type{sigset\_t}, che permette di
rappresentare un \textsl{insieme di segnali} (un \textit{signal set}, come
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}[stepnumber=0]{}
-struct sigaction
-{
- void (*sa_handler)(int);
- void (*sa_sigaction)(int, siginfo_t *, void *);
- sigset_t sa_mask;
- int sa_flags;
- void (*sa_restorer)(void);
-}
- \end{lstlisting}
+ \includestruct{listati/sigaction.h}
\end{minipage}
\normalsize
\caption{La struttura \structd{sigaction}.}
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}[stepnumber=0]{}
-siginfo_t {
- int si_signo; /* Signal number */
- int si_errno; /* An errno value */
- int si_code; /* Signal code */
- pid_t si_pid; /* Sending process ID */
- uid_t si_uid; /* Real user ID of sending process */
- int si_status; /* Exit value or signal */
- clock_t si_utime; /* User time consumed */
- clock_t si_stime; /* System time consumed */
- sigval_t si_value; /* Signal value */
- int si_int; /* POSIX.1b signal */
- void * si_ptr; /* POSIX.1b signal */
- void * si_addr; /* Memory location which caused fault */
- int si_band; /* Band event */
- int si_fd; /* File descriptor */
-}
- \end{lstlisting}
+ \includestruct{listati/siginfo_t.h}
\end{minipage}
\normalsize
\caption{La struttura \structd{siginfo\_t}.}
sempre il caso di evitare l'uso di \func{signal} a favore di \func{sigaction}.
\begin{figure}[!htb]
- \footnotesize
- \begin{lstlisting}{}
-typedef void SigFunc(int);
-inline SigFunc * Signal(int signo, SigFunc *func)
-{
- struct sigaction new_handl, old_handl;
- new_handl.sa_handler = func;
- /* clear signal mask: no signal blocked during execution of func */
- if (sigemptyset(&new_handl.sa_mask)!=0){ /* initialize signal set */
- return SIG_ERR;
- }
- new_handl.sa_flags=0; /* init to 0 all flags */
- /* change action for signo signal */
- if (sigaction(signo, &new_handl, &old_handl)){
- return SIG_ERR;
- }
- return (old_handl.sa_handler);
-}
- \end{lstlisting}
+ \footnotesize \centering
+ \begin{minipage}[c]{15.6cm}
+ \includecodesample{listati/Signal.c}
+ \end{minipage}
\normalsize
\caption{Una funzione equivalente a \func{signal} definita attraverso
\func{sigaction}.}
presenta neanche questa necessità.
\begin{figure}[!htb]
- \footnotesize
- \begin{lstlisting}{}
-void alarm_hand(int);
-unsigned int sleep(unsigned int seconds)
-{
- struct sigaction new_action, old_action;
- sigset_t old_mask, stop_mask, sleep_mask;
- /* set the signal handler */
- sigemptyset(&new_action.sa_mask); /* no signal blocked */
- new_action.sa_handler = alarm_hand; /* set handler */
- new_action.sa_flags = 0; /* no flags */
- sigaction(SIGALRM, &new_action, &old_action); /* install action */
- /* block SIGALRM to avoid race conditions */
- sigemptyset(&stop_mask); /* init mask to empty */
- sigaddset(&stop_mask, SIGALRM); /* add SIGALRM */
- sigprocmask(SIG_BLOCK, &stop_mask, &old_mask); /* add SIGALRM to blocked */
- /* send the alarm */
- alarm(seconds);
- /* going to sleep enabling SIGALRM */
- sleep_mask = old_mask; /* take mask */
- sigdelset(&sleep_mask, SIGALRM); /* remove SIGALRM */
- sigsuspend(&sleep_mask); /* go to sleep */
- /* restore previous settings */
- sigprocmask(SIG_SETMASK, &old_mask, NULL); /* reset signal mask */
- sigaction(SIGALRM, &old_action, NULL); /* reset signal action */
- /* return remaining time */
- return alarm(0);
-}
-void alarm_hand(int sig)
-{
- return; /* just return to interrupt sigsuspend */
-}
- \end{lstlisting}
+ \footnotesize \centering
+ \begin{minipage}[c]{15.6cm}
+ \includecodesample{listati/sleep.c}
+ \end{minipage}
\normalsize
\caption{Una implementazione completa di \func{sleep}.}
\label{fig:sig_sleep_ok}
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
\secref{sec:proc_mem_layout}) solo durante l'esecuzione di un
gestore. L'uso di uno stack alternativo è del tutto trasparente ai
gestori, occorre però seguire una certa procedura:
-\begin{enumerate*}
+\begin{enumerate}
\item Allocare un'area di memoria di dimensione sufficiente da usare come
stack alternativo.
\item Usare la funzione \func{sigaltstack} per rendere noto al sistema
specificando il flag \const{SA\_ONSTACK} (vedi \tabref{tab:sig_sa_flag}) per
dire al sistema di usare lo stack alternativo durante l'esecuzione del
gestore.
-\end{enumerate*}
+\end{enumerate}
In genere il primo passo viene effettuato allocando un'opportuna area di
memoria con \code{malloc}; in \file{signal.h} sono definite due costanti,
\const{SIGSTKSZ} e \const{MINSIGSTKSZ}, che possono essere utilizzate per
allocare una quantità di spazio opportuna, in modo da evitare overflow. La
prima delle due è la dimensione canonica per uno stack di segnali e di norma è
-sufficiente per tutti gli usi normali. La seconda è lo spazio che occorre al
-sistema per essere in grado di lanciare il gestore e la dimensione di uno
-stack alternativo deve essere sempre maggiore di questo valore. Quando si
-conosce esattamente quanto è lo spazio necessario al gestore gli si può
-aggiungere questo valore per allocare uno stack di dimensione sufficiente.
+sufficiente per tutti gli usi normali.
+
+La seconda è lo spazio che occorre al sistema per essere in grado di lanciare
+il gestore e la dimensione di uno stack alternativo deve essere sempre
+maggiore di questo valore. Quando si conosce esattamente quanto è lo spazio
+necessario al gestore gli si può 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 \funcd{sigaltstack}; il suo
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}[stepnumber=0]{}
-typedef struct {
- void *ss_sp; /* Base address of stack */
- int ss_flags; /* Flags */
- size_t ss_size; /* Number of bytes in stack */
-} stack_t;
- \end{lstlisting}
+ \includestruct{listati/stack_t.h}
\end{minipage}
\normalsize
\caption{La struttura \structd{stack\_t}.}
Resta quindi il problema di cosa succede alla maschera dei segnali quando si
esce da un gestore usando questa funzione. Il comportamento dipende
-dall'implementazione; in particolare BSD ripristina la maschera dei segnali
-precedente l'invocazione, come per un normale ritorno, mentre System V no. Lo
-standard POSIX.1 non specifica questo comportamento per \func{setjmp} e
+dall'implementazione; in particolare BSD prevede che sia ripristinata la
+maschera dei segnali precedente l'invocazione, come per un normale ritorno,
+mentre System V no.
+
+Lo standard POSIX.1 non specifica questo comportamento per \func{setjmp} e
\func{longjmp}, ed il comportamento delle \acr{glibc} dipende da quale delle
caratteristiche si sono abilitate con le macro viste in
\secref{sec:intro_gcc_glibc_std}.
\const{SA\_SIGINFO} che permette di utilizzare la forma estesa
\var{sa\_sigaction} (vedi \secref{sec:sig_sigaction}). In questo modo tutti i
segnali real-time possono restituire al gestore una serie di informazioni
-aggiuntive attraverso l'argomento \struct{siginfo\_t} (la cui definizione è
-riportata in \figref{fig:sig_siginfo_t}).
+aggiuntive attraverso l'argomento \struct{siginfo\_t}, la cui definizione
+abbiamo già visto in \figref{fig:sig_siginfo_t}, nella trattazione dei gestori
+in forma estesa.
In particolare i campi utilizzati dai segnali real-time sono \var{si\_pid} e
-\var{si\_uid} in cui vengono memorizzati rispettivamente \acr{pid} e userid
-effettivo del processo che ha inviato il segnale, mentre per la restituzione
-dei dati viene usato il campo \var{si\_value}, questo è una \ctyp{union} di
-tipo \struct{sigval\_t} (la sua definizione è in \figref{fig:sig_sigval}) in
-cui può essere memorizzato o un valore numerico o un indirizzo,\footnote{un
- campo di tipo \struct{sigval\_t} è presente anche nella struttura
- \struct{sigevent} che viene usata dai meccanismi di notifica come quelli per
- l'I/O asincrono (vedi \secref{sec:file_asyncronous_io}) o le code di
- messaggi POSIX (vedi \secref{sec:ipc_posix_mq}).}
+\var{si\_uid} in cui vengono memorizzati rispettivamente il \acr{pid} e
+l'user-ID effettivo del processo che ha inviato il segnale, mentre per la
+restituzione dei dati viene usato il campo \var{si\_value}.
+
+Questo è una \ctyp{union} di tipo \struct{sigval\_t} (la sua definizione è in
+\figref{fig:sig_sigval}) in cui può essere memorizzato o un valore numerico,
+se usata nella forma \var{sival\_int}, o un indirizzo, se usata nella forma
+\var{sival\_ptr}. L'unione viene usata dai segnali real-time e da vari
+meccanismi di notifica\footnote{un campo di tipo \struct{sigval\_t} è presente
+ anche nella struttura \struct{sigevent} che viene usata dai meccanismi di
+ notifica come quelli per l'I/O asincrono (vedi
+ \secref{sec:file_asyncronous_io}) o le code di messaggi POSIX (vedi
+ \secref{sec:ipc_posix_mq}).} per restituire dati al gestore del segnale; in
+alcune definizioni essa viene identificata anche come \code{union sigval}.
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}[stepnumber=0]{}
-union sigval_t {
- int sival_int;
- void *sival_ptr;
-}
- \end{lstlisting}
+ \includestruct{listati/sigval_t.h}
\end{minipage}
\normalsize
- \caption{La struttura \structd{sigval\_t}, una \ctyp{union} usata dai
- segnali real-time e dai meccanismi di notifica per restituire dati al
- gestore, (in alcune definizione essa viene identificata anche come
- \code{union sigval}).}
+ \caption{La unione \structd{sigval\_t}.}
\label{fig:sig_sigval}
\end{figure}
costante \const{SIGQUEUE\_MAX}, una della tante costanti di sistema definite
dallo standard POSIX, che non abbiamo riportato esplicitamente in
\secref{sec:sys_limits}. Il suo valore minimo secondo lo standard,
- \const{\_POSIX\_SIGQUEUE\_MAX}, è pari a 32.} nella coda) esso viene
-inserito e diventa pendente; una volta consegnato riporterà nel campo
-\var{si\_code} di \struct{siginfo} il valore \const{SI\_QUEUE} e il campo
-\var{si\_value} riceverà quanto inviato con \param{value}. Se invece si è
-installato un gestore nella forma classica il segnale sarà generato, ma tutte
-le caratteristiche tipiche dei segnali real-time (priorità e coda) saranno
-perse.
+ \const{\_POSIX\_SIGQUEUE\_MAX}, è pari a 32.} nella coda dei segnali
+real-time) esso viene inserito e diventa pendente; una volta consegnato
+riporterà nel campo \var{si\_code} di \struct{siginfo\_t} il valore
+\const{SI\_QUEUE} e il campo \var{si\_value} riceverà quanto inviato con
+\param{value}. Se invece si è installato un gestore nella forma classica il
+segnale sarà generato, ma tutte le caratteristiche tipiche dei segnali
+real-time (priorità e coda) saranno perse.
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
connessione ed altre informazioni. La voce resta nel file fino al logout,
quando viene cancellata e spostata in \file{/var/log/wtmp}.
-In questo modo il primo file viene utilizzato per registrare sta utilizzando
-il sistema al momento corrente, mentre il secondo mantiene la registrazione
-delle attività degli utenti. A quest'ultimo vengono anche aggiunte delle voci
-speciali per tenere conto dei cambiamenti del sistema, come la modifica del
-runlevel, il riavvio della macchina, ecc. Tutte queste informazioni sono
-descritte in dettaglio nel manuale delle \acr{glibc}.
+In questo modo il primo file viene utilizzato per registrare chi sta
+utilizzando il sistema al momento corrente, mentre il secondo mantiene la
+registrazione delle attività degli utenti. A quest'ultimo vengono anche
+aggiunte delle voci speciali per tenere conto dei cambiamenti del sistema,
+come la modifica del runlevel, il riavvio della macchina, ecc. Tutte queste
+informazioni sono descritte in dettaglio nel manuale delle \acr{glibc}.
Questi file non devono mai essere letti direttamente, ma le informazioni che
contengono possono essere ricavate attraverso le opportune funzioni di
-libreria. Queste sono analoghe alle precedenti (vedi
+libreria. Queste sono analoghe alle precedenti funzioni (vedi
\tabref{tab:sys_passwd_func}) usate per accedere al database degli utenti,
solo che in questo caso la struttura del database di accounting è molto più
complessa, dato che contiene diversi tipi di informazione.
\const{LOGIN\_PROCESS}& Identifica un processo di login. \\
\const{USER\_PROCESS} & Identifica un processo utente. \\
\const{DEAD\_PROCESS} & Identifica un processo terminato. \\
- \const{ACCOUNTING} & ??? \\
+% \const{ACCOUNTING} & ??? \\
\hline
\end{tabular}
\caption{Classificazione delle voci del database di accounting a seconda dei
\funcdecl{void logwtmp(const char *line, const char *name, const char
*host)} Aggiunge nel database di accounting una voce con i valori
specificati.
-
- \bodydesc{Le funzioni ritornano il puntatore ad una struttura \struct{utmp}
- in caso di successo e \val{NULL} in caso di errore.}
\end{functions}
La prima funzione permette l'aggiunta di una voce a \file{wmtp} specificando
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
- \var{errno} assumerà il valore \errval{EINVAL} se si è specificato un
- numero di errore non valido.}
+ \bodydesc{La funzione ritorna il puntatore ad una stringa di errore.}
\end{prototype}
-In generale \func{strerror} viene usata passando \var{errno} come parametro;
-nel caso si specifichi un codice sbagliato verrà restituito un messaggio di
-errore sconosciuto, e la funzione restituirà come errore \errcode{EINVAL}. La
-funzione tiene conto del valore della variabile di ambiente
-\val{LC\_MESSAGES} per usare eventuali traduzioni dei messaggi d'errore
-nella localizzazione presente.
+
+La funzione ritorna il puntatore alla stringa contenente il messaggio di
+errore corrispondente al valore di \param{errnum}, se questo non è un valore
+valido verrà comunque restituita una stringa valida contenente un messaggio
+che dice che l'errore è sconosciuto, e \var{errno} verrà modificata assumendo
+il valore \errval{EINVAL}.
+
+In generale \func{strerror} viene usata passando \var{errno} come parametro,
+ed il valore di quest'ultima non verrà modificato. La funzione inoltre tiene
+conto del valore della variabile di ambiente \val{LC\_MESSAGES} per usare le
+appropriate traduzioni dei messaggi d'errore nella localizzazione presente.
La funzione utilizza una stringa statica che non deve essere modificata dal
-programma e che è utilizzabile solo fino ad una chiamata successiva a
-\func{strerror}; per questo motivo non è rientrante e nel caso si usino i
-thread è provvista\footnote{questa funzione è la versione prevista dalle
- \acr{glibc}, ed effettivamente definita in \file{string.h}, ne esiste una
- analoga nello standard SUSv3 (quella riportata dalla pagina di manuale), che
- restituisce \code{int} al posto di \code{char *}, e che tronca la stringa
- restituita a \param{size}.} una versione apposita:
+programma; essa è utilizzabile solo fino ad una chiamata successiva a
+\func{strerror} o \func{perror}, nessun'altra funzione di libreria tocca
+questa stringa. In ogni caso l'uso di una stringa statica rende la funzione
+non rientrante, per cui nel caso nel caso si usino i thread le librerie
+forniscono\footnote{questa funzione è la versione prevista dalle \acr{glibc},
+ ed effettivamente definita in \file{string.h}, ne esiste una analoga nello
+ standard SUSv3 (quella riportata dalla pagina di manuale), che restituisce
+ \code{int} al posto di \code{char *}, e che tronca la stringa restituita a
+ \param{size}.} una apposita versione rientrante \func{strerror\_r}, il cui
+prototipo è:
\begin{prototype}{string.h}
{char * strerror\_r(int errnum, char *buf, size\_t size)}
- Analoga a \func{strerror} ma usa il buffer \param{buf} di lunghezza massima
- (compreso il terminatore) \param{size}.
-
- \bodydesc{La funzione restituisce il puntatore alla stringa; in caso di
- errore \var{errno} oltre a \errval{EINVAL} può assumere anche il valore
- \errval{ERANGE} per indicare che non c'è sufficiente memoria per contenere
- la stringa di descrizione.}
+ Restituisce una stringa con il messaggio di errore relativo ad
+ \param{errnum}.
+
+ \bodydesc{La funzione restituisce l'indirizzo del messaggio in caso di
+ successo e \val{NULL} in caso di errore; nel qual caso \var{errno}
+ assumerà i valori:
+ \begin{errlist}
+ \item[\errcode{EINVAL}] si è specificato un valore di \param{errnum} non
+ valido.
+ \item[\errcode{ERANGE}] la lunghezza di \param{buf} è insufficiente a
+ contenere la stringa di errore.
+ \end{errlist}}
\end{prototype}
\noindent
-che utilizza un buffer che il singolo thread deve allocare, per evitare i
-problemi connessi alla condivisione del buffer statico. La funzione
-restituisce l'indirizzo della stringa usata, che può essere contenuta nel
-buffer specificato da \param{buf}, per una lunghezza non superiore a
-\param{size}, nel qual caso la stringa sarebbe troncata e terminata con uno
-zero (il carattere NUL).
+La funzione è analoga a \func{strerror} ma restituisce la stringa di errore
+nel buffer \param{buf} che il singolo thread deve allocare autonomamente per
+evitare i problemi connessi alla condivisione del buffer statico. Il messaggio
+è copiato fino alla dimensione massima del buffer, specificata dall'argomento
+\param{size}, che deve comprendere pure il carattere di terminazione;
+altrimenti la stringa viene troncata.
Una seconda funzione usata per riportare i codici di errore in maniera
automatizzata sullo standard error (vedi \secref{sec:file_std_descr}) è
I messaggi di errore stampati sono gli stessi di \func{strerror}, (riportati
in \capref{cha:errors}), e, usando il valore corrente di \var{errno}, si
riferiscono all'ultimo errore avvenuto. La stringa specificata con
-\param{message} viene stampato prime del messaggio d'errore, seguita dai due
+\param{message} viene stampato prima del messaggio d'errore, seguita dai due
punti e da uno spazio, il messaggio è terminato con un a capo.
-Il messaggio può essere riportato anche usando altre variabili globali
-dichiarate in \file{errno.h}:
-\includecodesnip{listati/errlist.c}
-la prima contiene i puntatori alle stringhe di errore indicizzati da
-\var{errno}; la seconda esprime il valore più alto per un codice di errore,
-l'utilizzo di questa stringa è sostanzialmente equivalente a quello di
-\func{strerror}.
+Il messaggio può essere riportato anche usando le due variabili globali:
+\includecodesnip{listati/errlist.c}
+dichiarate in \file{errno.h}. La prima contiene i puntatori alle stringhe di
+errore indicizzati da \var{errno}; la seconda esprime il valore più alto per
+un codice di errore, l'utilizzo di questa stringa è sostanzialmente
+equivalente a quello di \func{strerror}.
\begin{figure}[!htb]
\footnotesize \centering
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, è
-\funcd{error\_at\_line}, che prende due argomenti aggiuntivi per indicare
-linea e file su cui è avvenuto l'errore; il suo prototipo è:
+Un'altra funzione per la stampa degli errori, ancora più sofisticata, che
+prende due argomenti aggiuntivi per indicare linea e file su cui è avvenuto
+l'errore è \funcd{error\_at\_line}; il suo prototipo è:
\begin{prototype}{stdio.h}
{void error\_at\_line(int status, int errnum, const char *fname,
unsigned int lineno, const char *format, ...)}