Thread Checker Improvements

I made a few small improvements to the dynamic thread checker tonight, after fixing another bug in DrJava’s latest stable release. Since we’re going to release another stable release soon, perhaps today, I wonder if we can demote the current stable to beta 4.

I wasn’t feeling too well on Saturday and Sunday, so unfortunately I didn’t get quite as much done as I had wanted. I nonetheless made two important additions… well, maybe one, but it seems like they’re two.

First of all, I added a dual @OnlyRunBy annotation that designates the only threads that may run the annotated code. @NotRunBy designates threads that may not run it. Implementing @OnlyRunBy was a lot harder than @NotRunBy, unfortunately. The latter fails immediately when a thread is found that matches one of the designated threads; @OnlyRunBy, however, only fails when it has not matched with any of the threads specified. That means I need to do some bookkeeping. I tried a few different ways, and then finally decided to add lists to the ThreadCheck class that first get filled and then processed in a single call.

The second addition is special treatment for the event thread by using an eventThread=true element in the annotation. I’ve only implemented this for @OnlyRunBy, though. That’s where it makes the most sense to me. Because @OnlyRunBy didn’t exist before today, maybe all of this was just one major addition, but eventThread=true seems pretty important in its own right.

Here is a sample program that creates a window with a button:

import edu.rice.cs.cunit.threadCheck.OnlyRunBy;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;

public class ThreadCheckTest2 {
public void run() {
JFrame frame = new JFrame("ThreadCheckTest2") {
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e);
if (WindowEvent.WINDOW_CLOSING == e.getID()) {
System.exit(0);
}
}
};
JPanel panel = new JPanel();
JButton button = new JButton("Button");
button.addActionListener(new ActionListener() {
@OnlyRunBy(threadNames={"AWT-EventQueue-.*"})
public void actionPerformed(ActionEvent e) {
handleButton();
}
});
panel.add(button);
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
handleButton();
}

@OnlyRunBy(eventThread = true)
private void handleButton() {
System.out.println("Button was pushed");
}

public static void main(String[] args) {
(new ThreadCheckTest2()).run();
}
}

Note that handleButton is called from the end of the run method even though handleButton has been annotated with @OnlyRunBy(eventThread = true). This generates the warning below:

Thread Violation: OnlyRunBy
        Current thread 'main', id 1, group 'main' did not match
        the event thread
        at ThreadCheckTest2.handleButton (ThreadCheckTest2.java:-1)
        at ThreadCheckTest2.run (ThreadCheckTest2.java:34)
        at ThreadCheckTest2.main (ThreadCheckTest2.java:51)

Farther up, annotating the ActionListener.actionPerformed method in the second anonymous class is another annotation @OnlyRunBy(threadNames={"AWT-EventQueue-.*"}) that pretty much does the same, except using the thread name, which is a little less reliable.

I haven’t dealt with the superclass/same method in superclass issue because I want to talk to Corky and the other students first and see what their intuition about this behavior is. I also started writing a version of the thread checker for both annotations purely using reflection, but I couldn’t figure out how to uniquely identify the method that was entered just using the data from a StackTraceElement. I get the class and method name, but their might be more than one method with that name. I guess I could statically make that determination in the instrumentor and then simply pass a parameter to the method. I’m just interested to see how well reflection performs compared to the code I have right now: The reflection code may be shorter, but I doubt it can be jitted as well.

I’ll see if I can go to sleep now, it’s just past 4 AM. Doubtful, but we’ll see…

Share

About Mathias

Software development engineer. Principal developer of DrJava. Recent Ph.D. graduate from the Department of Computer Science at Rice University.
This entry was posted in Concurrent Unit Testing, DrJava. Bookmark the permalink.

Leave a Reply