From 17e39705eccbaa9111592907195befd05dbbed2d Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Thu, 5 Dec 2002 00:58:49 +0000 Subject: [PATCH] Aggiunte alla shared memory --- ipc.tex | 153 +++++++++++++++++++++++++++++------------------ sources/Makefile | 2 +- 2 files changed, 95 insertions(+), 60 deletions(-) diff --git a/ipc.tex b/ipc.tex index 783bfee..2975185 100644 --- a/ipc.tex +++ b/ipc.tex @@ -1963,7 +1963,7 @@ soffrono di altri due, ben pi Il primo difetto è che non esiste una funzione che permetta di creare ed inizializzare un semaforo in un'unica chiamata; occorre prima creare l'insieme dei semafori con \func{semget} e poi inizializzarlo con \func{semctl}, si -perde così ogni possibilità di eseguire atomicamente questa operazione. +perde così ogni possibilità di eseguire l'operazione atomicamente. Il secondo difetto deriva dalla caratteristica generale degli oggetti del \textit{SysV IPC} di essere risorse globali di sistema, che non vengono @@ -2121,12 +2121,6 @@ specificata con \param{cmd}, ed opera o sull'intero insieme specificato da \param{semid} o sul singolo semaforo di un insieme, specificato da \param{semnum}. -Qualora la funzione operi con quattro argomenti \param{arg} è -un argomento generico, che conterrà un dato diverso a seconda dell'azione -richiesta; per unificare l'argomento esso deve essere passato come una -\var{union semun}, la cui definizione, con i possibili valori che può -assumere, è riportata in \figref{fig:ipc_semun}. - \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15cm} @@ -2146,6 +2140,12 @@ union semun { \label{fig:ipc_semun} \end{figure} +Qualora la funzione operi con quattro argomenti \param{arg} è +un argomento generico, che conterrà un dato diverso a seconda dell'azione +richiesta; per unificare l'argomento esso deve essere passato come una +\var{union semun}, la cui definizione, con i possibili valori che può +assumere, è riportata in \figref{fig:ipc_semun}. + Come già accennato sia il comportamento della funzione che il numero di parametri con cui deve essere invocata, dipendono dal valore dell'argomento \param{cmd}, che specifica l'azione da intraprendere; i valori validi (che @@ -2464,7 +2464,7 @@ nullo per segnalarne l'indisponibilit /* * Function MutexCreate: create a mutex/semaphore */ -inline int MutexCreate(key_t ipc_key) +int MutexCreate(key_t ipc_key) { const union semun semunion={1}; /* semaphore union structure */ int sem_id, ret; @@ -2481,14 +2481,14 @@ inline int MutexCreate(key_t ipc_key) /* * Function MutexFind: get the semaphore/mutex Id given the IPC key value */ -inline int MutexFind(key_t ipc_key) +int MutexFind(key_t ipc_key) { return semget(ipc_key,1,0); } /* * Function MutexRead: read the current value of the mutex/semaphore */ -inline int MutexRead(int sem_id) +int MutexRead(int sem_id) { return semctl(sem_id, 0, GETVAL); } @@ -2502,18 +2502,18 @@ struct sembuf sem_lock={ /* to lock semaphore */ struct sembuf sem_ulock={ /* to unlock semaphore */ 0, /* semaphore number (only one so 0) */ 1, /* operation (1 to release resource) */ - SEM_UNO}; /* flag (in this case 0) */ + SEM_UNDO}; /* flag (in this case 0) */ /* * Function MutexLock: to lock a mutex/semaphore */ -inline int MutexLock(int sem_id) +int MutexLock(int sem_id) { return semop(sem_id, &sem_lock, 1); } /* * Function MutexUnlock: to unlock a mutex/semaphore */ -inline int MutexUnlock(int sem_id) +int MutexUnlock(int sem_id) { return semop(sem_id, &sem_ulock, 1); } @@ -2561,21 +2561,21 @@ il mutex. Entrambe fanno da wrapper per \func{semop}, utilizzando le due strutture \var{sem\_lock} e \var{sem\_unlock} definite in precedenza (\texttt{\small 32--42}). Si noti come per queste ultime si sia fatto uso dell'opzione \macro{SEM\_UNDO} per evitare che il semaforo resti bloccato in -caso di terminazione imprevista del processo. Si noti infine come, essendo -tutte le funzioni riportate in \figref{fig:ipc_mutex_create} estremamente -semplici, se si sono definite tutte come \ctyp{inline}.\footnote{la direttiva - \func{inline} viene usata per dire al compilatore di non trattare la - funzione cui essa fa riferimento come una funzione, ma di inserire il codice - direttamente nel testo del programma. Anche se i compilatori più moderni - sono in grado di effettuare da soli queste manipolazioni (impostando le - opportune ottimizzazioni) questa è una tecnica usata per migliorare le - prestazioni per le funzioni piccole ed usate di frequente, in tal caso - infatti le istruzioni per creare un nuovo frame nello stack per chiamare la - funzione costituirebbero una parte rilevante del codice, appesantendo - inutilmente il programma. Originariamente questa era fatto utilizzando delle - macro, ma queste hanno tutta una serie di problemi di sintassi nel passaggio - degli argomenti (si veda ad esempio \cite{PratC} che in questo modo possono - essere evitati.} +caso di terminazione imprevista del processo.%% Si noti infine come, essendo +%% tutte le funzioni riportate in \figref{fig:ipc_mutex_create} estremamente +%% semplici, se si sono definite tutte come \ctyp{inline}.\footnote{la direttiva +%% \func{inline} viene usata per dire al compilatore di non trattare la +%% funzione cui essa fa riferimento come una funzione, ma di inserire il codice +%% direttamente nel testo del programma. Anche se i compilatori più moderni +%% sono in grado di effettuare da soli queste manipolazioni (impostando le +%% opportune ottimizzazioni) questa è una tecnica usata per migliorare le +%% prestazioni per le funzioni piccole ed usate di frequente, in tal caso +%% infatti le istruzioni per creare un nuovo frame nello stack per chiamare la +%% funzione costituirebbero una parte rilevante del codice, appesantendo +%% inutilmente il programma. Originariamente questa era fatto utilizzando delle +%% macro, ma queste hanno tutta una serie di problemi di sintassi nel passaggio +%% degli argomenti (si veda ad esempio \cite{PratC} che in questo modo possono +%% essere evitati.} Chiamare \func{MutexLock} decrementa il valore del semaforo: se questo è @@ -2594,8 +2594,6 @@ analoga senza questo problemi usando il file locking. - - \subsection{Memoria condivisa} \label{sec:ipc_sysv_shm} @@ -2648,7 +2646,7 @@ quest'ultimo non acceda al segmento di memoria condivisa prima che il primo non abbia completato le operazioni di scrittura, inoltre nel corso di una lettura si deve essere sicuri che i dati restano coerenti e non vengono sovrascritti da un accesso in scrittura sullo stesso segmento da parte di un -altro processo; per questo in genere la memoria condivisa viene sempre +altro processo. Per questo in genere la memoria condivisa viene sempre utilizzata in abbinamento ad un meccanismo di sincronizzazione, il che, di norma, significa insieme a dei semafori. @@ -2687,7 +2685,7 @@ invece: inizializzato al valore di \param{size}. \item il campo \var{shm\_ctime}, che esprime il tempo di creazione del segmento, viene inizializzato al tempo corrente. -\item i campi \var{shm\_atime} e \var{shm\_atime}, che esprimono +\item i campi \var{shm\_atime} e \var{shm\_dtime}, che esprimono rispettivamente il tempo dell'ultima volta che il segmento è stato agganciato o sganciato da un processo, vengono inizializzati a zero. \item il campo \var{shm\_lpid}, che esprime il \acr{pid} del processo che ha @@ -2699,11 +2697,14 @@ invece: \end{itemize*} Come per le code di messaggi e gli insiemi di semafori, anche per i segmenti -di memoria condivisa esistono una serie di limiti, i cui valori, riportati in -\tabref{tab:ipc_shm_limits} sono associati ad altrettante costanti. Alcuni di -questi limiti sono al solito accessibili e modificabili attraverso +di memoria condivisa esistono una serie di limiti imposti dal sistema. Alcuni +di questi limiti sono al solito accessibili e modificabili attraverso \func{sysctl} o scrivendo direttamente nei rispettivi file di -\file{/proc/sys/kernel/}. +\file{/proc/sys/kernel/}. In \tabref{tab:ipc_shm_limits} si sono riportate le +costanti simboliche associate a ciascuno di essi, il loro significato, i +valori preimpostati, e, quando presente, il file in \file{/proc/sys/kernel/} +che permettono di cambiarne il valore. + \begin{table}[htb] \footnotesize @@ -2714,15 +2715,25 @@ questi limiti sono al solito accessibili e modificabili attraverso & \textbf{Significato} \\ \hline \hline - \macro{SHMALL}&0x200000&\file{shmall}& Numero massimo di pagine che + \macro{SHMALL}& 0x200000&\file{shmall}& Numero massimo di pagine che possono essere usate per i segmenti di memoria condivisa. \\ \macro{SHMMAX}&0x2000000&\file{shmmax}& Dimensione massima di un segmento - di memoria condivisa.\\ - \macro{SHMMNI}&4096&\file{msgmni}& Numero massimo di segmenti di memoria - condivisa presenti nel kernel.\\ - \macro{SHMMIN}& 1& --- & Dimensione minima di un segmento di - memoria condivisa. \\ + di memoria condivisa.\\ + \macro{SHMMNI}& 4096&\file{msgmni}& Numero massimo di segmenti di + memoria condivisa presenti nel + kernel.\\ + \macro{SHMMIN}& 1& --- & Dimensione minima di un segmento di + memoria condivisa. \\ + \macro{SHMLBA}&\macro{PAGE\_SIZE}&--- & Limite inferiore per le dimensioni + minime di un segmento (deve essere + allineato alle dimensioni di una + pagina di memoria). \\ + \macro{SHMSEG}& --- & --- & Numero massimo di segmenti di + memoria condivisa + per ciascun processo.\\ + + \hline \end{tabular} \caption{Valori delle costanti associate ai limiti dei segmenti di memoria @@ -2767,18 +2778,20 @@ attraverso l'argomento \param{cmd}, i valori possibili sono i seguenti: \item[\macro{IPC\_RMID}] Marca il segmento di memoria condivisa per la rimozione, questo verrà cancellato effettivamente solo quando l'ultimo processo ad esso agganciato si sarà staccato. Questo comando può essere - eseguito solo da un processo con userid effettivo, corrispondente al - creatore o al proprietario della coda, o all'amministratore. + eseguito solo da un processo con userid effettivo corrispondente o al + creatore della coda, o al proprietario della coda, o all'amministratore. \item[\macro{IPC\_SET}] Permette di modificare i permessi ed il proprietario del segmento. Per modificare i valori di \var{shm\_perm.mode}, \var{shm\_perm.uid} e \var{shm\_perm.gid} occorre essere il proprietario o il creatore della coda, oppure l'amministratore. Compiuta l'operazione aggiorna anche il valore del campo \var{shm\_ctime}. \item[\macro{SHM\_LOCK}] Abilita il \textit{memory locking}\index{memory - locking} (vedi \secref{sec:proc_mem_lock}) sul segmento di memoria + locking}\footnote{impedisce cioè che la memoria usata per il segmento + venga salvata su disco dal meccanismo della memoria virtuale; si ricordi + quanto trattato in \secref{sec:proc_mem_lock}.} sul segmento di memoria condivisa. Solo l'amministratore può utilizzare questo comando. -\item[\macro{SHM\_UNLOCK}] Disabilita il \textit{memory locking}. Solo - l'amministratore può utilizzare questo comando. +\item[\macro{SHM\_UNLOCK}] Disabilita il \textit{memory locking} sul segmento + di memoria condivisa. Solo l'amministratore può utilizzare questo comando. \end{basedescript} i primi tre comandi sono gli stessi già visti anche per le code ed i semafori, gli ultimi due sono delle estensioni previste da Linux. @@ -2811,8 +2824,10 @@ La funzione inserisce un segmento di memoria condivisa all'interno dello spazio di indirizzi del processo, in modo che questo possa accedervi direttamente, la situazione dopo l'esecuzione di \func{shmat} è illustrata in \figref{fig:ipc_shmem_layout} (per la comprensione del resto dello schema si -ricordi quanto illustrato al proposito in \secref{sec:proc_mem_layout}). Si -tenga presente che la funzione ha successo anche se il segmento è stato +ricordi quanto illustrato al proposito in \secref{sec:proc_mem_layout}). In +particolare l'indirizzo finale del segmento dati (quello impostato da +\func{brk}, vedi \secref{sec:proc_mem_sbrk}) non viene influenzato. Si tenga +presente infine che la funzione ha successo anche se il segmento è stato marcato per la cancellazione. \begin{figure}[htb] @@ -2834,7 +2849,13 @@ memoria libera (questo Altrimenti il kernel aggancia il segmento all'indirizzo specificato da \param{shmaddr}; questo però può avvenire solo se l'indirizzo coincide con il limite di una pagina, cioè se è un multiplo esatto del parametro di sistema -\macro{SHMLBA}, che in Linux è sempre uguale \macro{PAGE\_SIZE}. +\macro{SHMLBA}, che in Linux è sempre uguale \macro{PAGE\_SIZE}. + +Si tenga presente però che quando si usa \macro{NULL} come valore di +\param{shmaddr}, l'indirizzo restituito da \func{shmat} può cambiare da +processo a processo; pertanto se nell'area di memoria condivisa si salvano +anche degli indirizzi, si deve avere cura di usare valori relativi (in genere +riferiti all'indirizzo di partenza del segmento). L'argomento \param{shmflg} permette di cambiare il comportamento della funzione; esso va specificato come maschera binaria, i bit utilizzati sono @@ -2845,15 +2866,16 @@ solo due e sono identificati dalle costanti \macro{SHM\_RND} e un valore qualunque per \param{shmaddr}, e il segmento verrà comunque agganciato, ma al più vicino multiplo di \macro{SHMLBA} (il nome della costante sta infatti per \textit{rounded}, e serve per specificare un -indirizzo come arrotondamento). +indirizzo come arrotondamento, in Linux è equivalente a \macro{PAGE\_SIZE}). -Il secondo bit permette di agganciare il segmento in sola lettura (si ricordi -che anche le pagine di memoria hanno dei permessi), in tal caso un tentativo -di scrivere sul segmento comporterà una violazione di accesso con l'emissione -di un segnale di \macro{SIGSEGV}. Il comportamento usuale di \func{shmat} è -quello di agganciare il segmento con l'accesso in lettura e scrittura (ed il -processo deve aver questi permessi in \var{shm\_perm}), non è prevista la -possibilità di agganciare un segmento in sola scrittura. +L'uso di \macro{SHM\_RDONLY} permette di agganciare il segmento in sola +lettura (si ricordi che anche le pagine di memoria hanno dei permessi), in tal +caso un tentativo di scrivere sul segmento comporterà una violazione di +accesso con l'emissione di un segnale di \macro{SIGSEGV}. Il comportamento +usuale di \func{shmat} è quello di agganciare il segmento con l'accesso in +lettura e scrittura (ed il processo deve aver questi permessi in +\var{shm\_perm}), non è prevista la possibilità di agganciare un segmento in +sola scrittura. In caso di successo la funzione aggiorna anche i seguenti campi di \var{shmid\_ds}: @@ -2875,7 +2897,6 @@ diverso, tutti i segmenti agganciati al processo originario vengono automaticamente sganciati. Lo stesso avviene all'uscita del processo attraverso una \func{exit}. - Una volta che un segmento di memoria condivisa non serve più, si può sganciarlo esplicitamente dal processo usando l'altra funzione dell'interfaccia, \func{shmdt}, il cui prototipo è: @@ -2897,6 +2918,20 @@ memoria condivisa; questo viene identificato con l'indirizzo \param{shmaddr} restituito dalla precedente chiamata a \func{shmat} con il quale era stato agganciato al processo. +In caso di successo la funzione aggiorna anche i seguenti campi di +\var{shmid\_ds}: +\begin{itemize*} +\item il tempo \var{shm\_dtime} dell'ultima operazione di sganciamento viene + impostato al tempo corrente. +\item il \acr{pid} \var{shm\_lpid} dell'ultimo processo che ha operato sul + segmento viene impostato a quello del processo corrente. +\item il numero \var{shm\_nattch} di processi agganciati al segmento viene + decrementato di uno. +\end{itemize*} +inoltre la regione di indirizzi usata per il segmento di memoria condivisa +viene tolta dallo spazio di indirizzi del processo. + + %% Per capire meglio il funzionamento delle funzioni facciamo ancora una volta %% riferimento alle strutture con cui il kernel implementa i segmenti di memoria %% condivisa; uno schema semplificato della struttura è illustrato in diff --git a/sources/Makefile b/sources/Makefile index 64f7648..a4e31fd 100644 --- a/sources/Makefile +++ b/sources/Makefile @@ -25,7 +25,7 @@ all: $(FINAL) $(LIB) flock: Flock.c $(CC) $(CFLAGJ) $^ -o $@ -mqfortune: MQFortuneClient.c +mqfortune: MQFortuneClient.c FortuneParse.c $(CC) $(CFLAGJ) $^ -o $@ mqfortuned: MQFortuneServer.c FortuneParse.c -- 2.30.2