{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual
caso \var{errno} assumerà gli uno dei valori:
- \begin{errlist}
+ \begin{errlist}
\item[\errcode{EACCES}] non si hanno i permessi per cancellare la coda.
\item[\errcode{ENAMETOOLONG}] il nome indicato è troppo lungo.
\item[\errcode{ENOENT}] non esiste una coda con il nome indicato.
struct mq\_attr *omqstat)}
\fdesc{Modifica gli attributi di una coda di messaggi POSIX.}
}
-
-{Entrambe le funzioni ritornano $0$ in caso di successo e $-1$ per un errore,
+{
+Entrambe le funzioni ritornano $0$ in caso di successo e $-1$ per un errore,
nel qual caso \var{errno} assumerà i valori \errval{EBADF}
o \errval{EINVAL} nel loro significato generico.
}
\item[\errcode{ETIMEDOUT}] l'inserimento del messaggio non è stato
effettuato entro il tempo stabilito (solo \func{mq\_timedsend}).
\end{errlist}
- ed inoltre \errval{EBADF}, \errval{EINTR} nel suo significato generico. }
+ ed inoltre \errval{EBADF} e \errval{EINTR} nel loro significato generico.
+}
\end{funcproto}
Entrambe le funzioni richiedono un puntatore ad un buffer in memoria
esistente.
\end{errlist}
ed inoltre \errval{ENOMEM} nel suo significato generico.
-
}
\end{funcproto}
La funzione che permette di aprire un segmento di memoria condivisa POSIX, ed
eventualmente di crearlo se non esiste ancora, è \funcd{shm\_open}; il suo
prototipo è:
-\begin{functions}
- \headdecl{sys/mman.h}
- \headdecl{sys/stat.h}
- \headdecl{fcntl.h}
- \funcdecl{int shm\_open(const char *name, int oflag, mode\_t mode)}
+\begin{funcproto}{
+\fhead{sys/mman.h}
+\fhead{sys/stat.h}
+\fhead{fcntl.h}
+\fdecl{int shm\_open(const char *name, int oflag, mode\_t mode)}
+
+\fdesc{Apre un segmento di memoria condivisa.}
+}
+
+{La funzione ritorna un file descriptor in caso di successo e $-1$ per un
+ errore, nel qual caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EACCES}] non si hanno i permessi di aprire il segmento nella
+ modalità scelta o si richiesto \const{O\_TRUNC} per un segmento su cui non
+ si ha il permesso di scrittura.
+ \item[\errcode{EINVAL}] si è utilizzato un nome non valido.
+ \end{errlist}
+ ed inoltre \errval{EEXIST}, \errval{EMFILE}, \errval{ENAMETOOLONG},
+ \errval{ENFILE} e \errval{ENOENT} nello stesso significato che hanno per
+ \func{open}.
+}
+\end{funcproto}
- Apre un segmento di memoria condivisa.
-
- \bodydesc{La funzione restituisce un file descriptor positivo in caso di
- successo e -1 in caso di errore; nel quel caso \var{errno} assumerà gli
- stessi valori riportati da \func{open}.}
-\end{functions}
La funzione apre un segmento di memoria condivisa identificato dal nome
\param{name}. Come già spiegato in sez.~\ref{sec:ipc_posix_generic} questo
nome può essere specificato in forma standard solo facendolo iniziare per
-``\file{/}'' e senza ulteriori ``\file{/}''. Linux supporta comunque nomi
+``\texttt{/}'' e senza ulteriori ``\texttt{/}''. Linux supporta comunque nomi
generici, che verranno interpretati prendendo come radice
\file{/dev/shm}.\footnote{occorre pertanto evitare di specificare qualcosa del
tipo \file{/dev/shm/nome} all'interno di \param{name}, perché questo
\end{basedescript}
In caso di successo la funzione restituisce un file descriptor associato al
-segmento di memoria condiviso con le stesse modalità di
-\func{open}\footnote{in realtà, come accennato, \func{shm\_open} è un semplice
- wrapper per \func{open}, usare direttamente quest'ultima avrebbe lo stesso
- effetto.} viste in sez.~\ref{sec:file_open_close}; in particolare viene impostato
-il flag \const{FD\_CLOEXEC}. Chiamate effettuate da diversi processi usando
-lo stesso nome, restituiranno file descriptor associati allo stesso segmento
-(così come, nel caso di file di dati, essi sono associati allo stesso
-\itindex{inode} inode). In questo modo è possibile effettuare una chiamata ad
-\func{mmap} sul file descriptor restituito da \func{shm\_open} ed i processi
-vedranno lo stesso segmento di memoria condivisa.
-
-Quando il nome non esiste il segmento può essere creato specificando
+segmento di memoria condiviso con le stesse modalità di \func{open} viste in
+sez.~\ref{sec:file_open_close}. Inoltre sul file descriptor viene sempre
+impostato il flag \const{FD\_CLOEXEC}. Chiamate effettuate da diversi
+processi usando lo stesso nome restituiranno file descriptor associati allo
+stesso segmento, così come, nel caso di file ordinari, essi sono associati
+allo stesso \itindex{inode} inode. In questo modo è possibile effettuare una
+chiamata ad \func{mmap} sul file descriptor restituito da \func{shm\_open} ed
+i processi vedranno lo stesso segmento di memoria condivisa.
+
+Quando il nome non esiste si può creare un nuovo segmento specificando
\const{O\_CREAT}; in tal caso il segmento avrà (così come i nuovi file)
-lunghezza nulla. Dato che un segmento di lunghezza nulla è di scarsa utilità,
-per impostarne la dimensione si deve usare \func{ftruncate} (vedi
-sez.~\ref{sec:file_file_size}), prima di mapparlo in memoria con \func{mmap}.
-Si tenga presente che una volta chiamata \func{mmap} si può chiudere il file
-descriptor (con \func{close}), senza che la mappatura ne risenta.
-
-Come per i file, quando si vuole effettivamente rimuovere segmento di memoria
-condivisa, occorre usare la funzione \funcd{shm\_unlink}, il cui prototipo è:
-\begin{prototype}{sys/mman.h}
-{int shm\_unlink(const char *name)}
-
-Rimuove un segmento di memoria condivisa.
-
-\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
- errore; nel quel caso \var{errno} assumerà gli stessi valori riportati da
- \func{unlink}.}
-\end{prototype}
+lunghezza nulla. Il nuovo segmento verrà creato con i permessi indicati
+da \param{mode} (di cui vengono usati solo i 9 bit meno significativi, non si
+applicano pertanto i permessi speciali di sez.~\ref{sec:file_special_perm})
+filtrati dal valore dell'\textit{umask} del processo. Come gruppo ed utente
+propritario del segmento saranno presi quelli facenti parte del gruppo
+\textit{effective} del processo chiamante.
+
+Dato che un segmento di lunghezza nulla è di scarsa utilità, una vola che lo
+si è creato per impostarne la dimensione si devrà poi usare \func{ftruncate}
+(vedi sez.~\ref{sec:file_file_size}) prima di mapparlo in memoria con
+\func{mmap}. Si tenga presente che una volta chiamata \func{mmap} si può
+chiudere il file descriptor ad esso associato (semplicemente con
+\func{close}), senza che la mappatura ne risenta, e che questa può essere
+rimossa usando \func{munmap}.
+
+Come per i file, quando si vuole rimuovere completamente un segmento di
+memoria condivisa occorre usare la funzione \funcd{shm\_unlink}, il cui
+prototipo è:
+
+\begin{funcproto}{
+\fhead{sys/mman.h}
+\fdecl{int shm\_unlink(const char *name)}
+
+\fdesc{Rimuove un segmento di memoria condivisa.}
+}
+
+{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual
+ caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EACCES}] non si è proprietari del segmento.
+ \end{errlist}
+ ed inoltre \errval{ENAMETOOLONG} e \errval{ENOENT}, nel loro significato
+ generico.
+}
+\end{funcproto}
La funzione è del tutto analoga ad \func{unlink}, e si limita a cancellare il
nome del segmento da \file{/dev/shm}, senza nessun effetto né sui file
usato \const{O\_CREAT}, in quest'ultimo caso comunque si otterrà un file
descriptor che fa riferimento ad un segmento distinto da eventuali precedenti.
-\begin{figure}[!htbp]
+Dato che i segmenti di memoria condivisa sono trattati come file del
+filesystem \texttt{tmpfs}, si possono usare su di essi, con lo stesso
+significato che assumono sui file ordinari, anche funzioni come quelle delle
+famiglie \func{fstat}, \func{fchown} e \func{fchmod}. Inoltre a partire dal
+kernel 2.6.19 per i permessi sono supportate anche le ACL illustrate in
+sez.~\ref{sec:file_ACL}.
+
+Come esempio dell'uso delle funzioni attinenti ai segmenti di memoria
+condivisa POSIX, vediamo come è possibile riscrivere una interfaccia
+semplificata analoga a quella vista in fig.~\ref{fig:ipc_sysv_shm_func} per la
+memoria condivisa in stile SysV. Il codice completo, di cui si sono riportate
+le parti esseziali in fig.~\ref{fig:ipc_posix_shmmem}, è contenuto nel file
+\file{SharedMem.c} dei sorgenti allegati.
+
+\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{\codesamplewidth}
\includecodesample{listati/MemShared.c}
\label{fig:ipc_posix_shmmem}
\end{figure}
-Come esempio per l'uso di queste funzioni vediamo come è possibile riscrivere
-una interfaccia semplificata analoga a quella vista in
-fig.~\ref{fig:ipc_sysv_shm_func} per la memoria condivisa in stile SysV. Il
-codice, riportato in fig.~\ref{fig:ipc_posix_shmmem}, è sempre contenuto nel
-file \file{SharedMem.c} dei sorgenti allegati.
-
La prima funzione (\texttt{\small 1--24}) è \func{CreateShm} che, dato un nome
nell'argomento \var{name} crea un nuovo segmento di memoria condivisa,
accessibile in lettura e scrittura, e ne restituisce l'indirizzo. Anzitutto si
definiscono (\texttt{\small 8}) i flag per la successiva (\texttt{\small 9})
chiamata a \func{shm\_open}, che apre il segmento in lettura e scrittura
(creandolo se non esiste, ed uscendo in caso contrario) assegnandogli sul
-filesystem i permessi specificati dall'argomento \var{perm}. In caso di errore
-(\texttt{\small 10--12}) si restituisce un puntatore nullo, altrimenti si
-prosegue impostando (\texttt{\small 14}) la dimensione del segmento con
-\func{ftruncate}. Di nuovo (\texttt{\small 15--16}) si esce immediatamente
-restituendo un puntatore nullo in caso di errore. Poi si passa (\texttt{\small
- 18}) a mappare in memoria il segmento con \func{mmap} specificando dei
-diritti di accesso corrispondenti alla modalità di apertura. Di nuovo si
-restituisce (\texttt{\small 19--21}) un puntatore nullo in caso di errore,
-altrimenti si inizializza (\texttt{\small 22}) il contenuto del segmento al
-valore specificato dall'argomento \var{fill} con \func{memset}, e se ne
-restituisce (\texttt{\small 23}) l'indirizzo.
+filesystem i permessi specificati dall'argomento \var{perm}.
+
+In caso di errore (\texttt{\small 10--12}) si restituisce un puntatore nullo,
+altrimenti si prosegue impostando (\texttt{\small 14}) la dimensione del
+segmento con \func{ftruncate}. Di nuovo (\texttt{\small 15--16}) si esce
+immediatamente restituendo un puntatore nullo in caso di errore. Poi si passa
+(\texttt{\small 18}) a mappare in memoria il segmento con \func{mmap}
+specificando dei diritti di accesso corrispondenti alla modalità di apertura.
+Di nuovo si restituisce (\texttt{\small 19--21}) un puntatore nullo in caso di
+errore, altrimenti si inizializza (\texttt{\small 22}) il contenuto del
+segmento al valore specificato dall'argomento \var{fill} con \func{memset}, e
+se ne restituisce (\texttt{\small 23}) l'indirizzo.
La seconda funzione (\texttt{\small 25--40}) è \func{FindShm} che trova un
-segmento di memoria condiviso già esistente, restituendone l'indirizzo. In
-questo caso si apre (\texttt{\small 31}) il segmento con \func{shm\_open}
-richiedendo che il segmento sia già esistente, in caso di errore
-(\texttt{\small 31--33}) si ritorna immediatamente un puntatore nullo.
-Ottenuto il file descriptor del segmento lo si mappa (\texttt{\small 35}) in
-memoria con \func{mmap}, restituendo (\texttt{\small 36--38}) un puntatore
-nullo in caso di errore, o l'indirizzo (\texttt{\small 39}) dello stesso in
-caso di successo.
+segmento di memoria condiviso esistente, restituendone l'indirizzo. In questo
+caso si apre (\texttt{\small 31}) il segmento con \func{shm\_open} richiedendo
+che il segmento sia già esistente, in caso di errore (\texttt{\small 31--33})
+si ritorna immediatamente un puntatore nullo. Ottenuto il file descriptor del
+segmento lo si mappa (\texttt{\small 35}) in memoria con \func{mmap},
+restituendo (\texttt{\small 36--38}) un puntatore nullo in caso di errore, o
+l'indirizzo (\texttt{\small 39}) dello stesso in caso di successo.
La terza funzione (\texttt{\small 40--45}) è \func{RemoveShm}, e serve a
cancellare un segmento di memoria condivisa. Dato che al contrario di quanto
erano visibili solo all'interno dei \itindex{thread} \textit{thread} creati
da un singolo processo, e non potevano essere usati come meccanismo di
sincronizzazione fra processi diversi.} fornita attraverso la sezione delle
-estensioni \textit{real-time} della \acr{glibc}.\footnote{quelle che si
- accedono collegandosi alla libreria \texttt{librt}.} Esisteva inoltre una
-libreria che realizzava (parzialmente) l'interfaccia POSIX usando le funzioni
-dei semafori di \textit{SysV-IPC} (mantenendo così tutti i problemi
-sottolineati in sez.~\ref{sec:ipc_sysv_sem}).
+estensioni \textit{real-time} della \acr{glibc} (quelle che si accedono
+collegandosi alla libreria \texttt{librt}). Esisteva inoltre una libreria che
+realizzava (parzialmente) l'interfaccia POSIX usando le funzioni dei semafori
+di \textit{SysV-IPC} (mantenendo così tutti i problemi sottolineati in
+sez.~\ref{sec:ipc_sysv_sem}).
A partire dal kernel 2.5.7 è stato introdotto un meccanismo di
-sincronizzazione completamente nuovo, basato sui cosiddetti
-\textit{futex},\footnote{la sigla sta per \textit{fast user mode mutex}.} con
-il quale è stato possibile implementare una versione nativa dei semafori
-POSIX. Grazie a questo con i kernel della serie 2.6 e le nuove versioni della
-\acr{glibc} che usano questa nuova infrastruttura per quella che viene che
-viene chiamata \textit{New Posix Thread Library}, sono state implementate
-anche tutte le funzioni dell'interfaccia dei semafori POSIX.
+sincronizzazione completamente nuovo, basato sui cosiddetti \textit{futex} (la
+sigla sta per \textit{fast user mode mutex}) con il quale è stato possibile
+implementare una versione nativa dei semafori POSIX. Grazie a questo con i
+kernel della serie 2.6 e le nuove versioni della \acr{glibc} che usano questa
+nuova infrastruttura per quella che viene che viene chiamata \textit{New Posix
+ Thread Library}, sono state implementate anche tutte le funzioni
+dell'interfaccia dei semafori POSIX.
Anche in questo caso è necessario appoggiarsi alla libreria per le estensioni
\textit{real-time} \texttt{librt}, questo significa che se si vuole utilizzare
questa interfaccia, oltre ad utilizzare gli opportuni file di definizione,
-occorrerà compilare i programmi con l'opzione \texttt{-lrt}.
+occorrerà compilare i programmi con l'opzione \texttt{-lrt} o con
+\texttt{-lpthread} se si usano questi ultimi.
La funzione che permette di creare un nuovo semaforo POSIX, creando il
relativo file, o di accedere ad uno esistente, è \funcd{sem\_open}, questa
prevede due forme diverse a seconda che sia utilizzata per aprire un semaforo
esistente o per crearne uno nuovi, i relativi prototipi sono:
-\begin{functions}
- \headdecl{semaphore.h}
-
- \funcdecl{sem\_t *sem\_open(const char *name, int oflag)}
-
- \funcdecl{sem\_t *sem\_open(const char *name, int oflag, mode\_t mode,
+
+\begin{funcproto}{
+\fhead{semaphore.h}
+\fhead{sys/stat.h}
+\fhead{fcntl.h}
+\fdecl{sem\_t *sem\_open(const char *name, int oflag)}
+\fdecl{sem\_t *sem\_open(const char *name, int oflag, mode\_t mode,
unsigned int value)}
- Crea un semaforo o ne apre uno esistente.
-
- \bodydesc{La funzione restituisce l'indirizzo del semaforo in caso di
- successo e \const{SEM\_FAILED} in caso di errore; nel quel caso
- \var{errno} assumerà i valori:
- \begin{errlist}
+\fdesc{Crea un semaforo o ne apre uno esistente.}
+}
+{La funzione ritorna l'indirizzo del semaforo in caso di successo e
+ \const{SEM\_FAILED} per un errore, nel qual caso \var{errno} assumerà uno
+ dei valori:
+ \begin{errlist}
\item[\errcode{EACCES}] il semaforo esiste ma non si hanno permessi
sufficienti per accedervi.
\item[\errcode{EEXIST}] si sono specificati \const{O\_CREAT} e
\const{O\_EXCL} ma il semaforo esiste.
\item[\errcode{EINVAL}] il valore di \param{value} eccede
- \const{SEM\_VALUE\_MAX}.
+ \const{SEM\_VALUE\_MAX} o il nome è solo ``\texttt{/}''.
\item[\errcode{ENAMETOOLONG}] si è utilizzato un nome troppo lungo.
\item[\errcode{ENOENT}] non si è usato \const{O\_CREAT} ed il nome
specificato non esiste.
- \end{errlist}
- ed inoltre \errval{ENFILE} ed \errval{ENOMEM}.}
-\end{functions}
+ \end{errlist}
+ ed inoltre \errval{EMFILE}, \errval{ENFILE} ed \errval{ENOMEM} nel loro
+ significato generico.
+
+}
+\end{funcproto}
L'argomento \param{name} definisce il nome del semaforo che si vuole
utilizzare, ed è quello che permette a processi diversi di accedere allo
-stesso semaforo. Questo deve essere specificato con un \textit{pathname} nella
-forma \texttt{/qualchenome}, che non ha una corrispondenza diretta con un
-\textit{pathname} reale; con Linux infatti i file associati ai semafori sono
-mantenuti nel filesystem virtuale \texttt{/dev/shm}, e gli viene assegnato
-automaticamente un nome nella forma \texttt{sem.qualchenome}.\footnote{si ha
- cioè una corrispondenza per cui \texttt{/qualchenome} viene rimappato, nella
- creazione tramite \func{sem\_open}, su \texttt{/dev/shm/sem.qualchenome}.}
+stesso semaforo. Questo deve essere specificato nella stessa forma utilizzata
+per i segmenti di memoria condivisa, con un nome che inizia con ``\texttt{/}''
+e senza ulteriori ``\texttt{/}'', vale a dire nella forma
+\texttt{/nomesemaforo}.
+
+Con Linux i file associati ai semafori sono mantenuti nel filesystem virtuale
+\texttt{/dev/shm}, e gli viene assegnato automaticamente un nome nella forma
+\texttt{sem.nomesemaforo}, si ha cioè una corrispondenza per cui
+\texttt{/nomesemaforo} viene rimappato, nella creazione tramite
+\func{sem\_open}, su \texttt{/dev/shm/sem.nomesemaforo}. Per questo motivo la
+dimensione massima per il nome di un semaforo, a differenza di quanto avviene
+per i segmenti di memoria confivisa, è pari a \const{NAME\_MAX}$ - 4$.
L'argomento \param{oflag} è quello che controlla le modalità con cui opera la
funzione, ed è passato come maschera binaria; i bit corrispondono a quelli
quanto avviene per i semafori del \textit{SysV-IPC}, effettuare in maniera
atomica creazione ed inizializzazione di un semaforo usando una unica
funzione.} che una maschera dei permessi con l'argomento
-\param{mode};\footnote{anche questo argomento prende gli stessi valori
- utilizzati per l'analogo di \func{open}, che si sono illustrati in dettaglio
- sez.~\ref{sec:file_perm_overview}.} questi verranno assegnati al semaforo
-appena creato. Se il semaforo esiste già i suddetti valori saranno invece
+\param{mode}; se il semaforo esiste già questi saranno semplicemente
ignorati. Usando il flag \const{O\_EXCL} si richiede invece la verifica che il
-semaforo non esiste, usandolo insieme ad \const{O\_CREAT} la funzione fallisce
-qualora un semaforo con lo stesso nome sia già presente.
+semaforo non esista, ed usandolo insieme ad \const{O\_CREAT} la funzione
+fallisce qualora un semaforo con lo stesso nome sia già presente.
+
+Si tenga presente che, come accennato in sez.~\ref{sec:ipc_posix_generic}, i
+semafori usano la semantica standard dei file per quanto riguarda i controlli
+di accesso, questo significa che un nuovo semaforo viene sempre creato con
+l'\ids{UID} ed il \ids{GID} effettivo del processo chiamante, e che i permessi
+indicati con \param{mode} vengono filtrati dal valore della \itindex{umask}
+\textit{umask} del processo. Inoltre per poter aprire un semaforo è
+necessario avere su di esso sia il permesso di lettura che quello di
+scrittura.
La funzione restituisce in caso di successo un puntatore all'indirizzo del
semaforo con un valore di tipo \ctyp{sem\_t *}, è questo valore che dovrà
-essere passato alle altre funzioni per operare sul semaforo stesso. Si tenga
-presente che, come accennato in sez.~\ref{sec:ipc_posix_generic}, i semafori
-usano la semantica standard dei file per quanto riguarda i controlli di
-accesso.
-
-Questo significa che un nuovo semaforo viene sempre creato con l'\ids{UID} ed
-il \ids{GID} effettivo del processo chiamante, e che i permessi indicati con
-\param{mode} vengono filtrati dal valore della \itindex{umask} \textit{umask}
-del processo. Inoltre per poter aprire un semaforo è necessario avere su di
-esso sia il permesso di lettura che quello di scrittura.
+essere passato alle altre funzioni per operare sul semaforo stesso, e non sarà
+più necessario fare riferimento al nome, che potrebbe anche essere rimosso con
+\func{sem\_unlink}.
Una volta che si sia ottenuto l'indirizzo di un semaforo, sarà possibile
utilizzarlo; se si ricorda quanto detto all'inizio di
l'uso di una risorsa bloccando il semaforo e quella che rilascia la risorsa
liberando il semaforo. La prima operazione è effettuata dalla funzione
\funcd{sem\_wait}, il cui prototipo è:
-\begin{functions}
- \headdecl{semaphore.h}
-
- \funcdecl{int sem\_wait(sem\_t *sem)}
-
- Blocca 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}
+
+\begin{funcproto}{
+\fhead{semaphore.h}
+\fdecl{int sem\_wait(sem\_t *sem)}
+
+\fdesc{Blocca un semaforo.}
+}
+
+{La funzione ritorna $0$ in caso di successo 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}] il semaforo \param{sem} non esiste.
- \end{errlist}
-}
-\end{functions}
+ \end{errlist}
+}
+\end{funcproto}
La funzione cerca di decrementare il valore del semaforo indicato dal
puntatore \param{sem}, se questo ha un valore positivo, cosa che significa che
la risorsa è disponibile, la funzione ha successo, il valore del semaforo
-viene diminuito di 1 ed essa ritorna immediatamente; se il valore è nullo la
-funzione si blocca fintanto che il valore del semaforo non torni
-positivo\footnote{ovviamente per opera di altro processo che lo rilascia
- chiamando \func{sem\_post}.} così che poi essa possa decrementarlo con
-successo e proseguire.
-
-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 è richiesta la semantica BSD installando il relativo
-gestore con \const{SA\_RESTART} (vedi sez.~\ref{sec:sig_sigaction}) per
-riavviare le \textit{system call} interrotte.
+viene diminuito di 1 ed essa ritorna immediatamente consentendo la
+prosecuzione del processo.
+
+Se invece il valore è nullo la funzione si blocca (fermando l'esecuzione del
+processo) fintanto che il valore del semaforo non ritorna positivo (cosa che a
+questo punto può avvenire solo per opera di altro processo che rilascia il
+semaforo con una chiamata a \func{sem\_post}) così che poi essa possa
+decrementarlo con successo e proseguire.
+
+Si tenga presente che la funzione può sempre essere interrotta da un segnale,
+nel qual caso si avrà un errore di \const{EINTR}; inoltre questo avverrà
+comunque, anche qualora si fosse richiesta la gesione con la semantica BSD,
+installando il gestore del suddetto segnale con l'opzione \const{SA\_RESTART}
+(vedi sez.~\ref{sec:sig_sigaction}) per riavviare le \textit{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 è:
-\begin{functions}
- \headdecl{semaphore.h}
-
- \funcdecl{int sem\_trywait(sem\_t *sem)}
-
- Tenta di bloccare 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à gli stessi valori:
- \begin{errlist}
+
+\begin{funcproto}{
+\fhead{semaphore.h}
+\fdecl{int sem\_trywait(sem\_t *sem)}
+
+\fdesc{Tenta di bloccare un semaforo.}
+}
+{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual
+ caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
\item[\errcode{EAGAIN}] il semaforo non può essere acquisito senza
bloccarsi.
- \item[\errcode{EINVAL}] il semaforo \param{sem} non esiste.
- \end{errlist}
+ \item[\errcode{EINVAL}] l'argomento \param{sem} non indica un semaforo
+ valido.
+ \end{errlist}
}
-\end{functions}
+\end{funcproto}
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
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 \headfile{semaphore.h}, la funzione è
-\funcd{sem\_timedwait}, ed il suo prototipo è:
-\begin{functions}
- \headdecl{semaphore.h}
+ad un valore di almeno 600 o la macro \macro{\_POSIX\_C\_SOURCE} ad un valore
+uguale o maggiore di \texttt{200112L} prima di includere
+\headfile{semaphore.h}, la funzione è \funcd{sem\_timedwait}, ed il suo
+prototipo è:
- \funcdecl{int sem\_timedwait(sem\_t *sem, const struct timespec
+\begin{funcproto}{
+\fhead{semaphore.h}
+\fdecl{int sem\_timedwait(sem\_t *sem, const struct timespec
*abs\_timeout)}
-
- Blocca 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à gli stessi valori:
- \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}
+
+\fdesc{Blocca un semaforo.}
}
-\end{functions}
+
+{La funzione ritorna $0$ in caso di successo 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}] l'argomento \param{sem} non indica un semaforo
+ valido.
+ \item[\errcode{ETIMEDOUT}] è scaduto il tempo massimo di attesa.
+ \end{errlist}
+}
+\end{funcproto}
Anche in questo caso il comportamento della funzione è identico a quello di
-\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}
-
- \funcdecl{int sem\_post(sem\_t *sem)}
-
- Rilascia 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}
+\func{sem\_wait}, ma è possibile impostare un tempo limite per l'attesa
+tramite la struttura \struct{timespec} (vedi
+fig.~\ref{fig:sys_timespec_struct}) puntata
+dall'argomento \param{abs\_timeout}, indicato in secondi e nonosecondi a
+partire dalla cosiddetta \textit{Epoch} (00:00:00, 1 January 1970
+UTC). Scaduto il limite la funzione ritorna anche se non è possibile acquisire
+il semaforo fallendo con un errore di \errval{ETIMEDOUT}.
+
+La seconda funzione principale utilizzata per l'uso dei semafori è quella 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 (si
+ricordi che in generale un semaforo viene usato come indicatore di un numero
+di risorse disponibili). Detta funzione è \funcd{sem\_post} ed il suo
+prototipo è:
+
+\begin{funcproto}{
+\fhead{semaphore.h}
+\fdecl{int sem\_post(sem\_t *sem)}
+
+\fdesc{Rilascia un semaforo.}
}
-\end{functions}
+
+{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual
+ caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EINVAL}] l'argomento \param{sem} non indica un semaforo
+ valido.
+ \item[\errcode{EOVERFLOW}] si superato il massimo valore di un semaforo.
+ \end{errlist}
+}
+\end{funcproto}
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 \itindex{thread} \textit{thread})
-eventualmente bloccato in una \func{sem\_wait} sul semaforo potrà essere
+eventualmente bloccato in una \func{sem\_wait} sul semaforo possa 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}
+Se invece di operare su un semaforo se ne volesse semplicemente leggere il
+valore, si potrà usare la funzione \funcd{sem\_getvalue}, il cui prototipo è:
+
+\begin{funcproto}{
+\fhead{semaphore.h}
+\fdecl{int sem\_getvalue(sem\_t *sem, int *sval)}
+
+\fdesc{Richiede il valore di un semaforo.}
}
-\end{functions}
+{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual
+ caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EINVAL}] l'argomento \param{sem} non indica un semaforo
+ valido.
+ \end{errlist}
+}
+\end{funcproto}
La funzione legge il valore del semaforo indicato dall'argomento \param{sem} e
lo restituisce nella variabile intera puntata dall'argomento
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}
+
+\begin{funcproto}{
+\fhead{semaphore.h}
+\fdecl{int sem\_close(sem\_t *sem)}
+
+\fdesc{Chiude un semaforo.}
}
-\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.
+
+{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual
+ caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EINVAL}] l'argomento \param{sem} non indica un semaforo
+ valido.
+ \end{errlist}
+}
+\end{funcproto}
+
+La funzione chiude il semaforo indicato dall'argomento \param{sem}, che non
+potrà più essere utilizzato nelle altre funzioni. La chiusura comporta anche
+che tutte le risorse che il sistema poteva avere assegnato al processo
+nell'uso del semaforo vengono immediatamente rilasciate. Questo significa che
+un eventuale altro processo bloccato sul semaforo a causa della acquisizione
+dello stesso da parte del processo che chiama \func{sem\_close} potrà essere
+immediatamente riavviato.
+
+Si tenga presente poi che come avviene per i file, all'uscita di un processo
+anche 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 infine 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
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}
+
+\begin{funcproto}{
+\fhead{semaphore.h}
+\fdecl{int sem\_unlink(const char *name)}
+
+\fdesc{Rimuove un semaforo.}
+}
+
+{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual
+ caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
\item[\errcode{EACCES}] 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}
+ \end{errlist}
+}
+\end{funcproto}
La funzione rimuove il semaforo indicato dall'argomento \param{name}, che
prende un valore identico a quello usato per creare il semaforo stesso con
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}
+\begin{funcproto}{
+\fhead{semaphore.h}
+\fdecl{int sem\_init(sem\_t *sem, int pshared, unsigned int value)}
+\fdesc{Inizializza un semaforo anonimo.}
+}
+
+{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual
+ caso \var{errno} assumerà uno dei 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}
+ \end{errlist}
+}
+\end{funcproto}
La funzione inizializza un semaforo all'indirizzo puntato dall'argomento
\param{sem}, e come per \func{sem\_open} consente di impostare un valore
sez.~\ref{sec:ipc_sysv_shm}) che con \func{shm\_open} (vedi
sez.~\ref{sec:ipc_posix_shm}), oppure, nel caso che tutti i processi in gioco
abbiano un genitore comune, con una mappatura anonima con \func{mmap} (vedi
-sez.~\ref{sec:file_memory_map}),\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.
+sez.~\ref{sec:file_memory_map}) a cui essi poi potranno accedere (si ricordi
+che i tratti di memoria condivisa vengono mantenuti nei processi figli
+attraverso la funzione \func{fork}).
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.
-Una volta che non si intenda più utilizzare un semaforo anonimo questo può
-essere eliminato dal sistema; per far questo di deve utilizzare una apposita
+Qualora non si intenda più utilizzare un semaforo anonimo questo può essere
+eliminato dal sistema; per far questo di deve utilizzare una apposita
funzione, \funcd{sem\_destroy}, il cui prototipo è:
-\begin{functions}
- \headdecl{semaphore.h}
-
- \funcdecl{int sem\_destroy(sem\_t *sem)}
- Elimina 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}.
- \end{errlist}
+\begin{funcproto}{
+\fhead{semaphore.h}
+\fdecl{int sem\_destroy(sem\_t *sem)}
+\fdesc{Elimina un semaforo anonimo.}
}
-\end{functions}
+{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual
+ caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EINVAL}] l'argomento \param{sem} non indica un semaforo
+ valido.
+ \end{errlist}
+}
+\end{funcproto}
La funzione prende come unico argomento l'indirizzo di un semaforo che deve
essere stato inizializzato con \func{sem\_init}; non deve quindi essere
Come prima istruzione (\texttt{\small 10}) si è provveduto ad installare un
gestore di segnale che consentirà di effettuare le operazioni di pulizia
(usando la funzione \func{Signal} illustrata in
-fig.~\ref{fig:sig_Signal_code}), dopo di che (\texttt{\small 10--16}) si è
+fig.~\ref{fig:sig_Signal_code}), dopo di che (\texttt{\small 12--16}) si è
creato il segmento di memoria condivisa con la funzione \func{CreateShm} che
abbiamo appena trattato in sez.~\ref{sec:ipc_posix_shm}, uscendo con un
messaggio in caso di errore.
notazione ottale). Infine il semaforo verrà inizializzato ad un valore nullo
(il quarto argomento), corrispondete allo stato in cui risulta bloccato.
-A questo punto (\texttt{\small 23}) si potrà inizializzare il messaggio posto
+A questo punto (\texttt{\small 22}) si potrà inizializzare il messaggio posto
nel segmento di memoria condivisa usando la stringa passata come argomento al
programma. Essendo il semaforo stato creato già bloccato non ci si dovrà
preoccupare di eventuali \itindex{race~condition} \textit{race condition}
qualora il programma di modifica del messaggio venisse lanciato proprio in
questo momento. Una volta inizializzato il messaggio occorrerà però
-rilasciare il semaforo (\texttt{\small 25--28}) per consentirne l'uso; in
+rilasciare il semaforo (\texttt{\small 24--27}) per consentirne l'uso; in
tutte queste operazioni si provvederà ad uscire dal programma con un opportuno
messaggio in caso di errore.
semaforo ad inizio del ciclo; seguito (\texttt{\small 35--36}) dal tempo
corrente.
-\begin{figure}[!htbp]
+\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{\codesamplewidth}
\includecodesample{listati/HandSigInt.c}
\end{figure}
Prima della stampa del messaggio invece si deve acquisire il semaforo
-(\texttt{\small 31--34}) per evitare accessi concorrenti alla stringa da parte
+(\texttt{\small 30--33}) per evitare accessi concorrenti alla stringa da parte
del programma di modifica. Una volta eseguita la stampa (\texttt{\small 41})
il semaforo dovrà essere rilasciato (\texttt{\small 42--45}). Il passo finale
(\texttt{\small 46}) è attendere per un secondo prima di eseguire da capo il
ciclo.
-Per uscire in maniera corretta dal programma sarà necessario interromperlo con
-il break da tastiera (\texttt{C-c}), che corrisponde all'invio del segnale
+Per uscire in maniera corretta dal programma sarà necessario fermarlo con una
+interruzione da tastiera (\texttt{C-c}), che corrisponde all'invio del segnale
\signal{SIGINT}, per il quale si è installato (\texttt{\small 10}) una
opportuna funzione di gestione, riportata in
fig.~\ref{fig:ipc_posix_sem_shm_message_server_handler}. La funzione è molto
condivisa che per il semaforo, garantendo così che possa essere riaperto
ex-novo senza errori in un futuro riutilizzo del comando.
-\begin{figure}[!htbp]
+\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{\codesamplewidth}
\includecodesample{listati/message_setter.c}