410 likes | 714 Views
SC per IPC. Pipe. Pipe. B. A. pipe. Pipe : file speciali utilizzati per connettere due processi con un canale di comunicazione. Se B cerca di leggere da una pipe vuota si blocca Quando la pipe è piena A viene automaticamente sospeso L’ampiezza della pipe dipende dal sistema (in Lunux 4K).
E N D
SC per IPC Pipe
Pipe B A pipe • Pipe:file speciali utilizzati per connettere due processi con un canale di comunicazione • Se B cerca di leggere da una pipe vuota si blocca • Quando la pipe è piena A viene automaticamente sospeso • L’ampiezza della pipe dipende dal sistema (in Lunux 4K)
Pipe con nome e senza nome • pipe senza nome (unnamed) file senza un nome visibile, che viene utilizzato per comunicazioni fra processi che condividono puntatori alla tabella dei file aperti (es. padre figlio, nonno nipote etc) • pipe con nome (named) file speciale (p) con nome visibile a tutti gli altri processi sulla stessa macchina • in entrambi i casi lettura/scrittura dalla pipe viene effettuata con le SC read() write() utilizzate anche per gli altri file
Creazione di pipe senza nome: pipe() int pipe(int filedes[2]); • crea un file speciale di tipo pipe • restituisce due file descriptor: • filedes[1]per la scrittura sul pipe e • filedes[0]per la lettura dal pipe • restituisce 0 in caso di successo • restituisce -1 in caso di fallimento • es. il processo stra usando troppi file descriptor ...
Creazione di pipe senza nome (2) /* frammento che crea un nuovo pipe */ int fd[2]; /* per i descrittori */ … IFERROR( pipe(fd),”creazione pipe”); /* da qua fd[1] puo’ essere usato per la scrittura e fd[0] per la lettura */
Uso di una pipe senza nome • Processo scrittore : • usa le write() • può scrivere solo se il file descriptor per la lettura (fd[0]) non è stato ancora chiuso • altrimenti riceve un segnale SIGPIPE che per default termina il processo • la scrittura è atomica (a meno di non aver raggiunto la capienza massima del pipe)
Uso di una pipe senza nome (2) • Processo lettore : • usa la read() • se il file descriptor per la scrittura (fd[1]) è stato chiuso la read restituisce 0 (che indica la fine dell’input dalla pipe) • se la pipe è vuota ma fd[1] non è stato ancora chiuso la read si blocca in attesa di dati sul pipe • se si cerca di leggere più byte di quelli presenti nel pipe la read ha successo ma il numero di byte letti restituito è minore del valore del terzo parametro
Uso di una pipe senza nome (3) • Non ha senso usare lseek!! • Solo per processi discendenti • si passano i file descriptor attraverso la condivisione dei puntatori alla tabella dei file aperti • Si usa per comunicazione unidirezionale • Non esiste il concetto di messaggio • byte non strutturati • i processi comunicanti devono stabilire un protocollo esplicito per scambiarsi messaggi di una certa lunghezza o messaggi di lunghezza variabile
Uso di una pipe senza nome (4) • Sequenza tipica di utilizzo di una pipe senza nome: • il padre crea la pipe • il padre si duplica con una fork() • i file descriptor del padre sono copiati nella file descriptor table del figlio • il processo scrittore (padre o figlio) chiude fd[0] mentre il processo lettore chiude fd[1] • i processo comunicano con read/write • quando la comunicazione è finita ognuno chiude la propria estremità
Uso di una pipe senza nome (5) int fd[2]; /* per i descrittori */ char msg[100]; /* msg di lunghezza 100*/ IFERROR( pipe(fd),”creazione pipe”); IFERROR( pid=fork(),”creazione figlio”); if ( pid ) { /* siamo nel padre */ close(fd[1]); /* chiude scrittura */ read(fd[0],msg,100; WRITELN(msg); /* scrive il msg letto*/ }else { /* siamo nel figlio */ close(fd[0]); /* chiude lettura */ sprintf(msg,”Da %d: Hi!!\n”,getpid()); write(fd[1],msg,100); close(fd[1]);}
Messaggi di lunghezza variabile • Possibile protocollo: • ogni messaggio logico è implementato da due messaggi fisici sul canale • il primo messaggio (di lunghezza nota), specifica la lunghezza lung • il secondo messaggio (di lunghezza lung) codifica il messaggio vero e proprio • vediamo un frammento di possibile implementazione
Messaggi di lunghezza variabile (2) … }else { /* siamo nel figlio */ int lung; /* per la lunghezza*/ close(fd[0]); /* chiude lettura */ sprintf(msg,”Da %d: Hi!!\n”,getpid()); lung = strlen(msg) + 1; /* terminatore */ /* primo messaggio*/ write(fd[1], &lung,sizeof(int)); /* secondo messaggio */ write(fd[1],msg,lung); close(fd[1]); }
Messaggi di lunghezza variabile (3) … if ( pid ) { /* siamo nel padre */ int l,lung; /* per la lunghezza */ char* msg; /* per il messaggio*/ close(fd[1]); /* chiude scrittura */ IFERROR(l=read(fd[0],&lung,sizeof(int)), ”lettura”); msg = malloc(lung); IFERROR(l=read(fd[0],&msg,lung), ”lettura”); WRITELN(msg); /* scrive il msg letto*/ free(msg); /* se non serve piu’ */ close(fd[0]); }
Creazione di pipe con nome: mkfifo int mkfifo(const char * pathname, mode_t mode); • crea un file speciale di tipo pipe con il nome e la posizione specificati in pathname ed i diritti di accesso specificati da mode • restituisce 0 se ha avuto successo e -1 altrimenti • se il file esiste già da errore • attenzione ai diritti! I diritti del file creato non sono direttamente 0644 ma vengono modificati a seconda del valore di una variabile della shell (umask) • vale ogni volta che creiamo un file (es. open …)
Shell : umask • es. se create un file con open(“ff”,O_CREAT|O_RDWR,0666) probabilmente i diritti del file ff dopo l’esecuzione deall SC saranno r w - r - - r - - e non, come specificato dal terzo parametro r w - r w - r w - 1 1 0 1 1 0 1 1 0 6 6 6 ?????????
Shell : umask (2) • umask è una maschera che fornisce una restrizione ai diritti di accesso (modo) di un file al momento della creazione • il modo del file viene calcolato come (modo&~(umask)) • Tipicamente umask = 022 quindi : 1 1 0 1 1 0 1 1 0 (modo 0666) 0 0 0 0 1 0 0 1 0 (umask) 1 1 1 1 0 1 1 0 1 (~umask) 1 1 0 1 0 0 1 0 0 (modo & (~umask)) r w - r - - r - -
Shell : umask (3) • Si può modificare il valore di umask con il comando umask • $umask fornisce il valore corrente della maschera • $umask valore_ottale setta umask al valore_ottale specificato • Il valore di umask viene ereditato dal padre e vale fino alla prossima modifica • I file creati con la ridirezione usano la open() con modo 0666, e quindi sono sensibili al valore di umask
Creazione di pipe con nome: mkfifo (2) Es: mkfifo(“pippo”, 0664); • se i diritti del file non sono quelli desiderati: > ls -l pippo prw-r--r-- 1 susanna …… pippo possiamo cambiarli con chmod() es chmod(“pippo”, 0664); adesso … > ls -l pippo prw-rw-r-- 1 susanna …… pippo
Creazione di pipe con nome (3) /* frammento che crea un nuovo pipe con nome */ … IFERROR( mkfifo(“ff”,0664),”creazione pipe”); IFERROR( chmod(“ff”,0664),”diritti pipe”);
Uso di una pipe con nome • Prima di iniziare a scrivere/leggere la pipe deve essere aperta contemporaneamente da un lettore e da uno scrittore: • Apertura da parte di un processo scrittore : • usa le open() • se nessun lettore ha ancora invocato la open() si blocca in attesa del primo lettore • usando le opzioni O_NONBLOCK, O_NDELAY se non ci sono lettori la open termina subito con fallimento
Uso di una pipe con nome (2) • Apertura da parte di un processo lettore : • usa le open() • se nessun scrittore ha ancora invocato la open() si blocca in attesa dello scrittore • usando le opzioni O_NONBLOCK, O_NDELAY se non ci sono scrittori la open termina subito con successo
Uso di una pipe con nome (3) • Tipico uso : più client e un server • il server crea la pipe e la apre in lettura • i client aprono in scrittura la stessa pipe • La capienza è 40K
Rimozione di uan pipe: unlink() int unlink(const char*patname); • decrementa il conto degli hard link del file indicato da pathname • se il numero degli hard link si è azzerato e nessun processo ha il file aperto si elimina il file dal file system • se un processo ha ancora il file aperto, • un file regolare continua ad esistere finche l’ultimo descrittore è chiuso • un pipe con nome può essere usato solo da chi loha già aperto (viene rimosso il nome) • ritorna 0 (successo) o -1 (fallimanto)
Shell • È un interprete di comandi che gira in modo utente • Nella versione base, esegue un ciclo infinito: • accetta un nuovo comando (cmd) • crea un processo P che esegue cmd • si mette in attesa della terminazione di P • Può anche eseguire una serie di comandi salvati su file (script)
Shell (2) • Ci sono vari tipi di shell (Bourne, C) • vedremo delle caratteristiche comuni a tutte • Come si attiva una shell ? • Automaticamente con il login o eseguendo il codice corrispondente (es. sh, csh) • All’attivazione esegue prima di tutto un file di inizializzazione • .bashrc per la Bourne .cshrc per la C-shell • La shell termina quando legge un EOF
Shell: metacaratteri • Sono caratteri che la shell interpreta in modo ‘speciale’ • &, >, >>, <, ~, | , *…. • Forniscono alla shell indicazioni su come comportarsi nella fase di interpretazione del comando • vediamone alcuni ...
Shell: metacaratteri (2) • Wildcard : permettono di scrivere espressioni regolari che denotano un insieme di nomi di file • ‘*’ qualsiasi stringa • es. $ls *.c uno.c g.c h.c • ‘?’ qualsiasi carattere • es. $ls ?.c g.c h.c
Shell: ridirezione • Ogni processo Unix ha dei ‘canali di comunicazione’ predefiniti con il mondo esterno • es. $sort stdout Tipicamente lo schermo P stdin Tipicamente la tastiera stderr Tipicamente lo schermo
Shell: ridirezione (2) • >, <, >>, &>, &>> permettono di ridirigere questi canali • es. $sort > pippo ‘pippo’ Scrive l’output del comando ls nel file ‘pippo’ P stdin Tipicamente la tastiera stderr Tipicamente lo schermo
Shell: ridirezione (3) • >, <, >>, &>, &>> permettono di ridirigere questi canali • es. $sort > pippo < pippuzzo pippo Scrive l’output del comando ls nel file ‘pippo’ P pippuzzo L’input viene letto dal file ‘pippuzzo’ stderr Tipicamente lo schermo
Shell: ridirezione (4) • >, <, >>, &>, &>> permettono di ridirigere questi canali • es. $sort >> pippo < pippuzzo Scrive l’output del comando ls nel file ‘pippo’. Se pippo esiste aggiunge in fondo pippo P pippuzzo L’input viene letto dal file ‘pippuzzo’ stderr Tipicamente lo schermo
Shell: ridirezione (5) • >, <, >>, &>, &>> permettono di ridirigere questi canali • es. $sort &> pippo < pippuzzo Scrive l’output del comando ls nel file ‘pippo’. Se pippo esiste aggiunge in fondo pippo P pippuzzo stderr L’input viene letto dal file ‘pippuzzo’ Anche i messaggi di errore vengono scritti su ‘pippo’
Shell: processi in background • & permette di attivare un processo in background • es. $emacs & $ la shell non invoca la waitpid() immediatamente
Shell: pipelining • |, |& permettono di eseguire in pipeline più processi relativi a comandi diversi • es. $ls *.c | grep ciccio | sort stderr stderr stderr ls sort pipe stdin grep stdout stdout stdin pipe stdout Elimina tutte le linee che non contengono ‘ciccio’
Shell: pipelining • |, |& permettono di eseguire in pipeline più processi relativi a comandi diversi • es. $ls *.c |& grep cic | sort stderr stderr stderr ls sort pipe stdin grep stdout stdout stdin pipe stdout Elimina tutte le linee che non contengono ‘cic’
Shell : environment • Le shell hanno delle variabili di environment che mantengono informazioni sotto forma di stringhe (nome=valore) • Alcune sono predefinite. Es. • $PATH contiene le directory in cui la shell va a cercare un comando • $MANPATH contiene le directory in cui la shell va a cercare i manuali in linea • $HOME pathname della home directory • $SHELL pathname della login shell
Shell : environment (2) • Le variabili di environment si possono leggere e modificare. La sintassi dipende dal tipo di shell usata • es. nella bash $echo $PATH ... valore di PATH PATH=/usr/local/bin:/usr/bin/ $export PATH=$PATH:. $echo $PATH ... valore di PATH PATH=/usr/local/bin:/usr/bin/:.
Shell : umask • es. se create un file con open(“ff”,O_CREAT|O_RDWR,0666) probabilmente i diritti del file ff dopo l’esecuzione saranno r w - r - - r - - e non, come specificato dal terzo parametro r w - r w - r w - 1 1 0 1 1 0 1 1 0 6 6 6 ?????????
Shell : umask (2) • umask è una maschera che fornisce una restrizione ai diritti di accesso (modo) di un file al momento della creazione • il modo del file viene calcolato come (modo&~(umask)) • Tipicamente umask = 022 quindi : 1 1 0 1 1 0 1 1 0 (modo 0666) 0 0 0 0 1 0 0 1 0 (umask) 1 1 1 1 0 1 1 0 1 (~umask) 1 1 0 1 0 0 1 0 0 (modo & (~umask)) r w - r - - r - -
Shell : umask (3) • Si può modificare il valore di umask con il comando umask • $umask fornisce il valore corrente della maschera • $umask valore_ottale setta umask al valore_ottale specificato • Il valore di umask viene ereditato dal padre e vale fino alla prossima modifica • I file creati con la ridirezione usano la open() con modo 0666, e quindi sono sensibili al valore di umask