2009-06-26 31 views
5

Estoy investigando un problema de Java (utilizando IBM JVM 1.4.2 de 64 bits) en Red Hat Linux. Me pregunto si alguien ha visto este mensaje de error antes y sabe si hay una solución a este problema.Error de Java: java.lang.IllegalArgumentException: Señal ya utilizada por VM: INT

Fuente:

import sun.misc.Signal; 
import sun.misc.SignalHandler; 

public class SignalTest extends Thread 
{ 
    private static Signal signal = new Signal("INT"); 

    private static ShutdownHandler handler = new ShutdownHandler(); 

    private static class ShutdownHandler implements SignalHandler 
    { 
     public void handle(Signal sig) 
     { 
     } 
    } 

    public static void main(String[] args) 
    { 
     try 
     { 
      Signal.handle(signal, handler); 
     } 
     catch(Throwable e) 
     { 
      e.printStackTrace(); 
     } 

     try { Thread.sleep(5000); } catch(Exception e) { e.printStackTrace(); } 

     System.exit(0); 
    } 
} 

Salida:

java.lang.IllegalArgumentException <Signal already used by VM: INT> 
java.lang.IllegalArgumentException: Signal already used by VM: INT 
at 
com.ibm.misc.SignalDispatcher.registerSignal(SignalDispatcher.java:145) 
at sun.misc.Signal.handle(Signal.java:199) 
at xxx 

Información adicional:

descubrí algo extraño. La razón por la que falla es porque estoy ejecutando el programa dentro de un script de shell como proceso en segundo plano.

es decir sigtest.sh:

#!/bin/bash 
java -cp . SignalTest >> sigtest.log 2>&1 & 

Si corro el programa desde la línea de comandos, o quite la "&" (es decir, lo convierten en un proceso en primer plano dentro de la secuencia de comandos shell), no lo hace tiene un problema ... No entiendo por qué este es el caso.

+0

Jin, dado su comentario sobre mi respuesta, la JVM no le permite registrar un enlace en este evento. ¿Puedes describir más sobre lo que estás tratando de lograr? Tal vez haya una forma de hacerlo que esté más en sintonía con las expectativas de la JVM. – Yishai

+0

Quiero que el programa salga con gracia ejecutando un código de "limpieza" si se interrumpe. –

+0

El problema era específico de JVM. Atribuí la recompensa a Jitter, ya que su respuesta incluía "implementación específica de JVM" y proporcionó la mayoría de las herramientas para diagnosticar mi problema. Gracias a todos. –

Respuesta

3

Esto puede ser un problema específico de la implementación de JVM. Estamos utilizando una API no documentada/no compatible (sun.misc.Signal/SignalHandler) y, por lo tanto, no se garantiza ningún contrato sobre el comportamiento de la API.

La implementación de IBM JVM podría hacer cosas relacionadas con la gestión de señal de forma diferente a la implementación de SUN JVM y, por lo tanto, causar este problema. Para que este caso de uso específico funcione en SUN JVM pero no en IBM JVM.

Pero tratar el siguiente (no puedo probarlo yo mismo):

¿Todas las combinaciones de iniciar la JVM con uno/dos/tres de esos parámetros y allá posibles combinaciones de valores.

  1. la opción -Xrs especificado/no especificado
  2. la propiedad ibm.signalhandling.sigint conjunto a true/false
  3. la propiedad ibm.signalhandling.rs conjunto a true/false

(Las propiedades fueron encontrados a través de Google en varios error dumps pero no puedo encontrar ninguna documentación específica sobre ellos)

No sé si la JVM de IBM también es compatible con esta bandera especial, pero se podría intentar agregar esto también, que en la JVM de Sun parece ser específica para algunos problemas con los gestores de señales bajo Linux/Solaris

-XX:-AllowUserSignalHandlers 

o tratar de usando un controlador de señal nativo si esa es una opción para ti. Echa un vistazo a los ejemplos de código proporcionados:

A pesar de que no esté relacionada con su problema específico, en un artículo de IBM JVM manejo de señal (ligeramente anticuado pero aún mayormente correcto). Con muestras de manejadores de señales de código nativo:

Revelations on Java signal handling and termination


Pero supongo que todo esto puede ser en vano ya que la implementación JVM de IBM podría depender de manejo SIGINT sí para funcionar correctamente y por lo tanto nunca un dar posibilidad de manejar SIGINT usted mismo.

Btw. desde el description to the -Xrs flag Entiendo que realmente puede dificultarle hacer lo que desea. Se dice

When -Xrs is used on Sun's JVM, the signal masks for SIGINT, SIGTERM, SIGHUP, and SIGQUIT are not changed by the JVM, and signal handlers for these signals are not installed.

O podría significar que sólo las acciones predeterminadas JVM para las señales no se ejecutan. O podría depender de la implementación de JVM lo que realmente significa.

+0

la cuestión era JVM específica. Tuve que instalar otra JVM para obtener el comportamiento que deseaba. –

0

La excepción se produce porque la máquina virtual ya tiene un controlador de señal establecido para SIGINT. Lo que puede/debe hacer al respecto depende del contexto en el que se produce esta excepción.

0

He intentado con el mismo código y funciona para mí. Así que supongo que puede haber alguna diferencia en la configuración.

Después de añadir

System.out.println("Hello"); 

al mensaje de mango que se puede ejecutar la clase de esa manera:

[email protected]:/tmp/so$ java SignalTest & sleep 1s && kill -2 $! 
[1] 20467 
[email protected]:/tmp/so$ Hello 
[email protected]:/tmp/so$ 
[email protected]:/tmp/so$ java SignalTest 
[1]+ Done    java SignalTest 
+0

Sí, tengo dos entornos. Uno es Linux de 32 bits, funciona bien con Sun JVM. Uno es Linux de 64 bits, no funciona en este caso. –

+0

Mi configuración es de 64 bits (2.6.24 ...) usando Sun JVM (HotSpot, 1.6.0_11). –

+0

Empiezo a sentir que esto es menos un problema de programación y más un problema de JVM. –

2

Trate de comenzar la JVM con una opción -Xrs que es válido en la JVM de IBM según this de todos modos. Eso podría evitar el conflicto.

EDIT: En respuesta a su deseo subyacente, mire:

Runtime.getRuntime().addShutdownHook(Thread)

subclase un objeto hilo, y se iniciará como parte del cierre (sacar ese -Xrs para que esto funcione bien). Algunas cosas (como detener llamadas en Runtime) pueden evitar que eso ocurra, por lo que debe ser consciente de la posibilidad de que simplemente no termine sucediendo.

+0

que cambia la salida de: java.lang.IllegalArgumentException a lo siguiente: java.lang.IllegalArgumentException

1

Según lo escrito por Heinz Kabutz, las señales que puede capturar dependen del sistema operativo en el que se está ejecutando y de manera probable la versión de JVM. Si una determinada combinación de os/jvm no le permite registrar su señal, entonces no tiene suerte. Tal vez ajustar con la configuración os/vm podría ayudar.

Según su comentario, agregar shutdown hook según lo propuesto por Yishai debería hacer el truco.

0

Lo hice funcionar usando una implementación de JVM diferente (SuSE) en lugar de IBM. Al tratar con características no documentadas, parece que las JVM no son muy consistentes en el comportamiento.

0

Yo también tengo el mismo problema. Ejecuto el programa java desde un script ksh. Si funciono el guión con la cuenta que tiene el perfil CSH es decir, en/etc/passwd

usuariox: *: 7260: 20 ::/home/usuariox:/usr/bin/csh

La secuencia de comandos se ejecutará con éxito. Pero si lo ejecuto con una cuenta que tiene otro perfil que no sea sh, está dando el mismo error.

Por lo tanto, la solución es cambiar el perfil de usuario de unix a csh.

0

También he encontrado este problema con IBM JVM (64 bit) en Linux. Resultó que la JVM es sensible a la máscara de señal del proceso que la llama.

> grep Sig /proc/self/status 
SigQ: 1/1030663 
SigPnd: 0000000000000000 
SigBlk: 0000000000000000 
SigIgn: 0000000001001006 
SigCgt: 0000000000000000 

Tenga en cuenta que el bit para SIGINT (valor 2) se establece en SigIgn. Al iniciar IBM JVM con esta máscara, se niega a instalar un controlador para SIGINT. Trabajé en torno al problema con el lanzamiento de la JVM a través de un envoltorio de Python que restablece el controlador de SIGINT en el valor predeterminado:

#!/usr/bin/env python 

import os 
import signal 
import sys 

signal.signal(signal.SIGINT, signal.SIG_DFL) 

args = sys.argv[1:] 
os.execv(args[0], args) 

El primer argumento de la envoltura es el comando java, a continuación, siga los argumentos a favor de la JVM.

Cuestiones relacionadas