Upload
elena-gentili
View
217
Download
2
Embed Size (px)
Citation preview
1
SC che operano su processi
Getpid, fork, exec, wait, waitpid, exit, dup, dup2
2
Process identifier: getpid,getppid– pid indice del processo all’interno della tabella dei processi– ppid indice del processo padre all’interno della tabella dei processi– il kernel ha pid 0 e init ha pid 1– si possono ottenere con
pid_t getpid(void)
pid_t getppid(void)
3
PID: getpid,getppid (2)/* frammento che stampa il pid del processo in esecuzione e quello del padre usando la macro WRITE di stampa (in sysmacro.h) … */
char buf[N]; /* stringa da stampare */
…
sprintf(buf,”Processo %d, mio padre e’ %d\n.”, getpid(),getppid());
WRITELN(buf); …
4
PID: getpid,getppid (2.1)/* da sysmacro.h … */
#define STIN 0
#define STDOUT 1
#define STDERR 2
#define WRITE(m) \ IFERROR(write(STDOUT,m,strlen(m)),m)
#define WRITELN(m) WRITE(m); WRITE(m);
5
Creazione : fork() pid_t fork(void);– crea un nuovo processo con indice pid– lo spazio di indirizzamento del nuovo processo è un duplicato di quello del padre
– padre e figlio hanno due tabelle dei descrittori di file diverse (il figlio ha una copia di quella del padre)
– MA …. condividono la tabella dei file aperti (e quindi anche il puntatore alla locazione corrente di ogni file)
6
Creazione : fork() (2) pid_t fork(void);– restituisce 0 al figlio e pid al padre,
– oppure -1 (solo al padre) in caso di fallimento• es. la tabella dei processi non ha più spazio ...
7
Text
Data
Stack
Area vuota
0
232 - 1
heap
Creazione di processi (2)• Spazio di indirizzamento di padre e figlio dopo
una fork terminata con successo
SI padre
Text
Data
Stack
Area vuota
0
232 - 1
heap
SI figlio
copia
8
Text
Data
Stack
Area vuota
0
232 - 1
heap
Creazione di processi (3)• Come prosegue l’esecuzione nei processi padre e
figlio
SI padre (pid=34)
Text
Data
Stack
Area vuota
0
232 - 1
heap
SI figlio (pid = 45)
0&x&x 45
PC = istruzionesuccessiva a fork
9
Creazione di processi (4)/* frammento che crea un nuovo processo */
int pid; /* pid del processo creato */
…
IFERROR( pid = fork(),”main: creazione”);
if ( pid ) { /* siamo nel padre */
sprintf(buf,”Processo %d, ho creato %d\n.”,
getpid(),pid);
WRITELN(buf); }
else { /* siamo nel figlio */
sprintf(buf,”Processo %d, mio padre e’ %d\n.”,
getpid(),getppid());
WRITELN(buf);
}
10
Terminazione : exit() void exit(int status);– chiude tutti i descrittori di file,– libera lo spazio di indirizzamento,– invia un segnale SIGCHLD al padre– salva il primo byte (0-255) di status nella tabella dei processi in attesa che il padre lo accetti (con la wait(), waitpid())– se il processo padre è terminato, il processo ‘orfano’ viene adottato da init (cioè ppid viene settato a 1) – se eseguita nel main è equivalente ad una return
11
Attesa di terminazione del figliopid_t wait(int *status)
pid_t waitpid(pid_t pid,int *status,int options)– restituisce informazioni sul tipo di terminazione del figlio e il byte meno significativo ritornato con la exit()
• per leggere queste informazioni c’è bisogno di opportune maschereWIFEXITED(status)
WEXITSTATUS(status)
– in caso di errore (es non ci sono figli …) viene ritornato il valore -1
12
Attesa di terminazione ...(2)pid_t wait(int *status)
pid_t waitpid(pid_t pid,int *status,int options)– la waitpid permette di fare attese non bloccanti
• WNOHANG specificato nelle opzioni indica di non attendere se nessun figlio è ancora terminato
– permette di attendere un figlio con un pid specifico (pid)
13
Esempio : wait() ed exit() int status ; /* conterra’ lo stato */
IFERROR( pid = fork(),”main: creazione”);
if ( pid ) { /* siamo nel padre */
sleep(20); /* aspetta 10 secondi */
pid = wait(&status);
if (WIFEXITED(status)) {
/*!=0 se il figlio e’terminato normalmente, (exit o return) non ucciso da signal */
printf(“stato %d\n”, WEXITSTATUS(status));
}
else { /* siamo nel figlio */
printf(“Processo %d, figlio.\n”,getpid());
exit(17); /*termina con stato 17 */ }
14
Esempio : wait() ed exit() (2) cosa accade se eseguiamo un main contenente il codice dell’esempio :
$ a.out & -- avvio l’esecuzione in bg
Processo 1246, figlio. -- stampato dal figlio
15
Esempio : wait() ed exit() (3) prima che i 20 secoondi siano finiti ...
$ a.out & -- avvio l’esecuzione in bg
Processo 1246, figlio. -- stampato dal figlio $ ps -l
… S UID PID PPID ………… CMD
… Z 501 1246 1245 …………… a.out
-- il figlio e’ un processo zombie
16
Esempio : wait() ed exit() (4) quando il padre si risveglia ed esegue la wait() ...
$ a.out & -- avvio l’esecuzione in bg
Processo 1246, figlio. -- stampato dal figlio $ ps -l
… S UID PID PPID ………… CMD
… Z 501 1246 1245 …………… a.out
-- il figlio e’ un processo zombie (Z)
$
Stato 17. -- stampato dal padre
$
18
Differenziazione : le exec()• execve
– è l’unica chiamata di sistema vera
• execl, execlp,execle,execv, execvp– sono funzioni di libreria con differenze sul tipo di parametri– alla fine invocano la execve
• tutte le exec*()– differenziano un processo rimpiazzando il suo spazio di
indirizzamento con quello di un file eseguibile passato come parametro
19
Differenziazione : le exec() (2)• execl, execlp,execle,execv, execvp, execve
– è possibile richiedere che la exec() cerchi il file nelle directory specificate dalla variabile di ambiente PATH è (p nel nome)
– è possible passare un array di argomenti secondo il formato di argv[] (v nel nome)
– è possible passare un array di stringhe che descrivono l’environment (e nel nome)
– è possibile passare gli argomenti o l’environment come lista (terminato da NULL) (l nel nome)
20
Differenziazione : le exec() (3)• execl, execlp,execle,execv, execvp, execve
– le exec() non ritornano in caso di successo!!!– Restituiscono -1 in caso di fallimento
• non trova il file, il file non è eseguibile etc...
– ATTENZIONE 1: le exec non creano nuovi processi!!– ATTENZIONE 2: padre e figlio continuano a
condividere la tabella dei file aperti ….
21
Text segment
I-Data segmentAmpiezza BSS
Altre info
Magic number
Variabili globaliinizializzate
Ampiezza area dimemoria occupata dalle variabiliglobali NON inizializzate
Numero che contraddistingue il file come eseguibile
Codice del programma (assemblato)
Differenziazione : le exec() (4)• Formato di un file eseguibile
– risultato di compilazione, linking etc ...
22
Differenziazione : le exec() (5)– (1) il contenuto del file eseguibile viene usato per sovrascrivere
lo spazio di indirizzamento del processo che la invoca
Text
I-Data segment
StackArea vuota
0
232 - 1
BSS-segment
Text segment
I-Data segmentAmpiezza BSS Data
FRAME per la funzione main
envVariabili di ambiente (envp)
argvAgomenti (argv)
File eseguibile
23
Differenziazione : le exec() (6)– (2) si carica in PC l’indirizzo iniziale X
Text
I-Data segment
StackArea vuota
0
232 - 1
BSS-segment
Text segment
I-Data segmentAmpiezza BSS
env
Indirizzo della prima istruzione compilata di main()
argv
X
X
24
Esempio : una shell semplificataint pid, status;
char * argv[];
while (TRUE) { /*ciclo infinito*/
type_prompt(); /* stampa prompt*/
argv = read_comm(); /*legge command line*/
IFERROR3(pid = fork(),”Nella fork”,continue);
if (pid) {/* codice padre */
wait(&status);
if (WIFEXITED(status)) …/*gest. stato*/ }
else {/*codice figlio*/
IFERROR(execvp(argv[0],argv),”nella execvp”);
}
25
Duplicazione dei descrittori di file: dup() e dup2()
int dup(int oldfd);
int dup2(int oldfd,int newfd);– creano entrambi una copia del descrittore di file oldfd ,– entrambi i descrittori puntano alla stassa locazione della tabella dei file aperti e possono essere utilizzati per lavorare sullo stesso file– dup cerca la prima posizione libera– dup2 chiude prima newfd (se aperto) e poi ci copia oldfd
26
Es: la redirezione– La shell permette di ridirigere stdin/out/error– Es.
$ ls
indirizzi.pdf k.c s.doc
27
Es: la redirezione– La shell permette di ridirigere stdin/out/error– Es.
$ ls
indirizzi.pdf k.c s.doc
$ ls > pippo
28
Es: la redirezione– La shell permette di ridirigere stdin/out/error– Es.
$ ls
indirizzi.pdf k.c s.doc
$ ls > pippo
$ more pippo
indirizzi.pdf
k.c
s.doc
29
Es: la redirezione (2)– La shell permette di ridirigere stdin/out/error. Es (2)
$ more pippo
i.pdf
s.doc
k.c
$ sort < pippo
k.c
i.pdf
s.doc
30
Es: la redirezione (3)– Redirezione dello stdout ed error su file diversi
$ more pippo.c pluto.c 1> out 2> log
31
Es: la redirezione (3)– Redirezione dello stdout ed error su file diversi
$ more pippo.c pluto.c > out &> log
32
Es: la redirezione (3)– Redirezione dello stdout ed error su file diversi
$ more pippo.c pluto.c 1> out 2> log
$ more log
pippo.c: No such file or directory
33
Es: la redirezione (3)– Redirezione dello stdout ed error su file diversi
$ more pippo.c pluto.c 1> out 2> log
$ more log
pippo.c: No such file or directory
$ more out /* frammento che stampa il pid del processo in esecuzione e quello del padre usando la macro WRITE di stampa (in sysmacro.h) … */
char buf[N]; /* stringa da stampare */ …
sprintf(buf,”Processo %d, mio padre e’ %d\n.”,
getpid(),getppid());
34
Es: la redirezione (3.1)– Attenzione: out e log vengono sovrascritti!!!!!– Per appendere usare ‘>>’
$ more pippo.c pluto.c 1>> out 2>> log
35
Es: la redirezione (3.1)– Attenzione: out e log vengono sovrascritti!!!!!– Per appendere usare ‘>>’
$ more pippo.c pluto.c 1>> out 2>> log
$ more log
pippo.c: No such file or directory
pippo.c: No such file or directory
36
Es: redirezione con dup() e dup2()– Es. voglio ridirigere lo standard output (file descriptor 1) su un file pippo int fd;
...
IFERROR(fd=open(“pippo”,O_WRONLY|O_TRUNC|O_CREAT,0644),”nella open”);
dup2(fd,STDOUT); /* duplica fd sullo standard output*/
close(fd); /* fd non serve piu’ */
printf(“Questo viene scritto in pippo!”);
...
37
Come la shell implementa la redirezione ...
• Es. $ ls -l > pippo– Il processo shell si duplica con una fork()e si mette in attesa della terminazione del figlio con una wait– Il figlio apre in scrittura il file pippo (creandolo o troncandolo)– Il figlio duplica il descrittore di pippo con la dup2 sullo stdout e chiude il descrittore originario– Il figlio invoca una exec di ls -l, la quale conserva i descrittori dei file, e quindi va a scrivere in pippo ogni volta che usa il file descriptor 1
38
Come la shell implementa la redirezione … (2)
• Es. $ ls -l > pippo (cont.)– Quando il figlio termina, il padre riprende la computazione con i sui descrittori di file invariati.– (padre e figlio hanno ognuno la sua tabella dei descrittori e casomai puntano alla stessa locazione della tabella dei
file aperti)