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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | 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…