In this domanda precedente Ho postato la maggior parte del mio codice shell. Il mio prossimo passo è quello di implementare l'esecuzione del processo in primo piano e in background e attendere che si concludano in modo che non rimangano come "zombi".Come attendere correttamente i processi in primo piano/in background nella mia shell in C?
Prima di aggiungere la possibilità di eseguirli in background, tutti i processi erano in esecuzione in primo piano. E per questo, ho semplicemente chiamato wait (NULL) dopo l'esecuzione di qualsiasi processo con execvp(). Ora, controllo il carattere '&' come ultimo argomento e se è presente, eseguo il processo in background non chiamando wait (NULL) e il processo può essere eseguito felicemente in background, tornerò nella mia shell.
Questo funziona correttamente (credo), il problema ora è che devo anche chiamare wait() (o waitpid()?) In qualche modo in modo che il processo in background non rimanga "zombie". Questo è il mio problema, non sono sicuro di come farlo ...
Credo di dover gestire SIGCHLD e fare qualcosa lì, ma devo ancora capire quando viene inviato il segnale SIGCHLD perché ho provato anche a aggiungi wait (NULL) a childSignalHandler() ma non ha funzionato perché non appena ho eseguito un processo in background, è stata chiamata la funzione childSignalHandler() e, di conseguenza, l'attesa (NULL), il che significa che non ho potuto fare nulla con la mia shell fino al termine del processo "background". Che non funzionava più sullo sfondo a causa dell'attesa nel gestore del segnale.
Cosa mi manca in tutto questo?
Un'ultima cosa, parte di questo esercizio, ho anche bisogno di stampare le modifiche dello stato dei processi, come la terminazione del processo. Quindi, qualsiasi intuizione su questo è anche molto apprezzata.
Questo è il mio codice completo in questo momento:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <wait.h>
#include <signal.h>
#include <sys/types.h>
#include "data.h" // Boolean typedef and true/false macros
void childSignalHandler(int signum) {
//
}
int main(int argc, char **argv) {
char bBuffer[BUFSIZ], *pArgs[10], *aPtr = NULL, *sPtr;
bool background;
ssize_t rBytes;
int aCount;
pid_t pid;
//signal(SIGINT, SIG_IGN);
signal(SIGCHLD, childSignalHandler);
while(1) {
write(1, "\e[1;31mmyBash \e[1;32m# \e[0m", 27);
rBytes = read(0, bBuffer, BUFSIZ-1);
if(rBytes == -1) {
perror("read");
exit(1);
}
bBuffer[rBytes-1] = '\0';
if(!strcasecmp(bBuffer, "exit")) {
exit(0);
}
sPtr = bBuffer;
aCount = 0;
do {
aPtr = strsep(&sPtr, " ");
pArgs[aCount++] = aPtr;
} while(aPtr);
background = FALSE;
if(!strcmp(pArgs[aCount-2], "&")) {
pArgs[aCount-2] = NULL;
background = TRUE;
}
if(strlen(pArgs[0]) > 1) {
pid = fork();
if(pid == -1) {
perror("fork");
exit(1);
}
if(pid == 0) {
execvp(pArgs[0], pArgs);
exit(0);
}
if(!background) {
wait(NULL);
}
}
}
return 0;
}
Grazie, ma ho davvero bisogno di usare il gestore del segnale, fa parte dell'esercizio. –
Ho appena visto la tua modifica ... Ho inserito l'waitpid() nel gestore del segnale ma ho il problema che descrivi nel tuo secondo paragrafo. Non volevo usare le variabili globali per risolvere il problema, ma non sono sicuro di come risolverlo senza di loro ... –
Evitare le variabili globali è buono, ma comunicare con un gestore di segnale è uno dei casi in cui sono " necessario. – dwc