exec und rückmeldung im parent ohne zombie
-
OK sry, hab das exec vergessen. Dein Prozess kann nicht sagen, wenn es geklappt hat (wurde ja ersetzt durch exec). Du kannst nur mitteilen, falls es nicht geklappt hat. Da du darauf aber nicht warten kann(weil ja möglichcerweise nichts kommt), sind pipes vielleicht doch nicht so geeignet.
Aber es könnte so gehen:
Du machst den Signalhandler für SIGCHLD, der ein waitpid(-1, &status, WNOHANG) aufruft (braucht keine Schleife bei einem Kind).
Und dann untersuchst du den Statuscode.Also:
V: Vater, K:Kind
V: installiere Signalhandler
V: fork()
V: arbeite normal weiter K: mache ein exec
V: arbeite ... K: falls erfolgreich passiert nix(dein Programmcode ist ja weg)
V: arbeite ... K: falls Fehler: exit(237)
V: Arbeit unterbrochen von func K: Zombie
V: waitpid(-1, &status, WNOHANG) K: Zombie verschwindet
V: teste Staus mit WIFEXITED(status)
V: falls ja: teste ob WEXITSTATUS(status) = 237
wobei du
- keine Benachrichtigung kriegst, falls es erfolgreich war
- nicht weißt, wo der Fehler aufgetreten ist (wenn exec klappt aber das neue Programm sich zufällig mit z.B. 237 als code beendet siehst du den Unterschied nicht.Und die Signalhandler warten nur auf Signale, blockieren aber den Ablauf nicht, sodass die GUI trotzdem laufen sollte.
frank schrieb:
Wenn ich das richtig interpretiere (mit der while-schleife) würde ich mit der func vermutlich den gleichen Effekt haben, wie mit system...die Grafische Oberfläche (GTK) wird nicht mehr gezeichnet und navigieren darauf wird unmöglich.
du rufst func selbst nicht auf. Das macht das betriebsystem für dich und zwar sobald ein Prozess beendet wurde. Dann geht die Schleife her, rattert einmal über alle Prozesse, deren Status sich geändert hat drüber,(bei dir genau dieser eine) entsorgt diesen Zombie und wird wegen dem WNOHANG danach gleich 0 zurückliefern und die func wieder verlassen. Da sollte nichts blockieren.
-
Hallo,
ich hab jetzt so, und es funktioniert super, soweit ich es nach bisherigen Tests beurteilen kannvoid child_callback(int param) { pid_t pid; int status; pid=waitpid(-1, &status, WNOHANG); g_print("child terminated (%d)\n",status); if (status>0) ShowError("Fehler bei der Ausführung!"); } bool Exec(string command,string parameters,string file) { bool ret=true; //arg-array bauen pid_t pid=fork(); if (pid==-1) { g_print("problem while forking\n");//return false; //problem while forking ret=false; }else if (pid==0)//child-process { if(execvp(command.c_str(), args) == -1) { perror("execvp"); _Exit(EXIT_FAILURE);//errors in child are handled by signal-handler } } else { //parent process struct sigaction sa; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART | SA_NOCLDSTOP; sa.sa_handler = child_callback; sigaction(SIGCHLD, &sa, NULL); } return ret; }
Danke Baer
Gruß Frank
-
Hi,
glück gehabt
Prinzipiell alles richtig, nur musst du den Signal-Handler nicht im Vaterprozess anlegen, sondern noch vor dem fork();
Problem sonst: fork() -> Kind wird als erstes ausgeführt -> terminiert
und erst dann kommt der Vater wieder dran und darf weiterrechnen -> installiert Handler, aber Signal kam ja schon vorher = verloren
Wenn du vor dem fork den Handler installierst, hat ihn der Vater schon und wenn dann das Kind zuerst rechnen darf und sich gleich beendet wird das erkannt.P.S fork() übernimmt die eingestellten Handler(heißt Kind hat den auch installiert, wobei es kein eigenes Kind hat, also nutzlos^^), aber beim exec wird der SIgnalhandler dann ausm Kind gelöscht.
-
wenn ich den signal-handler-block vor dem fork platziere, hängt der parent
-
hm. da bin ich überfragt . Bei mir hat das immer tadellos funktioniert.
Ich werde das demnächst mal bei mir testen.int Exec(char * command, char ** parameters, char * file) { int ret=1; //arg-array bauen struct sigaction sa; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART | SA_NOCLDSTOP; sa.sa_handler = child_callback; sigaction(SIGCHLD, &sa, NULL); pid_t pid=fork(); if (pid==-1) { g_print("problem while forking\n");//return false; //problem while forking ret=false; }else if (pid==0)//child-process { execlp(command, NULL); perror("execvp"); _Exit(EXIT_FAILURE);//errors in child are handled by signal-handler } else { //parent process /*int i = 0; for (;i < 100000000; i++) { printf("%c", 0); }*/ } printf("Vater fertig\n"); return ret; }
So funktioniert das bei mir.
- Die Schleife mit printf() habe ich testhalber drinnen gehabt um zu simulieren, dass das Kind zuerst terminiert bevor der Signalhandler installiert werden konnte (->< Signal war verloren).
- Nachdem ich den Signal-Block nach vorne geschoben habe, lief es mit und ohne Schleife
- Ich hab die If-Abfrage bei execvp (habs tsethalber in execlp geändert) weggelassen, da execvp sowieso immer -1 zurückliefert (im Erfolgsfall ist dein Programmcode ja weg)Hast du in der call_back oder in der Exec noch Code der unerwünschte Nebeneffekte haben könnte? Oder wo genau hängt der Vater?
Tut mir leid, dass das immer noch nicht ganz richtig läuft.
-
habe meine komplette callback geposted...das einzige "komplexe" ist ShowError,
welches den Text in einer GtkInfoBar (im parent) anzeigt (wär hier vermutlich bisschen viel zum posten [in Klasse eingebetter])die zeile mit dem perror wird trotzdem nicht erreicht (nur im fehlerfall)?
der parent hängt nachdem das child beendet wurde:
letzte Ausgabe:
execvp: No such file or directory
child terminated (256)der child-prozess ist bei "ps auxf" nicht (mehr) sichtbar
-
frank schrieb:
letzte Ausgabe:
execvp: No such file or directory
child terminated (256)der child-prozess ist bei "ps auxf" nicht (mehr) sichtbar
das heißt immerhin, dass das Signal richtig abgefangen wird und waitpid() den Zombie richtig aufräumt.
Ich denke du solltest nicht status verwenden zum Anzeigen,sondern WEXITSTATUS(status). Da stecken mehrere Daten drinnen als der reine Exitcode, aber das sind erstmal Details.Das mit der komplexen ShowMessage könnte möglicherweise das Problem sein, weil nicht alle Funktionen sicher vor überlagerung sind, also wenn dein Vater die Funktion aufruft und mittendrin durch das Signal unterbrochen wird und der die gleiche Funktion aufruft.
Wenn du die ShowMessage auskommentierst, sollte es eigentlich laufen, oder?
Wenn das das Problem ist, fällt mir jetzt nur ein, diese problematische Funktion möglichst zu ersetzten, oder im Vaater vor jedem Aufruf das SIGCHLD temporär zu blockieren.
-
mhm..scheint an der error-funktion zu liegen...
diese sieht erstmal so aus:
void ShowError(string message) { g_print("Error: %s\n",message.c_str()); message="Fehler: "+message; Mainform.InfoBar->ShowBar(GTK_MESSAGE_ERROR,message.c_str(),true); }
die erste zeile ist ja ein g_print...welches aber scheinbar schon nicht ausgeführt wird...
selbst wenn ich die beiden letzten Zeilen auskommentiere, hängt sich der parent auf...warum ist mir unklar, da ja auch nur ein g_print drin ist...meine callback sieht jetzt so aus:
void child_callback(int param) { pid_t pid; int status; while( (pid=waitpid(-1, &status, WNOHANG)) > 0 ) { int exitcode=WEXITSTATUS(status); g_print("child terminated (%d)\n",exitcode); if (exitcode>0) g_print("Error in child...\n"); //ShowError("Wiedergabeprogramm konnte nicht gestartet werden!"); } }
-
also so wie ich das sehe funktioniert das erste g_print(), aber das zweite nicht?
Ich kannte die Funktion g_print() leider nicht, aber vielleicht hat sie einen Puffer der nicht automatisch bei '\n' geleert wird oder hat sonstige Probleme, die nichts mit dem Signalhandler zu tun haben?
Interessant fände ich auch mal, was in errorcode drinsteht, denn die "least significant 8 bits" wie in der Man-page steht ergeben 0 wenn der statuscode 256 ist.
Funktioniert es, wenn du z.B. ein Printf() an die stelle machst?Das sind jetzt nur noch wage Vermutungen, weil es langsam absolut keinen Sinn mehr ergibt.
Tut mir echt leid, dass ich da keine Idee mehr habe...
-
Die ersten beiden g_print in der child_callback funktionieren.nur das g_print in der showerror nicht. Der exitcode ist da ubrigends 1 (exit_failure)
-
ich habe den code mal isoliert in ein separetes Programm kopiert, da funktioniert er...irgendwas blockiert im Haupt-programm scheinbar...aber keine Ahnung, wo und was...
ich könnte dir zwar den kompletten Code geben, aber ich denke, es ist zuviel verlangt, dass du mein Programm debuggst
Gruß Frank