- A Concurrent Affair - https://www.concurrentaffair.org -

Thread Checker Improvements

I made a few small improvements to the dynamic thread checker tonight, after fixing another bug [1] 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 [2] frame = new JFrame [2]("ThreadCheckTest2") {
            protected void processWindowEvent(WindowEvent [3] e) {
                super.processWindowEvent(e);
                if (WindowEvent [3].WINDOW_CLOSING == e.getID()) {
                    System [4].exit(0);
                }
            }
        };
        JPanel [5] panel = new JPanel [5]();
        JButton [6] button = new JButton [6]("Button");
        button.addActionListener(new ActionListener [7]() {
            @OnlyRunBy(threadNames={"AWT-EventQueue-.*"})
            public void actionPerformed(ActionEvent [8] e) {
                handleButton();
            }
        });
        panel.add(button);
        frame.getContentPane().add(panel);
        frame.pack();
        frame.setVisible(true);
        handleButton();
    }

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

    public static void main(String [9][] 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 [10]. 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…

[11] [12]Share [13]