Wie Sie richtig zu warten, für Vordergrund - /hintergrund-Prozesse, die in meiner eigenen shell in C?
In diese vorherigen Frage habe ich geschrieben, die meisten meiner eigenen shell-code. Mein Nächster Schritt ist die Umsetzung der Vordergrund-und hintergrund-Prozess-Ausführung und ordnungsgemäß zu warten, für Sie zu kündigen, damit Sie nicht Aufenthalt als "zombies".
Bevor Sie die Möglichkeit im hintergrund ausführen lassen, wurden sämtliche Prozesse laufen im Vordergrund. Und für die, die ich einfach als wait(NULL) nach der Ausführung jeder Prozess mit execvp(). Nun, ich checke das '&' - Zeichen als letztes argument und wenn Sie da ist, führen Sie den Prozess im hintergrund durch den Aufruf nicht warten, (NULL), und der Prozess kann laufen gerne im hintergrund bin ich wieder auf meiner shell.
Ist dies alles richtig funktioniert (glaube ich), das problem jetzt ist, dass ich auch benötigen, rufen Sie wait() (bzw. waitpid() ?) irgendwie so, dass der Hintergrundprozess nicht bleiben "zombie". Das ist mein problem, ich bin mir nicht sicher, wie das zu tun...
Ich glaube, ich habe das handle SIGCHLD und tun etwas gibt, aber ich habe noch zu verstehen, wenn das SIGCHLD-signal gesendet wird, denn ich habe versucht, fügen Sie auch wait(NULL) zu childSignalHandler (), aber es hat nicht funktioniert, weil sobald ich ausgeführt, ein Prozess im hintergrund, der childSignalHandler () - Funktion aufgerufen wurde, und somit die wait(NULL), was bedeutet, ich konnte nichts mit meiner shell, bis die "hintergrund" - Prozess beendet. Das war nicht im hintergrund laufen nicht mehr, weil das warten in der signal-handler.
Was bin ich in alldem?
Eine Letzte Sache, Teil dieser übung, die ich auch drucken müssen, die änderungen der Prozesse, der status, wie Beendigung des Prozesses. Also, keine Einsicht auf, dass auch wirklich geschätzt.
Dies ist mein vollständiger code im 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;
}
Du musst angemeldet sein, um einen Kommentar abzugeben.
Gibt es verschiedene Optionen, um
waitpid()
um Ihnen zu helfen (Zitate aus dem POSIX-standard):Insbesondere, WNOHANG Ihnen erlauben zu sehen, ob es irgendwelche Leichen zu sammeln, ohne dass Ihr Prozess zu block wartet auf eine Leiche.
Werden Sie wahrscheinlich nicht wollen, zu ignorieren SIGCHLD, etc, und Ihre signal-handler sollten wohl festlegen ein flag zu sagen, Ihre Haupt-Schleife "Hoppla, es gibt tote Kind gehen sammeln, die Leiche!".
Den SIGCONT und SIGSTOP Signale werden auch von Relevanz für Sie - Sie werden verwendet, um starten Sie und beenden Sie ein Kind-Prozess, beziehungsweise (in diesem Kontext jedenfalls).
Ich würde empfehlen, sich auf Rochkind Buch oder Stevens' Buch " - Sie decken diese Themen im detail.
Dieser sollte Ihnen den Einstieg. Der wesentliche Unterschied ist, dass ich losgeworden der Kind-handler und Hinzugefügt
waitpid
in der main-loop ein feedback. Getestet und funktioniert, aber offensichtlich braucht mehr TLC.EDIT: Hinzufügen zurück in signal handling ist nicht schwer mit
waitpid()
mit WNOHANG. Es ist so einfach wie das verschieben derwaitpid()
Zeug aus der Spitze der Schleife in die signal-handler. Sollte man sich zweier Dinge bewusst sein, aber:Erste, auch "Vordergrund" - Prozesse wird SIGCHLD senden. Da kann es nur einen Vordergrund-Prozess, können Sie einfach speichern Sie die Vorder-pid (parent ' s Rückgabewert von
fork()
) in eine variable sichtbar ist, um die signal-handler-wenn Sie möchten, um spezielle Handhabung von Vorder-vs. hintergrund.Zweiten Sie gerade tun-blocking I/O über standard-Eingabe (der
read()
am main loop-top). Sie sind sehr wahrscheinlich zu sein blockiert aufread()
wenn SIGCHLD Auftritt, was in einer interrupted system call. Je nach OS kann es starten Sie das system aufrufen, automatisch, oder es kann ein signal senden, die Sie behandeln müssen.Können Sie verwenden:
Diese Weise wird der Prozess blockiert, bis er erhält die
SIGCHLD
- signal und die signal-handler tun, die Sachen warten.background
und ruftpause()
? Es gibt eine race-Bedingung hier.Anstatt eine Globale variable, ich dachte an eine andere Lösung:
Wenn ich ein Vordergrund-Prozess "löschen" der handler für SIGCHLD, so dass es nicht aufgerufen. Dann, nach waitpid(), stellen Sie die hf wieder. Auf diese Weise werden nur die Prozesse im hintergrund abgewickelt werden.
Glaubst du, es gibt etwas falsch mit dieser Lösung?
signal()
sollte ein Zeiger auf ein signal-handler-Funktion, oderSIG_IGN
oderSIG_DFL
;NULL
ist keine gültige option, obwohlSIG_IGN
ist oft eine Funktion null-Zeiger. Sie sollten wahrscheinlich capture der return-Wert von der erstensignal()
und wiederherzustellen, die es in den zweiten Anruf. Wenn andere Signale, die SIGCHLD ankommen,waitpid()
zurückkehren konnte früh mit EINTR. Mitsigaction()
stattsignal()
würde Ihnen erlauben, zu Steuern, welche Signale erlaubt sind.