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

interpreter : sequentialExec.c

sᴀʟᴠᴀᴛᴏʀᴇ ʙ edited this page Jul 23, 2017 · 1 revision
void sequentialExec() {
	printf("Nota: Premere INVIO per terminare\n");
	int termination_flag = 0;
	int count = 0;
	pid_t pid;
	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 ((pid = fork()) == 0) {
				//processo figlio
				//la memoria dinamica istanziata in parseCommand sara'
				//liberata automaticamente al termine di questo processo
				//in caso di errore mantengo STDOUT
				int saved_stdout = dup(STDOUT_FILENO);
				char **command = parseCommand(str);
				createFile(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
				int status;
				wait(&status);
				if (WIFEXITED(status))
		printf("Il processo id:%d è terminato con successo.\n",pid);
				else {
					perror("Errore processo: ");
				}
			}
		} else {
			termination_flag = 0;
		}
		free(str);
	} while (termination_flag != 0);
}

Il ciclo do…while parte con la readCommand() che è ovviamente eseguita dal processo padre, nel caso la stringa ricevuta sia uguale a NULL allora il ciclo termina impostando il flag di uscita a 0. Altrimenti si incrementa la variabile “count”, cioè il numero di processi creati (serve a impostare l’indice dei file di output) e si esegue la fork.

Si analizza separatamente il codice di padre e figli:

  • FIGLIO

Nel blocco del figlio si esegue parseCommand() sulla linea digitata dall’utente e si crea il relativo file invocando createFile(count); a questo punto possono accadere 2 eventi: il comando è riconosciuto ed eseguito, l’output (se presente) viene redirezionato su file e il processo figlio termina; il comando non è stato riconosciuto e si avverte l’utente sul terminale.

NOTA: particolarmente importante è il fatto che la chiamata a parseCommand() avviene localmente al processo figlio, pertanto la memoria dinamicamente allocata non è responsabilità del padre e non è costretto a liberarla; l’esecuzione di exec() rimuove l’immagine del processo per rimpiazzarla con il nuovo programma e di conseguenza il SO riacquisisce la memoria (nel caso in cui exec non fosse eseguita il processo termina con exit() ed il SO può comunque riacquisire quello spazio, senza incappare in memory leak).

  • PADRE

Nel blocco del padre si attende tramite wait la terminazione del figlio (ciò realizza la sequenzialità dell’esecuzione) ed in base allo status si stampa un messaggio appropriato (l’esecuzione di dup2 nel figlio non influenza il padre, il cui STDOUT è rimasto lo stesso e non è necessario modificarlo). Infine il padre libera la memoria della stringa letta da readCommand().

void createFile(int count) {
	char fileName[100];
	if (argv[1] != '\0' && argv[1] != NULL) {
		char* path = "";
		if (argv[1][strlen(argv[1]) - 1] == '/')
			path = strcat(argv[1], "out.%d");
		else
			path = strcat(argv[1], "/out.%d");
		sprintf(fileName, path, count);
	} else {
		sprintf(fileName, "./output_file/out.%d", count);
	}

//crea il file se non esiste, altrimenti truncate. Permesso di lettura/scrittura per l'owner
	int fd = open(fileName, O_CREAT | O_TRUNC | O_WRONLY, 0600);
	if (fd < 0) {
		perror("Apertura file: ");
		exit(EXIT_FAILURE);
	}
	dup2(fd, 1); // redirezione dell'output su stdout
	close(fd);
}

La funzione createFile(int count) si occupa della creazione del file che conterrà l’output del comando eseguito, ricevendo come argomento l’indice da inserire. Il controllo iniziale serve a determinare se l’utente abbia specificato una cartella di preferenza, altrimenti salva nella cartella output_file. Il file viene creato e attraverso dup2 si ridireziona lo STDOUT in quest’ultimo. Questa operazione eseguita dal processo figlio non ha conseguenze sullo STDOUT del padre o su quello di altri figli.

Clone this wiki locally