Comment bien attendre pour l'avant-plan/arrière-plan dans mon propre coque en C?
Dans cette question précédente que j'ai posté plus de mon propre shell code. Ma prochaine étape est la mise en œuvre de premier plan et d'arrière-plan de l'exécution du processus et bien d'attendre pour eux de mettre fin, de sorte qu'ils ne restent pas comme des "zombies".
Avant d'ajouter la possibilité de les exécuter en arrière-plan, tous les processus étaient en cours d'exécution en arrière-plan. Et pour cela, j'ai simplement appelé wait(NULL) après l'exécution de tout processus avec execvp(). Maintenant, je vérifie pour le '&' comme le dernier argument, et si c'est là, lancez le processus en arrière-plan et ne pas appeler wait(NULL) et le processus peut s'exécuter heureux dans le fond, je suis retourné à ma coquille.
C'est tout fonctionne correctement (je pense), le problème, c'est que maintenant j'ai aussi besoin de l'appel en attente() (ou waitpid() ?) d'une certaine manière, de sorte que le processus d'arrière-plan ne reste pas en "zombie". C'est mon problème, je ne suis pas sûr de la façon de le faire...
Je crois que j'ai à gérer SIGCHLD et de faire quelque chose là, mais je n'ai pas encore pleinement comprendre quand le signal SIGCHLD est envoyé parce que j'ai essayé d'ajouter aussi de wait(NULL) pour childSignalHandler() mais cela ne fonctionne pas car dès que j'ai exécuté un processus en arrière-plan, la childSignalHandler() la fonction a été appelée et, par conséquent, le wait(NULL), ce qui signifie que je ne pouvais pas faire n'importe quoi avec ma coquille jusqu'à ce que le "fond" le processus est terminé. Ce qui n'était pas en cours d'exécution sur le fond plus à cause de l'attente dans le gestionnaire de signal.
Ce qui me manque dans tout cela?
Une dernière chose, une partie de cet exercice, j'ai aussi besoin d'imprimer les changements de processus d'état, comme la fin du processus. Ainsi, aucune information sur qui est également vraiment appréciée.
C'est mon code pour le moment:
#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;
}
OriginalL'auteur Ricardo Amaral | 2009-05-22
Vous devez vous connecter pour publier un commentaire.
Il existe diverses options pour
waitpid()
pour vous aider (citations de la norme POSIX):En particulier, WNOHANG vous permettra de voir s'il y a des cadavres de recueillir des sans la cause de votre processus de bloc d'attente pour un cadavre.
Vous ne voulez probablement pas à être ignorant SIGCHLD, etc, et votre gestionnaire de signal devrait probablement être un indicateur de dire à votre boucle principale "Oups; il y a l'enfant mort - aller recueillir ce cadavre!".
Le son état et SIGSTOP signaux seront également de la pertinence pour vous - ils sont utilisés pour redémarrer et arrêter un processus enfant, respectivement (dans ce contexte, en tout cas).
Je vous recommande de regarder Rochkind du livre ou de Stevens livre " qu'ils traitent de ces questions dans le détail.
OriginalL'auteur Jonathan Leffler
Cela devrait vous obtenir a commencé. La différence majeure est que je me suis débarrassé de l'enfant, de gestionnaire et a ajouté
waitpid
dans la boucle principale, avec quelques commentaires. Testé et de travail, mais de toute évidence besoin de plus de TLC.EDIT: en rajoutant dans le traitement du signal n'est pas difficile avec
waitpid()
à l'aide de WNOHANG. C'est aussi simple que de déplacer lewaitpid()
des trucs dans le haut de la boucle dans le gestionnaire de signal. Vous devez être conscient de deux choses l'une:Tout d'abord, même "de premier plan" processus enverra SIGCHLD. Puisqu'il ne peut être qu'un processus d'arrière-plan vous pouvez simplement stocker le premier plan pid (parent de la valeur de retour de
fork()
) dans une variable visible pour le gestionnaire de signal si vous voulez faire une manipulation spéciale de premier plan vs. arrière-plan.Deuxième, vous êtes en train de faire le blocage des I/O sur l'entrée standard (le
read()
dans la boucle principale en haut). Vous êtes extrêmement nombreux à être bloqué surread()
quand SIGCHLD se produit, entraînant un appel système interrompu. Selon le système d'exploitation il peut redémarrer le système d'appel automatiquement, ou il peut envoyer un signal que vous devez gérer.Je viens de voir ton edit... je n'ai mis le waitpid() dans le gestionnaire de signal, mais que j'ai le problème que vous décrivez dans votre deuxième paragraphe. Je ne voulais pas utiliser de variables globales pour résoudre le problème, mais je ne suis pas sûr de la façon de réparer sans eux...
Éviter les variables globales est bonne, mais le fait de communiquer avec un gestionnaire de signal est un des cas où ils sont nécessaires.
Veuillez voir ma dernière réponse...
OriginalL'auteur dwc
Vous pouvez utiliser:
De cette façon, le processus se bloque jusqu'à ce qu'il reçoit le
SIGCHLD
signal, et le gestionnaire de signal fera l'attente des choses.background
et de l'appel depause()
? Il y a une condition de course ici.OriginalL'auteur aaa
Au lieu d'utiliser une variable globale, j'ai pensé à une autre solution:
Si je suis à court d'un processus d'arrière-plan "supprimer" le gestionnaire pour SIGCHLD de sorte qu'il n'est pas appelée. Puis, après waitpid(), définir le gestionnaire de nouveau. De cette façon, seuls les processus d'arrière-plan seront traitées.
Pensez-vous qu'il ya quelque chose de mal avec cette solution?
Mais je suis toujours pas à voir une façon de mettre en œuvre une variable globale pour cela, et aussi éviter une situation de concurrence. La façon dont je le vois, l'ajout d'une variable globale pour gérer cette situation va encore créer une race condition. Soins à donner un exemple où il n'a pas d'introduire une condition de concurrence?
Notez que le deuxième argument de
signal()
doit être un pointeur vers un gestionnaire de signal fonction, ouSIG_IGN
ouSIG_DFL
;NULL
n'est pas une option valable, même siSIG_IGN
est souvent un null le pointeur de fonction. Vous devriez probablement de capturer la valeur de retour de la premièresignal()
et de le rétablir dans le deuxième appel. Si d'autres signaux de l'SIGCHLD arriver,waitpid()
pourrait revenir plus tôt avec EINTR. À l'aide desigaction()
au lieu designal()
vous permettra de contrôler les signaux sont admis dans.OriginalL'auteur Ricardo Amaral