2010-11-09 12 views
14

Tenemos una aplicación C++ con una JVM integrada (Sun). Debido a que registramos nuestros propios manejadores de señal, se recomienda que lo hagamos antes de inicializar la JVM, ya que instala sus propios manejadores (see here).Cadena de señal JVM SIGPIPE

Por lo que he entendido, la JVM sabe internamente si la señal se originó a partir de su propio código y si no lo pasa a lo largo de la cadena - a nuestros controladores.

lo que empezamos viendo es que nos estamos SIGPIPEs, con una pila de llamadas que se ve más o menos así (la entrada superior es nuestro manejador de señales):

/.../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] 

Parece que la JVM es decidir que el SIGPIPE que se generó desde send se debe pasar a nuestro dispositivo de transmisión de señal. ¿Está bien al hacerlo?

Además, ¿por qué la pila de llamadas está incompleta? Quiero decir, obviamente, no puede mostrarme código de Java antes de socketWrite0, pero ¿por qué no puedo ver la pila antes del código de Java?

+0

¿Ha instalado un controlador de señal para SIGPIPE? (De ser así, sí, es común obtener SIGPIPE de llamadas a send() cuando alguien escribe en un socket roto) – nos

+0

Sé que 'send' puede generar SIGPIPE. Solo estoy cuestionando la decisión de la JVM de pasarmelas, ¿por qué no plantea una excepción? –

+0

¿Pero no instaló un controlador para ello? – nos

Respuesta

7

La JVM no puede decir si el SIGPIPE vino de su propio código o de su código. Esa información simplemente no está dada por la señal. Como no quiere que se pierda ningún evento posible que pueda interesarle, tiene que pasar todos los SIGPIPE, incluso los que resultaron de su propio código.

Las señales Unix vienen en dos sabores: "síncrono" y "asíncrono". Algunas condiciones excepcionales cuando se acaba de ejecutar el código pueden causar trampas y generar señales "síncronas". Estas son cosas como acceso a memoria no alineado (SIGBUS), acceso a memoria ilegal, a menudo NULL, (SIGSEGV), división por cero y otros errores matemáticos (SIGFPE), instrucciones indecodificables (SIGILL), y así sucesivamente. Estos tienen un contexto de ejecución preciso y se entregan directamente al hilo que los causó. El manejador de señal puede buscar la pila y ver "hey, tengo un acceso ilegal a la memoria ejecutando el código java, y el puntero era un NULL. Déjame ir a arreglar eso".

Por el contrario, las señales que interactúan con el mundo exterior son la variedad "asíncrona" e incluyen cosas como SIGTERM, SIGQUIT, SIGUSR1, etc. No tienen un contexto de ejecución fijo. Para los programas de subprocesos, se entregan casi al azar a cualquier subproceso. Es importante destacar que SIGPIPE está entre estos. Sí, en cierto sentido, normalmente se asocia con una llamada al sistema. Pero es muy posible (por ejemplo) tener dos hilos escuchando dos conexiones separadas, las cuales se cierran antes de que cualquiera de los hilos esté programado. El kernel simplemente se asegura de que haya un SIGPIPE pendiente (la implementación habitual es como una máscara de bits de señales pendientes), y se ocupa de reprogramar cualquiera de los hilos en el proceso. Este es solo uno de los casos más simples posibles donde la JVM podría no tener suficiente información para descartar que su código de cliente esté interesado en esta señal.

(En cuanto a lo que ocurre con las llamadas de lectura, vuelven "hubo un error: EINTR". Y continuar En este punto, la JVM puede convertir eso en una excepción, pero el retorno sucede después la señal la entrega y el manejador de señales se activan.)

El resultado es que tendrá que lidiar con falsos positivos. (Y trate de obtener solo una señal donde podrían haberse esperado dos).

+0

, entonces, ¿cómo sabe si todas las otras señales registradas están en su código? –

+0

Tengo manejadores de señal para casi cada señal, este es el primero en mostrar un comportamiento aparentemente malo. Además, la JVM está registrada para manejar SIGPIPE, una prueba de ello es la 'JVM_handle_linux_signal' en la pila de llamadas. Este documento también establece que la JVM captura SIGPIPE http://www.oracle.com/technetwork/java/javase/signals- 139944.html # gbzbl Hay situaciones más complejas en las que la JVM simplemente "sabe" si una señal proviene de su propio código, por ejemplo la optimización del puntero nulo, por lo que todavía no entiendo su argumento. –

+0

Gracias, su explicación tiene sentido y es más o menos cómo imaginé que la JVM tomó la decisión de encadenar la señal o no. Pero aún así, si miras la pila de llamadas que obtuve en mi manejador de señal, es bastante posible que la JVM examine la pila y se dé cuenta de que el SIGPIPE se originó a partir de su propio código, por ejemplo al ver la dirección 'Java_java_net_SocketOutputStream_socketWrite0' en la pila de llamadas . –