Aggiunto programmino di test.
authorSimone Piccardi <piccardi@gnulinux.it>
Fri, 16 Aug 2002 22:29:38 +0000 (22:29 +0000)
committerSimone Piccardi <piccardi@gnulinux.it>
Fri, 16 Aug 2002 22:29:38 +0000 (22:29 +0000)
ipc.tex
sources/IPCTestId.c [new file with mode: 0644]

diff --git a/ipc.tex b/ipc.tex
index 261de58..ed2d492 100644 (file)
--- a/ipc.tex
+++ b/ipc.tex
@@ -597,20 +597,26 @@ La principale caratteristica del sistema di IPC di System V 
 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
@@ -701,12 +707,13 @@ devono solo accedere, in quanto, a parte gli eventuali controlli sugli altri
 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}
@@ -755,7 +762,7 @@ il controllo avr
 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
@@ -766,9 +773,151 @@ dei file, ed avviene secondo questa sequenza:
 \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}
@@ -834,8 +983,7 @@ successo solo se l'oggetto non esiste gi
 
 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
 
 
 
@@ -889,7 +1037,7 @@ prototipo 
     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
 
 
@@ -904,6 +1052,21 @@ evitasse i principali problemi evidenziati in coda a
 
 
 
+\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
diff --git a/sources/IPCTestId.c b/sources/IPCTestId.c
new file mode 100644 (file)
index 0000000..de39a47
--- /dev/null
@@ -0,0 +1,145 @@
+/* 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);
+}
+