Chaînage du signal JVM SIGPIPE

Nous avons une application C ++ avec une JVM intégrée (Sun). Comme nous enregistrons nos propres gestionnaires de signaux, il est recommandé de le faire avant d’initialiser la JVM car elle installe ses propres gestionnaires ( voir ici ).

D’après ce que j’ai compris, la JVM sait en interne si le signal provient de son propre code et, sinon, il le transmet le long de la chaîne – à nos gestionnaires.

Ce que nous avons commencé à voir, c’est que nous obtenons des SIGPIPE, avec une stack d’appels qui ressemble à ceci (la première entrée est notre gestionnaire de signal):

/.../libos_independent_utilities.so(_ZN2os32smart_synchronous_signal_handlerEiP7siginfoPv+0x9) [0x2b124f7a3989] /.../jvm/jre/lib/amd64/server/libjvm.so [0x2aaaab05dc6c] /.../jvm/jre/lib/amd64/server/libjvm.so [0x2aaaab05bffb] /.../jvm/jre/lib/amd64/server/libjvm.so(JVM_handle_linux_signal+0x718) [0x2aaaab05e878] /.../jvm/jre/lib/amd64/server/libjvm.so [0x2aaaab05bf0e] /lib64/libpthread.so.0 [0x3c2140e4c0] /lib64/libpthread.so.0(send+0x91) [0x3c2140d841] /.../jvm/jre/lib/amd64/libnet.so [0x2aaabd360269] /.../jvm/jre/lib/amd64/libnet.so(Java_java_net_SocketOutputStream_socketWrite0+0xee) [0x2aaabd35cf4e] [0x2aaaaeb3bf7f] 

Il semble que la JVM décide que le SIGPIPE généré par l’ send doit être transmis à notre transmetteur de signaux. Est-ce juste de le faire?

Aussi, pourquoi la stack d’appels est-elle incomplète? Je veux dire évidemment, il ne peut pas me montrer le code java avant socketWrite0 mais pourquoi ne puis-je pas voir la stack avant le code Java?

La JVM ne peut pas dire si le SIGPIPE provient de son propre code ou de votre code. Cette information n’est pas donnée par le signal. Comme il ne veut pas que vous ne manquiez aucun événement susceptible de vous intéresser, il doit vous transmettre tous les SIGPIPE, même ceux qui se sont avérés provenir de son propre code.

Les signaux Unix se présentent sous deux formes: “synchrone” et “asynchrone”. Quelques conditions exceptionnelles, lorsqu’il s’agit simplement d’exécuter du code, peuvent provoquer des interruptions et générer des signaux “synchrones”. Ce sont des éléments tels que l’access mémoire non aligné (SIGBUS), l’access illégal à la mémoire, souvent NULL (SIGSEGV), la division par zéro et autres erreurs mathématiques (SIGFPE), les instructions indécodables (SIGILL), etc. Celles-ci ont un contexte d’exécution précis et sont livrées directement au thread qui les a provoquées. Le gestionnaire de signaux peut rechercher la stack et voir “J’ai un access illégal à la mémoire exécutant du code Java, et le pointeur était un NULL. Laissez-moi y remédier.”

En revanche, les signaux qui interagissent avec le monde extérieur sont de type “asynchrone” et incluent des éléments tels que SIGTERM, SIGQUIT, SIGUSR1, etc. Ils n’ont pas de contexte d’exécution fixe. Pour les programmes threadés, ils sont livrés au hasard à n’importe quel thread. Fait important, SIGPIPE en fait partie. Oui, dans un certain sens, il est normalement associé à un appel système. Mais il est tout à fait possible (par exemple) d’avoir deux threads écoutant deux connexions distinctes, qui se ferment toutes les deux avant la planification de l’un ou l’autre thread. Le kernel s’assure simplement qu’il y a un SIGPIPE en attente (l’implémentation habituelle est un masque de bits des signaux en attente), et traite de la reprogrammation des threads du processus. Ce n’est que l’un des cas les plus simples possibles où la JVM peut ne pas avoir suffisamment d’informations pour exclure que votre code client ne soit intéressé par ce signal.

(En ce qui concerne les appels en lecture, ils renvoient “une erreur: EINTR” et continuent. À ce stade, la JVM peut en faire une exception, mais le retour se produit après la dissortingbution du signal et le gestionnaire du signal. .)

Le résultat est que vous devrez simplement faire face à des faux positifs. (Et faire face à l’obtention d’un seul signal là où deux auraient pu être attendus.)