basato su oggetti permanenti che risiedono nel kernel. Questi, a differenza di
quanto avviene per i file descriptor, non mantengono un contatore dei
riferimenti, e non vengono cancellati dal sistema una volta che non sono più
-in uso. Questo comporta che, al contrario di quanto avviene per pipe e fifo,
-la memoria allocata per questi oggetti non viene rilasciata automaticamente,
-ed essi devono essere cancellati esplicitamente, altrimenti resteranno attivi
-fino al riavvio del sistema.
+in uso.
+
+Questo comporta due problemi: il primo è che, al contrario di quanto avviene
+per pipe e fifo, la memoria allocata per questi oggetti non viene rilasciata
+automaticamente quando nessuno li vuole più utilizzare, ed essi devono essere
+cancellati esplicitamente, se non si vuole che restino attivi fino al riavvio
+del sistema. Il secondo è che, dato che non c'è un contatore di riferimenti,
+essi possono essere cancellati anche se ci sono dei processi che li stanno
+utilizzando, con tutte le conseguenze (negative) del caso.
Gli oggetti usati nel System V IPC vengono creati direttamente dal kernel, e
sono accessibili solo specificando il relativo \textsl{identificatore}. Questo
-è il numero progressivo che il kernel assengna a ciascuno di essi quanto
-vengono creati (il prodedimento è simile a quello con cui si assegna il
-\acr{pid} ai processi). L'identificatore viene restituito dalle funzioni che
-creano l'oggetto, ed è quindi locale al processo che le ha eseguite. Dato che
-l'identificatore viene assegnato dinamicamente dal kernel non è possibile
-prevedere quale sarà, ne utilizzare un qualche valore statico, si pone perciò
-il problema di come processi diversi possono accedere allo stesso oggetto.
+è un numero progressivo (un po' come il \acr{pid} dei processi) che il kernel
+assegna a ciascuno di essi quanto vengono creati (sul prodedimento di
+assegnazione torneremo in \secref{sec:ipc_sysv_id_use}). L'identificatore
+viene restituito dalle funzioni che creano l'oggetto, ed è quindi locale al
+processo che le ha eseguite. Dato che l'identificatore viene assegnato
+dinamicamente dal kernel non è possibile prevedere quale sarà, ne utilizzare
+un qualche valore statico, si pone perciò il problema di come processi diversi
+possono accedere allo stesso oggetto.
Per risolvere il problema il kernel associa a ciascun oggetto una struttura
\var{ipc\_perm}; questa contiene una \textsl{chiave}, identificata da una
attributi di \var{ipc\_perm}, non esiste una modalità semplice per essere
sicuri della validità di una certa chiave.
-Questo è, insieme al fatto che gli oggetti sono permanenti e devono essere
-cancellati esplicitamente, il principale problema del sistema di IPC di System
-V. Non esiste infatti una modalità chiara per identificare un oggetto, come
-sarebbe stato se lo si fosse associato ad in file, e tutta l'interfaccia è
-inutilmente complessa. Per questo ne è stata effettuata una revisione
-completa nello standard POSIX.1b, che tratteremo in \secref{sec:ipc_posix}.
+Questo è, insieme al fatto che gli oggetti sono permanenti e non mantengono un
+contatore di riferimenti per la cancellazione automatica, il principale
+problema del sistema di IPC di System V. Non esiste infatti una modalità
+chiara per identificare un oggetto, come sarebbe stato se lo si fosse
+associato ad in file, e tutta l'interfaccia è inutilmente complessa. Per
+questo ne è stata effettuata una revisione completa nello standard POSIX.1b,
+che tratteremo in \secref{sec:ipc_posix}.
\subsection{Il controllo di accesso}
Il secondo livello è quello delle varie funzioni che accedono (in lettura o
scrittura) all'oggetto. In tal caso lo schema dei controlli è simile a quello
dei file, ed avviene secondo questa sequenza:
-\begin{enumerate}
+\begin{itemize}
\item se il processo ha i privilegi di amministatore l'accesso è sempre
consentito.
\item se l'userid effettivo del processo corrisponde o al valore del campo
\item se il groupid effettivo del processo corrisponde o al
valore del campo \var{cgid} o a quello del campo \var{gid} ed il permesso
per il gruppo in \var{mode} è appropriato l'accesso è consentito.
-\item
-\end{enumerate}
+\item se il permesso per gli altri è appropriato l'accesso è consentito.
+\end{itemize}
+solo se tutti i controlli elencati falliscono l'accesso è negato. Si noti che
+a differenza di quanto avviene per i permessi dei file, fallire in uno dei
+passi elencati non comporta il fallimento dell'accesso. Un'altra differenza è
+che per gli oggetti di IPC il valore di \var{umask} (si ricordi quanto esposto
+in \secref{sec:file_umask}) non ha alcun effetto.
+
+
+\subsection{Gli identificatori ed il loro utilizzo}
+\label{sec:ipc_sysv_id_use}
+
+L'unico campo di \var{ipc\_perm} del quale non abbiamo ancora parlato è
+\var{seq}, che in \figref{fig:ipc_ipc_perm} è qualificato con un criptico
+``\textit{numero di sequenza}'', ne parliamo adesso dato che esso è
+strettamente attinente alle modalità con cui il kernel assegna gli
+identificatori degli oggetti del sistema di IPC.
+
+Quando il sistema si avvia, alla creazione di ogni nuovo oggetto di IPC viene
+assegnato un numero progressivo, pari al numero di oggetti di quel tipo
+esistenti. Se il comportamente fosse sempre questo sarebbe identico a quello
+usato nell'assegnazione dei file descriptor nei processi, ed i valori degli
+identificatori tenderebbero ad essere riutilizzati spesso e restare di piccole
+dimensioni ed inferiori al numero massimo di oggetti diponibili.
+
+Questo va benissimo nel caso dei file descriptor, che sono locali ad un
+processo, ma qui il comportamento varrebbe per tutto il sistema, e per
+processi del tutto scorrelati fra loro. Così si potrebbero avere situazioni
+come quella in cui un server esce e cancella le sue code di messaggi, ed il
+relativo identificatore viene immediatamente assegnato a quelle di un altro
+server partito subito dopo, con la possibilità che i client del primo non
+facciano in tempo ad accorgersi dell'avvenuto, e finiscano con l'interagire
+con gli oggetti del secondo, con conseguenze imprevedibili.
+
+Proprio per evitare questo tipo di situazioni il sistema usa il valore di
+\var{req} per provvedere un meccanismo che porti gli identificatori ad
+assumere tutti i valori possibili, rendendo molto più lungo il periodo in cui
+un identificatore può venire riutilizzato.
+
+Il sistema dispone sempre di un numero fisso di oggetti di IPC,\footnote{fino
+ al kernel 2.2.x questo numero, ed altri limiti relativi al \textit{System V
+ IPC}, potevano essere cambiati solo con una ricompilazione del kernel,
+ andando a modificare le costanti definite nei relativi haeder 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 \texttt{syscntl}.} 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
+precedenza per restituire l'identificatore al numero di oggetti presenti viene
+sommato il valore di \var{seq} moltiplicato per il numero massimo di oggetti
+di quel tipo,\footnote{questo vale fino ai kernel della serie 2.2.x, dalla
+ serie 2.4.x viene usato lo stesso fattore per tutti gli oggetti, esso è dato
+ dalla costante \macro{IPCMNI}, definita in \file{include/linux/ipc.h}, che
+ indica il limite massimo per il numero di oggetti di IPC, il cui valore è
+ 32768.} si evita così il riutilizzo degli stessi numeri, e si fa sì che
+l'identificatore assuma tutti i valori possibili.
+
+In \figref{fig:ipc_sysv_idtest} è riportato il codice di un semplice programma
+di test che si limita a creare un oggetto (specificato a riga di comando),
+stamparne il numero di identificatore e cancellarlo per un numero specificato
+di volte.
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}{}
+int main(int argc, char *argv[])
+{
+ ...
+ switch (type) {
+ case 'q': /* Message Queue */
+ debug("Message Queue Try\n");
+ for (i=0; i<n; i++) {
+ id = msgget(IPC_PRIVATE, IPC_CREAT|0666);
+ printf("Identifier Value %d \n", id);
+ msgctl(id, IPC_RMID, NULL);
+ }
+ break;
+ case 's': /* Semaphore */
+ debug("Semaphore\n");
+ for (i=0; i<n; i++) {
+ id = semget(IPC_PRIVATE, 1, IPC_CREAT|0666);
+ printf("Identifier Value %d \n", id);
+ semctl(id, 0, IPC_RMID);
+ }
+ break;
+ case 'm': /* Shared Memory */
+ debug("Shared Memory\n");
+ for (i=0; i<n; i++) {
+ id = shmget(IPC_PRIVATE, 1000, IPC_CREAT|0666);
+ printf("Identifier Value %d \n", id);
+ shmctl(id, IPC_RMID, NULL);
+ }
+ break;
+ default: /* should not reached */
+ return -1;
+ }
+ return 0;
+}
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{Sezione principale del programma di test per l'assegnazione degli
+ identificatori degli oggetti di IPC \file{IPCTestId.c}.}
+ \label{fig:ipc_sysv_idtest}
+\end{figure}
+
+La figura non riporta il codice di selezione delle opzioni, che permette di
+inizializzare i valori delle variabili \var{type} al tipo di oggetto voluto, e
+\var{n} al numero di volte che si vuole effettuare il ciclo di creazione,
+stampa, cancellazione. I valori di default sono per l'uso delle code di
+messaggi e un ciclo di 10 volte. Se si lancia il comando si otterrà qualcosa
+del tipo:
+\begin{verbatim}
+piccardi@gont sources]$ ./ipctestid
+Identifier Value 0
+Identifier Value 32768
+Identifier Value 65536
+Identifier Value 98304
+Identifier Value 131072
+Identifier Value 163840
+Identifier Value 196608
+Identifier Value 229376
+Identifier Value 262144
+Identifier Value 294912
+\end{verbatim}%$
+il che ci mostra che abbiamo un kernel della serie 2.4.x nel quale non avevamo
+ancora usato nessuna coda di messaggi. Se ripetiamo il comando otterremo
+ancora:
+\begin{verbatim}
+[piccardi@gont sources]$ ./ipctestid
+Identifier Value 327680
+Identifier Value 360448
+Identifier Value 393216
+Identifier Value 425984
+Identifier Value 458752
+Identifier Value 491520
+Identifier Value 524288
+Identifier Value 557056
+Identifier Value 589824
+Identifier Value 622592
+\end{verbatim}%$
+che ci mostra come il valore di \var{seq} sia in effetti una quantità
+mantenuta staticamente all'interno del sistema.
\subsection{Code di messaggi}
Una coda di messaggi è costituita da una \textit{linked list} in cui nuovi
messaggi vengono inseriti in coda e letti dalla cima, con una struttura del
-tipo di quella illustrata in
-
+tipo di quella illustrata in
valori visti per \func{msgget}.}
\end{functions}
-La funzione, come per \func{semget}, è del tutto analoga a \func{msgget}, ed
+La funzione, come \func{semget}, è del tutto analoga a \func{msgget}, ed
identico è l'uso degli argomenti \param{key} e \param{flag}. L'argomento
+\subsection{Considerazioni generali}
+\label{sec:ipc_posix_generic}
+
+
+
+\subsection{Code di messaggi}
+\label{sec:ipc_posix_mq}
+
+
+\subsection{Semafori}
+\label{sec:ipc_posix_sem}
+
+
+\subsection{Memoria condivisa}
+\label{sec:ipc_sysv_shm}
%%% Local Variables:
%%% mode: latex
--- /dev/null
+/* IPCTestId.c
+ *
+ * Copyright (C) 2001 Simone Piccardi
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/****************************************************************
+ *
+ * Program IPCTestId.c:
+ * Program to test IPC identifiers
+ *
+ * Author: Simone Piccardi
+ * Aug. 2002
+ *
+ * Usage: ipctestid -h give all info's
+ *
+ * $Id: IPCTestId.c,v 1.1 2002/08/16 22:29:38 piccardi Exp $
+ *
+ ****************************************************************/
+/*
+ * Include needed headers
+ */
+#include <errno.h> /* error definitions and routines */
+#include <stdlib.h> /* C standard library */
+#include <unistd.h> /* unix standard library */
+#include <stdio.h> /* standard I/O library */
+#include <string.h> /* string functions */
+#include <sys/ipc.h> /* SysV IPC functions */
+#include <sys/msg.h> /* SysV Message Queue */
+#include <sys/sem.h> /* SysV Semaphores */
+#include <sys/shm.h> /* SysV Shared Memory */
+
+#include "macros.h" /* My macros */
+/* Help printing routine */
+void usage(void);
+
+int main(int argc, char *argv[])
+{
+/*
+ * Variables definition
+ */
+ int i;
+ int n = 10; /* default is 10 tryes */
+ char type='q'; /* default is use queues */
+ int id;
+ /*
+ * Input section: decode command line parameters
+ * Use getopt function
+ */
+ opterr = 0; /* don't want writing to stderr */
+ while ( (i = getopt(argc, argv, "hqsmn:")) != -1) {
+ switch (i) {
+ /*
+ * Handling options
+ */
+ case 'h': /* help option */
+ printf("Wrong -h option use\n");
+ usage();
+ return -1;
+ break;
+ case 'q': /* Message Queue */
+ debug("Message Queue\n");
+ type = i;
+ break;
+ case 's': /* Semaphore */
+ debug("Semaphore\n");
+ type = i;
+ break;
+ case 'm': /* Shared Memory */
+ debug("Shared Memory\n");
+ type = i;
+ break;
+ case 'n': /* Number of tryes */
+ debug("Number of tryes\n");
+ n = strtol(optarg, NULL, 10);
+ break;
+ default: /* should not reached */
+ usage();
+ }
+ }
+ /* ***********************************************************
+ *
+ * Options processing completed
+ *
+ * Main code beginning
+ *
+ * ***********************************************************/
+ switch (type) {
+ case 'q': /* Message Queue */
+ debug("Message Queue Try\n");
+ for (i=0; i<n; i++) {
+ id = msgget(IPC_PRIVATE, IPC_CREAT|0666);
+ printf("Identifier Value %d \n", id);
+ msgctl(id, IPC_RMID, NULL);
+ }
+ break;
+ case 's': /* Semaphore */
+ debug("Semaphore\n");
+ for (i=0; i<n; i++) {
+ id = semget(IPC_PRIVATE, 1, IPC_CREAT|0666);
+ printf("Identifier Value %d \n", id);
+ semctl(id, 0, IPC_RMID);
+ }
+ break;
+ case 'm': /* Shared Memory */
+ debug("Shared Memory\n");
+ for (i=0; i<n; i++) {
+ id = shmget(IPC_PRIVATE, 1000, IPC_CREAT|0666);
+ printf("Identifier Value %d \n", id);
+ shmctl(id, IPC_RMID, NULL);
+ }
+ break;
+ default: /* should not reached */
+ return -1;
+ }
+ return 0;
+}
+/*
+ * routine to print usage info and exit
+ */
+void usage(void) {
+ printf("Program ipctestid : test IPC identifier number assignment\n");
+ printf("Usage:\n");
+ printf(" ipctestid [-h] [-qsm] [-n N] \n");
+ printf(" -h print this help\n");
+ printf(" -q try for message queue identifiers\n");
+ printf(" -s try for semaphore identifiers\n");
+ printf(" -m try for shared memory identifiers\n");
+ printf(" -n XX try XX times\n");
+
+ exit(1);
+}
+