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