del \acr{pid} del processo.
Quando si richiede un lock il kernel effettua una scansione di tutti i lock
-presenti sul file\footnoote{scandisce cioè la linked list delle strutture
+presenti sul file\footnote{scandisce cioè la linked list delle strutture
\var{file\_lock}, scartando automaticamente quelle per cui \var{fl\_flags}
non è \macro{FL\_POSIX}, così che le due interfacce restano ben separate.}
per verificare se la regione richiesta non si sovrappone ad una già bloccata,
che le regioni bloccate da essa risultanti siano coerenti con quanto
necessario a soddisfare l'operazione richiesta.
-Come esempio dell'uso di questa funzione si è scritto un programma che
-permette di bloccare una sezione a piacere di un qualunque file; in
-\figref{fig:file_flock_code} è riportata la sezione principale del codice del
-programma, (il testo completo è allegato nella directory dei sorgenti).
-
-
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
\begin{lstlisting}{}
int main(int argc, char *argv[])
{
-/*
- * Variables definition
- */
- int type = F_UNLCK;
- off_t start;
- off_t len;
- int fd, res, i;
- int cmd = F_SETLK ;
- struct flock lock;
+ int type = F_UNLCK; /* lock type: default to unlock (invalid) */
+ off_t start = 0; /* start of the locked region: default to 0 */
+ off_t len = 0; /* length of the locked region: default to 0 */
+ int fd, res, i; /* internal variables */
+ int bsd = 0; /* semantic type: default to POSIX */
+ int cmd = F_SETLK; /* lock command: default to non-blocking */
+ struct flock lock; /* file lock structure */
...
if ((argc - optind) != 1) { /* There must be remaing parameters */
printf("Wrong number of arguments %d\n", argc - optind);
usage();
}
- if (type == F_UNLCK) { /* Just lock */
+ if (type == F_UNLCK) { /* There must be a -w or -r option set */
printf("You should set a read or a write lock\n");
usage();
}
- fd = open(argv[optind], O_RDWR);
- if (fd < 0) {
+ fd = open(argv[optind], O_RDWR); /* open the file to be locked */
+ if (fd < 0) { /* on error exit */
perror("Wrong filename");
exit(1);
}
- /* setting lock structure */
- lock.l_type = type;
- lock.l_whence = SEEK_SET;
- lock.l_start = start;
- lock.l_len = len;
/* do lock */
- res = fcntl(fd, cmd, &lock);
- if (res) {
+ if (bsd) { /* if BSD locking */
+ /* rewrite cmd for suitables flock operation values */
+ if (cmd == F_SETLKW) { /* if no-blocking */
+ cmd = LOCK_NB; /* set the value for flock operation */
+ } else { /* else */
+ cmd = 0; /* default is null */
+ }
+ if (type == F_RDLCK) cmd |= LOCK_SH; /* set for shared lock */
+ if (type == F_WRLCK) cmd |= LOCK_EX; /* set for exclusive lock */
+ res = flock(fd, cmd); /* esecute lock */
+ } else { /* if POSIX locking */
+ /* setting flock structure */
+ lock.l_type = type; /* set type: read or write */
+ lock.l_whence = SEEK_SET; /* start from the beginning of the file */
+ lock.l_start = start; /* set the start of the locked region */
+ lock.l_len = len; /* set the length of the locked region */
+ res = fcntl(fd, cmd, &lock); /* do lock */
+ }
+ /* check lock results */
+ if (res) { /* on error exit */
perror("Failed lock");
exit(1);
+ } else { /* else write message */
+ printf("Lock acquired\n");
}
- pause();
+ pause(); /* stop the process, use a signal to exit */
return 0;
}
\end{lstlisting}
\label{fig:file_flock_code}
\end{figure}
-La parte più complessa del programma è in realtà la logica della gestione
-delle opzioni (che qui si è omessa), che si cura di impostare le variabili
-\var{type}, \var{start} e \var{len}; queste ultime due vengono inizializzate
-al valore numerico fornito rispettivamente tramite gli switch \code{-s} e
-\cmd{-l}, mentre con \cmd{-w} e \cmd{-r} si richiede rispettivamente un write
-lock o read lock.
+Per fare qualche esempio sul file locking si è scritto un programma che
+permette di bloccare una sezione di un file usando la semantica POSIX, o un
+intero file usando la semantica BSD; in \figref{fig:file_flock_code} è
+riportata il corpo principale del codice del programma, (il testo completo è
+allegato nella directory dei sorgenti).
+
+La sezione relativa alla gestione delle opzioni al solito si è omessa, come la
+funzione che stampa le istruzioni per l'uso del programma, essa si cura di
+impostare le variabili \var{type}, \var{start} e \var{len}; queste ultime due
+vengono inizializzate al valore numerico fornito rispettivamente tramite gli
+switch \code{-s} e \cmd{-l}, mentre il valore della prima viene impostato con
+le opzioni \cmd{-w} e \cmd{-r} si richiede rispettivamente o un write lock o
+read lock (i due valori sono esclusivi, la variabile assumerà quello che si è
+specificato per ultimo). Oltre a queste tre vengono pure impostate la
+variabile \var{bsd}, che abilita la semantica omonima quando si invoca
+l'opzione \cmd{-f} (il valore preimpostato è nullo, ad indicare la semantica
+POSIX), e la variabile \var{cmd} che specifica la modalità di richiesta del
+lock (bloccante o meno), a seconda dell'opzione \cmd{-b}.
+
+Il programma inizia col controllare (\texttt{\small 11--14}) che venga passato
+un parametro (il file da bloccare), che sia stato scelto (\texttt{\small
+ 15--18}) il tipo di lock, dopo di che apre (\texttt{\small 19}) il file,
+uscendo (\texttt{\small 20--23}) in caso di errore. A questo punto il
+comportamento dipende dalla semantica scelta; nel caso sia BSD occorre
+reimpostare il valore di \var{cmd} per l'uso con \func{flock}; infatti il
+valore preimpostato fa riferimento alla semantica POSIX e vale rispettivamente
+\macro{F\_SETLKW} o \macro{F\_SETLK} a seconda che si sia impostato o meno la
+modalità bloccante.
+
+Nel caso si sia scelta la semantica BSD (\texttt{\small 25--34}) prima si
+controlla (\texttt{\small 27--31}) il valore di \var{cmd} per determinare se
+si vuole effettuare una chiamata bloccante o meno, reimpostandone il valore
+opportunamente, dopo di che a seconda del tipo di lock al valore viene
+aggiunta la relativa opzione (con un OR aritmetico, dato che \func{flock}
+vuole un argomento \param{operation} in forma di maschera binaria. Nel caso
+invece che si sia scelta la semantica POSIX le operazioni sono molto più
+immediate, si prepara (\texttt{\small 36--40}) la struttura per il lock, e lo
+esegue (\texttt{\small 41}).
+
+
+In entrambi i casi dopo aver richiesto il lock viene controllato il risultato
+uscendo (\texttt{\small 44--46}) in caso di errore, o stampando un messaggio
+(\texttt{\small 47--49}) in caso di successo. Infine il programma si pone in
+attesa (\texttt{\small 50}) finché un segnale (ad esempio un \cmd{C-c} dato da
+tastiera) non lo interrompa; in questo caso il programma termina, e tutti i
+lock vengono rilasciati.
\subsection{La funzione \func{lockf}}
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-/****************************************************************
+/*****************************************************************************
*
* Program Flock.c:
* Program to test file locking
*
* Usage: flock -h give all info's
*
- * $Id: Flock.c,v 1.1 2002/11/16 14:11:55 piccardi Exp $
+ * $Id: Flock.c,v 1.2 2002/11/17 17:30:51 piccardi Exp $
*
- ****************************************************************/
+ *****************************************************************************/
/*
* Include needed headers
*/
#include <unistd.h> /* unix standard library */
#include <stdio.h> /* standard I/O library */
#include <string.h> /* string functions */
-#include <fcntl.h> /* string functions */
-
-
-#include "macros.h"
+#include <fcntl.h> /* string functions */
+/* user defined header */
+#include "macros.h" /* some useful macros */
/* Help printing routine */
void usage(void);
/*
* Variables definition
*/
- int type = F_UNLCK;
- off_t start;
- off_t len;
- int fd, res, i;
- int cmd = F_SETLK ;
- struct flock lock;
+ int type = F_UNLCK; /* lock type: default to unlock (invalid) */
+ off_t start = 0; /* start of the locked region: default to 0 */
+ off_t len = 0; /* length of the locked region: default to 0 */
+ int fd, res, i; /* internal variables */
+ int bsd = 0; /* semantic type: default to POSIX */
+ int cmd = F_SETLK; /* lock command: default to non-blocking */
+ struct flock lock; /* file lock structure */
/*
* Input section: decode command line parameters
* Use getopt function
*/
opterr = 0; /* don't want writing to stderr */
- while ( (i = getopt(argc, argv, "hs:l:wrb")) != -1) {
+ while ( (i = getopt(argc, argv, "hs:l:wrbf")) != -1) {
switch (i) {
/*
* Handling options
*/
- case 'h': /* help option */
+ case 'h': /* help option */
printf("Wrong -h option use\n");
usage();
return -1;
break;
- case 's': /* take wait time for childen */
- start = strtol(optarg, NULL, 10); /* convert input */
+ case 's': /* take start point of the lock */
+ start = strtol(optarg, NULL, 10); /* convert input */
break;
- case 'l': /* take wait time for childen */
- len = strtol(optarg, NULL, 10); /* convert input */
+ case 'l': /* take length of the lock */
+ len = strtol(optarg, NULL, 10); /* convert input */
break;
- case 'w':
+ case 'w': /* set type to write lock */
type = F_WRLCK;
break;
- case 'r':
+ case 'r': /* set type to read lock */
type = F_RDLCK;
break;
- case 'b':
+ case 'b': /* set lock to blocking */
cmd = F_SETLKW;
break;
- case '?': /* unrecognized options */
+ case 'f': /* enable BSD semantic */
+ bsd = 1;
+ break;
+ case '?': /* unrecognized options */
printf("Unrecognized options -%c\n",optopt);
usage();
- default: /* should not reached */
+ default: /* should not reached */
usage();
}
}
* Main code beginning
*
* ***********************************************************/
- /* There must be remaing parameters */
- if (type == F_UNLCK) {
- printf("You should set a read or a write lock\n");
- usage();
- }
- if ((argc - optind) != 1) {
+ if ((argc - optind) != 1) { /* There must be remaing parameters */
printf("Wrong number of arguments %d\n", argc - optind);
usage();
}
- fd = open(argv[optind], O_RDWR);
- if (fd < 0) {
+ if (type == F_UNLCK) { /* There must be a -w or -r option set */
+ printf("You should set a read or a write lock\n");
+ usage();
+ }
+ fd = open(argv[optind], O_RDWR); /* open the file to be locked */
+ if (fd < 0) { /* on error exit */
perror("Wrong filename");
exit(1);
}
- /* setting lock structure */
- lock.l_type = type;
- lock.l_whence = SEEK_SET;
- lock.l_start = start;
- lock.l_len = len;
/* do lock */
- res = fcntl(fd, cmd, &lock);
- if (res) {
+ if (bsd) { /* if BSD locking */
+ /* rewrite cmd for suitables flock operation values */
+ if (cmd == F_SETLK) { /* if no-blocking */
+ cmd = LOCK_NB; /* set the value for flock operation */
+ } else { /* else */
+ cmd = 0; /* default is null */
+ }
+ if (type == F_RDLCK) cmd |= LOCK_SH; /* set for shared lock */
+ if (type == F_WRLCK) cmd |= LOCK_EX; /* set for exclusive lock */
+ res = flock(fd, cmd); /* esecute lock */
+ } else { /* if POSIX locking */
+ /* setting flock structure */
+ lock.l_type = type; /* set type: read or write */
+ lock.l_whence = SEEK_SET; /* start from the beginning of the file */
+ lock.l_start = start; /* set the start of the locked region */
+ lock.l_len = len; /* set the length of the locked region */
+ res = fcntl(fd, cmd, &lock); /* do lock */
+ }
+ /* check lock results */
+ if (res) { /* on error exit */
perror("Failed lock");
exit(1);
+ } else { /* else write message */
+ printf("Lock acquired\n");
}
- pause();
+ pause(); /* stop the process, use a signal to exit */
return 0;
}
/*
printf(" -w write lock\n");
printf(" -r read lock\n");
printf(" -b block when locking impossible\n");
-
+ printf(" -f enable BSD semantic\n");
exit(1);
}