Fournir / passer un argument au gestionnaire de signaux

Puis-je fournir / transmettre des arguments au gestionnaire de signaux?

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

Maintenant, le gestionnaire ressemble à ceci:

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

Si je veux faire quelque chose de spécial, c’est-à-dire supprimer des fichiers temporaires, puis-je fournir ces fichiers comme argument à ce gestionnaire?

Edit 0: Merci pour les réponses. Nous évitons / déconseillons généralement l’utilisation de variables globales. Et dans ce cas, si vous avez un programme énorme, les choses peuvent mal se passer à différents endroits et vous devrez peut-être faire beaucoup de nettoyage. Pourquoi l’API a-t-elle été conçue de cette manière?

Vous ne pouvez pas avoir vos propres données transmises au gestionnaire de signaux en tant que parameters. Au lieu de cela, vous devrez stocker vos parameters dans des variables globales. (Et soyez vraiment, vraiment prudent si vous avez besoin de changer ces données après avoir installé le gestionnaire de signal).

Réponse à l’édition 0: Raisons historiques. Les signaux sont une conception vraiment ancienne et de bas niveau. Fondamentalement, vous venez de donner au kernel une adresse unique à un code machine et de lui demander d’aller à cette adresse spécifique si cela se produit. Nous sums de retour dans la mentalité de “l’assembleur portable”, où les kernelx fournissent un service basique sans fioritures, et quel que soit le processus utilisateur auquel on peut raisonnablement s’attendre, il doit se faire tout seul.

De plus, les arguments habituels contre les variables globales ne s’appliquent pas vraiment ici. Le gestionnaire de signal luimême est un paramètre global, il n’y a donc pas de possibilité pertinente de disposer de plusieurs jeux de parameters spécifiés par l’utilisateur. (Eh bien, en réalité, il n’est pas entièrement global, mais seulement global pour les threads. Mais l’API de thread comprend un mécanisme pour le stockage local de thread, ce qui est exactement ce dont vous avez besoin dans ce cas).

Un enregistrement de gestionnaire de signal est déjà un état global équivalent aux variables globales. Il n’est donc pas plus grave d’utiliser des variables globales pour lui transmettre des arguments. Cependant, c’est une erreur énorme (presque certainement un comportement indéfini, sauf si vous êtes un expert!) Pour faire n’importe quoi à partir d’un gestionnaire de signal de toute façon. Si, au lieu de cela, vous ne faites que bloquer les signaux et les interroger depuis la boucle de votre programme principal, vous pouvez éviter tous ces problèmes.

C’est une question vraiment ancienne mais je pense que je peux vous montrer un bon truc qui aurait répondu à votre problème. Pas besoin d’utiliser sigqueue ou autre.

Je n’aime pas non plus l’utilisation de variables globales, j’ai donc dû trouver un moyen intelligent, dans mon cas, d’envoyer un void ptr (que vous pourrez ensuite convertir selon vos besoins).

En fait, vous pouvez le faire:

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

Alors votre sighandler ressemblerait à ceci:

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

Vous pourriez demander: Comment obtenir le * ptr alors?

Voici comment: à l’initialisation

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

Dans votre 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); } 

Stockez les noms des fichiers dans une variable globale, puis accédez-y depuis le gestionnaire. L’argument du gestionnaire de signal ne sera transmis qu’à un seul argument: l’ID du signal réel à l’origine du problème (par exemple, SIGINT, SIGTSTP)

Edit 0: “Il doit y avoir une raison solide de ne pas autoriser les arguments au gestionnaire.” <- Il y a un vecteur d'interruption (en gros, un ensemble d'adresses de saut à des routines pour chaque signal possible). Étant donné la façon dont l’interruption est déclenchée, sur la base du vecteur d’interruption, une fonction particulière est appelée. Malheureusement, on ne sait pas où la mémoire associée à la variable sera appelée, et en fonction de l'interruption, cette mémoire peut effectivement être corrompue. Il existe un moyen de contourner le problème, mais vous ne pouvez pas utiliser l'instruction d'assemblage int 0x80 existante (que certains systèmes utilisent encore).

Absolument. Vous pouvez passer des entiers et des pointeurs aux gestionnaires de signaux en utilisant sigqueue () au lieu de kill () habituel.

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

Vous pouvez utiliser un gestionnaire de signal qui est une méthode d’une classe. Ensuite, ce gestionnaire peut accéder aux données des membres de cette classe. Je ne suis pas tout à fait sûr de ce que Python fait sous les couvertures de l’appel C signal (), mais il faut redéfinir les données?

J’ai été surpris que cela fonctionne, mais c’est le cas. Exécutez ceci et ensuite tuez le processus d’un autre terminal.

 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)