interpreter : Analisi e progettazione - Owanesh/unifi-eos GitHub Wiki

La politica di esecuzione viene scelta dall’utente all’avvio del programma, attraverso un menù di selezione. Si esaminano separatamente la progettazione delle due richieste effettuate nel testo:

Esecuzione sequenziale

Il processo main (presente dall’attivazione del programma) gestisce l’acquisizione dei comandi da parte dell’utente, delegandoli uno per uno ad un processo figlio appositamente creato sul momento; dal momento che il testo esplicita che l’esecuzione è sequenziale, il padre attende che il figlio termini il suo compito prima di tornare a ricevere il comando successivo.

Un esempio di esecuzione è il seguente:

  • Il processo main attende un comando;
  • L’utente digita “ls” e preme “invio”;
  • Alla digitazione di “invio” il processo main crea un processo figlio tramite fork() e si mette in attesa tramite wait();
  • Il processo figlio sostituisce il proprio codice tramite exec() e avanza fino alla terminazione del suo compito, evento che verrà segnalato al processo padre;
  • Il processo main viene risvegliato e torna ad attendere un comando dall’utente; Notare quindi come l’esecuzione avviene in maniera sequenziale, non ci sono processi eseguiti parallelamente (inoltre non possono essere presenti allo stesso tempo 2 o più processi figli, ma il processo main e l’eventuale figlio).

Esecuzione parallela

Non essendo ulteriormente specificato nel testo, per il contesto dell’esecuzione parallela la realizzazione è molto simile a quella dell’esecuzione sequenziale, con l’unica differenza che il processo main non si metterà in attesa del figlio ma tornerà subito a disposizione dell’utente: ciò permette quindi a più processi figli di essere attivi nel sistema contemporaneamente assieme al padre. Ogni qual volta che un processo figlio termina, non ci sarà il padre a raccoglierne lo stato di terminazione perché ciò implicherebbe l’impossibilità da parte dell’utente di inserire comandi (come nella esecuzione sequenziale): per evitare la proliferazione di zombies è presente un handler specifico che li rimuove dalla tabella dei processi.

Analogamente, se il padre terminasse prima dei figli, essi sarebbero promossi a figli di init, il quale gestirebbe automaticamente la loro terminazione.

L’utente potrà passare come argomento il percorso della cartella in cui salvare i file di output prodotti dall’esecuzione dei figli, se non specificato verrà usato quello di default “./output_file”. Il percorso selezionato deve esistere o verrà mostrato un messaggio d’errore all’esecuzione di qualsiasi comando.

Si riportano le dipendenze dei moduli (sintassi simile ad un file .make, dove a sinistra in grassetto è presente il modulo oggetto e a destra la lista delle dipendenze):

main.o: main.c. parallelExec.h  readCommand.h  handle_sigchld.h  sequentialExec.h  utilities.h
parallelExec.o: parallelExec.c  parallelExec.h  readCommand.h. handle_sigchld.h   utilities.h
handle_sigchld.o: handle_sigchld.c  handle_sigchld.h
readCommand.o: readCommand.c  readCommand.h  utilities.h
sequentialExec.o: sequentialExec.c  sequentialExec.h  readCommand.h   utilities.h
utilities.o: utilities.c  utilities.h