System call fcntl e record locking



Похожие документы
I/O su Socket TCP: read()

Introduzione alla programmazione in C

Sincronizzazione e comunicazione tra processi in Unix. usati per trasferire ad un processo l indicazione che un determinato evento si è verificato.

Tipi primitivi. Ad esempio, il codice seguente dichiara una variabile di tipo intero, le assegna il valore 5 e stampa a schermo il suo contenuto:

Funzioni in C. Violetta Lonati

ESERCIZI DI PROGRAMMAZIONE C IN AMBIENTE UNIX

Gestione dei processi

Lab. di Sistemi Operativi - Esercitazione n 9- -Thread-

IPC System V. Code di messaggi

Inter-Process Communication

I file di dati. Unità didattica D1 1

1. Che cos è la multiprogrammazione? Si può realizzare su un sistema monoprocessore? 2. Quali sono i servizi offerti dai sistemi operativi?

Lab. di Sistemi Operativi - Esercitazione n 7- -Gestione dei processi Unix-

Sistemi Operativi mod. B. Sistemi Operativi mod. B A B C A B C P P P P P P < P 1, >

Corso di Sistemi Operativi Ingegneria Elettronica e Informatica prof. Rocco Aversa. Raccolta prove scritte. Prova scritta

AXO. Operativo. Architetture dei Calcolatori e Sistema. programmazione di sistema

Per scrivere una procedura che non deve restituire nessun valore e deve solo contenere le informazioni per le modalità delle porte e controlli

Thread: sincronizzazione Esercitazioni del 09 Ottobre 2009

(Esercizi Tratti da Temi d esame degli ordinamenti precedenti)

ISTITUTO TECNICO INDUSTRIALE STATALE LA GESTIONE DEI FILE DI TESTO IN C++

Funzioni. Il modello console. Interfaccia in modalità console

Esercizio sulla gestione di file in Unix

Corso di Laboratorio di Sistemi Operativi

Gestione dei File in C

Introduzione al Linguaggio C

Lab 11 Gestione file di testo"

Monitor. Introduzione. Struttura di un TDA Monitor

Strutture. Strutture e Unioni. Definizione di strutture (2) Definizione di strutture (1)

Realizzazione di Politiche di Gestione delle Risorse: i Semafori Privati

void funzioneprova() { int x=2; cout<<"dentro la funzione x="<<x<<endl; }

Le funzioni in C. I programmi C sono costituiti da definizioni di variabili e funzioni.

I puntatori e l allocazione dinamica di memoria

Sistemi Operativi. Interfaccia del File System FILE SYSTEM : INTERFACCIA. Concetto di File. Metodi di Accesso. Struttura delle Directory

Elementi di Architettura e Sistemi Operativi

Algoritmi e strutture dati. Codici di Huffman

Esempio: dest = parolagigante, lettere = PROVA dest (dopo l'invocazione di tipo pari ) = pprrlogvgante

Drivers. Introduzione Tipologie Struttura Interazione con il kernel

SISTEMI OPERATIVI 14 settembre 2015 corso A nuovo ordinamento e parte di teoria del vecchio ordinamento indirizzo SR

Università di Roma Tor Vergata Corso di Laurea triennale in Informatica Sistemi operativi e reti A.A Pietro Frasca.

I database relazionali (Access)

Introduzione al MATLAB c Parte 2

dall argomento argomento della malloc()

Fondamenti di Informatica 2

Università degli Studi di Cassino Corso di Fondamenti di Informatica Puntatori. Anno Accademico 2010/2011 Francesco Tortorella

Laboratorio di Sistemi Operativi

costruttori e distruttori

L utility Unix awk [Aho-Weinberger-Kernighan]

Esercitazione [5] Input/Output su Socket

Java Virtual Machine

Fondamenti di Informatica T-1, 2009/2010 Modulo 2 Prova d Esame 5 di Giovedì 15 Luglio 2010 tempo a disposizione 2h30'

La struttura dati ad albero binario

Sommario. Definizione di informatica. Definizione di un calcolatore come esecutore. Gli algoritmi.

CREAZIONE PROCESSI IN UNIX 20

Sistemi Operativi MECCANISMI E POLITICHE DI PROTEZIONE. D. Talia - UNICAL. Sistemi Operativi 13.1

MECCANISMI E POLITICHE DI PROTEZIONE 13.1

STRUTTURE DEI SISTEMI DI CALCOLO

Operazioni di input e output in Fortran 90

Descrizione di un algoritmo

Calcolatori Elettronici Parte X: l'assemblatore as88

Automatizzare i compiti ripetitivi. I file batch. File batch (1) File batch (2) Visualizzazione (2) Visualizzazione

Esercitazione N7:Gioco dei 21 fiammiferi (impariamo java giocando)

Chiamate di sistema per la Gestione dei processi in POSIX. E.Mumolo, DEEI

Alcune regole di base per scrivere un programma in linguaggio C

Esempio produttori consumatori. Primitive asincrone

Realizzazione di una classe con un associazione

Elementi di Architettura e Sistemi Operativi. problema punti massimi i tuoi punti problema 1 6 problema 2 7 problema 3 7 problema 4 10 totale 30

Allocazione dinamica della memoria - riepilogo

Sistemi Operativi L-A. Esercizi 14 Giugno Esercizio monitor

Laboratorio di programmazione

Protezione. Protezione. Protezione. Obiettivi della protezione

Record in C: il costruttore struct.

Compito di Fondamenti di Informatica

Inizializzazione, Assegnamento e Distruzione di Classi

Ricorsione. (da lucidi di Marco Benedetti)

Java: Compilatore e Interprete

Matematica - SMID : Programmazione Febbraio 2009 FOGLIO RISPOSTE

Strutturazione logica dei dati: i file

COSTER. Import/Export su SWC701. SwcImportExport

Sistema di gestione Certificato MANUALE PER L'UTENTE

Esercizio 1. Esercizio 2

Esercitazione finale per il corso di Sistemi Operativi (A.A. 2004/2005)

T E O R I A D I P R O G E T T A Z I O N E D E L S O F T W A R E

CAP. 6: Nucleo del sistema operativo (La gestione dei processi)

Gli array. Gli array. Gli array. Classi di memorizzazione per array. Inizializzazione esplicita degli array. Array e puntatori

Uso di JUnit. Fondamenti di informatica Oggetti e Java. JUnit. Luca Cabibbo. ottobre 2012

Транскрипт:

System call fcntl e record locking Esempio: prenotazione di voli aerei La compagnia ACME Airlines usa un sistema di prenotazione dei voli basato su unix. Possiede due uffici per la prenotazione, A e B, ciascuno con un terminale connesso al computer della compagnia. Da ciascuno dei terminali si può accedere al database delle prenotazioni, implementato come le unix, attraverso il programma acmebook. Questo programma permette di leggere e aggiornare il database. In particolare, è possibile decrementare di uno il numero di posti liberi su un determinato volo. Una situazione critica Supponiamo che sul volo ACM501 per Londra sia rimasto libero esattamente un posto. Il Sig.Jones e il Sig.Smith entrano nell ufficio A e B, rispettivamente, chiedendo un biglietto per quel volo. Consideriamo la seguente sequenza di eventi: 1. Dall ufficio A viene lanciato il programma acmebook. Sia PA il processo risultante. 2. Dall ufficio B viene lanciato il programma acmebook. Sia PB il processo risultante. 3. PA accede al database con una read e scopre che c è un posto libero. 4. PB fa una read sul database e scopre che c è un posto libero. 5. PA azzera il contatore di posti liberi con una write e consegna il biglietto al Sig.Jones. 6. PB, non sapendo che l unico posto rimasto è stato già assegnato, azzera il contatore di posti liberi con una write e consegna il biglietto al Sig.Smith. Come conseguenza è stato assegnato un posto in più rispetto a quelli disponibili. Il problema nasce perchè più processi possono accedere contemporaneamente ad uno stesso file. Inoltre una singola operazione logica (la prenotazione), costituita da diverse chiamate alle system call lseek, read, write, può essere effettuata da più processi concorrenti. Una soluzione consiste nel consentire ad un processo di fare il locking della parte di file sulla quale sta lavorando durante la prenotazione. La sistem call fcntl consente di effettuare il locking di (parte di) un file. Record locking con fcntl La system call fcntl offre due tipi di locking: 1. Read locking: Serve per evitare che i dati vengano modificati da un processo, compreso il processo che ha effettuato il read locking. Tuttavia tutti i processi possono accedere ai dati in lettura. In particolare, il read locking non consente a nessun processo di effettuare un write locking. Più processi possono effettuare un read locking contemporaneamente. 2. Write locking: Il processo che lo ha effettuato può modificare la parte di file su cui ha effettuato il write locking. Ma nessun altro processo può effettuare un read/write locking su quella parte di file. Uso della system call fcntl per il locking

#include <fcntl.h> int fcntl(int filedes, int cmd, struct flock *ldata); filedes è un descrittore di file aperto con il parametro O RDONLY oppure O RDWR, nel caso di un read locking, O WRONLY oppure O RDWR, nel caso di un write locking. cmd specifica l azione da effettuare tramite valori definiti in <fcntl.h>: - F GETLK Fornisce la descrizione dei locking in base al contenuto di ldata. L informazione restituita descrive il primo lock che blocca il lock descritto in ldata. - F SETLK Effettua un locking su un file; termina subito se non è possibile. Serve anche per rimuovere un lock. - F SETLKW Effettua un locking su un file, va in sleep se il lock è bloccato da un lock precedentemente effettuato da un altro processo. La struttura ldata contiene la descrizione del locking. In particolare, comprende i seguenti campi: short l_type; /* descrive il tipo di lock */ short l_whence; /* offset */ off_t l_start ; /* offset in byte */ off_t l_len; /* dimensione del segmento in byte */ pid_t l_pid; /* definito dal comando F_GETLK */ I campi l whence, l start, l len specificano il segmento su cui effettuare, controllare o togliere il locking. l whence determina da dove calcolare l offset e può essere SEEK SET (dall inizio del file), SEEK CUR (dalla posizione corrente), SEEK END (dalla fine del file). l start fornisce la posizione di partenza del segmento relativamente a l whence. l len è la lunghezza del segmento in byte. l type fornisce il tipo di lock: - F RDLCK read locking - F WRLCK write locking - F UNLCK unlocking Il campo l pid è rilevante solo se il parametro cmd vale F GETLK. Se esiste un lock che blocca il lock descritto dagli altri membri della struttura, a l pid viene assegnato l identificatore del processo che ha effettuato il locking. Esercizio 1 Scrivere un programma che simuli il sistema di prenotazione di voli ACME. Il programma acquisisce da std input il numero di posti da riservare rispettivamente dall ufficio A e dall ufficio B. Il main crea due processi figli, PA e PB, a cui passa il numero di posti da riservare rispettivamente dall ufficio A e dall ufficio B. I processi PA e PB chiamano ripetutamente la funzione acmebook per riservare i posti uno alla volta. La funzione acmebook utilizza il meccanismo del locking per effettuare le prenotazioni. Quando non ci sono pi`u posti liberi, il programma termina, altrimenti aspetta da std input un altra coppia di interi, rappresentanti i posti da riservare dagli uffici A e B.

Soluzione: #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/types.h> #include <sys/wait.h> #define MAXLENGTH 3 char buf[maxlength]; void prenota(int n); int acmebook(); main() { int n,n1,n2,fd,pid1,pid2; while(1) { if((fd=open("prenotazioni.txt",o_rdonly))==-1) { perror("errore in apertura del file delle prenotazioni"); /* Lettura dei posti disponibili. */ if(read(fd,buf,maxlength)>0) { n=atoi(buf); if(n==0) { printf("non ci sono piu` posti disponibili.\n"); exit(0); else break; close(fd); printf("posti disponibili: %d\n",n); /* Viene chiesto il numero di posti da prenotare dall'ufficio A. */ printf("numero di posti da riservare dall'ufficio A: "); scanf("%d",&n1); /* Viene chiesto il numero di posti da prenotare dall'ufficio B. */ printf("numero di posti da riservare dall'ufficio B: "); scanf("%d",&n2); switch(pid1=fork()) { case -1: perror("errore nella creazione del primo figlio"); exit(2); case 0: prenota(n1); default: switch(pid2=fork()) { case -1: perror("errore nella creazione del secondo figlio"); exit(3); case 0:

prenota(n2); default: /* Il padre attende la terminazione dei figli. */ waitpid(pid1,null,0); waitpid(pid2,null,0); void prenota(int n) { int i,error_code; for(i=0;i<n;i++) { /* se acmebook restituisce -1 significa che non vi sono * posti disponibili per soddisfare la prenotazione. */ if((error_code=acmebook())==-1) { printf("numero di posti insufficiente.\n"); exit(error_code); exit(0); int acmebook() { struct flock ldata; ldata.l_type=f_wrlck; ldata.l_whence=seek_set; ldata.l_start=0; ldata.l_len=maxlength; int error_code=0,fd,n,i; /* Apertura in lettura/scrittura del file delle prenotazioni */ if((fd=open("prenotazioni.txt",o_rdwr))==-1) { perror("errore in apertura del file delle prenotazioni"); /* Write locking del file delle prenotazioni con eventuale * sospensione del processo nel caso in cui il file sia * gia` bloccato da un altro processo. */ if(fcntl(fd,f_setlkw,&ldata)==-1) { perror("errore nel blocco del file delle prenotazioni"); exit(4); if(read(fd,buf,maxlength)>0) { n=atoi(buf); if(n>0) { n--; sprintf(buf,"%d",n); /* Riposizionamento all'inizio del file prima della scrittura. */ if(lseek(fd,0,seek_set)==-1) { perror("errore di riposizionamento nel file delle prenotazioni");

exit(5); /* Il buffer viene 'ripulito' da eventuali caratteri spuri. */ for(i=strlen(buf);i<maxlength;i++) buf[i]=' '; /* Scrittura su disco del nuovo numero di posti disponibili. */ if(write(fd,buf,maxlength)==-1) { perror("errore in scrittura nel file delle prenotazioni"); exit(6); else error_code=-1; /* Impostazione del componente l_type della struttura flock * per rimuovere il lock. */ ldata.l_type=f_unlck; /* Rilascio del blocco sul file delle prenotazioni. */ if(fcntl(fd,f_setlkw,&ldata)==-1) { perror("errore nel rilascio del file delle prenotazioni"); exit(5); close(fd); return error_code; Esercizio 2 Siano P1 e P2 due processi che lavorano sullo stesso file. Supponiamo che P1 esegua un lock sulla sezione SX del file e P2 esegua un lock sulla sezione SY dello stesso file. Che cosa succede se poi P1 tenta di fare un lock su SY con F SETLKW e P2 tenta di fare un lock su SX con F SETLKW? Soluzione: #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> main() { int fd; struct flock first_lock; struct flock second_lock; first_lock.l_type=f_wrlck; first_lock.l_whence=seek_set; first_lock.l_start=0; first_lock.l_len=10; second_lock.l_type=f_wrlck;

second_lock.l_whence=seek_set; second_lock.l_start=10; second_lock.l_len=5; if((fd=open("file",o_rdwr))==-1) { perror("errore nell'apertura del file"); if(fcntl(fd,f_setlkw,&first_lock)==-1) { perror("errore nell'esecuzione della prima operazione di blocco"); exit(2); printf("a: blocco completato con successo (PID %d)\n",getpid()); switch(fork()) { case -1: perror("errore nell'esecuzione della fork"); exit(3); case 0: if(fcntl(fd,f_setlkw,&second_lock)==-1) { perror("errore nell'esecuzione della seconda operazione di blocco"); exit(4); printf("b: blocco completato con successo (PID %d)\n",getpid()); if(fcntl(fd,f_setlkw,&first_lock)==-1) { perror("errore nell'esecuzione della terza operazione di blocco"); exit(5); printf("c: blocco completato con successo (PID %d)\n",getpid()); exit(0); default: /* Pausa di 10 secondi. */ sleep(10); if(fcntl(fd,f_setlkw,&second_lock)==-1) { perror("errore nell'esecuzione della quarta operazione di blocco"); exit(6); printf("d: blocco completato con successo (PID %d)\n",getpid()); Quello che succede lanciando il programma e riportato qui di seguito: A: blocco completato con successo (PID 3603) B: blocco completato con successo (PID 3604) Errore nell'esecuzione della quarta operazione di blocco: Resource deadlock avoided C: blocco completato con successo (PID 3604) Quindi Unix e in grado di identicare il deadlock che si verica, segnalandolo con un opportuno messaggio d'errore (ed evitando la situazione di stallo dei due processi). In questo caso infatti la chiamata a fcntl ritorna immediatamente restituendo -1 al chiamante ed impostando la variabile speciale errno con il valore EDEADLK. Nel caso in cui il deadlock coinvolga piu di due processi

tuttavia fcntl non e in grado di rilevarlo. Esercizio 3 Modicare il programma dell esercizio 1 in modo da implementare l'accesso esclusivo al le delle prenotazioni tramite regioni critiche gestite da semafori. Soluzione: Il programma riportato di seguito e stato ottenuto da quello dell esercizio 1, sostituendo le chiamate a fcntl con chiamate a p e v (includendo ovviamente le opportune direttive include, define e le dichiarazioni delle funzioni ausiliarie): #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/sem.h> #include <errno.h> #define SEMPERM 0600 #define MAXLENGTH 3 char buf[maxlength]; typedef union _semun { int val; struct semid_ds *buf; ushort *array; semun; int p(int semid); int v(int semid); int initsem(key_t semkey); void prenota(int n,key_t semkey); int acmebook(); main() { key_t semkey=0x200; int n,n1,n2,fd,pid1,pid2,semid; semun ctl_arg; while(1) { if((fd=open("prenotazioni.txt",o_rdonly))==-1) { perror("errore in apertura del file delle prenotazioni"); /* Lettura dei posti disponibili. */ if(read(fd,buf,maxlength)>0) { n=atoi(buf);

if(n==0) { printf("non ci sono piu` posti disponibili.\n"); exit(0); else break; close(fd); printf("posti disponibili: %d\n",n); /* Viene chiesto il numero di posti da prenotare dall'ufficio A. */ printf("numero di posti da riservare dall'ufficio A: "); scanf("%d",&n1); /* Viene chiesto il numero di posti da prenotare dall'ufficio B. */ printf("numero di posti da riservare dall'ufficio B: "); scanf("%d",&n2); switch(pid1=fork()) { case -1: perror("errore nella creazione del primo figlio"); exit(2); case 0: prenota(n1,semkey); default: switch(pid2=fork()) { case -1: perror("errore nella creazione del secondo figlio"); exit(3); case 0: prenota(n2,semkey); default: /* Il padre attende la terminazione dei figli. */ waitpid(pid1,null,0); waitpid(pid2,null,0); semid=initsem(semkey); /* Rimozione del semaforo. */ if(semctl(semid,0,ipc_rmid,ctl_arg)==-1) { perror("errore nella rimozione del semaforo"); exit(7); void prenota(int n,key_t semkey) { int i,error_code; for(i=0;i<n;i++) { /* se acmebook restituisce -1 significa che non vi sono * posti disponibili per soddisfare la prenotazione. */

error_code=acmebook(semkey); if(error_code==-1) { printf("numero di posti insufficiente.\n"); exit(error_code); if(error_code==-2) { printf("errore nell'inizializzazione del semaforo.\n"); exit(error_code); exit(0); int acmebook(key_t semkey) { int error_code=0,fd,n,i,semid; if((semid=initsem(semkey))<0) return -2; /* Apertura in lettura/scrittura del file delle prenotazioni */ if((fd=open("prenotazioni.txt",o_rdwr))==-1) { perror("errore in apertura del file delle prenotazioni"); /* Inizio della regione critica */ p(semid); if(read(fd,buf,maxlength)>0) { n=atoi(buf); if(n>0) { n--; sprintf(buf,"%d",n); /* Riposizionamento all'inizio del file prima della scrittura. */ if(lseek(fd,0,seek_set)==-1) { perror("errore di riposizionamento nel file delle prenotazioni"); exit(5); /* Il buffer viene 'ripulito' da eventuali caratteri spuri. */ for(i=strlen(buf);i<maxlength;i++) buf[i]=' '; /* Scrittura su disco del nuovo numero di posti disponibili. */ if(write(fd,buf,maxlength)==-1) { perror("errore in scrittura nel file delle prenotazioni"); exit(6); else error_code=-1; /* Fine della regione critica */ v(semid); close(fd); return error_code;

int initsem(key_t semkey) { int status=0,semid; if((semid=semget(semkey,1,semperm IPC_CREAT IPC_EXCL))==-1) { if(errno==eexist) semid=semget(semkey,1,0); else { semun arg; arg.val=1; status=semctl(semid,0,setval,arg); if(semid==-1 status==-1) { perror("initsem fallita"); return -1; return semid; int p(int semid) { struct sembuf p_buf; p_buf.sem_num=0; p_buf.sem_op=-1; p_buf.sem_flg=sem_undo; if(semop(semid,&p_buf,1)==-1) { perror("p(semid) fallita"); return 0; int v(int semid) { struct sembuf v_buf; v_buf.sem_num=0; v_buf.sem_op=1; v_buf.sem_flg=sem_undo; if(semop(semid,&v_buf,1)==-1) { perror("v(semid) fallita"); return 0;