Pipe anonimi e con nome

Transcript

Pipe anonimi e con nome
Program m azione di Sist em a – 5
Lucidi per il corso di Laboratorio di Sistemi Operativi tenuto da Paolo Baldan presso l'Università Ca' Foscari di
Venezia, anno accademico 2004/ 2005. Parte di questo materiale è rielaborato dai lucidi del Corso di Laboratorio di
Sistemi Operativi tenuto da Rosario Pugliese presso l'Università di Firenze, anno accademico 2001/ 02.
IPC: Int er Process Com m unicat ion
Meccanism i che perm et t ono a processi dist int i di
com unicare e scam biare inform azioni.
I processi che com unicano possono risiedere
sulla st essa m acchina (segnali, pipe, fifo, socket )
su m acchine diverse (socket )
La com unicazione può essere finalizzat a a
cooperazione: i processi scam biano dat i per
l'ot t enim ent o di un fine com une.
sincronizzazione: lo scam bio di inform azioni perm et t e a
processi indipendent i, m a correlat i, di schedulare
corret t am ent e la propria at t ivit à (es. di non accedere
cont em poraneam ent e ad una risorsa condivisa).
2
Pipe e Fifo
Pipe anonim i e con nom e (FIFO)
Meccanism o ut ilizzat o frequent em ent e da una shell
per connet t ere l'out put di un com ando all'input di un
alt ro (pipeline).
$ who | sort
I due processi connessi da un pipe sono eseguit i
concorrent em ent e.
Un pipe m em orizza aut om at icam ent e l'out put dello
scrit t ore (who) in un buffer.
Se il buffer è pieno, lo scrit t ore si sospende fino a che
alcuni dat i non vengono let t i.
Se il buffer è vuot o, il let t ore (sort) si sospende fino a
che divent ano disponibili dei dat i in out put .
4
Pipe con nom e e anonim i (FIFO)
Pipe Anonim i
Present i in t ut t e le versioni di UNIX
ut ilizzat i, ad es., dalle shell per le pipeline.
Pipe con nom e o FIFO
Present i in UNIX Syst em .
5
Pipe anonim i
Un pipe anonim o è un canale di com unicazione che
unisce due processi (creat o con pipe())
unidirezionale
perm et t e la com unicazione solo t ra processi con un
ant enat o com une
Mem orizza il suo input in un buffer (la m assim a
dim ensione varia, m a è t ipicam ent e int orno ai 5K)
Un pipe present a due lat i di accesso (in/out ), ciascuno
associat o ad un descrit t ore di file
il lat o di scrit t ura è accedut o invocando write()
il lat o di let t ura è accedut o invocando read().
Quando un processo ha finit o di usare un (lat o di un)
pipe chiude il descrit t ore con close().
6
Pipe anonim i: pipe()
int pipe (int fd[2])
crea un pipe anonim o e rest it uisce due file descript or
lat o di let t ura fd[0] (apert o in let t ura)
lat o di scrit t ura fd[1] (apert o in scrit t ura)
fd [0 ]
fd [1]
p ip e
Processo
Kern el
Fallisce rest it uendo -1 se il kernel non ha più spazio
per un nuovo pipe; alt rim ent i rest it uisce 0.
7
Pipe anonim i: let t ura
Se un processo legge da un pipe
se il lat o scrit t ura è st at o chiuso, read() rest it uisce 0
che indica la fine dell'input ;
se il pipe è vuot o e il lat o di scrit t ura è ancora apert o, si
sospende fino a che divent a disponibile qualche input ;
se il processo t ent a di leggere più byt e di quelli present i
nel buffer associat o, i byt e disponibili vengono let t i e
read() rest it uisce il num ero dei byt e effet t ivam . let t i.
8
Pipe anonim i: scrit t ura
Se un processo scrive su di un pipe
se il lat o di let t ura è st at o chiuso, write() fallisce ed allo
scrit t ore è inviat o un segnale SIGPIPE, la cui azione di
default è di far t erm inare il ricevent e;
se scrive m eno byt e di quelli che un pipe può cont enere,
write() viene eseguit a in m odo at om ico (non possono
avvenire int erleaving dei dat i scrit t i da processi diversi
sullo st esso pipe);
se scrive più byt e di quelli che un pipe può cont enere
(PIPE_BUF), non c'è garanzia di at om icit à.
lseek() non ha senso se applicat a ad un pipe.
Dat o che l'accesso ad un pipe anonim o avviene
t ram it e file descript or, solo il processo creat ore ed i
suoi discendent i possono accedere al pipe.
9
Pipe anonim i: pipe()
La t ipica sequenza di event i è
il processo crea un pipe anonim o (pipe());
il processo crea un figlio (fork());
lo scrit t ore chiude il suo lat o di let t ura del pipe ed il
let t ore chiude il suo lat o scrit t ura (close());
i processi com unicano usando write() e read();
ogni processo chiude (close()) il suo descrit t ore quando
ha finit o.
Una com unicazione bidirezionale si può realizzare
ut ilizzando due pipe.
10
Esem pio: t alk.c (scam bio di m essaggio)
Il program m a talk.c usa un pipe per perm et t ere al
padre di leggere un m essaggio inviat o dal figlio.
L'inclusione del carat t ere NULL perm et t e al let t ore di
det erm inare la fine del m essaggio.
11
Esem pio: t alk.c (scam bio di m essaggio)
#include <stdio.h>
#define READ
0
/* The index of the read end of the pipe */
#define WRITE 1
/* The index of the write end of the pipe */
char *phrase = "Stuff this in your pipe";
int main (void) {
int fd [2], bytesRead;
char message [100]; /* Parent process' message buffer */
pipe (fd);
/* Create an unnamed pipe */
if (fork () == 0) {
/* Child, writer */
close(fd[READ]);
/* Close unused end */
write (fd[WRITE], phrase, strlen (phrase) + 1); /* include \0 */
close (fd[WRITE]);
/* Close used end */
}
else { /* Parent, reader*/
close (fd[WRITE]);
/* Close unused end */
bytesRead = read (fd[READ], message, 100);
printf ("Read %d bytes: %s\n", bytesRead, message);
close (fd[READ]);
/* Close used end */
}
12
}
Esem pio: t alk.c (scam bio di m essaggio)
Esem pio di esecuzione ...
$ ./talk
Read 24 bytes: Stuff this in your pipe
$
13
Com unicazione t ram it e pipe (e non solo)
Quando un processo “ scrit t ore” invia m essaggi di
lunghezza variabile t ram it e un pipe, occorre fissare un
prot ocollo di com unicazione che perm et t a al processo
“ let t ore” di individuare la fine di ogni singolo
m essaggio.
Alcune possibilit à sono
inviare la lunghezza del m essaggio (dat o di dim ensione
fissa e not a) prim a del m essaggio st esso;
t erm inare un m essaggio con un carat t ere speciale com e
NULL o un newline.
Più in generale, il prot ocollo st abilisce la sequenza di
m essaggi at t esa delle due part i.
14
Esem pio: connect .c (ridirezione con pipe)
Il program m a connect.c esegue due program m i e
connet t e l'out put di uno all'input dell'alt ro.
I nom i dei program m i sono passat i com e argom ent i e
si assum e che nessuno dei due program m i sia
invocat o con argom ent i.
15
Esem pio: connect .c (ridirezione con pipe)
#include <stdio.h>
#define READ
0
#define WRITE 1
/* connect cmd1 cmd2
redirige lo stdout di cmd1
sullo stdin di cmd2 */
int main (int argc, char *argv []) {
int fd [2];
pipe (fd); /* Create an unamed pipe */
if (fork () != 0) { /* Parent, writer */
close (fd[READ]); /* Close unused end */
dup2 (fd[WRITE], 1); /* Duplicate used end to stdout */
close (fd[WRITE]); /* Close original used end */
execlp (argv[1], argv[1], NULL); /* Execute writer program */
perror ("connect"); /* Should never execute */
} else { /* Child, reader */
close (fd[WRITE]); /* Close unused end */
dup2 (fd[READ], 0); /* Duplicate used end to stdin */
close (fd[READ]); /* Close original used end */
execlp (argv[2], argv[2], NULL); /* Execute reader program */
perror ("connect"); /* Should never execute */
}
}
16
Pipe con nom e (FIFO)
I pipe con nom e, o FIFO, sono più flessibili di quelli
anonim i ed offrono i seguent i vant aggi
esist ono com e file speciali nel file syst em ;
il loro uso non è lim it at o a processi con ant enat i com uni;
un pipe con nom e può essere usat o da qualunque
processo che conosca il nom e del file corrispondent e.
esist ono fino a che non sono esplicit am ent e rim ossi;
hanno capacit à di buffer fino a 40K (m acro PIPE_BUF in
limits.h); t ut t avia, sono support at i solo da variant i del
Syst em V.
Sono file speciali e possono essere creat i
usando l'ut ilit y UNIX mknod;
usando la syst em call mknod().
17
Ut ilit y m knod
mknod [-m mode] name p
Perm et t e al superuser di creare vari t ipi di file speciali.
La sint assi specificat a consent e ad un ut ent e qualsiasi
di creare un file speciale di t ipo pipe con nom e
(opzione p) individuat o dal nom e name.
I dirit t i di accesso ad un pipe sono assegnat i
cont est ualm ent e alla creazione con l'opzione -m, dove
mode specifica i dirit t i in ot t ale;
successivam ent e alla creazione con il com ando chmod,
com e per i file regolari.
Un com ando equivalent e è
mkfifo [-m mode] name.
18
Nam ed pipe (esem pio)
Un analogo del com ando ls | more può essere realizzat o
creando una pipe, su cui ls scrive e more legge ...
Il com ando ls appena lanciat o si blocca poiché apre in
scrit t ura una pipe priva di let t ori ...
$ mknod -m 0660 prova p
$ ls -l prov*
prw-rw---1 rossi users
$ ls -l > prova &
[3] 827
$ more < prova
total 22
-rwxr-xr-x
1 baldan users
...
-rwxr-xr-x
1 baldan users
-rw-r--r-1 baldan users
[1]+ Done
$
0
May 28 10:35 prova
4230 May 22
4591 May 29
669 May 29
ls -l > prova
2000 background
2000 writer
2000 writer.c
19
Syst em call m knod()
int mknod (const char *path, mode_t mode, dev_t dev)
Perm et t e a un superuser di creare un nodo del file
syst em (file regolare, file speciale di disposit ivo, pipe
con nom e).
Rest it uisce 0 se ha successo; -1 alt rim ent i.
20
Syst em call m knod()
Un ut ent e generico può invocare mknod() solo per
creare un pipe con nom e. In quest o caso
pathname
è il nom e di file che ident ifica il pipe con nom e;
mode
specifica i dirit t i di accesso ed il t ipo di file da creare,
com binat i t ram it e “ |” . In prat ica
S_IFIFO | diritti
dove il flag S_IFIFO indica che il nodo da creare è un
pipe con nom e.
dev
è un param et ro che viene ignorat o nel caso dei pipe con
nom e, e quindi post o a 0.
21
Syst em call m knod()
I perm essi sono m odificat i da umask nel solit o m odo: i
perm essi effet t ivi del file creat o sono
mode & ~ umask.
Un funzione di libreria che perm et t e di ot t enere lo
st esso risult at o è
int mkfifo (const char *path, mode_t mode)
22
Pipe con nom e: open()
int open (const char *pathname, int flags)
Per i FIFO, i param et ri t ipici di open() sono
pathname: il nom e del pipe che si vuole aprire (se non
esist e, si ot t iene l'errore E_NOENT);
flags: indicano il t ipo di accesso al pipe
O_RDONLY: sola let t ura;
O_WRONLY: sola scrit t ura;
O_NONBLOCK: apert ura in m odalit à non bloccant e.
Rest it uisce un descrit t ore di file, se ha successo; -1
alt rim ent i.
23
Pipe con nom e: open()
Com port am ent o bloccant e
Norm alm ent e, l'apert ura di un FIFO in let t ura blocca il
processo fino a che il FIFO non viene apert o anche in
scrit t ura, e viceversa.
Con il flag O_NONBLOCK
l'apert ura in sola let t ura avrà successo anche se il FIFO
non è st at o ancora apert o in scrit t ura
l'apert ura in sola scrit t ura fallirà (con errore ENXIO) a
m eno che il lat o di let t ura non sia già st at o apert o.
I pipe con nom e sono file, quindi per pot erli ut ilizzare,
diversam ent e dai pipe anonim i, vanno prim a apert i.
24
Pipe con nom e: read()
ssize_t read (int fd, void *buf, size_t count)
La let t ura da un pipe con nom e avviene com e per i file
regolari.
Norm alm ent e...
read() è bloccant e: il processo è sospeso fino a che
divengono disponibili i byt e richiest i.
Se è st at o specificat o O_NONBLOCK
Se non ci sono sufficient i byt e da leggere
read() rest it uisce il num ero di carat t eri let t i
segnala l'errore EAGAIN.
25
Pipe con nom e: writ e()
ssize_t write (int fd, const void *buf,
size_t count)
La scrit t ura su un pipe con nom e avviene com e per i
file regolari.
La scrit t ura su di un FIFO il cui lat o di let t ura è chiuso
fallisce ed il processo riceve un segnale SIGPIPE.
26
Pipe con nom e: close() e unlink()
int close (int fd)
Un volt a t erm inat e le operazioni su di un pipe con
nom e, il suo descrit t ore fd viene chiuso con close()
(com e per i file regolari).
int unlink (const char *filename)
Com e per i file regolari, unlink() rim uove il link hard
da filename al file relat ivo. Se filename è l'ult im o
link al file, anche le risorse del file sono deallocat e.
27
Pipe con nom e: esem pio
L'esem pio si com pone di un processo let t ore e due
processi scrit t ori.
reader.c crea un pipe con nom e aPipe e lo apre in
let t ura; quindi legge e st am pa sullo scherm o delle linee
che t erm inano con 0 fino a che il pipe è chiuso da t ut t i i
processi scrit t ori.
writer.c apre in scrit t ura aPipe e scrive t re m essaggi;
quindi chiude il pipe e t erm ina. Se quando writer.c
t ent a di aprire aPipe il file non esist e, writer.c ci
riprova dopo un secondo fin quando non ha successo.
Il let t ore at t ende di leggere fino a che un processo
qualsiasi non ha apert o il FIFO, legge quello che di volt a
in volt a viene scrit t o e capisce che non c'è più nient e da
leggere quando legge EOF. A quest o punt o il let t ore
chiude il suo descrit t ore e rim uove il FIFO.
28
reader.c
#include
#include
#include
#include
<stdio.h>
<sys/types.h>
<sys/stat.h>
<fcntl.h>
/* For S_IFIFO */
int readLine (int fd, char *str) {
/* Read a single '\0'-terminated line into str from fd */
/* Return 0 when the end-of-input is reached and 1 otherwise */
int n;
do {
/* Read characters until '\0' or end-of-input */
n = read (fd, str, 1); /* Read one character */
} while (n > 0 && *str++ != '\0');
return (n > 0); /* Return false if end-of-input */
}
29
reader.c
int main (void) {
int fd;
char str[100];
unlink("aPipe"); /* Remove named pipe if it already exists
*/
mknod ("aPipe", S_IFIFO, 0); /* Create named pipe */
chmod ("aPipe", 0660); /* Change its permissions */
fd = open ("aPipe", O_RDONLY); /* Open it for reading */
while (readLine (fd, str)) /* Display received messages */
printf ("%s\n", str);
close (fd); /* Close pipe */
unlink("aPipe"); /* Remove used pipe */
}
30
writ er.c
#include <stdio.h>
#include <fcntl.h>
int main (void) {
int fd, messageLen, i;
char message [100];
/* Prepare message */
sprintf (message, "Hello from PID %d", getpid ());
messageLen = strlen (message) + 1;
do { /* Keep trying to open the file until successful */
fd = open ("aPipe", O_WRONLY); /* Open named pipe for writing */
} while (fd == -1);
for (i = 1; i <= 3; i++) { /* Send three messages */
write (fd, message, messageLen); /* Write message down pipe */
sleep (3); /* Pause a while */
}
close (fd); /* Close pipe descriptor */
return 0;
}
31
Pipe con nom e: esem pio
Esem pio di esecuzione...
$ reader & writer & writer &
[5] 1268
[6] 1269
[7] 1270
$ Hello from PID 1269
Hello from PID 1270
Hello from PID 1269
Hello from PID 1270
Hello from PID 1269
Hello from PID 1270
<return>
[5]
Done
[6]- Done
[7]+ Done
$
reader
writer
writer
32