exec und rückmeldung im parent ohne zombie



  • Hallo,
    ich hab jetzt so, und es funktioniert super, soweit ich es nach bisherigen Tests beurteilen kann

    void 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


Anmelden zum Antworten