Good Morning

Ok, I guess that was my sleep tonight.

I discovered that instrumenting rt.jar for thread checking is actually blowing the default-sized heap, so I quickly wrote a SoftHashMap that uses SoftReferences the garbage collector is free to evict.

I also did some analysis on the caching of class and method annotations:

ThreadChecker Cache Info:
Class cache 85499/13225, method cache 24748/111845 (hits/misses)

That means it definitely works, there’s no error. It works very well for classes (86%), probably because it is looking for the same classes very often (Object, d’uh), but it’s working pretty badly for methods (18%).

I don’t know off hand how I can improve the latter. I could perhaps scan all methods when I have a class file open. I think I’ll look at my second suggestion, temporary directories, first, though.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Current Java API Annotations

Here are my current Java API annotations, both in XML form:





































































































































































































and in a more human-readable form after being processed by the XMLAnnotToText tool:

class javax.swing.plaf.TextUI {

	@OnlyRunBy(@ThreadDesc(eventthread="true"))
	java.awt.Rectangle modelToView(javax.swing.text.JTextComponent a, int b);

	@OnlyRunBy(@ThreadDesc(eventthread="true"))
	java.awt.Rectangle modelToView(javax.swing.text.JTextComponent a, int b,
	   javax.swing.text.Position$Bias c);
}

class javax.swing.text.DefaultCaret {

	@OnlyRunBy(@ThreadDesc(eventthread="true"))
	void repaintNewCaret();

	@OnlyRunBy(@ThreadDesc(eventthread=".*"))
	void repaint();
}

class javax.swing.text.JTextComponent {

	@OnlyRunBy(@ThreadDesc(name=".*"))
	void replaceSelection(java.lang.String a);

	@OnlyRunBy(@ThreadDesc(name=".*"))
	void setText(java.lang.String a);
}

class javax.swing.text.Document {

	@OnlyRunBy(@ThreadDesc(name=".*"))
	void render(java.lang.Runnable a);
}

class javax.swing.text.PlainDocument {

	@OnlyRunBy(@ThreadDesc(name=".*"))
	void insertString(int a, java.lang.String b, javax.swing.text.AttributeSet c);
}

class javax.swing.text.DefaultStyledDocument {

	@OnlyRunBy(@ThreadDesc(name=".*"))
	void insert(int a, javax.swing.text.DefaultStyledDocument$ElementSpec[] b);

	@OnlyRunBy(@ThreadDesc(name=".*"))
	void setLogicalStyle(int a, javax.swing.text.Style b);

	@OnlyRunBy(@ThreadDesc(name=".*"))
	void setCharacterAttributes(int a, int b, javax.swing.text.AttributeSet c, boolean d);

	@OnlyRunBy(@ThreadDesc(name=".*"))
	void setParagraphAttributes(int a, int b, javax.swing.text.AttributeSet c, boolean d);
}

class javax.swing.text.StyleContext {

	@OnlyRunBy(@ThreadDesc(name=".*"))
	javax.swing.text.AttributeSet addAttribute(javax.swing.text.AttributeSet a,
	  java.lang.Object b, java.langObject c);

	@OnlyRunBy(@ThreadDesc(name=".*"))
	javax.swing.text.AttributeSet addAttributes(javax.swing.text.AttributeSet a,
	  javax.swing.text.AttributeSet b);

	@OnlyRunBy(@ThreadDesc(name=".*"))
	javax.swing.text.AttributeSet removeAttribute(javax.swing.text.AttributeSet a,
	  java.lang.Object b);

	@OnlyRunBy(@ThreadDesc(name=".*"))
	javax.swing.text.AttributeSet removeAttributes(javax.swing.text.AttributeSet a,
	  java.util.Enumeration b);

	@OnlyRunBy(@ThreadDesc(name=".*"))
	javax.swing.text.AttributeSet removeAttributes(javax.swing.text.AttributeSet a,
	  javax.swing.text.AttributeSet b);

	@OnlyRunBy(@ThreadDesc(name=".*"))
	void reclaim(javax.swing.text.AttributeSet a);
}

class javax.swing.text.html.HTMLEditorKit$Parser {

	@OnlyRunBy(@ThreadDesc(name=".*"))
	void parse(java.io.Reader a, javax.swing.text.html.HTMLEditorKit$
	  ParserCallback b, boolean c);
}

class javax.swing.undo.UndoManager {

	@OnlyRunBy(@ThreadDesc(name=".*"))
	boolean addEdit(javax.swing.undo.UndoableEdit a);

	@OnlyRunBy(@ThreadDesc(name=".*"))
	boolean canRedo();

	@OnlyRunBy(@ThreadDesc(name=".*"))
	boolean canUndo();

	@OnlyRunBy(@ThreadDesc(name=".*"))
	boolean canUndoOrRedo();

	@OnlyRunBy(@ThreadDesc(name=".*"))
	void discardAllEdits();

	@OnlyRunBy(@ThreadDesc(name=".*"))
	void end();

	@OnlyRunBy(@ThreadDesc(name=".*"))
	int getLimit();

	@OnlyRunBy(@ThreadDesc(name=".*"))
	java.lang.String getRedoPresentationName();

	@OnlyRunBy(@ThreadDesc(name=".*"))
	java.lang.String getUndoPresentationName();

	@OnlyRunBy(@ThreadDesc(name=".*"))
	java.lang.String getUndoOrRedoPresentationName();

	@OnlyRunBy(@ThreadDesc(name=".*"))
	void redo();

	@OnlyRunBy(@ThreadDesc(name=".*"))
	void setLimit(int a);

	@OnlyRunBy(@ThreadDesc(name=".*"))
	void undo();

	@OnlyRunBy(@ThreadDesc(name=".*"))
	void undoOrRedo();
}

class javax.swing.JComponent {

	@OnlyRunBy(@ThreadDesc(name=".*"))
	void revalidate();
}

class javax.swing.JTextArea {

	@OnlyRunBy(@ThreadDesc(name=".*"))
	void append(java.lang.String a);

	@OnlyRunBy(@ThreadDesc(name=".*"))
	void insert(java.lang.String a, int b);

	@OnlyRunBy(@ThreadDesc(name=".*"))
	void replaceRange(java.lang.String a, int b, int c);
}

class javax.swing.JTextPane {

	@OnlyRunBy(@ThreadDesc(name=".*"))
	void insertComponent(java.awt.Component a);

	@OnlyRunBy(@ThreadDesc(name=".*"))
	void insertIcon(javax.swing.Icon a);

	@OnlyRunBy(@ThreadDesc(name=".*"))
	void setLogicalStyle(javax.swing.text.Style a);

	@OnlyRunBy(@ThreadDesc(name=".*"))
	void setCharacterAttributes(javax.swing.text.AttributeSet a, boolean b);

	@OnlyRunBy(@ThreadDesc(name=".*"))
	void setParagraphAttributes(javax.swing.text.AttributeSet a, boolean b);
}

class java.awt.Component {

	@OnlyRunBy(@ThreadDesc(name=".*"))
	void repaint();

	@OnlyRunBy(@ThreadDesc(name=".*"))
	void invalidate();
}
Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Change to the XML Format

I spent a few hours going over the list of methods that were supposedly thread-safe and also searched through the API source. I now have an XML annotation file that describes the methods that are supposedly safe to run by any thread.

When I was done with creating that XML file by hand, I looked at it and realized that — without some graphical tool — it was pretty hard to get a quick overview of what classes and methods were affected. The XML format is easy to create, read, and use in the program, but the packages are nested, so it’s hard to consider classes in isolation.

I decided to write a tool that converts an XML annotation file (which I can automatically create from annotated class files, as mentioned before) to a more human-readable format, something like an abbreviated, abstract Java file.

While doing that I realized that my XML file format was ambiguous. If you recall, my file format used to look like this:









It was “concutest/threadcheck” followed by packages, then the class name, and then <class> and <method> tags. There’s no way that a <class> tag could be mistaken for a package or a class name, since class is a keyword; but method isn’t! So it’s not immediately clear if a <method> tag describes a package or class or indeed a method.

I changed the format and put the <method> tags inside the <class> tag. That means now there is a <class> tag even if there aren’t any class-level annotations if there are annotated methods.

The XML annotations above now look like this:









I had to change all the strategies and the XML annotation files that I had already written, of course.

Now that I have created a list of methods that are safe to be run by any thread, I can start on marking many, many classes and methods as unsafe for execution outside the event thread. That should hopefully make things with DrJava more interesting. So far, I discovered nothing serious, even though I haven’t run the unit tests yet. If I don’t find anything, that’s great, it means DrJava is a solid piece of software. But it would be nice to demonstrate my tools on some buggy programs too…

I slightly extended the strategy that adds the thread checks: It’s now able to handle an arbitrary number of XML annotation files. That way I can keep the annotations for the Java API separate from anything else. The instrumentation is running now, and it’s taking a while. I’ve noticed that already when I was instrumenting the drjava-15.jar file. The frequent checks for superclasses and interfaces seem to get very slow whenever jar files are involved.

There are two things that I need to check:

  1. Is caching of class and method annotations working? What kinds of hit and miss rates am I getting?
  2. Should I unpack jar files into a temporary directory, work with them as loose class files there, and then pack them back together at the end? That could potentially speed processing up a lot, if the space is available.

This was a productive night of work, now it’s Labor Day and I should work on sleeping for a bit.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Safe for Any Thread

Annotating a method with @OnlyRunBy(@ThreadDesc(name=".*")) works to override all other, more narrow annotations and allow all threads to run, as expected. It looks pretty cumbersome, though, and doesn’t allow me to generate adequate warnings.

I think I should introduce a @OnlyRunBy(@ThreadDesc(anyThread=true)) annotation. If such an annotation is found, then the entire @OnlyRunBy can be removed, but warnings should be emited that a superclass annotation overrides subclass annotations: It’s a just another subtyping violation.

Actually… I guess it’s the same as having no annotation at all. So in principle I could just not annotate these methods. It may still be easier to annotate an entire class as @OnlyRunBy(@ThreadDesc(eventThread=true)) and then have @OnlyRunBy(@ThreadDesc(anyThread=true)) annotations for a few methods.

I need to think about this for a while…

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Thread Checking Swing

I’m getting more and more the feeling that annotating the Java API side, primarily Swing, will be more important and hopefully produce more results than just annotating the DrJava side. I’ve collected a small number of methods alreaydy by grepping the Java API source, but picking the methods this way is extremely cumbersome, both because it requires reading a lot of code and because writing the method signatures by hand actually isn’t all that easy:


















I think I may after all write a GUI tool, a class file browser, that scans the classpath and then allows you to click your way through the packages, classes and methods and attach annotations. I had that idea before, but I just didn’t get to it and then thought maybe it wasn’t necessary.

I’ve also browsed the web and tried to find references for what is and what isn’t allowed with Swing. It’s sad that there isn’t too much that really seems authorative, and the comments in the API source are more than sparse either. Here’s what I’ve found, in no particular order, sometimes with quotes, emphasis by me:

  • Threads and Swing

    Once a Swing component has been realized, all code that might affect or depend on the state of that component should be executed in the event-dispatching thread.

    The single-thread rule: Realized means that the component’s paint() method has been or might be called. A Swing component that’s a top-level window is realized by having one of these methods invoked on it: setVisible(true), show(), or (this might surprise you) pack(). Once a window is realized, all components that it contains are realized. Another way to realize a component is to add it to a container that’s already realized.

    Comment: I guess that means I could add a flag or poll some methods when I’m doing the @OnlyRunBy(@ThreadDesc(eventThread=true)) check. But as explained farther below, Sun now recommends doing all GUI construction in the event thread using invokeAndWait.

    Exceptions to the rule: A few methods are thread-safe: In the Swing API documentation, thread-safe methods are marked with this text: This method is thread safe, although most Swing methods are not.

    Comment: I’ll have to grep for that. I tried, but it’s not spelled the same way in all instances. Anyway, these methods will probably be pretty rare.

    An application’s GUI can often be constructed and shown in the main thread.

    Comment: Again, Sun now recommends doing all GUI construction in the event thread using invokeAndWait, so I guess this is out-dated.

    The following JComponent methods are safe to call from any thread: repaint(), revalidate(), and invalidate(). The repaint() and revalidate() methods queue requests for the event-dispatching thread to call paint() and validate(), respectively. The invalidate() method just marks a component and all of its direct ancestors as requiring validation.

    Listener lists can be modified from any thread: It’s always safe to call the addListenerTypeListener() and removeListenerTypeListener() methods. The add/remove operations have no effect on an event dispatch that’s under way.

    Comment: Nice. I have to test it, but I should be able to annotate these methods with @OnlyRunBy(@ThreadDesc(name=".*")) and therefore allow all threads to call them. It should override more restrictive annotations. Other articles mention a few more methods.

  • The Last Word in Swing Threads

    Swing’s single-thread rule says that Swing components can only be accessed by a single thread. This rule applies to both gets and sets, and the single thread is known as the event-dispatch thread.

    Comment: Gets for some primitive data might actually be safe, but for references it’s definitely unsafe.

    Swing components will generally not comply with the single-thread rule unless all their events are sent and received on the event-dispatch thread. For example, property-change events should be sent on the event-dispatch thread, and model-change events should be received on the event-dispatch thread.

    For model-based components such as JTable and JTree, the single-thread rule implies that the model itself can only be accessed by the event-dispatch thread.

    Comment: Somehow I thought that model code could be accessed outside the event thread. It’s good to know that this is not the case. I wonder where that will draw the boundary in DrJava.

  • Painting in AWT and Swing

    It is not recommended that programs invoke paint() directly.

    Programs should not invoke this method [paintImmediately()] directly unless there is a valid need for real-time painting.

    Comment: That implies they should only be run by the event thread.

    The program invokes repaint() on the component, which registers an asynchronous request to the AWT that this component needs to be repainted. The AWT causes the event dispatching thread to invoke update() on the component. NOTE: If multiple calls to repaint() occur on a component before the initial repaint request is processed, the multiple requests may be collapsed into a single call to update().

    Comment: That explains why repaint(), etc. is safe.

  • Concurrency In Swing Text

    The primary form of concurrency support in the text package is designed to support building and maintenance (also called mutations) of the document model on a separate thread from the event dispatching thread. A concurrent application will typically interact with the model and have no direct interest in the GUI.

    Comment: So the models of text components can be accessed from outside the event thread, but those of JTable and JTree can’t? I’ll have to check that more closely, but I guess this was what I remembered.

    The most time-consuming part of laying out a large box is calculating preferred sizes for the children, and then waiting for the actual layout that the children perform. If these two operations are performed synchronously, it may even turn out that a lot of this work is useless.

    Comment: It seems like text components use additional “layout threads”. May they access methods that can only be run by the event thread?

  • Swing : Java Glossary

    There are a few exceptions to the general rule of having to invoke Swing methods from the EventDispatchThread, most notably it is safe to call to the following methods from any thread:
    Component.repaint
    JComponent.revalidate
    JEditorPane.replaceSelection
    JTextArea.append
    JTextArea.insert
    JTextArea.replaceRange
    JTextComponent.replaceSelection
    JTextComponent.setText
    JTextPane.insertIcon
    JTextPane.insertLogicalStyle
    JTextPane.setCharacterAttributes
    JTextPane.setParagraphAttributes
    PlainDocument.setText

    Comment: I need to check that these are actually correct. Also, Component.invalidate was missing from this list.

  • How to Use Threads

    We used to say that you could create the GUI on the main thread as long as you didn’t modify components that had already been realized. […] To avoid the possibility of thread problems, we recommend that you use invokeLater to create the GUI on the event-dispatching thread for all new applications.

    Comment: That means I will not write a special case for access to event thread-only methods if the components haven’t been realized yet.

  • Multithreaded Swing Applications

    If you modify Swing component data from any thread other than the event dispatching thread, you must take precautions to ensure data integrity. An exception to this rule is the setText method on a JTextComponent or any of its subclasses, or any Swing component method whose documentation explicitly states it is thread safe.

    Comment: Interesting… Have to check that and may mark them as @OnlyRunBy(@ThreadDesc(name=".*")).

As a summary, I can probably say that most of Swing should be event thread-only, except for the few methods mentioned in the list below. Text models may be ok to be called from outside the event thread, but JTable and JTree models are not. And Sun has made my life a little bit easier by retracting their statement that a GUI can be constructed in the main thread as long as it hasn’t been realized.

Component.repaint
Container.invalidate
JComponent.revalidate
JEditorPane.replaceSelection
JTextArea.append
JTextArea.insert
JTextArea.replaceRange
JTextComponent.replaceSelection
JTextComponent.setText
JTextPane.insertComponent
JTextPane.insertIcon
JTextPane.setLogicalStyle
JTextPane.setCharacterAttributes
JTextPane.setParagraphAttributes
DefaultStyledDocument.setLogicalStyle
PlainDocument.setText

The comments for DefaultMutableTreeNode indeed say it’s not thread-safe. However, this does not really mean that it should only be accessed by the event thread; there just has to be additional synchronization in place. Can I check for that — without using full-scale Eraser? Should I force access from within the event thread?

* This is not a thread safe class.If you intend to use
* a DefaultMutableTreeNode (or a tree of TreeNodes) in more than one thread, you
* need to do your own synchronizing. A good convention to adopt is
* synchronizing on the root node of a tree.

Many methods on the text model side do state they are thread-safe. Some inner classes in javax.swing.text.html.StyleSheet, however, explicitly state they are not thread-safe. Again, the above applies: Running outside the event-thread is ok, as long as there is additional synchronization.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Thread Checking DrJava

After writing a few more auxiliary strategies, like one that can turn annotated class files into an XML configuration file with the equivalent annotations, I’ve created a branch for DrJava now and am adding my thread checking annotations.

So far, I’ve just searched for the string event thread” and put a @OnlyRunBy(@ThreadDesc(eventThread=true)) annotation in front of all the method that claimed they “should only be run in the event thread”. I haven’t performed any deeper analysis on whether that’s actually necessary or not. This pretty random process has lead me to insert 77 annotations.

There were three subtyping warnings that were produced:

edu.rice.cs.drjava.model.DefaultGlobalModel$ConcreteOpenDefDoc.runMain()V
    has @OnlyRunBy event thread
    but edu.rice.cs.drjava.model.AbstractGlobalModel$ConcreteOpenDefDoc.runMain()V
    does not

edu.rice.cs.drjava.ui.MainFrame.pack()V has @OnlyRunBy event thread
    but java.awt.Window.pack()V does not

edu.rice.cs.util.docnavigation.JListSortNavigator.addDocument
    (Ledu/rice/cs/util/docnavigation/INavigatorItem;)V
    has @OnlyRunBy event thread
    but edu.rice.cs.util.docnavigation.JListNavigator.addDocument
    (Ledu/rice/cs/util/docnavigation/INavigatorItem;)V
    does not

The first one is a semi-valid concern: The supermethod should be annotated as well; since there are no other subclasses in this case, though, it did not really matter. Except for the comment that this method “is usually executed in the event thread”, I also did not find a reason for it. I added the annotation anyway.

The second warning is bogus, I think. To me it seems like calling pack is always safe. Here’s the code in question:

/** Ensures that pack() is run in the event thread. Only used in test code */
@OnlyRunBy(@ThreadDesc(eventThread=true))
public void pack() {
Utilities.invokeAndWait(new Runnable() { public void run() { packHelp(); } });
}

/** Helper method that provides access to super.pack() within the
* anonymous class new Runnable() {...} above */
private void packHelp() { super.pack(); }

I think it’s more an issue of making sure that the “packing” has already occurred when the code continues rather than making sure it happens in the event thread. I ended up removing that annotation.

The third one was just a case where I had missed to add the annotation. With these three changes made, there were no more subtyping warnings. So far, so good.

When I started an instrumented version of the drjava-15.jar file, I already got my first violation:

Thread Violation: OnlyRunBy
        Current thread 'main', id 1, group 'main' did not match
        the event thread
        at edu.rice.cs.drjava.config.KeyStrokeOption. (KeyStrokeOption.java:-1)
        at edu.rice.cs.drjava.config.OptionConstants. (OptionConstants.java:278)
        at sun.misc.Unsafe.ensureClassInitialized (Unsafe.java:-2)
        at sun.reflect.UnsafeFieldAccessorFactory.newFieldAccessor (UnsafeFieldAccessorFac
        at sun.reflect.ReflectionFactory.newFieldAccessor (ReflectionFactory.java:122)
        at java.lang.reflect.Field.acquireFieldAccessor (Field.java:917)
        at java.lang.reflect.Field.getFieldAccessor (Field.java:898)
        at java.lang.reflect.Field.get (Field.java:357)
        at edu.rice.cs.drjava.config.OptionMapLoader. (OptionMapLoader.java:57)
        at edu.rice.cs.drjava.config.SavableConfiguration.loadConfiguration (SavableConfig
        at edu.rice.cs.drjava.config.FileConfiguration.loadConfiguration (FileConfiguratio
        at edu.rice.cs.drjava.DrJava._initConfig (DrJava.java:432)
        at edu.rice.cs.drjava.DrJava. (DrJava.java:117)
        at edu.rice.cs.drjava.DrJavaRoot.main (DrJavaRoot.java:97)

The code for KeyStrokeOption states that only the event thread accesses the methods in this class:

/** Class representing all configuration options with values of type KeyStroke.
* This code should only run in the event thread, so no synchronization is necessary
* (or advisable).*/
@OnlyRunBy(@ThreadDesc(eventThread=true))
public class KeyStrokeOption extends Option {

Obviously that isn’t true, the main thread also runs it. This is probably not a big issue, but it’s an error in the documentation. Other than that, DrJava has been holding up quite admirably so far. But right now I’m only checking against a few of our own constraints, and I haven’t run the unit tests yet.

I’ve also started looking at the Java API, and that, of course, is where it gets really interesting. I’ve found this comment in javax.swing.text.DefaultCaret, for example:

/** ...
* The repaint of the new caret location will occur on the event thread in any case,
* as calls to modelToView are only safe on the event thread.

I’m sure that I should mark javax.swing.text.DefaultCaret.repaintNewCaret() as event thread-only, but doesn’t the comment really imply that javax.swing.plaf.TextUI.modelToView should only be called in the event thread? I’ve marked those methods event thread-only too now, even though they seem to be used in many places without special concern.

Share
Posted in Concurrent Unit Testing, DrJava | Leave a comment

Print This Post Print This Post  

More Static Checking?

I’m wondering whether I should warn about unnecessary annotations, e.g. if a method is annotated, but the supermethod is, too. It’s not strictly necessary, but it may be a good idea for clarity and conciseness. Then again, it’s additional documentation.

I’m also thinking that perhaps I should do some static checking when certain thread properties are known for a method. The main method could, for example, be annotated with @RunsThread(@ThreadDesc(name="main", group="main", id=1, eventThread=false)). Other threads could run it too, but this is definitely one possibility. When a call is made to a method annotated with @NotRunBy that matches this description or @OnlyRunBy that doesn’t match this description, a static error could be generated.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Screw Ups

People screw up, and I definitely do, too. But let me start with other people screwing up first: Dr. Nguyen told me today that he couldn’t run DrJava in Symonds II lab. When we looked at the situation together, we determined that the file (actually, pretty much the entire user drive) that DrJava uses for its preferences file (.drjava) was neither readable nor writable. IT screwed up.

Fortunately, I had earlier fixed DrJava bug 1543649 and could provide the following work-around:

Note for Rice Users Fall 2006: The IT department seems to have configured its network server for the ADRICE domain improperly, preventing DrJava to access its preferences file in the user’s home directory (typically U:\pcprofile\.drjava). This prevents DrJava from saving its preferences and under some circumstances even prevents it from starting. Until the IT department fixes this problem, here is a work-around:

  1. Download the latest version of DrJava as a jar file (drjava-stable-20060821-1502 or later)
  2. Save the file to a directory on the computer’s local drive, i.e. C:\ not somewhere on U:\
  3. Open a command shell by clicking on the “Start” button, selecting “Run…”, typing in “cmd” in the edit field, and pressing “OK”.
  4. Change into the directory where you saved the DrJava jar file. Example: If you saved it to C:\Temp, then you would type in the following commands in the command shell, each followed by pressing the “return” key:
    • C:
    • cd \Temp
  5. Now you’re in the directory with the DrJava jar file and you can run it. However, because of the IT department problems, you have to start it differently and specify an alternate preferences file using the -config switch. This is how you do it:
    • java -jar drjava.jar -config drjava.cfg
  6. Depending on the name of the DrJava version you downloaded, you may have to change the name of the DrJava jar file, e.g. from drjava.jar to drjava-stable-20060821-1502.jar.
  7. You should also make sure that the alternate preferences file, in this example drjava.cfg, does not initially exist. Just choose a name that is not in use. That will make DrJava start out with everything at the default preferences. All changes to the preferences will be saved to that file.
  8. When you start DrJava again later and want to re-use the preferences from the last execution, make sure to start from the same directory and specify the same alternate preferences file, in this example drjava.cfg. That will make DrJava re-load the preferences you saved when you last quit DrJava.
  9. If you need any help while the IT department resolves this problem, please let us know.

I’m always utterly amazed by how thorougly IT manages to screw the instructors over. Out of the, oh, ten semesters I guess that maybe three went smoothly. They even swapped the versions of Microsoft Office after Dr. Nguyen had ordered the textbooks!

Now to me screwing up: I’ve started instrumenting DrJava, and DrJava is a bit bigger than the test files I’ve worked with before. One of the situations that I ran into for the first time was a short that was “so large”, Java interpreted it as negative (Java only has signed datatypes). Negative array indices are sort of problematic. Now I’ve switched the entire codebase to using int and added a few assert statements to make sure that the numbers are equal to or less than unsigned 0xffff. I hope I found all of the places. My unit tests pass, but I think I’ll have to look around a little bit more.

Anyway, just as a test, I decided to write a simple external XML file and then run DrJava. Both the XML file and the resulting log are shown below:














When DrJava is run, the main method is of course entered by the main thread, so the annotation is violated:

Thread Name Violation: NotRunBy
        Current thread 'main', id 1, group 'main'
        Natched disallowed pattern 'main'
        at edu.rice.cs.drjava.DrJava.main (DrJava.java:-1)

Again I didn’t get to writing a class/jar browser that allows the developer to write these XML files more easily (or perhaps to generate them from the annotations), but at least I did get started with DrJava, and I improved the file instrumentor a little.

Now it’s time to sleep. Oh no wait, it’s not. It’s past 7 AM. I guess it’s time to get up. I have an appointment at 9:30 AM.

Share
Posted in Concurrent Unit Testing, DrJava, Uncategorized | Leave a comment

Print This Post Print This Post  

External XML Annotations

There are several cases when you either cannot put annotations in the source code to make the thread checker work: Either you decide you do not want to pollute the source with the annotations (even though I see them more as enhanced documentation), or you do not have the source to begin with. The latter is sort of the case with the Java Standard API. The source is there, but I do not want to recompile it.

For these cases, I have developed an XML format that allows the developer to specify the threads allowed or not allowed to run certain methods or classes in an external file. It’s based on the XML configuration library that I wrote a while ago. Consider the file below:
















This XML file expresses the same checks as the annotations in the Java file here:

...
@OnlyRunBy(@ThreadDesc(name="childclass1"),
@ThreadDesc(group="childclassgroup1"),
@ThreadDesc(id=1001),
@ThreadDesc(eventThread=true))
@NotRunBy(@ThreadDesc(name="childclass2"),
@ThreadDesc(group="childclassgroup2"),
@ThreadDesc(id=1002))
public class ThreadCheckSample4 ... {

@OnlyRunBy(@ThreadDesc(name="childclass-method1"))
@NotRunBy(@ThreadDesc(name="childclass-method2"))
public void run() { ... }
}

The rationale for this design was the paths I use to access nodes in the XML. The path to get to the <ThreadCheckSample4> node, for example, is concutest.threadcheck.sample.threadCheck.ThreadCheckSample4, so if you ignore the initial concutest.threadcheck, which designates the project and sub-project, then that’s exactly the fully-qualified class name, so look-up is trivial.

Then there is a <class> tag that can contain any number of nested <name>, <group>, <id> and <eventThread> tags that correspond to the @ThreadDesc annotations. A type attribute chooses between @OnlyRunBy and @NotRunBy, and a value attribute actually contains the thread description.

For methods, there can be any number of <method> nodes. Which method they describe is chosen by the sig attribute that contains a concatenated method name and descriptor. The rest is the same as for the <class> node.

What I need now is an easy way to generate these XML files, perhaps by using some sort of class/jar file browser, and generally an easier way to perform the instrumentation so I can release the thread checker independently from the rest of the framework.

Now that I have a list of methods that are deemed save, I can start marking many, many classes and methods as unsafe to be executed outside the event thread. That’s when things will actually get interesting. And I also need to run the DrJava unit test suite. In normal operation and without Swing annotated, I didn’t find a serious problem in DrJava yet. That’s good, of course. It may stay that way. But it would also be kind of nice to show my tools on buggy programs…

I’ve extended the strategy that adds thread checks a little: It can now handle an arbitrary number of XML annotation files, separated by the "path.separator". That way I can create a dedicated file just for the Java runtime.

The instrumentation is running now and I’m taking a blogging break, and it’s taking a while… I noticed that when instrumenting the drjava-15.jar file already. It seems like the frequent queries for superclasses and superinterfaces take a long time whenever jar files are involved.

So there are two things that I need to check:

  1. Does caching of class and method annotations work? What kind of cache efficiency am I getting?
  2. Should I create a temporary directory, unpack a jar file, work with loose class files, then pack them up again and delete the directory?

This was a good night’s work on the eve of labor day, but I should seriously work on sleeping soon.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Unit Tests for Thread Checker

I’ve started writing unit tests for the thread checker. This turns out to be quite a difficult matter because so many things are involved:

  1. The source code needs to be compiled.
  2. The compiled classes need to be instrumented.
  3. The instrumented classes need to be examined and executed.

Additionally, checking correctness is complicated by these issues:

  • The checks may occur in any permutation, as long as all of them occur.
  • No additional checks may occur.

I wanted to be able to run the test programs independently, so I decided to include them as regular source files in the repository. The test cases require that the source was compiled and then copies the test classes to a temporary directory. There they are instrumented, analyzed and run. I analyze both the bytecode and the output of the log file.

So far I’ve written simple tests both for @NotRunBy and @OnlyRunBy, now I still have to write more complicated tests that involve inheritance and subtyping warnings.

I also just fixed another DrJava bug that involved regions in the Bookmarks panel not properly updating when the document was changed. This sounds very similar to another bug I had fixed earlier, where Find All results displayed the same behavior. Today I determined that both had the same cause: The regions only held integer offsets, not Positions that move within the document. Bookmark sections now update properly, but I left the fix for Find All results in place, so they’re still static. I like the idea that the results of Find All represent a “snapshot” of the program at the time of the search.

Share
Posted in Concurrent Unit Testing, DrJava | Leave a comment

Print This Post Print This Post  

New Annotatation Format

I must admit I haven’t been able to do as much as I had hoped during the last two days, but I did experiment with a new, more flexible format for the annotations. It’s a bit more verbose, but it essentially gives me what I had wanted (see end of this posting).

The preferred (and most future-proof) way of specifying threads now uses the value element, an array of @ThreadDesc annotations. The choice of value as name has the advantage that the programmer can drop the value= part if only the value element is assigned to. The @ThreadDesc annotation now contains the four elements name, id, group and eventThread (notice singular form on the first three), but only one of the four may be used at the same time, i.e. @ThreadDesc(name="foo") and @ThreadDesc(id=5) are legal, but @ThreadDesc(name="foo",id=5) is not.

The old elements of @NotRunBy and @OnlyRunBy, i.e. threadNames, threadIds, threadGroups and eventThread are still available and can be mixed with the new value element in any way, as long as anything regarding the event thread is not specified more than once, like in the following (illegal) annotation: @OnlyRunBy(eventThread=true, value=@ThreadDesc(eventThread=true)).

Here are some examples of the new style:

@NotRunBy({@ThreadDesc(name="bar"), @ThreadDesc(id=1)})
@NotRunBy({@ThreadDesc(name="main"), @ThreadDesc(name="fum")})
@OnlyRunBy(@ThreadDesc(eventThread=true))
@OnlyRunBy(value={@ThreadDesc(name="main3"), @ThreadDesc(group="foo")},
threadGroups={"bar"}, threadIds={3, 4})

The major advantage is that I can add additional elements to the @ThreadDesc annotation, such as conditionals as discussed previously.

I also changed the way class-level annotations affect methods and floowed Corky’s advice: An annotation on a class, from now on only influences methods that were defined by that class, or are going to be defined in subclasses. Let’s look at a quick example:

abstract class Base {
@OnlyRunBy(eventThread=true)
public abstract void run();
public abstract void doSomething();
}
public boolean equals(Object other) { ... }

In this class only the run method is annotated (and all methods in subclasses); >doSomething is not annotated.

Let’s look at a subclass:

@OnlyRunBy(eventThread=true)
class Sub extends Base {
public void run() { ... }
public void doSomething() { ... }
public abstract void doSomethingElse() { ... }
}

Here, we have a class-level annotation: In my initial version, this annotation would have applied to all three methods in the Sub class; however, that caused a lot of warnings if subtyping was taken seriously. Now the annotation only applies to the doSomethingElse method, because both run and doSomething were already defined in the Base class. The Sub.run method nonetheless is annotated to allow only the event thread to run since Base.run is annotated with @OnlyRunBy(eventThread=true) and that applies to all subclasses as well.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

What I Don’t (and Probably Won’t) Do

I mentioned earlier that the checker currently generates a lot of warnings, many of which seem unnecessary. When I change the checker to match Corky’s suggestion, that will reduce the number of warnings, but there could potentially still be a lot.

I do filter out multiple warnings that are exactly the same, and I also remove warnings that concern an individual method if the entire class is affected. For efficiency reasons, I also don’t match a thread name or group name against the same regular expression twice. What I don’t do, and I guess that deserves to be mentioned, is see if matching a thread name or group name against a particular regular expression R1 is unnecessary because the language accepted by R1 is already a subset of the language accepted by a second regular expression R2.

While determining whether the language of one regular expression is the subset of another is decidable, I don’t think this is necessary here. I don’t think Java’s builtin java.util.regex package can do minimization or compare regular expressions somehow. It’s theoretically interesting but practically probably rather irrelevant.

Thinking about this got me wondering whether creating one long regular expression for all the @OnlyRunBy thread names or group names is more efficient than what I do right now. If I have the annotation @OnlyRunBy(threadNames={"foo","bar"}), I could just match the thread name against the regular expression "(foo)|(bar)"… I have a feeling that’s better. I’m gonna try that now.

Update

No, using one single long regular expression apparently is not good. I ran the following method 1,000,000 times with the old system (preparing a list of regexes with a call per pattern, then checking it with another call) and the new system (statically preparing one long regex, then making one call to check it):

@OnlyRunBy(threadNames={"main","main2","main3","main4","main5"})
public static void allowed() {
}

The new system with the more complex regex was on average about five times slower.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Talk about Thread Checker

Good, I didn’t oversleep again. I just talked to Corky about the dynamic thread checker again. Here’s what he suggested:

  • Annotations at class level, e.g. @OnlyRunBy(...) class Foo { ... } should not apply to all the methods in the class, but only to those methods that are introduced by the class or by one of its subclasses. That would probably avoid a lot of the warnings that I’m generating right now, and if you really want to annotate a method somewhere where it was not introduced, you can still do that using a method annotation.
  • Certain AWT/Swing methods are always safe, e.g. java.awt.Component.repaint. If I’m only using method annotations, then these methods just would not be annotated, but if I’m using class annotations, then I may have to have a method annotation that overrides the class annotation. I think I’ll ignore this for now.
  • AWT/Swing components are probably safe as long as they or any of their subcomponents aren’t “live” yet. He mentioned that methods such as setVisible and pack make an object “live”, but I have to find a more accurate description. Another question is how do I determine that a component is still safe? Do I add a special element to the annotations, e.g. @OnlyRunBy(eventThread=true, AWTsafe=true), or do I go for more general conditions, like @OnlyRunBy(eventThread=true, condition="!isVisible()"). The latter would, of course, be much more difficult, so at least initially I’m opting for the former. But how do I implement that? Do I add a flag to the class and then set it in one of the methods that make an object “live”?

    Update: Actually, Sun doesn’t recommend this practice anymore. I found that out while searching the web for texts on Swing and concurrency. So maybe I can save myself the effort. I’ll have to talk to Corky and find out if he really wants this.

  • Even on the view side of AWT/Swing, many objects are probably safe, as long as what they’re doing is volatile, i.e. other threads get to see the effects immediately, and as long as they don’t export an object with mutable state. How do I determine that? Well, I don’t know…

Corky really stressed that we should avoid generating many false positives. That’s what he disliked about the static tools that exist, like FindBugs. After writing more unit tests for the instrumentation strategy I’ll start with annotating DrJava’s codebase and from there work my way into the Java API if I have to.

I think I may want a more flexible format of annotations, though. It’s a little problematic that I cannot use the same annotation class on a class or method twice. I would just like the following format much better:

@OnlyRunBy(eventThread=true)
@OnlyRunBy(threadName="helper")
...

If I can specify each allowed or disallowed thread one by one, then it’s much easier to modify just one of them, e.g. by somehow making it conditional:

// running by event thread is always safe
@OnlyRunBy(eventThread=true)
// running by "helper" is safe as long as not "live"
@OnlyRunBy(threadName="helper" AWTsafe=true) ...

Maybe I’ll have to rethink my annotation format…

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

More Thread Checker

Today was pretty much a repeat from yesterday: I fixed (or at least worked on) another DrJava bug and made improvements to my dynamic thread checker. Unfortunately, the bug fix did not make it into our new new stable release anymore. I also couldn’t reproduce the “Unsupported major.minor version” error, but that may even be a good thing.

I was a little bit late to our research meeting, but when I talked about the thread checker, Corky agreed that annotations on superclasses or methods in superclasses should be considered in subclasses as well. He also said I could go ahead and use DrJava as test codebase. We didn’t talk very much, but when I mentioned the warnings that should be raised when a subclass has an annotation but a superclass does not, he suggested that perhaps an annotation should only be allowed where a method is first introduced, and not in a subclass or implementing class.

We both agreed that this might not be practical, though: Often programmers implement Standard Java API interfaces, like ActionListener, and then they would not be able to annotate those implementing classes.

I still need to do a little more testing and write unit tests, but I did write the code tonight that checks superclasses and interfaces for annotations as well. The code for subtyping warnings is there too, but it generates a lot of warnings… More than may be useful. They currently look like this:

ThreadCheckTest has @NotRunBy thread name 'foo' but java.lang.Object does not
ThreadCheckTest3 has @OnlyRunBy thread name 'main2' but java.lang.Object does not
ThreadCheckTest4.run()V has @NotRunBy thread name 'childclass-method2' but ThreadCheckTest4SuperClass.run()V does not

I think I may want to exclude java.lang.Object from this. And perhaps even more.

This sort of brings up the topic of instrumenting library code. There are probably a lot of AWT/Swing methods that should only be executed by the event thread, for example, but how do I instrument them? The source has been released, but I don’t think I actually want to compile it.

So what I have in mind now is an external text or XML file that just contains location-annotation pairs so the programmer can tell the instrumentor to attach a @OnlyRunBy(eventThread=true) to java.swing.text.Document or a @NotRunBy(threadName="main") to java.lang.Runtime.exit(I)V.

I’m excited to see the thread checker grow and to apply it to DrJava. I may actually have some statistical and benchmarking data soon. All right, it’s nearly 5 AM again, and I think I should try to sleep (but not oversleep) again.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

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
Posted in Concurrent Unit Testing, DrJava | Leave a comment

Print This Post Print This Post  

Dynamic Thread Checker

After spending some more time working on DrJava and fixing a few unfortunate bugs that only became apparent after our release of the new stable version on Monday, Thursday and Friday, I finally found time tonight on Friday night to work on my dynamic thread checker.

It uses annotations to specify which threads should not ever be running code in a particular class or method. The threads can be identified by regular expressions for name or group name or by their ID as produced by Thread.getId. It doesn’t do everything I’ve planned, but I must say I got a lot done tonight: The tool is already usable, I would say. Take a look at this example file:

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

@NotRunBy(threadNames={"foo"})
public class ThreadCheckTest {
@NotRunBy(threadGroups={".*ai.*"})
public ThreadCheckTest() {
System.out.println("ctor");
}

@NotRunBy(threadNames={"bar"}, threadIds={1})
public void run() {
System.out.println("run");
}

@NotRunBy(threadNames={"main","fum"})
public static void main(String[] args) {
System.out.println("main");
final Thread ct = Thread.currentThread();
System.out.println("thread name = '"+ct.getName()+"'");
System.out.println("thread id = "+ct.getId());
System.out.println("thread grp = '"+ct.getThreadGroup().getName()+"'");
(new ThreadCheckTest()).run();
}
}

The @NotRunBy annotation appears four times, once in front of the class, and three times in front of individual methods or constructors. If it appears in front of the class, then it applies to all its methods, i.e. instead of writing @NotRunBy(threadNames={"foo"}) in front of the class, I could have listed "foo" in the threadNames array of the annotations in front of the methods.

The annotations allow you to specify an arbitrary number of thread names, group names or IDs, and as soon as the current thread entering into a method matches one of them, a violation is printed into a log file. If I run the test above, I get the following violations since the thread name is “main”, its ID is 1 and its group also is “main”:

Thread Name Violation:
        Current thread 'main', id 1, group 'main'
        Natched disallowed pattern 'main'
        at ThreadCheckTest.main (ThreadCheckTest.java:-1)

Thread Group Name Violation:
        Current thread 'main', id 1, group 'main'
        Matched disallowed group name pattern '.*ai.*'
        at ThreadCheckTest. (ThreadCheckTest.java:-1)
        at ThreadCheckTest.main (ThreadCheckTest.java:31)

Thread Id Violation:
        Current thread 'main', id 1, group 'main'
        Matched disallowed id 1
        at ThreadCheckTest.run (ThreadCheckTest.java:-1)
        at ThreadCheckTest.main (ThreadCheckTest.java:31)

Here’s what I would still like it to do:

  1. I think you would want to be able to specify an @NotRunBy annotation in a superclass and make it apply to all subclasses too, or specify it for a method in a superclass, and then have it apply to all overriding/implementing methods in subclasses as well. This would give the programmer very strong tools to keep threads out of major portions of the code without having to modify every file. Right now, I only look at a single method and its enclosing class.
  2. At the same time, it seems like if you have an @NotRunBy annotation somewhere in a subclass, you may want to hoist it into the superclass because the subclass has higher demands than the superclass, so it cannot really be treated as equal to other subclasses if we are programming at the highest level of abstraction. So I might want to also have a way for annotations to percolate up into their superclasses. That would also allow us to cover a lot of code quickly.
  3. So far, everything is either based on names, which are often not used at all, and that’s one problem. The other problem is that anyone can assume a name. So I think I could also do a stack analysis and prevent certain classes or methods to even appear as distant callers. This wouldn’t necessarily be very much focused on the thread anymore, but perhaps we know where a thread that we want to keep out originated.

There is still a lot to do. Tomorrow I’ll make a few smaller examples, also with GUI, to demonstrate that my tool can easily find these bugs. Then I might take a look at the annotations in superclasses.

If Corky and the others like this, I will probably soon need a large codebase of multithreaded code to work with… Identify thread, and give them good names… Find classes were threads need to be kept out, write annotation… Run… I would like to use DrJava as such case study because of the double benefit of my work: I work with my thread checker, actually apply it, improve it, get it out there. And I work on DrJava, make it more robust, better commented, and perhaps I’ll even fix a few bugs.

Now it’s time to snuggle up and apologize to my girlfried that I’ve left her alone in for over 4 hours.

Share
Posted in Concurrent Unit Testing, DrJava | Leave a comment

Print This Post Print This Post  

Ideas and Another Bug to Catch

I found another kind of concurrency problem that can easily be caught using the random delays, and it’s a very common one: It’s an atomicity violation caused when the result of one synchronized method is used as input for another synchronized method, but the whole thing isn’t part of a synchronized block. The example the DrJava developers at Rice are most familiar with is the following:

public synchronized int getLength() { ... }
public synchronized void remove(int offs, int len) { ... }
...
remove(getLength()-1, 1);

The code is supposed to remove the last character of the document. Both methods are synchronized, the two calls are not atomic, i.e. the thread may get preempted after the call to getLength, another thread may change the document and its length, and then the original thread resumes with an incorrect length, removing either a character that’s not the last or accessing out of bounds.

If at least one method of such a two-call process is synchronized, then a delay will get inserted between the two methods, and that greatly increases the probability that preemption and corruption will occur and a unit test detects it. I’m in the process of writing a concise demonstration.

I also came up with an improvement of detecting “doomed waits” that I need to put in writing right now: Regardless of whether I decrement and increment the “running threads” (maybe “live threads” is a better name”) variable at monitorenter opcodes and use that to determine whether concurrency exists, I should keep a second “running threads” variable that does get decremented before a monitorenter and incremented after it.

This “running threads” variable is then only used to determine “doomed waits” and deadlocks: If a call to a wait is made, and only one user thread is running, regardless of how many are alive, then the wait is doomed and an exception is thrown. This situation could arise if the thread that should send the notification is involved in a deadlock.

There is a small problem, though: Unless I keep track of which locks a thread owns (strategy 3), the “running threads” variable will be decremented before a monitorenter even if the thread already owns that lock and thus does not get blocked. If the variable gets decremented, and then a task switch occurs to a thread that calls wait, then that wait could erroneously be declared as “doomed”.

The solution to this problem that I came up with while napping this morning after my all-nighter is this: Don’t immediately declare a “doomed wait“, but instead set a “progress made” flag to false and wait a few milliseconds. If a thread passes through its monitorenter — and therefore wasn’t blocked — it increments the “running threads” variable and sets the “progress made” flag to true. When the original thread resumes, it checks if the “progress made” flag is still false and only then declares the wait as “doomed”.

I need to get to campus now so I can perhaps discuss a few ideas with Corky.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

First Cut of the “Doomed wait” Solution

I made a small change to my random delay code to improve how tests with “doomed waits” are being dealt with: Instead of just calling SyncPointBuffer.randomDelay, before a wait I now make a call to SyncPointBuffer.delayObjectWait. This method first checks if there’s only one user thread alive, and if that’s the case, throws an error. Here’s the output of such an execution:

$ ant run-delay -Dtest-class-name=SyncProblem3
Buildfile: build.xml

run-delay:
     [echo] Test name = SyncProblem3
     [java] .Main thread starting worker thread...
     [java] Main thread started worker thread...
     [java] Worker thread running
     [java] Main thread waits...
     [java] Worker thread calling notify
     [java] E
     [java] Time: 3.328
     [java] There was 1 error:
     [java] 1) testNotifyTooEarly(SyncProblem3)java.lang.AssertionError:
              Call to Object.wait with only one user thread alive (_runningThreads==3)
     [java]     at edu.rice.cs.cunit.SyncPointBuffer.delayObjectWait
                   (SyncPointBuffer.java:825)
     [java]     at SyncProblem3.testNotifyTooEarly
                   (SyncProblem3.java:42)
     [java]     at sun.reflect.NativeMethodAccessorImpl.invoke0
                   (Native Method)
     [java]     at sun.reflect.NativeMethodAccessorImpl.invoke
                   (NativeMethodAccessorImpl.java:39)
     [java]     at sun.reflect.DelegatingMethodAccessorImpl.invoke
                   (DelegatingMethodAccessorImpl.java:25)

     [java] FAILURES!!!
     [java] Tests run: 1,  Failures: 0,  Errors: 1


BUILD FAILED
R:\Concutest\ClassLoader\build.xml:722: Java returned: 1

Total time: 4 seconds

But like I’ve written in an update to an earlier post, my tests indicate that a wait without timeout should be broken down into a series of wait calls with timeouts and interspersed checks of the number of living threads. There is a chance that — because we’re dealing with concurrency here — the second-to-last thread has not died at the time the check is made, but then dies before wait is called.

To make this change, I have to write my own version of Object.wait and replace calls to it with calls to my own version. I’ve done that before already, so it shouldn’t be difficult.

I have to admit, though, that this situation has so far been hard to coerce with random delays, and even then it only works on a small scale: If there are several other threads running in the background, e.g. a GUI event thread, then the thread count will not drop sufficiently. For the GUI event thread, I can probably modify the minimum number, but if there are additional user threads alive, then the “doomed wait” will not be detected.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Delay Balance

I’ve just finished the last instrumentor to delays to programs. That means my instrumentation is currently inserting delays before

  • monitorenter
  • Object.wait
  • Object.notify
  • Object.notifyAll
  • Thread.join
  • Thread.exit

and delays after

  • monitorenter
  • monitorexit
  • Object.wait
  • Thread.join
  • Thread.start
  • Thread.run

After I added delays before and after calls to Object.wait, though, the test case with the early notification wasn’t hanging anymore. I think because now I have delays in all the important places, on average the delays often balance out and preserve the original order.

I think what I want to do is try to skew the schedule maximally in one way and then in the other, e.g. first put delays on wait but not on notify, then in another run do it the other way around.

The following of those relationships come to mind:

  • Object.wait vs. Object.notify, Object.notifyAll
  • Thread.run vs. Thread.join
  • Thread.run vs. Thread.start
  • Thread.exit vs. Thread.start

There are many combinations here, especially since some of these sync points may have delays before and after them. I definitely need to investigate the relationships more closely… when I’m more awake.

Update

Another idea instead of random delays are calls to Thread.yield that occur randomly.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Another Concurrency Bug I Might Detect

The first problem that execution with random delays can catch is a temporal dependency: Thread 1 expects that thread 2 has finished performing a task, but this is not enforced through synchronization.

My girlfriend asked if I could detect the exact opposite: What if thread 1 expects that thread 2 has not finished performing some task, but it actually has? This is probably another common problem, especially with novices. It gets particularly bad if it involves wait and notify, and one thread is waiting for another thread’s notification, but that notification was done before the first thread was ready for it. Here’s an example:

import junit.framework.TestCase;
/**
* A multithreaded test case exhibiting a problem with synchronization:
* One thread is waiting for another thread's notify, but that notify
* has already occurred.
* @author Mathias Ricken
*/
public class SyncProblem3 extends TestCase {
public void testNotifyTooEarly() {
final Character signal = new Character('x');
Thread worker = new Thread(new Runnable() {
public void run() {
System.out.println("Worker thread running");
try { Thread.sleep(2000); }
catch(InterruptedException e) { /* ignore */ }

synchronized(signal) {
System.out.println("Worker thread calling notify");
signal.notify();
}

try { Thread.sleep(3000); }
catch(InterruptedException e) { /* ignore */ }
System.out.println("Worker thread done");
}
});
System.out.println("Main thread starting worker thread...");
worker.start();
System.out.println("Main thread started worker thread...");
try {
synchronized(signal) {
System.out.println("Main thread waits...");
signal.wait();
System.out.println("Main thread woken up");
}
}
catch(InterruptedException e) { /* ignore */ }
System.out.println("Main thread done");
}
}

Here, the calls to Thread.sleep simulate performing some computation, of course. Under normal circumstances, the worker thread will call signal.notify() long after the main thread has reached signal.wait(), so the main thread gets woken up.

If, however, the main thread for some reason takes longer than usual to get to signal.wait(), then the notification may be lost. The correct way of doing this, of course, is to include a flag that’s protected by the lock of the same object that is being used for signaling: The flag is initially false, gets set to true before the call to notify, and wait is only called if the flag is still false.

...
public class SyncProblem3 extends TestCase {
boolean flag = false;
public void testNotifyTooEarly() {
...
Thread worker = new Thread(new Runnable() {
public void run() {
...
synchronized(signal) {
flag = true;
signal.notify();
}
...
}
});
...
try {
synchronized(signal) {
if (!flag) {
signal.wait();
}
}
}
...
}
}

Note that if the notify is reached first and the notification is lost, then this unit test does not fail but hangs. For this reason, any unit test should have a timeout set, and if the test has not finished executing after the specified time has run out, the test should be considered a failure. An examination of the thread stacks would then show that one of the threads had made a call to Object.wait.

There are probably more elegant ways of doing this. Two things come to my mind right now:

  • The test could be run with a different version of Object.wait that includes a timeout. If the time is exceeded, it throws an exception, forcing the test to fail.

    The problem again is the choice of the timeout length. Some tests could potentially run for a very long time and then succeed, and that is the expected behavior.

    The most flexible thing to do is to set the timeout length in an annotation, the way JUnit 4.0 already does it:

    @Test(timeout = 60L) void testNotifyTooEarly() ...

  • In some cases, it may be possible to detect that a thread cannot be woken up again, either because there are no other user threads left alive, or because there is a deadlock. The first case is easy to check just before the call to Object.notify (Update: My tests indicate that a wait without timeout should be broken down into a series of waits with timeouts and interspersed checks of the number of living threads); the second case would require the deadlock detector.

I’m confident I can provide a system that’s useful here, too. And I’m glad I have a smart girlfriend.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post