views:

277

answers:

5

I would like to somehow log every time Thread.interrupt() is called, logging which Thread issued the call (and its current stack) as well as identifying information about which Thread is being interrupted.

Is there a way to do this? Searching for information, I saw someone reference the possibility of implementing a security manager. Is this something that can be done at runtime (e.g., in an Applet or Web Start client), or do you need to tool the installed JVM to do this?

Or is there a better way to do this?

+3  A: 

Before trying anything too wild, have you considered using the Java debugging API? I'd think that capturing MethodEntryEvents on Thread.interrupt() would do it.

Eeek, that's the old interface, you should also check oout the new JVM Tool Interface.

Charlie Martin
I am vaguely aware of the Java debugging API, but I'm not sure how to use it from within the application that I would use it upon.
Eddie
I've given you a couple of links now; the short answer is that you add a flag to the JVM invocation, and then can connect to the JVM externally.
Charlie Martin
Unfortunately, your suggestions won't help me. The new JVM Tool Interface requires JNI and the old Java debugging API is not available to Applets. However, this information may prove useful for something else in the future. Thanks for the pointers.
Eddie
You should be able to get at JDPA in an applet; you need to get at the plugin control stuff. See http://java.sun.com/j2se/1.4.2/docs/guide/jpda/conninv.html#Plugin
Charlie Martin
+2  A: 

I would look at AspectJ and its capabilities to wrap method calls. An execution pointcut around the interrupt() method should help here.

Note that since you're looking to intercept a Java system method call (as opposed to your application code), the above may not be suitable. This thread seems to suggest it's possible, but note that he's created a woven rt.jar.

Brian Agnew
You can even wrap methods in the JVM libraries?
Eddie
That's a good point, and one I was considering just as I typed it. There are various different byte-weaving mechanisms, certainly (compile-time/run-time/class-load time) so one of these may work.
Brian Agnew
A: 

You could try also with JMX:

ManagementFactory.getThreadMXBean().getThreadInfo(aThreadID)

with the ThreadInfo object you can log:

  • the stack trace of the thread
  • general userful information like name, status, etc
  • etc

EDIT

use getAllThreadIds() in order to obtain the list of live thread ids:

long[] ids = ManagementFactory.getThreadMXBean().getAllThreadIds();
dfa
How do you mean that would catch the interrupt-call?
Fredrik
using another method (JVM instrumentation, debugging hooks, AOP, etc)?
dfa
+1  A: 

As others have said... If it is a one-time thing JVMTI is probably the most hardcore way to go. However, just as fun could be to use the asm library and the instrumentation APIs to create an agent that inserts a call to a static method you've created just before the Thread.interrupt() call (or maybe alters the Thread.interrupt() method to do the same, I think you can do that).

Both takes some time to learn but it is quite fun to work with and once you get the hold of it you can use them for all kinds of funny things in the future :-) I don't really have any good snippets to paste here right now but if you google around for ASM and maybe look at the JIP for some creative use of ASM I think you will find inspiration.

JIP: Java Interactive Profiler

Fredrik
I assume you're referring to http://asm.ow2.org/ ? Sounds very creative! I didn't have the time to investigate, but this looks like something that'll do me good in the future. Thanks.
Eddie
Correct, sorry for not including the URL.
Fredrik
+5  A: 

As a quick hack, this was a lot easier to do than I thought it would be. Since this is a quick hack, I didn't do things like ensure that the stack trace is deep enough before dereferencing the array, etc. I inserted the following in my signed Applet's constructor:

log.info("Old security manager = " + System.getSecurityManager());
System.setSecurityManager(new SecurityManager() {
      @Override
      public void checkAccess(final Thread t) {
        StackTraceElement[] list = Thread.currentThread().getStackTrace();
        StackTraceElement element = list[3];
        if (element.getMethodName().equals("interrupt")) {
          log.info("CheckAccess to interrupt(Thread = " + t.getName() + ") - "
                   + element.getMethodName());
          dumpThreadStack(Thread.currentThread());
        }
        super.checkAccess(t);
      }
    });

and the dumpThreadStack method is as follows:

public static void dumpThreadStack(final Thread thread) {
  StringBuilder builder = new StringBuilder('\n');
  try {
    for (StackTraceElement element : thread.getStackTrace()) {
      builder.append(element.toString()).append('\n');
    }
  } catch (SecurityException e) { /* ignore */ }
  log.info(builder.toString());
}

I could never, of course, leave this in production code, but it sufficed to tell me exactly which thread was causing an interrupt() that I didn't expect. That is, with this code in place, I get a stack dump for every call to Thread.interrupt().

Eddie