Getting stacktraces of the time when Runnables are created


Summary

Create Runnable that remembers the stack trace when it gets posted, return the stack trace in asString() and paste the trace onto a Stack Trace console.

The problem

You are in the run method of a runnable, but you have no idea how it got posted to the execution thread. The current stack trace is not really helpful, because it only tells you about the execution thread and nothing about the stack trace at the time when the Runnable was posted.

The solution

Create a Runnable that remembers the stack trace when it is created (or posted to the executor).

Here is a simple Runnable that remembers the stack trace when it was created and asString returns the stack trace in the same form as Throwable.printStackTrace().

abstract public class TracingRunnable implements Runnable {
  private final StackTraceElement[] fStackTrace;
  public TracingRunnable() {
    fStackTrace=Thread.currentThread().getStackTrace();
  }
  abstract public void run();
  /** 
   * return a stack trace in the same form as {@link Throwable.printStackTrace()}
   */
  public String toString() {
    StringBuilder builder=new StringBuilder();
        // ommit the first elements in the stack trace
        for (int i=3; i < fStackTrace.length; i++) {
          builder.append("\tat ");
          builder.append(fStackTrace[i].toString());
          builder.append("\n");
        }
    return builder.toString();
  }
}

This is how your code using a Runnable looks like:

    display.asyncExec(new Runnable() {
      public void run() {
        // your code
      }
    });

Use TracingRunnable instead:

    display.asyncExec(new TracingRunnable() {
      public void run() {
        // your code
      }
    });

Now you if you are in the run() method in the debugger, you can find out what the stack trace was, when the TracingRunnable was created. Click on the this pointer of the runnable in the variables view. In the details pane you get the stack trace of the runnable when it was created. Copy and paste this into a Stack Trace Console. Now you can click on the stack and find out how the runnable got created. Unfortunately, you cant get to the value of variables, but at least you know the call tree that resulted in creating the runnable....

There are many more variation of this principle possible. Create a TracingRunnableDecorator that can be used to wrap any Runnable.

public class TracingRunnableDecorator extends TracingRunnable {
  private final Runnable fRunnable;
  /**
   @param runnable to wrap
   */
  public TracingRunnableDecorator(Runnable runnable) {
    fRunnable=runnable;
  }
  final public void run() {
    fRunnable.run();
  }
}

If you can patch the asyncExec like this:

  public void asyncExec (Runnable runnable) {
    runnable=new TracingRunnableDecorator(runnable);
    //original code goes here...
  }

Then all your code is automatically traces. That could be done using AspectJ, but I leave that as exercise for the reader....

Michael