SC che operano su processi
Getpid, fork, exec, wait, waitpid, exit,
dup, dup2
1
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)
2
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);
…
3
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);
4
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)
5
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 ...
6
Creazione di processi (2)
• Spazio di indirizzamento di padre e figlio dopo
una fork terminata con successo
copia
232 - 1
0
Stack
232 - 1
Stack
Area vuota
Area vuota
heap
Data
heap
Data
Text
Text
SI padre
0
SI figlio
7
Creazione di processi (3)
• Come prosegue l’esecuzione nei processi padre e
figlio
232 - 1
&x
45
232 - 1
Stack
&x
0
Area vuota
heap
Data
0
Stack
Area vuota
PC = istruzione
successiva a fork
Text
SI padre (pid=34)
0
heap
Data
Text
SI figlio (pid = 45)
8
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);
}
9
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
10
Attesa di terminazione del figlio
pid_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
maschere
WIFEXITED(status)
WEXITSTATUS(status)
– in caso di errore (es non ci sono figli …) viene
ritornato il valore -1
11
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)
12
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 */ }
13
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
14
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
15
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
$
16
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
18
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)
19
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 ….
20
Differenziazione : le exec() (4)
• Formato di un file eseguibile
– risultato di compilazione, linking etc ...
Numero che contraddistingue
il file come eseguibile
Magic number
Altre info
Ampiezza area di
memoria occupata dalle variabili
globali NON inizializzate
Ampiezza BSS
Variabili globali
I-Data segment inizializzate
Text segment
Codice del programma
(assemblato)
21
Differenziazione : le exec() (5)
– (1) il contenuto del file eseguibile viene usato per
sovrascrivere lo spazio di indirizzamento del
processo che la invoca
Variabili di ambiente (envp)
Agomenti (argv)
FRAME per la funzione main
env
argv
Stack
Area vuota
232 - 1
BSS-segment
Ampiezza BSS
I-Data segment
I-Data segment
Text segment
Text
File eseguibile
Data
0
22
Differenziazione : le exec() (6)
– (2) si carica in PC l’indirizzo iniziale X
env
argv
Stack
Area vuota
Indirizzo della prima istruzione compilata
di main()
X
Ampiezza BSS
I-Data segment
Text segment
232 - 1
BSS-segment
I-Data segment
X
Text
0
23
Esempio : una shell semplificata
int 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”);
}
24
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
25
Es: la redirezione
– La shell permette di ridirigere stdin/out/error
– Es.
$ ls
indirizzi.pdf
k.c
s.doc
26
Es: la redirezione
– La shell permette di ridirigere stdin/out/error
– Es.
$ ls
indirizzi.pdf
$ ls > pippo
k.c
s.doc
27
Es: la redirezione
– La shell permette di ridirigere stdin/out/error
– Es.
$ ls
indirizzi.pdf
$ ls > pippo
$ more pippo
indirizzi.pdf
k.c
s.doc
k.c
s.doc
28
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
29
Es: la redirezione (3)
– Redirezione dello stdout ed error su file diversi
$ more pippo.c pluto.c 1> out 2> log
30
Es: la redirezione (3)
– Redirezione dello stdout ed error su file diversi
$ more pippo.c pluto.c > out &> log
31
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
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
$ 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());
33
Es: la redirezione (3.1)
– Attenzione: out e log vengono sovrascritti!!!!!
– Per appendere usare ‘>>’
$ more pippo.c pluto.c 1>> out 2>> log
34
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
35
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_CRE
AT,0644),”nella open”);
dup2(fd,STDOUT); /* duplica fd sullo standard
output*/
close(fd);
/* fd non serve piu’ */
printf(“Questo viene scritto in pippo!”);
...
36
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
37
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)
38
Scarica

fork,exec