Signalbehandlung und korrektes Beenden



  • Hallo,

    ich habe den Beitrag ursprünglich auf einer englischen Mailingliste gepostet, bis ich gemerkt haben, dass die leider ziemlich tot ist. Ich denke ausreichend Englisch zum lesen kann hier jeder, Antworten gerne in Deutsch oder Englisch.

    I'm developing a scientific application that can be used standalone as well 
    as a library.

    We use connection files to exchange information about socket based 
    connection. Upon an unclean exit these connection linger around, causing 
    trouble on the next startup.

    I implemented a signal handler to clean up on unclean exit:

    signal(SIGSEGV, precice::utils::terminationSignalHandler);
      signal(SIGABRT, precice::utils::terminationSignalHandler);
      signal(SIGTERM, precice::utils::terminationSignalHandler);
      signal(SIGINT,  precice::utils::terminationSignalHandler);
    
    void terminationSignalHandler(int signal) { 
    // use boost filesystem to clean up 
    }
    

    Since I'm a rather high level programmer I haven't had much contact with 
    signals, some questions:

    1. Can I assume the application to be in a condition to actually do 
      something when these signals are called? I have doubts especially about 
      SIGSEGV regarding corruption of internal data structures.

    2. Can multiple signal handler be installed for one signal? Or do subsequent 
      invocations of signal(...) overwrite the handler for the resp. signal? If we 
      are used as a library and host application has installed own signal handler, 
      how can we omit overwriting them?

    3. If there are multiple handler for one signal, can we remove our handler 
      from the chain and re-emit the signal? Or should be just use std::exit or 
      std::abort?

    4. Is this the right way to go for the problem described? Any comments 
      welcome!

    Viele Grüße,
    Florian


  • Mod

    Horus107 schrieb:

    I'm developing a scientific application that can be used standalone as well 
    as a library.

    We use connection files to exchange information about socket based 
    connection. Upon an unclean exit these connection linger around, causing 
    trouble on the next startup.

    I implemented a signal handler to clean up on unclean exit:

    signal(SIGSEGV, precice::utils::terminationSignalHandler);
      signal(SIGABRT, precice::utils::terminationSignalHandler);
      signal(SIGTERM, precice::utils::terminationSignalHandler);
      signal(SIGINT,  precice::utils::terminationSignalHandler);
    
    void terminationSignalHandler(int signal) { 
    // use boost filesystem to clean up 
    }
    

    Falls es machbar ist, bietet es sich übrigens eher an, dass der Handler selber keine Ressourcen freigibt, sondern einfach ein Flag setzt, dass vom Hauptprogramm regelmäßig überprüft wird und dann gegebenenfalls ein normales Programmende über die normalen Freigabepfade ausgelöst wird.

    Und im Falle einer Bibliothek ist es auf keinen Fall deine Aufgabe, Signalhandler zu erstellen. Du stellst Funktionen zur Freigabe der von der Bibliothek genutzten Ressourcen bereit, der Anwender der Bibliothek ist verantwortlich, dass diese auch korrekt aufgerufen werden.

    Außerdem ist die signal-Funktion selbst böse und sollte nicht benutzt werden.

    Manpage zu signal schrieb:

    Avoid its use: use sigaction(2) instead.

    1. Can I assume the application to be in a condition to actually do 
      something when these signals are called? I have doubts especially about 
      SIGSEGV regarding corruption of internal data structures.

    Das kommt drauf an 🙂 . Siehe den Abschnitt über das Unterbrechen von Systemcalls und -funktionen in der Manpage zur Signalbehandlung. Wie du siehst, zählen die ganzen socket-Funktionen zu denen, an die man hier gesondert gedacht hat. Du kannst also davon ausgehen, dass deine socket-Ressourcen in einem definierten Zustand sind, außer die genannten Ausnahmen greifen.

    1. Can multiple signal handler be installed for one signal? Or do subsequent 
      invocations of signal(...) overwrite the handler for the resp. signal? If we 
      are used as a library and host application has installed own signal handler, 
      how can we omit overwriting them?

    Nein, es kann nur einen Handler pro Signal geben. Der letzte gesetzte Handler für ein Signal ist der aktuell gültige.

    Wie gesagt, sollte eine Bibliothek niemals Signale setzen.

    1. If there are multiple handler for one signal, can we remove our handler 
      from the chain and re-emit the signal? Or should be just use std::exit or 
      std::abort?

    Siehe oben.

    1. Is this the right way to go for the problem described? Any comments 
      welcome!

    Das hätte vielleicht die erste Frage sein sollen 😃 . Auf Anwendungsebene ist es durchaus richtig, Signalhandler zu benutzen, um das korrekte Freigeben von Ressourcen dieser Art zu gewährleisten (siehe aber mein Kommentar, dass der Handler selbst nicht der Freigeber sein sollte). Auf Bibliotheksebene, wie erklärt, nicht.

    Denk da dran, dass durchaus noch andere Abbruchpfade existieren können. Ich weiß nicht, welche Sprache du benutzt, daher sind konkrete Tipps schwierig. In C++ müsstest du beispielsweise aufpassen, dass die Laufzeitumgebung auch ein terminate auslösen kann, welches die normale Ressourcenverwaltung in C++ aushebelt und daher auch mit einem entsprechenden Handler behandelt werden sollte (dafür ist natürlich die normale Ressourcenverwaltung in C++ wesentlich angenehmer :p ). In allen Sprachen gibt es natürlich auch Signale, die nicht auffangbar sind, deine Infrastruktur sollte also im Notfall auch mit dem Fall zurecht kommen, dass eine Ressource mal nicht freigegeben wird.


Anmelden zum Antworten