From 47a55b7d6c9a34b283e91e6294ca5b7924ac5e7b Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Fri, 16 Aug 2002 22:29:38 +0000 Subject: [PATCH] Aggiunto programmino di test. --- ipc.tex | 209 +++++++++++++++++++++++++++++++++++++++----- sources/IPCTestId.c | 145 ++++++++++++++++++++++++++++++ 2 files changed, 331 insertions(+), 23 deletions(-) create mode 100644 sources/IPCTestId.c diff --git a/ipc.tex b/ipc.tex index 261de58..ed2d492 100644 --- 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 /* error definitions and routines */ +#include /* C standard library */ +#include /* unix standard library */ +#include /* standard I/O library */ +#include /* string functions */ +#include /* SysV IPC functions */ +#include /* SysV Message Queue */ +#include /* SysV Semaphores */ +#include /* 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