Bereitstellen/Übergeben eines Arguments an den Signalhandler

Lesezeit: 7 Minuten

Benutzeravatar von Hari
Hari

Kann ich dem Signal-Handler Argumente bereitstellen/übergeben?

/* Signal handling */
struct sigaction act;
act.sa_handler = signal_handler;
/* some more settings */

Jetzt sieht der Handler so aus:

void signal_handler(int signo) {
    /* some code */
}

Wenn ich etwas Besonderes tun möchte, dh temporäre Dateien löschen möchte, kann ich diese Dateien als Argument für diesen Handler angeben?

Bearbeiten 0: Danke für die Antworten. Wir vermeiden/raten im Allgemeinen von der Verwendung globaler Variablen ab. Und in diesem Fall, wenn Sie ein riesiges Programm haben, können Dinge an verschiedenen Stellen schief gehen und Sie müssen möglicherweise viel aufräumen. Warum wurde die API auf diese Weise entwickelt?

hmakholm hat Monicas Benutzer-Avatar hinterlassen
hmakholm hat Monica übrig gelassen

Sie können dem Signalhandler keine eigenen Daten als Parameter übergeben. Stattdessen müssen Sie Ihre Parameter in globalen Variablen speichern. (Und seien Sie wirklich, wirklich vorsichtig, wenn Sie jemals müssen Rückgeld diese Daten nach der Installation des Signalhandlers).

Antwort auf Bearbeiten 0: Historische Gründe. Signale sind ein wirklich altes und wirklich Low-Level-Design. Im Grunde erhalten Sie dem Kernel nur eine einzige Adresse für einen Maschinencode und bitten ihn, an diese bestimmte Adresse zu gehen, wenn dies und das passiert. Wir befinden uns hier wieder in der “portable Assembler”-Denkweise, wo die Kernel einen schnörkellosen Basisdienst bieten und was auch immer der Benutzerprozess vernünftigerweise für sich selbst erwarten kann, er muss es selbst tun.

Auch die üblichen Argumente gegen globale Variablen gelten hier nicht wirklich. Der Signalhandler selbst ist eine globale Einstellung, daher gibt es keine relevante Möglichkeit, mehrere verschiedene Sätze von benutzerdefinierten Parametern dafür zu haben. (Nun, eigentlich ist es nicht vollständig global, sondern nur Thread-global. Aber die Threading-API enthält einen Mechanismus für Thread-lokale Speicherung, was in diesem Fall genau das ist, was Sie brauchen).

  • Signal-Handler sind nicht pro Thread. Das Ändern des Handlers für ein Signal gilt für alle Threads.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    7. August 2011 um 2:51 Uhr

  • Recht. Aber es ist immer noch sinnvoll zu wollen, dass der Signalhandler auf den Thread reagiert, für den er verarbeitet, was TLS erreichen kann.

    – hmakholm hat Monica übrig gelassen

    7. August 2011 um 2:56 Uhr

  • Eigentlich ist es mir unklar, ob der Zugriff auf TLS von einem Signalhandler gültig ist. Bei glibc/NPTL ist es fast sicher ungültig im Allgemeinen, da ein Signal unmittelbar nach der Erstellung des Threads, aber bevor die Steuerung an die Startfunktion übergeben wird, übermittelt werden könnte, während die TLS-Kopie des Threads noch initialisiert wird. Wenn Sie zu diesem Zeitpunkt darauf achten, dass Signale blockiert werden, ist dies möglicherweise in Ordnung, aber es ist immer noch eine zweifelhafte Vorgehensweise …

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    7. August 2011 um 2:59 Uhr

  • Übrigens gibt es auch ohne TLS eine Möglichkeit, auf asynchronsignalsichere Weise zu identifizieren, von welchem ​​​​Thread der Signalhandler ausgeführt wird: &errno ist für jeden Thread einzigartig! Ich glaube jedoch, dass dies in glibc/NPTL aus dem gleichen Grund, den ich gerade beschrieben habe, möglicherweise nicht sicher ist. Wenn nicht, bin ich mir ziemlich sicher, dass es sich um einen Konformitätsfehler handelt, aber es ist wahrscheinlich ein ausreichend seltenes Rennen, um unentdeckt zu bleiben …

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    7. August 2011 um 4:00 Uhr

  • @R.. Signal-Handler können auf Thread-Basis sein. POSIX bietet Funktionen, mit denen Sie Signale an einzelne Threads innerhalb desselben Prozesses senden können.

    – Neugierig

    5. Januar 2016 um 12:47 Uhr

Eine Signal-Handler-Registrierung ist bereits ein globaler Staat Äquivalent zu globalen Variablen. Es ist also kein größeres Vergehen, globale Variablen zu verwenden, um Argumente an sie zu übergeben. Es ist jedoch ein großer Fehler (fast sicher undefiniertes Verhalten es sei denn, Sie sind ein Experte!), um sowieso etwas von einem Signal-Handler zu tun. Wenn Sie stattdessen nur Signale blockieren und sie von Ihrer Hauptprogrammschleife aus abrufen, können Sie all diese Probleme vermeiden.

  • Wenn Sie kein Experte für Signale sind, ist es sehr gefährlich, etwas von einem Signalhandler aus zu tun. Stattdessen könnten Sie einfach den Signal-Handler verwenden, um ein Flag zu speichern, dass das Signal aufgetreten ist, und es von verschiedenen Punkten außerhalb des Signal-Handlers überprüfen, oder Sie könnten Signale blockieren und verwenden sigpending oder sigwait nach Signalen abzufragen.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    7. August 2011 um 3:57 Uhr

  • Wow, das ist völlig neu für mich. Ich habe Code gesehen, der aufräumt, wie das Löschen von temporären Dateien oder das Aufräumen von untergeordneten Prozessen, bevor das Hauptprogramm beendet wird. Auch wenn Sie sagen, nach Flags suchen, wie kann das funktionieren, wenn Sie SIGTERM erhalten? Beendet sich Ihr Programm nicht sofort, wenn Sie das nicht in Ihrem Handler behandeln? Warum ist es dangerous Dinge in einem Handler tun?

    – hari

    7. August 2011 um 5:40 Uhr

  • Ein Signalhandler kann das Programm an jeder Stelle unterbrechen. Das heißt, wenn Sie nicht darauf geachtet haben, dass dies nicht passieren kann, könnte es mit verschiedenen Datenobjekten, mit denen es arbeiten möchte, in einem inkonsistenten Zustand ausgeführt werden. Zum Beispiel die Pufferzeiger in a FILE möglicherweise nur teilweise aktualisiert oder die verknüpfte Liste offen FILEs können teilweise mit einem halb eingefügten oder halb entfernten Element verknüpft sein. Oder das Innere malloc Datenstrukturen haben möglicherweise halbwegs freigegebenen Speicher, auf den verwiesen wird … Wenn der Signal-Handler Funktionen aufruft, die davon abhängen, dass dieser Zustand konsistent ist, werden sehr schlimme Dinge passieren!

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    7. August 2011 um 5:49 Uhr

  • Übrigens ist eine klassische und beliebte “sichere” Methode zur Verwendung von Signalhandlern, eine Pipe zu sich selbst zu öffnen und die Dateideskriptoren irgendwo global zu speichern. Der Signal-Handler kann in die Pipe schreiben (dies ist sicher) und Sie können auf Eingaben von der Pipe in Ihrem main warten select/poll Schleife zusammen mit anderen Dateideskriptoren, von denen Sie auf Eingaben warten.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    7. August 2011 um 6:03 Uhr

  • @R .. es gibt signalfd() unter Linux, das genau das tut. Immer noch eine gute Idee. Nur wenige Menschen erwägen die Verwendung von Pipes zur Kommunikation innerhalb ein Prozess. Macht die Kommunikation zwischen Threads viel einfacher und expliziter.

    – MauganRa

    2. März 2014 um 2:53 Uhr

Benutzeravatar von rak007
rak007

Dies ist eine wirklich alte Frage, aber ich denke, ich kann Ihnen einen netten Trick zeigen, der Ihr Problem gelöst hätte. Keine Notwendigkeit, Sigqueue oder was auch immer zu verwenden.

Ich mag auch die Verwendung von globalen Variablen nicht, also musste ich in meinem Fall einen cleveren Weg finden, um einen void ptr zu senden (den Sie später nach Bedarf umwandeln können).

Eigentlich kann man das machen:

signal(SIGWHATEVER, (void (*)(int))sighandler); // Yes it works ! Even with -Wall -Wextra -Werror using gcc

Dann würde Ihr Sighandler so aussehen:

int sighandler(const int signal, void *ptr) // Actually void can be replaced with anything you want , MAGIC !

Sie fragen sich vielleicht: Wie bekommt man dann den *ptr?

Hier ist wie :
Bei der Initialisierung

signal(SIGWHATEVER, (void (*)(int))sighandler)
sighandler(FAKE_SIGNAL, your_ptr);

In Ihrem Sighandler func
:

int sighandler(const int signal, void *ptr)
{
  static my_struct saved = NULL;

  if (saved == NULL)
     saved = ptr;
  if (signal == SIGNALWHATEVER)
     // DO YOUR STUFF OR FREE YOUR PTR
   return (0);
}

  • Netter Trick, aber leider vom Standard nicht definiert. Siehe 6.3.2.3(8): if a converted pointer is used to call a function whose type is not compatible with the referenced type, the behavior is undefined.

    – eush77

    26. Mai 2017 um 14:32 Uhr

Benutzeravatar von David Yeager
David Jäger

Unbedingt. Sie können Ganzzahlen und Zeiger an Signalhandler übergeben, indem Sie sigqueue() anstelle des üblichen kill() verwenden.

http://man7.org/linux/man-pages/man2/sigqueue.2.html

Benutzeravatar von Foo Bah
Foo Bah

Speichern Sie die Namen der Dateien in einer globalen Variablen und greifen Sie dann vom Handler aus darauf zu. Dem Signal-Handler-Callback wird nur ein Argument übergeben: die ID für das eigentliche Signal, das das Problem verursacht hat (z. B. SIGINT, SIGTSTP)

Bearbeiten 0: “Es muss einen felsenfesten Grund geben, dem Handler keine Argumente zu erlauben.” <-- Es gibt einen Unterbrechungsvektor (im Grunde ein Satz von Sprungadressen zu Routinen für jedes mögliche Signal). Aufgrund der Art und Weise, wie der Interrupt ausgelöst wird, wird basierend auf dem Interrupt-Vektor eine bestimmte Funktion aufgerufen. Leider ist nicht klar, wo der mit der Variablen verknüpfte Speicher aufgerufen wird, und je nach Interrupt kann dieser Speicher tatsächlich beschädigt sein. Es gibt eine Möglichkeit, dies zu umgehen, aber dann können Sie die vorhandene int 0x80-Assembler-Anweisung (die einige Systeme noch verwenden) nicht nutzen.

Benutzeravatar von fad
Mode

Ich denke, es ist besser, SA_SIGINFO in sa_flags zu verwenden, damit der Handler es bekommt
void signal_handler(int sig, siginfo_t *info, void *secret)
in siginfo_t können Sie Ihre Parameter angeben. Ty: HAPPY-Code

Benutzeravatar von drizzo4shizzo
drizzo4shizzo

Sie können einen Signalhandler verwenden, der eine Methode einer Klasse ist. Dann kann dieser Handler auf Mitgliedsdaten dieser Klasse zugreifen. Ich bin mir nicht ganz sicher, was Python hier unter der Decke rund um den Aufruf von C signal() macht, aber es muss sich um eine Neudefinition der Daten handeln?

Ich war erstaunt, dass dies funktioniert, aber es funktioniert. Führen Sie dies aus und beenden Sie den Prozess von einem anderen Terminal aus.

import os, signal, time

class someclass:
    def __init__(self):
        self.myvalue = "something initialized not globally defined"
        signal.signal(signal.SIGTERM, self.myHandler)
    def myHandler(self, s, f):
        # WTF u can do this?
        print "HEY I CAUGHT IT, AND CHECK THIS OUT", self.myvalue


print "Making an object"
a = someclass()

while 1:
    print "sleeping.  Kill me now."
    time.sleep(60)

  • Die Frage war über C … Obwohl sich Python höchstwahrscheinlich irgendwo an das Signal erinnert, um es später so schnell wie möglich zu verarbeiten (es ist gefährlich, Dinge innerhalb von Signal-Handlern zu tun). Eventuell über eine globale Variable.

    – MauganRa

    2. März 2014 um 3:05 Uhr

1417310cookie-checkBereitstellen/Übergeben eines Arguments an den Signalhandler

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy