Le signal peut-il être ignoré (perdu)?

9

J'ai une application qui communique avec les travailleurs via des signaux (notamment SIGUSR1 / SIGUSR2 / SIGSTOP).

Puis-je espérer que quoi qu'il arrive, chaque signal sera délivré et traité par le gestionnaire?

Que se passe-t-il si les signaux sont envoyés plus rapidement qu'il n'est possible pour l'application de les gérer (par exemple en raison de la charge élevée de l'hôte pour le moment)?

KaP
la source

Réponses:

8

Outre le problème du «trop de signaux», les signaux peuvent être explicitement ignorés. De man 2 signal:

If the signal signum is delivered to the process, then one of the
following happens:    
  *  If the disposition is set to SIG_IGN, then the signal is ignored.

Les signaux peuvent également être bloqués. De man 7 signal;

A signal may be blocked, which means that it will not be delivered
until it is later unblocked.  Between the time when it is generated
and when it is delivered a signal is said to be pending.

Les ensembles de signaux bloqués et ignorés sont hérités par les processus enfants, il peut donc arriver que le processus parent de votre application ait ignoré ou bloqué l'un de ces signaux.

Que se passe-t-il lorsque plusieurs signaux sont délivrés avant que le processus ait fini de traiter les précédents? Cela dépend du système d'exploitation. La signal(2)page de manuel liée ci-dessus en parle:

  • Le système V réinitialisera la disposition du signal par défaut. Pire, la livraison rapide de plusieurs signaux entraînerait des appels récursifs (?).
  • BSD bloquerait automatiquement le signal jusqu'à ce que le gestionnaire ait terminé.
  • Sous Linux, cela dépend des indicateurs de compilation définis pour GNU libc, mais je m'attendrais à ce que le comportement BSD.
muru
la source
4
La page de manuel de Linux pour signal(2)suggère catégoriquement d'éviter cette confusion en utilisant à la sigaction(2)place.
Nate Eldredge
7

Vous ne pouvez pas croire que chaque signal envoyé sera délivré. Par exemple, le noyau linux "fusionne" SIGCHLD si un processus met longtemps à gérer SIGCHLD à partir d'un processus enfant quitté.

Pour répondre à une autre partie de votre question, les signaux sont "mis en file d'attente" à l'intérieur du noyau si un certain nombre de signaux différents arrivent dans un intervalle trop court.

Vous devez utiliser sigaction()pour configurer le gestionnaire de signal avec le sa_sigactionmembre de siginfo_t, en définissant soigneusement le sa_maskmembre de l' siginfo_targument. Je pense que cela signifie masquer tous les signaux "asynchrone" au moins. Selon la page de manuel pour Linux sigaction(), vous masquerez également le signal traité. Je pense que vous devriez définir le sa_flagsmembre sur SA_SIGINFO, mais je ne me souviens pas pourquoi j'ai cette superstition. Je crois que cela donnera à votre processus un gestionnaire de signaux qui reste défini sans conditions de concurrence et qui ne sera pas interrompu par la plupart des autres signaux.

Écrivez votre fonction de gestionnaire de signaux très, très soigneusement. Fondamentalement, il suffit de définir une variable globale pour indiquer qu'un signal a été capturé et que le reste du processus gère l'action souhaitée pour ce signal. Les signaux seront masqués pendant le moins de temps possible.

De plus, vous voudrez tester votre code de gestion du signal de manière très approfondie. Mettez-le dans un petit processus de test et envoyez autant de signaux SIGUSR1 et SIGUSR2 que possible, peut-être à partir de 2 ou 3 programmes d'envoi de signaux spéciaux. Mélangez également d'autres signaux, une fois que vous êtes sûr que votre code peut gérer SIGUSR1 et SIGUSR2 rapidement et correctement. Préparez-vous à un débogage difficile.

Si vous utilisez Linux et uniquement Linux, vous pourriez penser à utiliser signalfd()pour créer un descripteur de fichier que vous pouvez select()interroger pour recevoir ces signaux. L'utilisation signalfd()pourrait faciliter le débogage.

Bruce Ediger
la source
2
Ce n'est pas seulement SIGCLD qui est fusionné: tous les signaux sont potentiellement fusionnés s'ils sont délivrés avant de pouvoir être traités.
Gilles 'SO- arrête d'être méchant'
Existe-t-il une mesure de la durée "trop ​​longue" pour les signaux SIGCHLD? Je rencontre ce problème dans mon programme en ce moment, et mon gestionnaire de signal ne prend pas plus de ~ 100 ms, je pense.
xrisk
@Rishav - à ma connaissance, il n'y a aucun moyen de savoir ce qu'est "trop ​​long". Je m'attendrais à ce que la charge globale du système soit importante. Autrement dit, ce que font les autres processus et le noyau affecterait "la durée" entre les signaux pour qu'ils se fusionnent. Pas une réponse utile, je pense.
Bruce Ediger
6

Un signal est garanti d'être délivré, dans le sens où si un processus appelle avec succès kill, alors la cible recevra le signal. C'est asynchrone: l'expéditeur n'a aucun moyen de savoir quand le signal est reçu ou traité. Cependant, cela ne garantit pas que le signal sera délivré. La cible pourrait mourir avant de pouvoir traiter le signal. Si la cible ignore le signal au moment où il est délivré, le signal n'aura aucun effet. Si la cible reçoit plusieurs instances du même numéro de signal avant de pouvoir les traiter, les signaux peuvent (et sont généralement) fusionnés: si vous envoyez deux fois le même signal à un processus, vous ne pouvez pas savoir si le processus recevra le signal. une fois ou deux. Les signaux sont principalement conçus pour tuer un processus ou pour faire attention à un processus, ils ne sont pas conçus pour la communication en tant que tels.

Si vous avez besoin d'une livraison fiable, vous avez besoin d'un mécanisme de communication différent. Il existe deux principaux mécanismes de communication entre les processus: un tuyau permet une communication unidirectionnelle; un socket permet une communication bidirectionnelle et plusieurs connexions au même serveur. Si vous avez besoin de la cible pour traiter autant de notifications que vous l'envoyez, envoyez des octets sur un canal.

Gilles 'SO- arrête d'être méchant'
la source
4
Vouliez-vous écrire «Un signal est garanti d'être délivré» puisque vous avez ensuite décrit certaines des façons dont le signal ne serait pas délivré (c.-à-d. Que le processus est mort avant sa réception ou que les signaux ont été fusionnés)?
Johnny
2

Le noyau est libre de fusionner les signaux standard si plus d'un est délivré alors qu'il est bloqué. Les signaux en temps réel, en revanche, ne sont pas pareillement handicapés.

Depuis la page de manuel signal (7) :

Les signaux en temps réel se distinguent par les éléments suivants:

  1. Plusieurs instances de signaux en temps réel peuvent être mises en file d'attente. En revanche, si plusieurs instances d'un signal standard sont délivrées alors que ce signal est actuellement bloqué, alors une seule instance est mise en file d'attente.

Essayez d'utiliser un signal avec un nombre compris entre SIGRTMIN et SIGRTMAX.

Graham Rushton
la source
Il y a une limite pour les signaux en temps réel, mais elle est assez élevée. Un signal sera supprimé si le nombre de signaux en attente envoyés par l'utilisateur dépasse RLIMIT_SIGPENDING. ulimit -iaffiche cette valeur comme 63432 sur Ubuntu 18.04.
bain