En this pregunta anterior publiqué la mayor parte de mi propio código de shell. Mi próximo paso es implementar la ejecución del proceso en primer plano y en segundo plano y esperar a que finalicen para que no queden como "zombies".¿Cómo esperar adecuadamente los procesos de primer plano/fondo en mi propio shell en C?
Antes de agregar la posibilidad de ejecutarlos en segundo plano, todos los procesos se ejecutaban en primer plano. Y para eso, simplemente llamé a wait (NULL) después de ejecutar cualquier proceso con execvp(). Ahora, compruebo el carácter '&' como último argumento y si está allí, ejecuto el proceso en segundo plano al no llamar a wait (NULL) y el proceso puede ejecutarse felizmente en segundo plano. Volveré a mi shell.
Todo esto funciona correctamente (creo), el problema ahora es que también necesito llamar a wait() (o waitpid()?) De alguna manera para que el proceso de fondo no permanezca "zombie". Ese es mi problema, no estoy seguro de cómo hacer eso ...
Creo que tengo que manejar SIGCHLD y hacer algo allí, pero todavía tengo que entender completamente cuándo se envía la señal SIGCHLD porque también intenté add wait (NULL) a childSignalHandler() pero no funcionó porque tan pronto como ejecuté un proceso en segundo plano, se llamó a la función childSignalHandler() y, en consecuencia, a la espera (NULL), lo que significa que no pude hacer nada con mi caparazón hasta que finalice el proceso de "fondo". Que ya no se ejecutaba en segundo plano debido a la espera en el manejador de señal.
¿Qué me estoy perdiendo en todo esto?
Una última cosa, parte de este ejercicio, también necesito imprimir los cambios del estado de los procesos, como la terminación del proceso. Por lo tanto, cualquier idea sobre eso también es muy apreciada.
Este es mi código completo en la actualidad
#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;
}
Gracias, pero realmente necesito usar el manejador de señal, es parte del ejercicio. –
Acabo de ver su edición ... Coloqué el waitpid() en el manejador de señal pero tengo el problema que describe en su segundo párrafo. Simplemente no quería usar variables globales para solucionar el problema, pero no estoy seguro de cómo solucionarlo sin ellas ... –
Evitar las variables globales es bueno, pero la comunicación con un manejador de señal es uno de los casos en los que re necesario. – dwc