Skip to content
This repository was archived by the owner on Nov 4, 2023. It is now read-only.

interpreter : parallelExec.c

sᴀʟᴠᴀᴛᴏʀᴇ ʙ edited this page Jul 23, 2017 · 2 revisions
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().

Clone this wiki locally