Si tenga presente che la funzione può sempre essere interrotta da un segnale
(nel qual caso si avrà un errore di \const{EINTR}) e che questo avverrà
-comunque, anche se si è installato il relativo gestore con \const{SA\_RESTART}
-(vedi sez.~\ref{sec:sig_sigaction}) per riavviare le system call interrotte.
+comunque, anche se si è richiesta la semantica BSD installando il relativo
+gestore con \const{SA\_RESTART} (vedi sez.~\ref{sec:sig_sigaction}) per
+riavviare le system call interrotte.
Della funzione \func{sem\_wait} esistono due varianti che consentono di
gestire diversamente le modalità di attesa in caso di risorsa occupata, la
-prima di queste è \funcd{sem\_trywait} che serve ad effettuare un tentativo di
-acquisizione senza bloccarsi; il suo prototipo è:
+prima di queste è \funcd{sem\_trywait}, che serve ad effettuare un tentativo
+di acquisizione senza bloccarsi; il suo prototipo è:
\begin{functions}
\headdecl{semaphore.h}
}
\end{functions}
-La funzione è identica a \func{sem\_wait} ed ha lo stesso effetto (vale a dire
-che in caso di risorsa disponibile questa viene immediatamente acquisita), la
-differenza è che nel caso in cui il semaforo è occupato essa non si blocca e
-ritorna invece immediatamente, con un errore di \errval{EAGAIN}.
-
-La seconda variante è una estensione che può essere utilizzata soltanto se si
-definisce la macro \macro{\_XOPEN\_SOURCE} ad un valore di 600 prima di
-includere \texttt{semaphore.h}, è \func{sem\_timedwait}, il cui prototipo è:
+La funzione è identica a \func{sem\_wait} ed se la risorsa è libera ha lo
+stesso effetto, vale a dire che in caso di semaforo diverso da zero la
+funzione lo decrementa e ritorna immediatamente; la differenza è che nel caso
+in cui il semaforo è occupato essa non si blocca e di nuovo ritorna
+immediatamente, restituendo però un errore di \errval{EAGAIN}, così che il
+programma possa proseguire.
+
+La seconda variante di \func{sem\_wait} è una estensione specifica che può
+essere utilizzata soltanto se viene definita la macro \macro{\_XOPEN\_SOURCE}
+ad un valore di 600 prima di includere \texttt{semaphore.h}, la funzione è
+\func{sem\_timedwait}, ed il suo prototipo è:
\begin{functions}
\headdecl{semaphore.h}
\begin{errlist}
\item[\errcode{ETIMEDOUT}] è scaduto il tempo massimo di attesa.
\item[\errcode{EINVAL}] il semaforo \param{sem} non esiste.
+ \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale.
\end{errlist}
}
\end{functions}
Anche in questo caso il comportamento della funzione è identico a quello di
-\func{sem\_wait}, solo che in questo caso è possibile impostare, con
-l'argomento \param{abs\_timeout}, un tempo limite scaduto il quale la funzione
-ritorna comunque anche se non è possibile acquisire il semaforo, riportando un
-errore di \errval{ETIMEDOUT}.
-
-La seconda funzione di gestione dei semafori è \funcd{sem\_post}, che viene
-utilizzata per rilasciare un semaforo occupato; il suo prototipo è:
+\func{sem\_wait}, la sola differenza consiste nel fatto che con questa
+funzione è possibile impostare tramite l'argomento \param{abs\_timeout} un
+tempo limite per l'attesa, scaduto il quale la funzione ritorna comunque,
+anche se non è possibile acquisire il semaforo. In tal caso la funzione
+fallirà, riportando un errore di \errval{ETIMEDOUT}.
+
+La seconda funzione principale utilizzata per l'uso dei semafori è
+\funcd{sem\_post}, che viene usata per rilasciare un semaforo occupato o, in
+generale, per aumentare di una unità il valore dello stesso anche qualora non
+fosse occupato;\footnote{si ricordi che in generale un semaforo viene usato
+ come indicatore di un numero di risorse disponibili.} il suo prototipo è:
\begin{functions}
\headdecl{semaphore.h}
}
\end{functions}
-La funzione incrementa il valore del semaforo puntato dall'argomento
-\param{sem}, se questo era nullo la relativa risorsa risulterà sbloccata,
-cosicché un altro processo (o thread) bloccato in una \func{sem\_wait} sul
-suddetto semaforo potrà essere svegliato e rimesso in esecuzione. Si tenga
-presente che la funzione è è sicura per l'uso all'interno di un gestore di
-segnali.
+La funzione incrementa di uno il valore corrente del semaforo indicato
+dall'argomento \param{sem}, se questo era nullo la relativa risorsa risulterà
+sbloccata, cosicché un altro processo (o thread) eventualmente bloccato in una
+\func{sem\_wait} sul semaforo potrà essere svegliato e rimesso in esecuzione.
+Si tenga presente che la funzione è sicura \index{funzioni~sicure} per l'uso
+all'interno di un gestore di segnali (si ricordi quanto detto in
+sez.~\ref{sec:sig_signal_handler}).
+
+Se invece di operare su un semaforo se ne vuole solamente leggere il valore,
+si può usare la funzione \funcd{sem\_getvalue}, il cui prototipo è:
+\begin{functions}
+ \headdecl{semaphore.h}
+
+ \funcdecl{int sem\_getvalue(sem\_t *sem, int *sval)}
+
+ Richiede il valore del semaforo \param{sem}.
+
+ \bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
+ errore; nel quel caso \var{errno} assumerà i valori:
+ \begin{errlist}
+ \item[\errcode{EINVAL}] il semaforo \param{sem} non esiste.
+ \end{errlist}
+}
+\end{functions}
+
+La funzione legge il valore del semaforo indicato dall'argomento \param{sem} e
+lo restituisce nella variabile intera puntata dall'argomento
+\param{sval}. Qualora ci siano uno o più processi bloccati in attesa sul
+semaforo lo standard prevede che la funzione possa restituire un valore nullo
+oppure il numero di processi bloccati in una \func{sem\_wait} sul suddetto
+semaforo; nel caso di Linux vale la prima opzione.
+
+Questa funzione può essere utilizzata per avere un suggerimento sullo stato di
+un semaforo, ovviamente non si può prendere il risultato riportato in
+\param{sval} che come indicazione, il valore del semaforo infatti potrebbe
+essere già stato modificato al ritorno della funzione.
+
+% TODO verificare comportamento sem_getvalue
+Una volta che non ci sia più la necessità di operare su un semaforo se ne può
+terminare l'uso con la funzione \funcd{sem\_close}, il cui prototipo è:
+\begin{functions}
+ \headdecl{semaphore.h}
+
+ \funcdecl{int sem\_close(sem\_t *sem)}
+
+ Chiude il semaforo \param{sem}.
+
+ \bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
+ errore; nel quel caso \var{errno} assumerà i valori:
+ \begin{errlist}
+ \item[\errcode{EINVAL}] il semaforo \param{sem} non esiste.
+ \end{errlist}
+}
+\end{functions}
+La funzione chiude il semaforo indicato dall'argomento \param{sem}; questo
+comporta che tutte le risorse che il sistema può avere assegnato al processo
+nell'uso dello stesso vengono rilasciate. Questo significa che un altro
+processo bloccato sul semaforo a causa della acquisizione da parte del
+processo che chiama \func{sem\_close} potrà essere riavviato.
+
+Si tenga presente poi che come per i file all'uscita di un processo tutti i
+semafori che questo aveva aperto vengono automaticamente chiusi; questo
+comportamento risolve il problema che si aveva con i semafori del \textit{SysV
+ IPC} (di cui si è parlato in sez.~\ref{sec:ipc_sysv_sem}) per i quali le
+risorse possono restare bloccate. Si tenga poi presente che, a differenza di
+quanto avviene per i file, in caso di una chiamata ad \func{execve} tutti i
+semafori vengono chiusi automaticamente.
+
+Come per i semafori del \textit{SysV IPC} anche quelli POSIX hanno una
+persistenza di sistema; questo significa che una volta che si è creato un
+semaforo con \func{sem\_open} questo continuerà ad esistere fintanto che il
+kernel resta attivo (vale a dire fino ad un successivo riavvio) a meno che non
+lo si cancelli esplicitamente. Per far questo si può utilizzare la funzione
+\funcd{sem\_unlink}, il cui prototipo è:
+\begin{functions}
+ \headdecl{semaphore.h}
+
+ \funcdecl{int sem\_unlink(const char *name)}
+
+ Rimuove il semaforo \param{name}.
+
+ \bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
+ errore; nel quel caso \var{errno} assumerà i valori:
+ \begin{errlist}
+ \item[\errcode{EACCESS}] non si hanno i permessi necessari a cancellare il
+ semaforo.
+ \item[\errcode{ENAMETOOLONG}] il nome indicato è troppo lungo.
+ \item[\errcode{ENOENT}] il semaforo \param{name} non esiste.
+ \end{errlist}
+}
+\end{functions}
+La funzione rimuove il semaforo indicato dall'argomento \param{name}, che
+prende un valore identico a quello usato per creare il semaforo stesso con
+\func{sem\_open}. Il semaforo viene rimosso dal filesystem immediatamente; ma
+il semaforo viene effettivamente cancellato dal sistema soltanto quando tutti
+i processi che lo avevano aperto lo chiudono. Si segue cioè la stessa
+semantica usata con \func{unlink} per i file, trattata in dettaglio in
+sez.~\ref{sec:file_link}.
Una delle caratteristiche peculiari dei semafori POSIX è che questi possono
-anche essere utilizzati in forma anonima. In questo caso si dovrà porre la
-variabile che contiene l'indirizzo del semaforo in un tratto di memoria che
-sia accessibile a tutti i processi in gioco. Questo può essere una variabile
-globale nel caso si usino i thread (nel qual caso si parla di
-\textit{thread-shared semaphore}), o un tratto di memoria condivisa nel caso
-si usino o processo (nel qual caso si parla di \textit{process-shared
- semaphore}).
+anche essere utilizzati anche in forma anonima, senza necessità di fare
+ricorso ad un nome sul filesystem o ad altri indicativi. In questo caso si
+dovrà porre la variabile che contiene l'indirizzo del semaforo in un tratto di
+memoria che sia accessibile a tutti i processi in gioco. La funzione che
+consente di inizializzare un semaforo anonimo è \funcd{sem\_init}, il cui
+prototipo è:
+\begin{functions}
+ \headdecl{semaphore.h}
+
+ \funcdecl{int sem\_init(sem\_t *sem, int pshared, unsigned int value)}
+
+ Inizializza il semaforo anonimo \param{sem}.
+
+ \bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
+ errore; nel quel caso \var{errno} assumerà i valori:
+ \begin{errlist}
+ \item[\errcode{EINVAL}] il valore di \param{value} eccede
+ \const{SEM\_VALUE\_MAX}.
+ \item[\errcode{ENOSYS}] il valore di \param{pshared} non è nullo ed il
+ sistema non supporta i semafori per i processi.
+ \end{errlist}
+}
+\end{functions}
+
+La funzione inizializza un semaforo all'indirizzo puntato dall'argomento
+\param{sem}, e come per \func{sem\_open} consente di impostare un valore
+iniziale con \param{value}. L'argomento \param{pshared} serve ad indicare se
+il semaforo deve essere utilizzato dai \itindex{thread} thread di uno stesso
+processo (con un valore nullo) o condiviso fra processi diversi (con un valore
+non nullo).
+
+Qualora il semaforo debba essere condiviso dai \itindex{thread} thread di uno
+stesso processo (nel qual caso si parla di \textit{thread-shared semaphore}),
+occorrerà che \param{sem} sia l'indirizzo di una variabile visibile da tutti i
+\itindex{thread} thread, si dovrà usare cioè una variabile globale o una
+variabile allocata dinamicamente nello \itindex{heap} heap.
+
+Qualora il semaforo debba essere condiviso fra più processi (nel qual caso si
+parla di \textit{process-shared semaphore}) la sola scelta possibile per
+renderlo visibile a tutti è di porlo in un tratto di memoria condivisa. In
+tal caso occorrerà che tutti i processi abbiano un genitore comune che ha
+allocato, con uno dei metodi possibili visti con \func{shm\_open}
+(sez.~\ref{sec:ipc_posix_shm}), \func{mmap} (sez.~\ref{sec:file_memory_map}) o
+\func{shmget} (sez.~\ref{sec:ipc_sysv_shm}) la memoria condivisa su cui si va
+a creare il semaforo,\footnote{si ricordi che i tratti di memoria condivisa
+ vengono mantenuti nei processi figli attraverso la funzione \func{fork}.} a
+cui essi poi potranno accedere.
+
+Una volta inizializzato il semaforo anonimo con \func{sem\_init} lo si potrà
+utilizzare nello stesso modo dei semafori normali con \func{sem\_wait} e
+\func{sem\_post}. Si tenga presente però che inizializzare due volte lo stesso
+semaforo può dar luogo ad un comportamento indefinito.
% LocalWords: lrt blocks PAGECACHE TRUNC CLOEXEC mmap ftruncate munmap FindShm
% LocalWords: CreateShm RemoveShm LIBRARY Library libmqueue FAILED EACCESS
% LocalWords: ENAMETOOLONG qualchenome RESTART trywait XOPEN SOURCE timedwait
-% LocalWords: process
+% LocalWords: process getvalue sval execve pshared ENOSYS heap
%%% Local Variables:
\func{longjmp}.
+\subsection{Criteri di programmazione per i gestori dei segnali}
+\label{sec:sig_signal_handler}
+
+Abbiamo finora parlato dei gestori dei segnali come funzioni chiamate in
+corrispondenza della consegna di un segnale. In realtà un gestore non può
+essere una funzione qualunque, in quanto esso può essere eseguito in
+corrispondenza all'interruzione in un punto qualunque del programma principale,
+ed ad esempio può essere problematico chiamare all'interno di un gestore di
+segnali la stessa funzione che dal segnale è stata interrotta.
+
+\index{funzioni~sicure|(}
+
+Il concetto è comunque più generale e porta ad una distinzione fra quelle che
+che POSIX chiama \textsl{funzioni insicure} (\textit{n'Usane function}) e
+\textsl{funzioni sicure} (\textit{safe function}); quando un segnale
+interrompe una funzione insicura ed il gestore chiama al suo interno una
+funzione insicura il sistema può dare luogo ad un comportamento indefinito.
+
+Tutto questo significa che un gestore di segnale deve essere programmato con
+molta cura per evitare questa evenienza, pertanto è non è possibile chiamare
+al suo interno una funzione qualunque, e si può ricorrere soltanto all'uso di
+funzioni sicure.
+
+L'elenco delle funzioni sicure varia a secondo dello standard a cui si fa
+riferimento, secondo quanto riportato dallo standard POSIX 1003.1 nella
+revisione del 2003, le ``\textit{signal safe function}'' che possono essere
+chiamate anche all'interno di un gestore di segnali sono quelle della lista
+riportata in fig.~\ref{fig:sig_safe_functions}.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \func{\_exit}, \func{abort}, \func{accept}, \func{access},
+ \func{aio\_error} \func{aio\_return}, \func{aio\_suspend}, \func{alarm},
+ \func{bind}, \func{cfgetispeed}, \func{cfgetospeed}, \func{cfsetispeed},
+ \func{cfsetospeed}, \func{chdir}, \func{chmod}, \func{chown},
+ \func{clock\_gettime}, \func{close}, \func{connect}, \func{creat},
+ \func{dup}, \func{dup2}, \func{execle}, \func{execve}, \func{fchmod},
+ \func{fchown}, \func{fcntl}, \func{fdatasync}, \func{fork},
+ \func{fpathconf}, \func{fstat}, \func{fsync}, \func{ftruncate},
+ \func{getegid}, \func{geteuid}, \func{getgid}, \func{getgroups},
+ \func{getpeername}, \func{getpgrp}, \func{getpid}, \func{getppid},
+ \func{getsockname}, \func{getsockopt}, \func{getuid}, \func{kill},
+ \func{link}, \func{listen}, \func{lseek}, \func{lstat}, \func{mkdir},
+ \func{mkfifo}, \func{open}, \func{pathconf}, \func{pause}, \func{pipe},
+ \func{poll}, \func{posix\_trace\_event}, \func{pselect}, \func{raise},
+ \func{read}, \func{readlink}, \func{recv}, \func{recvfrom},
+ \func{recvmsg}, \func{rename}, \func{rmdir}, \func{select},
+ \func{sem\_post}, \func{send}, \func{sendmsg}, \func{sendto},
+ \func{setgid}, \func{setpgid}, \func{setsid}, \func{setsockopt},
+ \func{setuid}, \func{shutdown}, \func{sigaction}, \func{sigaddset},
+ \func{sigdelset}, \func{sigemptyset}, \func{sigfillset},
+ \func{sigismember}, \func{signal}, \func{sigpause}, \func{sigpending},
+ \func{sigprocmask}, \func{sigqueue}, \func{sigset}, \func{sigsuspend},
+ \func{sleep}, \func{socket}, \func{socketpair}, \func{stat},
+ \func{symlink}, \func{sysconf}, \func{tcdrain}, \func{tcflow},
+ \func{tcflush}, \func{tcgetattr}, \func{tcgetgrp}, \func{tcsendbreak},
+ \func{tcsetattr}, \func{tcsetpgrp}, \func{time}, \func{timer\_getoverrun},
+ \func{timer\_gettime}, \func{timer\_settime}, \func{times}, \func{umask},
+ \func{uname}, \func{unlink}, \func{utime}, \func{wait}, \func{waitpid},
+ \func{write}.
+ \end{minipage}
+ \normalsize
+ \caption{Elenco delle funzioni sicure secondo lo standard POSIX
+ 1003.1-2003.}
+ \label{fig:sig_safe_functions}
+\end{figure}
+
+\index{funzioni~sicure|)}
+
+Per questo motivo è opportuno mantenere al minimo indispensabile le operazioni
+effettuate all'interno di un gestore di segnali, qualora si debbano compiere
+operazioni complesse è sempre preferibile utilizzare la tecnica in cui si usa
+il gestore per impostare il valore di una qualche variabile globale, e poi si
+eseguono le operazioni complesse nel programma verificando (con tutti gli
+accorgimenti visti in precedenza) il valore di questa variabile tutte le volte
+che si è rilevata una interruzione dovuta ad un segnale.
+
\subsection{I segnali real-time}
\label{sec:sig_real_time}
-
Lo standard POSIX.1b, nel definire una serie di nuove interfacce per i servizi
real-time, ha introdotto una estensione del modello classico dei segnali che
presenta dei significativi miglioramenti,\footnote{questa estensione è stata
dedicato alla gestione, che potrebbe riceverlo fra due chiamate successive.
+
+
% LocalWords: kernel POSIX timer shell control ctrl kill raise signal handler
% LocalWords: reliable unreliable fig race condition sez struct process table
% LocalWords: delivered pending scheduler sigpending l'I suspend SIGKILL wait
% LocalWords: how oldset BLOCK UNBLOCK SETMASK sigsuspend sigaltstack malloc
% LocalWords: SIGSTKSZ MINSIGSTKSZ ss oss ENOMEM flags DISABLE sp setrlimit LB
% LocalWords: RLIMIT rlim sigsetjmp siglongjmp sigjmp buf env savesigs jmp ptr
-% LocalWords: SIGRTMIN SIGRTMAX sigval sigevent sigqueue EAGAIN sysctl
-% LocalWords: QUEUE thread sigwait sigwaitinfo sigtimedwait info DEF SLB
+% LocalWords: SIGRTMIN SIGRTMAX sigval sigevent sigqueue EAGAIN sysctl safe
+% LocalWords: QUEUE thread sigwait sigwaitinfo sigtimedwait info DEF SLB bind
+% LocalWords: function accept return cfgetispeed cfgetospeed cfsetispeed chdir
+% LocalWords: cfsetospeed chmod chown gettime close connect creat dup execle
+% LocalWords: execve fchmod fchown fdatasync fpathconf fstat fsync ftruncate
+% LocalWords: getegid geteuid getgid getgroups getpeername getpgrp getppid sem
+% LocalWords: getsockname getsockopt getuid listen lseek lstat mkdir mkfifo
+% LocalWords: pathconf poll posix pselect read readlink recv recvfrom recvmsg
+% LocalWords: rename rmdir select send sendmsg sendto setgid setpgid setsid
+% LocalWords: setsockopt setuid shutdown sigpause socketpair stat symlink
+% LocalWords: sysconf tcdrain tcflow tcflush tcgetattr tcgetgrp tcsendbreak
+% LocalWords: tcsetattr tcsetpgrp getoverrun times umask uname unlink utime
+% LocalWords: write sival
+
%%% Local Variables:
%%% mode: latex