Programmstatus per SIGQUIT ausgeben

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
nezzcarth
User
Beiträge: 1634
Registriert: Samstag 16. April 2011, 12:47

Hallo :)

ich wollte heute mal zu folgendem Meinungen einholen:

Die gängige Linux-Implementation von 'ping' erlaubt es ja, per SIGQUIT (CTRL + \) einen Zwischenstatus auszugeben. Ich überlege gerade, ob ich diese Funktionalität in ein länger laufendes Skript mittels des "signal" Moduls einbauen sollte, um ebenfalls einen Zwischenstand auszugeben. Allerdings bin ich etwas unschlüssig, da ich den Eindruck habe, dass 'ping' dieses Signal, das eigentlich für etwas anderes gedacht ist, zweckentfremdet. Gegenüber SIGUSR1/2, das von einigen anderen Programmen verwendet wird und vielleicht etwas besser passt, hat SIGQUIT aber den Vorteil, dass es an eine Tastenkombination gebunden ist. Unter FreeBSD kann man den Zwischenstand per SIGINFO (CTRL + T) erhalten (während SIGQUIT richtigerweise einen core dump erzeugt), aber dieses Signal kennt Linux nicht.

Hat jemand schon mal so diese Funktionalität in ein Python Skript eingebaut? Welches Signal habt ihr verwendet? Was spricht für/gegen SIGQUIT, was ich vielleicht übersehen habe?
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@nezzcarth:
Für eine Statusausgabe würde ich eher überlegen, ob die Benutzung von Signalen überhaupt sinnvoll ist oder nicht z.B. ein aktiver Logger einfacher umzusetzen ist. Signalprogrammierung ist nicht trivial, Du musst bedenken, dass das Signal innerhalb Deines Programmes überall auftreten kann und Sorge dafür tragen, dass der "Rücksprung" nach Ausführung des Signalhandlers noch gültig ist, was gerade bei Systemcalls (z.B. Warten auf IO) zu Problemen führt. Sollen dann noch Threads dazukommen, "bricht die Hölle los".

Falls es unbedingt ein Signal sein muss - da würde ich eher auf USRx gehen (sind benutzerdefinierte Signale speziell für diesen Zweck). Default-Signale würde ich nur verbiegen, wenn es wirklich nicht anders geht...
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Was spricht dagegen, den Zwischenstand einfach in die Fehlerausgabe zu schreiben? Falls dies nicht immer gewünscht ist, ließe sich ja leicht eine ``--verbose``-Option einrichten.
nezzcarth
User
Beiträge: 1634
Registriert: Samstag 16. April 2011, 12:47

Danke euch beiden für die Antworten. Ich hatte halt diese Funktionalität bei einigen Unix-Programmen gesehen und fand sie ganz spannend. Es ist nicht so, dass ich das unbedingt so umsetzen muss.

@snafu:
Die Ausgabe über stderr bezieht sich ja nur auf den Kanal, nicht, wie diese Zwischenstandsausgabe ausgelöst wird. Man könnte das an Programmzustände koppeln, einen timer einbauen, einfach permanent ausgeben, etc. . Was ich an den Signalen so interessant finde, ist, dass man sie relativ einfach von außen absetzen und damit die Zustandsausgabe unmittelbar auslösen kann; da SIGQUIT (und SIGINFO) an Tastenkombinationen gebunden sind, ist es daher sehr einfach, schnell eine Ausgabe zu erhalten.

@jerch:
Ich habe bis dahin noch nie etwas mit Signalen gemacht und bin da vielleicht etwas zu naiv gewesen, was die Implementierungsschwierigkeit angeht; bei meinen einfachen Testskripten war das unproblematisch -- aber ich kann mir schon vorstellen, dass die Dinge, die du genannt hast schnell auftreten können. Insofern bin ich nun etwas unschlüssig, bzw. würde das wohl doch eher lassen.

Schade, an sich finde ich den Mechanismus nämlich ganz schick :)
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@nezzcarth:

Du kannst das schon benutzen, solltest dann aber genau wissen, wo in Deinem Programm syscalls abgesetzt werden und wie diese im Falle der Signalunterbrechung zu behandeln sind. Falls da viele Abhängigkeiten zu Drittmodulen drin sind, wird das halt mitunter schwierig zu überschauen. Was Du dagegen tun kannst: zerlege Dein Programm in atomare Schritte, die, falls da unbekannte syscalls drin vorkommen und genau dort das Signal getriggert wird, per Exception abgefangen werden und wiederholt werden können. Mal als Beispiel mit nackter Ausnahmebehandlung (falls Du nicht alle syscalls/Ausnahmetypen kennst):

Code: Alles auswählen

def atomic_interuptable(f, args, kwargs):
    while True:
        try:
            result = f(*args, **kwargs)
            break
        except XY: # handle specific other Exception
            raise
        except:  # loop unkown Exceptions
            pass
    return result

...
# somewhere in your code
from something import call_with_unkown_syscalls

# might lead to syscall exceptions on signal
xy = call_with_unkown_syscalls()

# always interruptable (assuming call_with_unkown_syscalls has no side effects)
xy = atomic_interruptable(call_with_unkown_syscalls, [], {})
Willst Du zusätzlich spezielle Fehler behandeln, kannst Du die Ausnahmebehandlung entsprechend erweitern und ein break oder raise dort absetzen, um aus der atomic-Schleife rauszukommen. Kennst Du die syscalls mit den Ausnahmetypen, wirst Du auch den nackten Handler los.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Was ich vergessen habe - syscalls, die einen äußeren Zustand modifizieren (sind leider die meisten, z.B. Dateioperationen, irgendwas Konsumierendes etc.) kannst Du nicht so leicht abfangen und einfach wiederholen. Bei solchen Operationen musst Du die Zustandintegrität selbst prüfen und ggf. den Zustand reparieren.

NB: Es gibt noch die Möglichkeit, syscalls nach einem Signal automatisch restarten zu lassen. Wie hilfreich das ist hängt vom Szenario ab. Unter Linux z.B. wird eine Dateileseaktion nur dann restartet, wenn sie im blocking-Modus war. Wurden schon bytes übertragen aber noch nicht alle angefragten, wird nicht restartet, sondern nur ein Teil der Dateidaten zurückgegeben. Da heisst es - Obacht.
nezzcarth
User
Beiträge: 1634
Registriert: Samstag 16. April 2011, 12:47

@jerch:
Besten dank für die Erklärungen/Tipps und das Beispiel. Ich lese da raus, dass das Hantieren mit Signalen nichts ist, was man einfach mal so eben in sein Skript einbauet (anders, als z. B. einfache Debuggingausgaben), sondern das fest im Programm vorsehen sollte, da es auch die Programmstruktur mitbestimmt. Insofern erfordert es also wohl mehr Planungs- und Implementierungsaufwand -- zumindest für etwas komplexere Programme. Ich denke, ich werde da doch mal ein bisschen mit rumspielen. :)
Antworten