-
Notifications
You must be signed in to change notification settings - Fork 0
interpreter : parallelExec.c
void parallelExec() {
signal(SIGUSR1, SIG_IGN); //ignoro SIGUSR1 perchè serve solo per evitare race con distino
bind_handler_sigchld(); // imposto l'handler opportuno per i SIGCHLD
printf("Nota: Premere INVIO per terminare\n");
int termination_flag = 0;
int count = 0;
pid_t pidPadre = getpid();
do {
printf("\n> ");
//acquisizione comando da parte dell'utente
char* str = readCommand();
if (str != NULL) {
termination_flag = 1;
count++; //incremento dell'indice degli output file
if (fork() == 0) {
//processo figlio
//la memoria dinamica istanziata in parseCommand sara'
//liberata automaticamente al termine di questo processo
int saved_stdout = dup(STDOUT_FILENO); //in caso di errore mantengo STDOUT
char **command = parseCommand(str); //il comando è stato salvato localmente, segnalo al padre il via libera al prossimo comando
kill(pidPadre, SIGUSR1);
createFileP(count);
//l'ouput è redirezionato anche dopo execvp
if (execvp(command[0], command) == -1) { //errore nell'esecuzione di execvp (probabilmente comando non riconosciuto)
dup2(saved_stdout, STDOUT_FILENO);
printf("Comando non riconosciuto.\n");
exit(EXIT_FAILURE);
}
} else {
//processo padre
//devo almeno attendere che il figlio abbia copiato localmente
//il comando da eseguire
pause(); //aspettando SIGUSR1
signal(SIGUSR1, SIG_IGN); //ripristino l’handler
}
} else {
termination_flag = 0;
}
free(str);
} while (termination_flag != 0);
}parallelExec.c mostra una struttura simile a sequential, ma in questo caso nel blocco del padre non viene eseguita nessuna wait ma solo una pause(): in effetti per evitare problemi di race condition il padre deve almeno attendere che il figlio abbia acquisito il parsing del comando, senza andare a liberare la memoria e ad acquisire il prossimo comando; per far ciò il padre attende il segnale SIGUSR1 che verrà semplicemente ignorato (ma avrà l’effetto di farlo ripartire). Dato che di default SIGUSR1 determina la terminazione del processo, esso è stato modificato attraverso
-> signal(SIGUSR1, SIG_IGN); cioè la prima istruzione.
La seconda riguarda invece la gestione dei figli che terminano mentre il padre è attivo, in particolare per evitare la proliferazione di zombies il padre sfrutta la funzione “handle_sigchld” descritta nel prossimo paragrafo.
Nota: Se il padre terminasse prima dei suoi figli, essi sarebbero automaticamente promossi a figli di init e sarebbe quest’ultimo ad accettare la loro terminazione.
Nel blocco del figlio è stato aggiunto l’invio del segnale SIGUSR1 attraverso la kill subito dopo il parseCommand().
Made with ❤️ by Owanesh and MatteoMauro | MIT ©