X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=ipc.tex;h=df279c99e6653bd34d7692eed29572b0ed1e954b;hp=b7ccdd8411a4f68dab756173ccc7f5275d204a60;hb=e7010c3fbd41a2de44c7b513c5de6e2c6d7ab4b4;hpb=bd30f25c8d511de4ffa7227a93272a71499cebc8 diff --git a/ipc.tex b/ipc.tex index b7ccdd8..df279c9 100644 --- a/ipc.tex +++ b/ipc.tex @@ -1017,8 +1017,9 @@ Il sistema dispone sempre di un numero fisso di oggetti di IPC,\footnote{fino altri limiti relativi al \textit{SysV IPC}) solo con una ricompilazione del kernel, andando a modificarne la definizione nei relativi header file. A partire dal kernel 2.4.x è possibile cambiare questi valori a sistema attivo - scrivendo sui file \file{shmmni}, \file{msgmni} e \file{sem} di - \file{/proc/sys/kernel} o con l'uso di \func{sysctl}.} e per ciascuno di + scrivendo sui file \procrelfile{/proc/sys/kernel}{shmmni}, + \procrelfile{/proc/sys/kernel}{msgmni} e \procrelfile{/proc/sys/kernel}{sem} + di \file{/proc/sys/kernel} o con l'uso di \func{sysctl}.} e per ciascuno di essi viene mantenuto in \var{seq} un numero di sequenza progressivo che viene incrementato di uno ogni volta che l'oggetto viene cancellato. Quando l'oggetto viene creato usando uno spazio che era già stato utilizzato in @@ -1160,7 +1161,7 @@ coda. \hline \hline \const{MSGMNI}& 16& \file{msgmni} & Numero massimo di code di - messaggi. \\ + messaggi.\\ \const{MSGMAX}& 8192& \file{msgmax} & Dimensione massima di un singolo messaggio.\\ \const{MSGMNB}&16384& \file{msgmnb} & Dimensione massima del contenuto di @@ -1175,7 +1176,9 @@ Le code di messaggi sono caratterizzate da tre limiti fondamentali, definiti negli header e corrispondenti alle prime tre costanti riportate in tab.~\ref{tab:ipc_msg_limits}, come accennato però in Linux è possibile modificare questi limiti attraverso l'uso di \func{sysctl} o scrivendo nei -file \file{msgmax}, \file{msgmnb} e \file{msgmni} di \file{/proc/sys/kernel/}. +file \procrelfile{/proc/sys/kernel}{msgmax}, +\procrelfile{/proc/sys/kernel}{msgmnb} e +\procrelfile{/proc/sys/kernel}{msgmni} di \file{/proc/sys/kernel/}. \begin{figure}[htb] @@ -1860,16 +1863,16 @@ indicano rispettivamente: \textbf{Costante} & \textbf{Valore} & \textbf{Significato} \\ \hline \hline - \const{SEMMNI}& 128 & Numero massimo di insiemi di semafori. \\ + \const{SEMMNI}& 128 & Numero massimo di insiemi di semafori.\\ \const{SEMMSL}& 250 & Numero massimo di semafori per insieme.\\ \const{SEMMNS}&\const{SEMMNI}*\const{SEMMSL}& Numero massimo di semafori - nel sistema .\\ + nel sistema.\\ \const{SEMVMX}& 32767 & Massimo valore per un semaforo.\\ \const{SEMOPM}& 32 & Massimo numero di operazioni per chiamata a \func{semop}. \\ \const{SEMMNU}&\const{SEMMNS}& Massimo numero di strutture di ripristino.\\ \const{SEMUME}&\const{SEMOPM}& Massimo numero di voci di ripristino.\\ - \const{SEMAEM}&\const{SEMVMX}& valore massimo per l'aggiustamento + \const{SEMAEM}&\const{SEMVMX}& Valore massimo per l'aggiustamento all'uscita. \\ \hline \end{tabular} @@ -1882,7 +1885,7 @@ Come per le code di messaggi anche per gli insiemi di semafori esistono una serie di limiti, i cui valori sono associati ad altrettante costanti, che si sono riportate in tab.~\ref{tab:ipc_sem_limits}. Alcuni di questi limiti sono al solito accessibili e modificabili attraverso \func{sysctl} o scrivendo -direttamente nel file \file{/proc/sys/kernel/sem}. +direttamente nel file \procfile{/proc/sys/kernel/sem}. La funzione che permette di effettuare le varie operazioni di controllo sui semafori (fra le quali, come accennato, è impropriamente compresa anche la @@ -2008,10 +2011,10 @@ tutti i semafori il cui valore viene modificato. \textbf{Operazione} & \textbf{Valore restituito} \\ \hline \hline - \const{GETNCNT}& valore di \var{semncnt}.\\ - \const{GETPID} & valore di \var{sempid}.\\ - \const{GETVAL} & valore di \var{semval}.\\ - \const{GETZCNT}& valore di \var{semzcnt}.\\ + \const{GETNCNT}& Valore di \var{semncnt}.\\ + \const{GETPID} & Valore di \var{sempid}.\\ + \const{GETVAL} & Valore di \var{semval}.\\ + \const{GETZCNT}& Valore di \var{semzcnt}.\\ \hline \end{tabular} \caption{Valori di ritorno della funzione \func{semctl}.} @@ -2428,23 +2431,25 @@ che permettono di cambiarne il valore. & \textbf{Significato} \\ \hline \hline - \const{SHMALL}& 0x200000&\file{shmall}& Numero massimo di pagine che - possono essere usate per i segmenti di - memoria condivisa. \\ - \const{SHMMAX}&0x2000000&\file{shmmax}& Dimensione massima di un segmento - di memoria condivisa.\\ - \const{SHMMNI}& 4096&\file{msgmni}& Numero massimo di segmenti di - memoria condivisa presenti nel - kernel.\\ + \const{SHMALL}& 0x200000&\procrelfile{/proc/sys/kernel}{shmall} + & Numero massimo di pagine che + possono essere usate per i segmenti di + memoria condivisa.\\ + \const{SHMMAX}&0x2000000&\procrelfile{/proc/sys/kernel}{shmmax} + & Dimensione massima di un segmento di memoria + condivisa.\\ + \const{SHMMNI}& 4096&\procrelfile{/proc/sys/kernel}{msgmni} + & Numero massimo di segmenti di memoria condivisa + presenti nel kernel.\\ \const{SHMMIN}& 1& --- & Dimensione minima di un segmento di - memoria condivisa. \\ + memoria condivisa.\\ \const{SHMLBA}&\const{PAGE\_SIZE}&--- & Limite inferiore per le dimensioni minime di un segmento (deve essere allineato alle dimensioni di una - pagina di memoria). \\ + pagina di memoria).\\ \const{SHMSEG}& --- & --- & Numero massimo di segmenti di - memoria condivisa - per ciascun processo.\\ + memoria condivisa per ciascun + processo.\\ \hline @@ -3234,6 +3239,7 @@ pi sez.~\ref{sec:ipc_sysv_shm} che possa restituisca i risultati via rete. \itindend{memory~mapping} +% TODO fare esempio di mmap anonima \section{Il sistema di comunicazione fra processi di POSIX} \label{sec:ipc_posix} @@ -3768,16 +3774,16 @@ suoi contenuti in memoria,\footnote{il filesystem \texttt{tmpfs} per la memoria condivisa; esso infatti non ha dimensione fissa, ed usa direttamente la cache interna del kernel (che viene usata anche per la shared memory in stile SysV). In più i suoi contenuti, essendo trattati - direttamente dalla memoria virtuale\index{memoria~virtuale} possono essere + direttamente dalla memoria virtuale \index{memoria~virtuale} possono essere salvati sullo swap automaticamente.} che viene attivato abilitando l'opzione \texttt{CONFIG\_TMPFS} in fase di compilazione del kernel. -Per potere utilizzare l'interfaccia POSIX per le code di messaggi le +Per potere utilizzare l'interfaccia POSIX per la memoria condivisa le \acr{glibc}\footnote{le funzioni sono state introdotte con le glibc-2.2.} richiedono di compilare i programmi con l'opzione \code{-lrt}; inoltre è necessario che in \file{/dev/shm} sia montato un filesystem \texttt{tmpfs}; -questo di norma viene eseguita aggiungendo una riga tipo: +questo di norma viene fatto aggiungendo una riga del tipo di: \begin{verbatim} tmpfs /dev/shm tmpfs defaults 0 0 \end{verbatim} @@ -3845,7 +3851,7 @@ segmento di memoria condiviso con le stesse modalit 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 -\index{inode}inode). In questo modo è possibile effettuare una chiamata ad +\index{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. @@ -3963,8 +3969,6 @@ Anche in questo caso questa interfaccia, oltre ad utilizzare gli opportuni file di definizione, occorrerà compilare i programmi con l'opzione \texttt{-lrt}. -% TODO trattare l'argomento a partire da man sem_overview. - 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 @@ -4074,13 +4078,14 @@ 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 è 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} @@ -4098,14 +4103,17 @@ acquisizione senza bloccarsi; il suo prototipo } \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} @@ -4119,18 +4127,23 @@ includere \texttt{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} @@ -4146,26 +4159,193 @@ utilizzata per rilasciare un semaforo occupato; il suo prototipo } \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. Questo +potrà essere ottenuto direttamente sia con \func{shmget} (vedi +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. + +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 indenda più utilizzare un semaforo anonimo questo può +essere eliminato da 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} +} +\end{functions} +La funzione prende come unico argomento l'indirizzo di un semaforo che deve +essere stato inizializzato con \func{sem\_init}; non deve quindi essere +applicata a semafori creati con \func{sem\_open}. Inoltre si deve essere +sicuri che il semaforo sia effettivamente inutilizzato, la distruzione di un +semaforo su cui sono presenti processi (o thread) in attesa (cioè bloccati in +una \func{sem\_wait}) provoca un comportamento indefinito. +Si tenga presente infine che utilizzare un semaforo che è stato distrutto con +\func{sem\_destroy} di nuovo può dare esito a comportamenti indefiniti. Nel +caso ci si trovi in una tale evenienza occorre reinizializzare il semaforo una +seconda volta con \func{sem\_init}. % LocalWords: like fifo System POSIX RPC Calls Common Object Request Brocker @@ -4218,7 +4398,7 @@ si usino o processo (nel qual caso si parla di \textit{process-shared % 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: