è in grado di visualizzarlo opportunamente.
Per realizzare quanto voluto useremo in sequenza i programmi \cmd{barcode} e
-\cmd{gs}, il primo infatti è in grado di generare immagini postscript di
+\cmd{gs}, il primo infatti è in grado di generare immagini PostScript di
codici a barre corrispondenti ad una qualunque stringa, mentre il secondo
serve per poter effettuare la conversione della stessa immagine in formato
JPEG. Usando una pipe potremo inviare l'output del primo sull'input del
Una volta create le pipe, il programma può creare (\texttt{\small 13-17}) il
primo processo figlio, che si incaricherà (\texttt{\small 19--25}) di eseguire
\cmd{barcode}. Quest'ultimo legge dallo standard input una stringa di
-caratteri, la converte nell'immagine postscript del codice a barre ad essa
+caratteri, la converte nell'immagine PostScript del codice a barre ad essa
corrispondente, e poi scrive il risultato direttamente sullo standard output.
Per poter utilizzare queste caratteristiche prima di eseguire \cmd{barcode} si
\func{dup2}. Si ricordi che invocando \func{dup2} il secondo file, qualora
risulti aperto, viene, come nel caso corrente, chiuso prima di effettuare la
duplicazione. Allo stesso modo, dato che \cmd{barcode} scrive l'immagine
-postscript del codice a barre sullo standard output, per poter effettuare una
+PostScript del codice a barre sullo standard output, per poter effettuare una
ulteriore redirezione il capo in lettura della seconda pipe viene chiuso
(\texttt{\small 22}) mentre il capo in scrittura viene collegato allo standard
output (\texttt{\small 23}).
In questo modo all'esecuzione (\texttt{\small 25}) di \cmd{barcode} (cui si
passa in \var{size} la dimensione della pagina per l'immagine) quest'ultimo
leggerà dalla prima pipe la stringa da codificare che gli sarà inviata dal
-padre, e scriverà l'immagine postscript del codice a barre sulla seconda.
+padre, e scriverà l'immagine PostScript del codice a barre sulla seconda.
Al contempo una volta lanciato il primo figlio, il processo padre prima chiude
(\texttt{\small 26}) il capo inutilizzato della prima pipe (quello in input) e
29}) che l'esecuzione di \cmd{barcode} sia completata.
Alla conclusione della sua esecuzione \cmd{barcode} avrà inviato l'immagine
-postscript del codice a barre sul capo in scrittura della seconda pipe; a
+PostScript del codice a barre sul capo in scrittura della seconda pipe; a
questo punto si può eseguire la seconda conversione, da PS a JPEG, usando il
programma \cmd{gs}. Per questo si crea (\texttt{\small 30--34}) un secondo
processo figlio, che poi (\texttt{\small 35--42}) eseguirà questo programma
-leggendo l'immagine postscript creata da \cmd{barcode} dallo standard input,
+leggendo l'immagine PostScript creata da \cmd{barcode} dallo standard input,
per convertirla in JPEG.
Per fare tutto ciò anzitutto si chiude (\texttt{\small 37}) il capo in
quanto funzionante, è (volutamente) codificato in maniera piuttosto complessa,
inoltre nella pratica sconta un problema di \cmd{gs} che non è in
grado\footnote{nella versione GNU Ghostscript 6.53 (2002-02-13).} di
-riconoscere correttamente l'encapsulated postscript, per cui deve essere usato
-il postscript e tutte le volte viene generata una pagina intera, invece che
+riconoscere correttamente l'Encapsulated PostScript, per cui deve essere usato
+il PostScript e tutte le volte viene generata una pagina intera, invece che
una immagine delle dimensioni corrispondenti al codice a barre.
Se si vuole generare una immagine di dimensioni appropriate si deve usare un
};
char content[]="Content-type: image/png\n\n";
int i;
- /* write mime-type to stout */
+ /* write mime-type to stdout */
write(STDOUT_FILENO, content, strlen(content));
/* execute chain of command */
for (i=0; i<4; i++) {
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 \texttt{syscntl}.} e per ciascuno 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
Le code di messaggi sono caratterizzate da tre limiti fondamentali, definiti
negli header e corrispondenti alle prime tre costanti riportate in
\tabref{tab:ipc_msg_limits}, come accennato però in Linux è possibile
-modificare questi limiti attraverso l'uso di \func{syscntl} o scrivendo nei
+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/}.
\end{lstlisting}
\end{minipage}
\normalsize
- \caption{La struttura \structd{msgid\_ds}, associata a ciascuna coda di
+ \caption{La struttura \structd{msqid\_ds}, associata a ciascuna coda di
messaggi.}
- \label{fig:ipc_msgid_ds}
+ \label{fig:ipc_msqid_ds}
\end{figure}
A ciascuna coda è associata una struttura \struct{msgid\_ds}, la cui
-definizione, è riportata in \secref{fig:ipc_msgid_ds}. In questa struttura il
+definizione, è riportata in \secref{fig:ipc_msqid_ds}. In questa struttura il
kernel mantiene le principali informazioni riguardo lo stato corrente della
coda.\footnote{come accennato questo vale fino ai kernel della serie 2.2.x,
essa viene usata nei kernel della serie 2.4.x solo per compatibilità in
sia una differenza con i campi mostrati nello schema di
\figref{fig:ipc_mq_schema} che sono presi dalla definizione di
\file{linux/msg.h}, e fanno riferimento alla definizione della omonima
- struttura usata nel kernel.} In \figref{fig:ipc_msgid_ds} sono elencati i
+ struttura usata nel kernel.} In \figref{fig:ipc_msqid_ds} sono elencati i
campi significativi definiti in \file{sys/msg.h}, a cui si sono aggiunti gli
ultimi tre campi che sono previsti dalla implementazione originale di System
V, ma non dallo standard Unix98.
\footnotesize \centering
\begin{minipage}[c]{15cm}
\begin{lstlisting}{}
-/*
- * Function MutexCreate: create a mutex/semaphore
- */
+/* Function MutexCreate: create a mutex/semaphore */
int MutexCreate(key_t ipc_key)
{
const union semun semunion={1}; /* semaphore union structure */
}
return sem_id;
}
-/*
- * Function MutexFind: get the semaphore/mutex Id given the IPC key value
- */
+/* Function MutexFind: get the semaphore/mutex Id given the IPC key value */
int MutexFind(key_t ipc_key)
{
return semget(ipc_key,1,0);
}
-/*
- * Function MutexRead: read the current value of the mutex/semaphore
- */
+/* Function MutexRead: read the current value of the mutex/semaphore */
int MutexRead(int sem_id)
{
return semctl(sem_id, 0, GETVAL);
}
-/*
- * Define sembuf structures to lock and unlock the semaphore
- */
+/* Define sembuf structures to lock and unlock the semaphore */
struct sembuf sem_lock={ /* to lock semaphore */
0, /* semaphore number (only one so 0) */
-1, /* operation (-1 to use resource) */
0, /* semaphore number (only one so 0) */
1, /* operation (1 to release resource) */
SEM_UNDO}; /* flag (in this case 0) */
-/*
- * Function MutexLock: to lock a mutex/semaphore
- */
+/* Function MutexLock: to lock a mutex/semaphore */
int MutexLock(int sem_id)
{
return semop(sem_id, &sem_lock, 1);
}
-/*
- * Function MutexUnlock: to unlock a mutex/semaphore
- */
+/* Function MutexUnlock: to unlock a mutex/semaphore */
int MutexUnlock(int sem_id)
{
return semop(sem_id, &sem_ulock, 1);
+}
+/* Function MutexRemove: remove a mutex/semaphore */
+int MutexRemove(int sem_id)
+{
+ return semctl(sem_id, 0, IPC_RMID);
}
\end{lstlisting}
\end{minipage}
\label{fig:ipc_mutex_create}
\end{figure}
-La prima funzione (\texttt{\small 1--17}) è \func{MutexCreate} che data una
+La prima funzione (\texttt{\small 2--15}) è \func{MutexCreate} che data una
chiave crea il semaforo usato per il mutex e lo inizializza, restituendone
-l'identificatore. Il primo passo (\texttt{\small 8}) è chiamare \func{semget}
+l'identificatore. Il primo passo (\texttt{\small 6}) è chiamare \func{semget}
con \const{IPC\_CREATE} per creare il semaforo qualora non esista,
assegnandogli i privilegi di lettura e scrittura per tutti. In caso di errore
-(\texttt{\small 9--11}) si ritorna subito il risultato di \func{semget},
-altrimenti (\texttt{\small 12}) si inizializza il semaforo chiamando
+(\texttt{\small 7--9}) si ritorna subito il risultato di \func{semget},
+altrimenti (\texttt{\small 10}) si inizializza il semaforo chiamando
\func{semctl} con il comando \const{SETVAL}, utilizzando l'unione
-\struct{semunion} dichiarata ed avvalorata in precedenza (\texttt{\small 6})
+\struct{semunion} dichiarata ed avvalorata in precedenza (\texttt{\small 4})
ad 1 per significare che risorsa è libera. In caso di errore (\texttt{\small
- 13--16}) si restituisce il valore di ritorno di \func{semctl}, altrimenti si
-ritorna l'identificatore del semaforo.
+ 11--13}) si restituisce il valore di ritorno di \func{semctl}, altrimenti
+(\texttt{\small 14}) si ritorna l'identificatore del semaforo.
-La seconda funzione (\texttt{\small 18--24}) è \func{MutexFind}, che data una
+La seconda funzione (\texttt{\small 17--20}) è \func{MutexFind}, che, data una
chiave, restituisce l'identificatore del semaforo ad essa associato. La
-comprensione del suo funzionamento è immediata in quanto è solo un
+comprensione del suo funzionamento è immediata in quanto essa è soltanto un
\textit{wrapper}\footnote{si chiama così una funzione usata per fare da
\textsl{involucro} alla chiamata di un altra, usata in genere per
semplificare un'interfaccia (come in questo caso) o per utilizzare con la
stessa funzione diversi substrati (librerie, ecc.) che possono fornire le
- stesse funzionalità.} di \func{semget} per cercare l'identificatore
-associato alla chiave, restituendo direttamente il valore di ritorno della
-funzione.
+ stesse funzionalità.} di una chiamata a \func{semget} per cercare
+l'identificatore associato alla chiave, il valore di ritorno di quest'ultima
+viene passato all'indietro al chiamante.
-La terza funzione (\texttt{\small 25--31}) è \func{MutexRead} che, dato
-l'identificatore, restituisce il valore del mutex. Anche in questo caso la
-funzione è un \textit{wrapper} per la chiamata di \func{semctl}, questa volta
-con il comando \const{GETVAL}, che permette di restituire il valore del
-semaforo.
+La terza funzione (\texttt{\small 22--25}) è \func{MutexRead} che, dato un
+identificatore, restituisce il valore del semaforo associato al mutex. Anche
+in questo caso la funzione è un \textit{wrapper} per una chiamata a
+\func{semctl} con il comando \const{GETVAL}, che permette di restituire il
+valore del semaforo.
-La quarta e la quinta funzione (\texttt{\small 43--56}) sono \func{MutexLock},
+La quarta e la quinta funzione (\texttt{\small 36--44}) sono \func{MutexLock},
e \func{MutexUnlock}, che permettono rispettivamente di bloccare e sbloccare
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
+(\texttt{\small 27--34}). Si noti come per queste ultime si sia fatto uso
dell'opzione \const{SEM\_UNDO} per evitare che il semaforo resti bloccato in
caso di terminazione imprevista del processo.
+L'ultima funzione (\texttt{\small 46--49}) della serie, è \func{MutexRemove},
+che rimuove il mutex. Anche in questo caso si ha un wrapper per una chiamata a
+\func{semctl} con il comando \const{IPC\_RMID}, che permette di cancellare il
+smemaforo; il valore di ritorno di quest'ultima viene passato all'indietro.
+
Chiamare \func{MutexLock} decrementa il valore del semaforo: se questo è
libero (ha già valore 1) sarà bloccato (valore nullo), se è bloccato la
chiamata a \func{semop} si bloccherà fintanto che la risorsa non venga
(bloccare la risorsa quando questa è considerata libera). Si tenga presente
che usare \func{MutexRead} per controllare il valore dei mutex prima di
proseguire non servirebbe comunque, dato che l'operazione non sarebbe atomica.
-Vedremo in \secref{sec:ipc_posix_sem} come è possibile ottenere un'interfaccia
-analoga senza questo problemi usando il file locking\index{file!locking}.
+Vedremo in \secref{sec:ipc_lock_file} come sia possibile ottenere
+un'interfaccia analoga a quella appena illustrata, senza incorrere in questi
+problemi, usando il file locking\index{file!locking}.
attraverso questo puntatore che potremo accedere alla memoria condivisa, che
sarà vista nella forma data da \struct{DirProp}. Infine con la stessa chiave
si crea (\texttt{\small 42--45}) anche un mutex (utilizzando le funzioni di
-intrfaccia già descritte in \secref{sec:ipc_sysv_sem}) che utilizzaremo per
+interfaccia già descritte in \secref{sec:ipc_sysv_sem}) che utilizzeremo per
regolare l'accesso alla memoria condivisa.
Una volta completata l'inizializzazione e la creazione degli oggetti di
\begin{lstlisting}{}
...
/*
- * Routine to print file name and size inside DirScan
+ * Routine to compute directory properties inside DirScan
*/
int ComputeValues(struct dirent * direntry)
{
printf("Ci sono %d link\n", shmptr->tot_link);
printf("Ci sono %d fifo\n", shmptr->tot_fifo);
printf("Ci sono %d socket\n", shmptr->tot_sock);
- printf("Ci sono %d device a carrateri\n", shmptr->tot_char);
+ printf("Ci sono %d device a caratteri\n", shmptr->tot_char);
printf("Ci sono %d device a blocchi\n", shmptr->tot_block);
MutexUnlock(mutex); /* unlock shared memory */
}
errore (\texttt{\small 18--21}). Una volta ottenuto l'identificatore si può
(\texttt{\small 22--25}) agganciare il segmento al processo (anche in questo
caso uscendo se qualcosa non funziona). Infine (\texttt{\small 26--29}) si
-richede pure l'identificatore del mutex.
+richiede pure l'identificatore del mutex.
Una volta completata l'inizializzazione ed ottenuti i riferimenti agli oggetti
di intercomunicazione necessari viene eseguito il corpo principale del
sincronizzazione, per cui alla fine l'uso delle code di messaggi classiche è
relativamente poco diffuso.
-
-
\subsection{I \textsl{file di lock}}
\label{sec:ipc_file_lock}
Un generale comunque l'uso di un \textsl{file di lock} presenta parecchi
problemi, che non lo rendono una alternativa praticabile per la
-sincronizzazione: anzitutto anche in questo caso, in caso di terminazione
-imprevista del processo, si lascia allocata la risorsa (il \textsl{file di
- lock}) e questa deve essere sempre cancellata esplicitamente. Inoltre il
-controllo della disponibilità può essere eseguito solo con una tecnica di
-\textit{polling}\index{polling}, ed è quindi molto inefficiente.
+sincronizzazione: anzitutto in caso di terminazione imprevista del processo,
+si lascia allocata la risorsa (il \textsl{file di lock}) e questa deve essere
+sempre cancellata esplicitamente. Inoltre il controllo della disponibilità
+può essere eseguito solo con una tecnica di \textit{polling}\index{polling},
+ed è quindi molto inefficiente.
-La tecnica dei file di lock non di meno ha una sua utilità, e può essere usata
+La tecnica dei file di lock ha comunque una sua utilità, e può essere usata
con successo quando l'esigenza è solo quella di segnalare l'occupazione di una
risorsa, senza necessità di attendere che questa si liberi; ad esempio la si
usa spesso per evitare interferenze sull'uso delle porte seriali da parte di
\label{sec:ipc_lock_file}
Dato che i file di lock presentano gli inconvenienti illustrati in precedenza,
-la tecnica alternativa più comune è quella di fare ricorso al \textit{file
- locking}\index{file!locking} (trattato in \secref{sec:file_locking}) usando
-\func{fcntl} su un file creato per l'occasione per ottenere un write lock. In
-questo modo potremo usare il lock come un \textit{mutex}: per bloccare la
-risorsa basterà acquisire il lock, per sbloccarla basterà rilasciare il lock;
-una richiesta fatta con un write lock metterà automaticamente il processo in
-stato di attesa, senza necessità di ricorrere al
-\textit{polling}\index{polling} per determinare la disponibilità della
-risorsa, e al rilascio della stessa da parte del processo che la occupava si
-otterrà il nuovo lock atomicamente.
+la tecnica alternativa di sincronizzazione più comune è quella di fare ricorso
+al \textit{file locking}\index{file!locking} (trattato in
+\secref{sec:file_locking}) usando \func{fcntl} su un file creato per
+l'occasione per ottenere un write lock. In questo modo potremo usare il lock
+come un \textit{mutex}: per bloccare la risorsa basterà acquisire il lock, per
+sbloccarla basterà rilasciare il lock; una richiesta fatta con un write lock
+metterà automaticamente il processo in stato di attesa, senza necessità di
+ricorrere al \textit{polling}\index{polling} per determinare la disponibilità
+della risorsa, e al rilascio della stessa da parte del processo che la
+occupava si otterrà il nuovo lock atomicamente.
Questo approccio presenta il notevole vantaggio che alla terminazione di un
processo tutti i lock acquisiti vengono rilasciati automaticamente (alla
\footnotesize \centering
\begin{minipage}[c]{15cm}
\begin{lstlisting}{}
-/*
- * Function LockMutex: lock a file (creating it if not existent).
- */
-int LockMutex(const char *path_name)
+/* Function CreateMutex: Create a mutex using file locking. */
+int CreateMutex(const char *path_name)
+{
+ return open(path_name, O_EXCL|O_CREAT);
+}
+/* Function UnlockMutex: unlock a file. */
+int FindMutex(const char *path_name)
+{
+ return open(path_name, O_RDWR);
+}
+/* Function LockMutex: lock mutex using file locking. */
+int LockMutex(int fd)
{
- int fd, res;
struct flock lock; /* file lock structure */
/* first open the file (creating it if not existent) */
- if ( (fd = open(path_name, O_EXCL|O_CREAT)) < 0) { /* first open file */
- return fd;
- }
/* set flock structure */
lock.l_type = F_WRLCK; /* set type: read or write */
lock.l_whence = SEEK_SET; /* start from the beginning of the file */
lock.l_start = 0; /* set the start of the locked region */
lock.l_len = 0; /* set the length of the locked region */
/* do locking */
- if ( (res = fcntl(fd, F_SETLKW, &lock)) < 0 ) {
- return res;
- }
- return 0;
+ return fcntl(fd, F_SETLKW, &lock);
}
-/*
- * Function UnLockMutex: unlock a file.
- */
-int UnlockMutex(const char *path_name)
+/* Function UnlockMutex: unlock a file. */
+int UnlockMutex(int fd)
{
- int fd, res;
struct flock lock; /* file lock structure */
- /* first open the file */
- if ( (fd = open(path_name, O_RDWR)) < 0) { /* first open file */
- return fd;
- }
/* set flock structure */
lock.l_type = F_UNLCK; /* set type: unlock */
lock.l_whence = SEEK_SET; /* start from the beginning of the file */
lock.l_start = 0; /* set the start of the locked region */
lock.l_len = 0; /* set the length of the locked region */
/* do locking */
- if ( (res = fcntl(fd, F_SETLK, &lock)) < 0 ) {
+ return fcntl(fd, F_SETLK, &lock);
+}
+/* Function RemoveMutex: remove a mutex (unlinking the lock file). */
+int RemoveMutex(const char *path_name)
+{
+ return unlink(path_name);
+}
+/* Function ReadMutex: read a mutex status. */
+int ReadMutex(int fd)
+{
+ int res;
+ struct flock lock; /* file lock structure */
+ /* set flock structure */
+ lock.l_type = F_WRLCK; /* set type: unlock */
+ lock.l_whence = SEEK_SET; /* start from the beginning of the file */
+ lock.l_start = 0; /* set the start of the locked region */
+ lock.l_len = 0; /* set the length of the locked region */
+ /* do locking */
+ if ( (res = fcntl(fd, F_GETLK, &lock)) ) {
return res;
}
- return 0;
+ return lock.l_type;
}
\end{lstlisting}
\end{minipage}
\label{fig:ipc_flock_mutex}
\end{figure}
-Il codice per implementare un mutex utilizzando il file
-locking\index{file!locking} è riportato in \figref{fig:ipc_flock_mutex}; a
-differenza del precedente caso in cui si sono usati i semafori le funzioni
-questa volta sono sufficienti due funzioni, \func{LockMutex} e
-\func{UnlockMutex}, usate rispettivamente per acquisire e rilasciare il mutex.
+Il codice delle varie funzioni definite per implementare un mutex utilizzando
+il file locking\index{file!locking} è riportato in
+\figref{fig:ipc_flock_mutex}; si è mantenuta una struttura analoga a quelle
+viste in precedenza, anche se le due interfacce non possono essere
+completamente equivalenti, specie per quanto riguarda la rimozione del mutex.
+
+
+
La prima funzione (\texttt{\small 1--22}) serve per acquisire il mutex.
Anzitutto si apre (\texttt{\small 9--11}), creandolo se non esiste, il file