Necessity of Data Annotations?

Right now I’m actually doubting that data annotations are necessary. It seems like assertions can do enough already. For method annotations, the important distinction was that the invariants in the annotations get inherited into subclasses.

The original idea of data annotations was that invariants would be checked every time an object is accessed. However, if I implement the scopes as discussed in the last post, then what’s the difference to assertions? You could simply place several assert statements in the code. Maybe the annotations would look cleaner, less littered, but is that really a justification for developing data annotations?

Originally, what intrigued me was calling a predicate method every time an object is accessed. In that predicate method, I could do whatever I wanted to do: This even includes implementing a lock-set algorithm and performing dynamic race condition detection.

But the scoping destroys that possibility, because the invariants would not be checked everywhere. So I think the scope idea is not the right way to go. Too bad, I already wrote a generified RangeMap that I would have used to store invariants that are active in a range of PC (program counter) values…

Maybe the right way to think about data annotations is that you specify the invariant at the time the object is created. Or maybe it’s class-based and you specify the properties inside the class, and then it applies to every instance. Maybe there are multiple places where you can specify invariants, e.g. when you define a field and when you define a parameter. But what invariants are checked when that field is passed as argument for that annotated parameter? Now the limited scope makes sense again. Or is everything merged?

I’ll have to think about this some more…

Update

Maybe it makes sense to have both scoped and unlimited invariants. The scoped invariants would pretty much replace assert statements littered in one particular area, while the unlimited invariants would follow an object throughout its entire lifetime.

One thing I’ve definitely realized is that the kind of opcode that is about to be executed should be transferred to the predicate method. That way, a predicate method could tell that it’s just before a monitorenter, for example.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Scope of Data Predicate Annotations

I’ve thought a bit about what the scope of data predicate annotations should be. At first, I thought every time an object encounters another predicate annotation, that predicate just gets added to the list of predicates that an object has to fulfill. I’m not so sure about that anymore. In fact, I don’t think this is right.

Consider the following class:

public class Test {
private static Integer _field;
public static void increment(@NeverPositive Integer param) {
++_field;
}
public static void decrement(@NeverNegative Integer param) {
_field = _field -1;
}
public static void main(String[] args) {
_field = -10;
while(_field<=0) increment(_field); _field += 9; while(_field>=0) decrement(_field);
}
}

It’s a pointless example. Here, I annotate the parameters of two methods: For increment, the parameter may never be positive. For decrement, the parameter may never be negative. In the main method, I start with -10 for the field’s value, then keep calling increment until the field is positive.

Then the program enters a second phase. I add 9 to the field, so the value of the field now is 10. I keep calling decrement until the field’s value has reached -1.

If an object keeps accumulating the predicates it encounters, then in the decrement phase, the field would have both the @NeverPositive and the @NeverNegative predicates, and it would only accept 0.

This leads me to believe that the predicates must be scoped. The scope of the parameter annotations here, for example, should be only the method. For local variable (if they worked), it should probably be the smallest enclosing block.

What about fields? Should the predicates only apply if the data is used in this class? Or should it span to other classes as well? I’m not sure. By the way, to make things clear, the idea is that the predicates will be checked every time the object is accessed, so in the bytecode, before the access, bytecode will be inserted.

If I take the example with the parameter annotations that should probably be limited to just the methods and expand it to fields and classes, then I think limiting the predicates to just the class seems right.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Data Predicate Annotations

I have thought a little about how to do predicate annotations on data. Of course there’s the local variable problem, but let’s ignore that for now.

Originally, I thought it would be rather easy: Whenever a field or parameter is declared, I run a check method every time it is accessed. This, of course, is wrong because the predicates should not be based on the declaration site but rather on the object that is created.

So I need to add fields to java.lang.Object that get filled in when the object is created to store the predicate class and method name. Of course, as we all know, you can’t add fields to Object, so I do what I have done for the object ID and add a method to Object that calls the real check method in edu.rice.cs.cunit.threadCheck.ThreadCheck, which then looks up the predicates in a hash table.

What I haven’t figured out is how I get the parameters from the annotations into the check method.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Vacation!

Since I have no idea right now when I’ll defend or when anyone will be in town, I decided I might as well not be in town for a while either. I’m joining Diana in California from July 25 to July 31. My first break since May 2005 and my first real vacation since the summer of 2003.

Share
Posted in Uncategorized | Leave a comment

Print This Post Print This Post  

Can’t Write Anymore

I really can’t add anymore to my thesis. I’m currently doing duplex prints, which cuts the 200 pages of the thesis to 100 pages. However… It becomes nearly impossible to staple 100 pages. So I think I have reached my limit.

Share
Posted in Concurrent Unit Testing, MS Thesis | Leave a comment

Print This Post Print This Post  

Thesis Progress

Currently 200 pages, 182 pages of content (excluding tables of contents and bibliography), 41,453 words.

What is... the Thesis? Loaned from Piled Higher and Deeper. Please visit www.phdcomics.com

The most recent draft is available here: A Framework for Testing Concurrent Programs.

Still to do:

  • go through blog comments and make sure everything important has been said
  • defend!
  • correct!
  • submit!

Growth of the thesis (overall, including front matter and bibliography):

  • 05/04: 182 pages
  • 05/03: 180 pages
  • 05/02: 196 pages
  • 04/26: 180 pages
  • 04/25: 166 pages
  • 04/24: 164 pages
  • 04/22: 154 pages
  • 04/20: 138 pages
  • 04/16: 113 pages
  • 04/15: 108 pages
  • 04/14: 95 pages
  • 04/13: 82 pages
  • 04/09: 82 pages
  • 04/08: 71 pages
  • 03/28: 65 pages
  • 03/16: 59 pages
  • 03/12: 49 pages

I can’t go further back in history because before 03/12, I had all sections stuffed with “Lorem Ipsup” pseudo-text to simulate the layout.

Since I only have one graph in my thesis, here’s another one: blue is the total number of pages, pink are the pages written per day, and yellow is the average number of pages written per day.

Pages per Day

PS: The image is borrowed from “Piled Higher and Deeper” (www.phdcomics.com). The 3rd book is about to be released — go and pre-order!

Share
Posted in Concurrent Unit Testing, MS Thesis | Leave a comment

Print This Post Print This Post  

Writing, Reading, Just Not Here

So it has obviously been a while since I have written about anything here. That doesn’t mean I haven’t written, as the “Thesis Progress” post shows. I’ve written a lot. I have read a lot. Without actually trying to write a lot, my MS thesis has grown to 197 pages total. Right now I’m proofreading the third hard copy of the document I’ve made. The first hard copy was still printed with empty backs; for the second, I already had to print with duplex, or I wouldn’t have been able to staple the pages together.

Yeah… So I’m proofreading, and I’m still finding mistakes. I also go back to my notes from the blog and sometimes add a sentence here or there, if I find an important thought is missing.

I have sent out two drafts of the thesis to my committee members. I think it’s about time to talk to them in greater detail and get feedback. And, at least in my opinion, it’s time to start arranging a defense date.

Obviously, I have missed the original deadline: Eight days ago, I was supposed to have defended my thesis and turned in the final version. I didn’t, and therefore I broke the timetable I had set up for myself in the petition for extending the MS deadline that I wrote last fall. I feel like I’m “close enough” in spirit, though, because I’m missing it only by a few weeks. I probably could have defended, but I wouldn’t have got feedback, and the document would have been very crappy.

Regardless, I need to write another petition and ask for an extension of the extension. I’m pretty sure it will be accepted, though, since I have 197 pages written, and it could have been many more. I saved a lot of detail for the PhD thesis already.

Share
Posted in Concurrent Unit Testing, MS Thesis | Leave a comment

Print This Post Print This Post  

Let’s See It

Ok, so it seems like I’m approaching the stage where I have to send out copies of my draft to my very friendly committee members. A lot of things are there, though I admit I have not checked for spelling mistakes, bad wording or layout problems. I just focused on getting content down.

Tomorrow, I think, I’ll provide the committee members a duplex printout of the current version and ask them to scribble any notes they have on the paper, or point out my mistakes in any way they feel comfortable. I’ll also ask a few of my friends to proof-read. While all of that is going on, I’ll flip through my blog to see if I have forgotten anything that is really crucial.

Well, and then, once the feedback from the committee members is in, I have to schedule a defense date. Do I want to defend before my mom gets here for her summer vacation, or do I let her be part of my audience? Of course I’d want her to be there, the problem is just that I have so many serious things going on in my family, I don’t want to be disturbed until this thing is done. And I also don’t want to make it seem like I’m using my mom to get my committee off my back. Anyway, I think now people (including me) have some reading ahead, and then I’ll either make improvements and get back to them, or we schedule a defense. Then I get to make a PowerPoint presentation about all of this. Yay.

So far, writing has been an interesting experience: Without a doubt, I can say that I’ve never written anything at this length. I’ve never got involved with anything this in-depth. However, sometimes I got bored writing about something that I had already done half a year ago and that worked. It felt like “I want to do something new!”

Now, when the MS defense is coming closer, though, I realize that after the MS are a lot more challenges for me. I need to pass the candidacy exam, and I need to finally get that replay algorithm to work, something I botched up but half a dozen other groups got working. I just hope that I have learned enough to get my second attempt to work.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

More Thesis Writing

By now, I’m way beyond the 100-page mark. There are still a bunch of “TODO”s in my text, but they are getting fewer. I’ve filled in many blanks. The conclusion isn’t written yet, but that’s ok. I’m going to revisit the abstract, introduction and conclusion at the very end anyway, to make sure that the abstract correctly expresses the content of the thesis, that the introduction starts at an appropriate point and properly introduces the material, and that the conclusion is valid.

I still have to start writing the chapter about bytecode rewriting. It was supposed to include some technical details and some other things that I worked on, namely the schedule recorder, the deadlock detector, and random sleep and yield. I think I will keep most of the random sleep and yield out of this thesis, though, because I haven’t really tested those instrumentors very well. I don’t have any results about how well they work and what delay lengths and probabilities I should choose.

Results generally are a problem. The results sections about the JUnit improvement and the invariant checker are still empty, too. I’m debating whether I need to explain the XML format in greater detail. I also need to go through and check my bibliography, add more citations, and do a better literature review. Then I need to revisit my notes from the blog and see if anything should be added.

Today I went through the thesis and fixed problems with the margin caused by the teletype font. I don’t think I’m doing it right, though, because I have to manually insert hyphenation points. Isn’t there a way to globally enable hyphenation for the teletype font, and for example tell LaTeX that it should make a line break after a dot, e.g. break java.lang.Object into java.lang. and Object?

I could also use proof-readers. Any volunteers? ;)

My mom will be here on May 9, and I think I want to defend either before she gets here or during the first few days of her stay, so that we can talk about the gravely serious issues in our lives later, without disturbing my concentration. That means I have two and a half, maybe three weeks until my defense. That means in the next week and a half, I should get some feedback from my committee, and then I need to schedule the defense. Time really flies.

I’m a little bummed out about not graduating this semester. It would have been very nice for my mom to see me walk again. But defending and finalizing the thesis by next Wednesday would have been impossible. I admit that I slacked off a bit in January and February and that probably ruined it, but I felt just really disturbed by the latest news from my family. I’m glad, though, that Corky doesn’t seem to mind if I postpone everything by a few weeks. It’s just sad that it’s a matter of a few weeks…

Share
Posted in Concurrent Unit Testing, MS Thesis | Leave a comment

Print This Post Print This Post  

Oh, Stinger

I’m just enjoying the last can of “Stinger Enraged Raspberry” energy drink. I bought four 24-packs for $50 shipped from Amazon last August. It doesn’t taste that great, a bit chalky, but I got used to it, and it really worked. And who can argue with a slightly “off” taste at 50 cents a can when four cans of Red Bull cost $7 plus tax? I got four cans for the price of one.

Now I’ll have to look for an alternative. I’m just not sure if one will ever come around again that is so darn cheap.

Share
Posted in Uncategorized | Leave a comment

Print This Post Print This Post  

One Hundred

Writing today worked out just wonderfully. I got up, showered, brushed my theeth and… basically started writing and haven’t done anything since. Unfortunately, I think I’ve neglected my nutrition and lovely girlfriend in the process. Yesterday, on Saturday, it was a bit harder to get started, so I wrote until late at night.

But in general, I wrote a lot during the last three days. I changed the order of a few sections, filled in many blanks, and today broke the 100-page barrier (including front matter and bibliography; without the title pages, tables of contents, and bibliography, I’m at 84 pages).

I never would have thought that I’ve got so much to write! 84 pages of content, more than 100 pages overall, and I haven’t even finished the “meatiest” parts of the thesis; I still have to describe predicate annotations, general ideas of bytecode rewriting, schedule recording, the deadlock monitor, and random sleeps and yields.

Maybe I am being too verbose. I’ll check that later. It’s always easier to take things out.

I made a sticky post with updates about my thesis writing progress.

Share
Posted in Concurrent Unit Testing, MS Thesis | Leave a comment

Print This Post Print This Post  

UPS = No Oops

Today we had a few showers (I managed to get soaked on my bike ride to the office, and later, when I checked the radar, it didn’t even show any precipitation! A mystery cloud rained on me!), and now at night, as predicted, there are some quite heavy thunderstorms. The lights have flickered several times already, and at least once, my UPSes kicked in.

I don’t know how many times my UPSes have saved my computers and my work in the approximately 600 days I’ve had them. What I can say is that at a price of about $120, and therefore $2 a day, it has probably saved (some) of my sanity.

UPSes rock.

Share
Posted in Uncategorized | Leave a comment

Print This Post Print This Post  

Contract4J and My Annotations

When I was looking up some basic theory on method preconditions today, just to make sure that my notion that preconditions act in a covariant way, I discovered an interesting piece of software: Contract4J.

It only works together with AspectJ, an aspect-oriented programming framework for Java, but seems to support convenient ways to specify pre- and postconditions for methods, fields, and classes. These conditions are much more extensive than what my annotations do. It seems like Contract4J allows programmers to specify a string of Java code that may include a few extra things, so it basically corresponds to the fourth option I considered but decided would be too difficult to implement. I think the aspect-oriented framework with their cuts made it easier to insert the source code than it would have been for plain Java, which is what I’m dealing with.

I’d love to eventually provide some support for strings like this, even if it’s just a way to replace the syntax for @Combine annotations, which I think is rather clunky, even though I believe it’s the best I can do without resorting to my own parsing. It would just be nice if I could replace the current way to combine annotations:

@Combine(value=Combine.Mode.AND, arguments=true)
public static @interface TestDistinctNotNullGreater {
TestDistinctNotNull distinctNotNull() default @TestDistinctNotNull;
TestGreater gt() default @TestGreater;
}

with something like this:

@Combine("@TestDistinctNotNull && @TestGreater")
public static @interface TestDistinctNotNullGreater { }

But then again it wouldn’t be a full-fledged annotation, and I couldn’t override the default behavior. But maybe I don’t even want that.

Right now, I think my implementation is very reasonable and very cost-effective. But maybe I should add postconditions too. They’d act covariantly; that could yield some more interesting theory.

Talking of theory: I’ve realized that it’s not only the @NotRunBy annotations that should act in a contravariant way and that can be used to statically detect problems with the concurrency invariants. That’s true for all annotations, as long as you assume that the annotations make the preconditions stricter. With @NotRunBy it’s easy to see that it makes the preconditions stricter, but @OnlyRunBy does the same, except in a much more radical way: It may very well reduce the allowed number of threads to just one, or even zero. Ignoring regular expressions, I could even prove this. Now, with predicate annotations, I can’t prove jack, but it’s still reasonable to make the assumption that an annotation makes a precondition stricter (or at least not less strict).

The result is that my subtyping relation can be applied to all the annotations that I provide in my library. That’s good.

Oh, while at the lab today, I also fixed a strange but pretty critical bug in DrJava: [ 1696060 ] Debugger Infinite Loop. Again, I heavily relied on the YourKit Java profiler to get an idea where DrJava gets stuck. After the first YourKit run, I realized that DrJava was deadlocking here:

java.awt.EventQueue.invokeAndWait(Runnable)
edu.rice.cs.util.swing.Utilities.invokeAndWait(Runnable)
edu.rice.cs.drjava.model.AbstractGlobalModel.setActiveDocument(OpenDefinitionsDocument)
edu.rice.cs.drjava.model.AbstractGlobalModel.openFile(FileOpenSelector)
edu.rice.cs.drjava.model.AbstractGlobalModel.getDocumentForFile(File)
edu.rice.cs.drjava.model.debug.jpda.JPDADebugger.scrollToSource(Location,
boolean)
edu.rice.cs.drjava.model.debug.jpda.JPDADebugger.scrollToSource(Location)
edu.rice.cs.drjava.model.debug.jpda.JPDADebugger._switchToSuspendedThread(boolean)
edu.rice.cs.drjava.model.debug.jpda.JPDADebugger._switchToSuspendedThread()
edu.rice.cs.drjava.model.debug.jpda.JPDADebugger.currThreadSuspended()
edu.rice.cs.drjava.model.debug.jpda.EventHandlerThread._handleStepEvent(StepEvent)
edu.rice.cs.drjava.model.debug.jpda.EventHandlerThread.handleEvent(Event)
edu.rice.cs.drjava.model.debug.jpda.EventHandlerThread.run()

The interesting thing about the call to setActiveDocument is that here it is not happening in the event thread, so the invokeAndWait uses Java’s original method, so the code gets put in the event queue. It looks like the event that is blocking the event queue is DebugPanel.updateData(). Somehow because it does not complete, the code from setActiveDocument never gets to run, and we have a deadlock.

In the end, I realized that the deadlock was a result of the debugger thread, already owning the lock
of the debugger, asking the global model to open a file, so setActiveDocument put code on the event queue. When this code executed, the event thread tried to call a synchronized method of the debugger, but never managed to acquire its lock, because the debugger thread already owned it.

I changed the code to have the debugger thread “preload” a document every time a step is made, before claiming the debugger lock. This brings setActiveDocument into action and the document is opened if necessary. Then the debugger lock is claimed and the response to the step is made, and the document is guaranteed to be open already, so the deadlock is avoided. The fix is in revision 4225.

YourKit does a lot for a developer. I have to admit, though, that it takes some skill to interpret the flood of information, and I’m thinking I’m getting better at it.

PS: Because in COMP 312 we were talking about some problems with Java’s very low-level implementation of concurrency tools, I again brought up an article that I had read a while ago. It’s “If I were king: A proposal for fixing the Java programming language’s threading problems” by Allen Holub. We briefly tossed around the ideas of acquiring several locks at the same time and the issues that brings up. I think all the problems can be avoided by the very common solution to the Dining Philosopher’s Problem: Putting locks in some arbitrary but fixed order, and then always acquiring them in that order. The world is very small: I just learned that Dr. Nguyen attended a seminar with Allen Holub and thus knows him first-hand.

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

Print This Post Print This Post  

Replacing Hard Drives in “vector”

The hard drive that I bought a few days ago has arrived today. I decided that I needed a new hard drive because two hard drives in “vector”, my second computer that I use as web and media server, have shown problems recently: One hard drive, the one containing all my web server content, suddenly disappeared, and then reappeared again a few hours later after I’d gone through a lot of trouble of restoring the latest backup and getting as many files that had been changed or added after that back as possible. The other drive often reverts to PIO instead of DMA transfer. I think that hard drive actually was in “scalar” before I bought the new Dell, and I had noticed problems there already.

So now I’m copying a few files, and then I’m going to put the new 250 GB Seagate drive in to replace the 120 GB Maxtor C:\ drive and the 80 GB Maxtor D:\ drive. I think I’ll partition it about 170 GB/80 GB and then use Ghost to clone the old hard drive contents into the new partitions. The slightly funny thing about this is the easiest way to accomplish that is to actually remove the 160 GB Seagate E:\ drive, the only drive of the three current drives that will stay in the system, and put the new 250 GB Seagate drive in its place for a while. The E:\ drive is in a mobile rack and therefore the easiest to replace.

The question that I still have to answer is this: What do I do with the 80 GB and the 120 GB Maxtor drives that I’ll take out of the system? I replaced them because I doubt their reliability. But they still kind of work… So I’m tempted to get mobile racks for them so I can use them somehow, perhaps as backup media. But if I doubt their reliability, then what good are they as backup media, something where reliability is really important? But having a 120 GB backup drive instead of the 20 GB drive that I currently use in the mobile rack would be nice… So should I buy two more trays (which are strangely enough more expensive than the racks that include a tray, but the racks are out of stock right now)?

Update:

Well, this was supposed to be really simple. I cloned the hard drives using Ghost, removed the old ones, like planned, and rebooted. But Windows wouldn’t start because the drive letters were still wrong. Now I’ve been trying to change the letter of the boot drive three times, I’ve cloned the drives three times, and I still haven’t been able to successfully boot from the new drive. Somehow my BIOS doesn’t recognize it as 250 GB, but as 128 GB, so it looks like it’s the 28-bit LBA limitation, but I’m pretty sure my BIOS can handle 48-bit LBA, because it does recognize the 160 GB Seagate as 160 GB.

On the other hand I’ve noticed that sometimes the new drive isn’t recognized, mostly when it’s connected to the far end of the PATA cable. I don’t know if that went to the 120 GB or the 80 GB drive, but I’m getting a feeling that I might have had cable issues, even though this was a really new rounded PATA cable, about a year old. I think the 120 GB drive might still be good after all.

Just for my own reference, three important websites:

  1. How to restore the system/boot drive letter in Windows
  2. Unable to log on if the boot partition drive letter has changed
  3. Hard Drive Size Limitations and Barriers

Update:

I’ve given up making the new 250 GB drive the boot drive. I kept the 120 GB drive and just added the new 250 GB drive in place of the 80 GB drive. For some reason I can access the new drive, but not boot from it.

Share
Posted in Uncategorized | Leave a comment

Print This Post Print This Post  

Synchronized Methods Harder to Protect

I’m working with the simple examples for my thesis again, and I realized another interesting thing: Synchronized methods are harder to protect than non-synchronized methods.

The example that I’m using is this:

import edu.rice.cs.cunit.threadCheck.SuppressSubtypingWarning;
import edu.rice.cs.cunit.threadCheck.predicates.NoneSynchronizedField;
public class BenignCall extends Benign {
private static Object o = new Object() {
public synchronized String toString() { return "foo"; }
};
public static void main(String[] args) {
final Benign b = new BenignCall();
synchronized(o) {
Thread aux = new Thread(new Runnable() {
@SuppressSubtypingWarning
@NoneSynchronizedField(fieldClass=BenignCall.class,fieldName="o")
public void run() {
b.run(o, o);
}
});
aux.start();
try { aux.join(); } catch(InterruptedException e) { }
}
// b.run(o,o); would have worked
}
}

I’m using a @NoneSynchronizedField annotation to express the invariant that no thread may hold the lock of the o field at the time the Runnable.run() method is invoked.

I just looked at it again and thought it would be much more natural to state that the lock of this may not be held when the overloaded toString() method is called:

@NoneSynchronizedThis
public synchronized String toString() { return "foo"; }

But I realized this wouldn’t work. With synchronized methods, Java grabs the lock automatically, behind the scenes, and by the time code in the method is executed, the lock is already held. Or not, in this example, the program may deadlock.

I think with this in mind, it may be a good idea to convert all synchronized methods to methods containing synchronized blocks, something that I already do quite often.

Update: I now have a parameter “convert-sync-methods” that can be passed to the Thread Checker instrumentation strategy that converts synchronized methods to methods containing synchronized blocks. So now the @NoneSynchronizedField annotation can be used there.

Share
Posted in Concurrent Unit Testing, MS Thesis | Leave a comment

Print This Post Print This Post  

Lock Not Owned By Any Thread

When I was looking at my simple examples again that demonstrate how benign code can be transformed into code that breaks concurrency invariants and deadlocks, I realized that the annotations I had for dealing with owning locks, namely OnlySynchronized\* and NotSynchronized\* are not enough. They only check if the current thread owns or does not own the lock. I need to know if any thread owns a lock.

I’ve now added a two groups of annotations, AnySynchronized\* and NoneSynchronized\*, which express the invariant “any thread owns a lock” and “no thread owns a lock”, respectively.

The implementation is a bit of a hack, as it spawns another thread that may be doomed, but it kind of works, and with a higher level of instrumentation, i.e. instrumenting the rt.jar and probably all monitorenter and monitorexit calls, I could do a better and more definite job, but I’m trying to keep it lightweight here.

The difficulties arise mostly because of Java’s very limited model of object monitors and monitorenter and monitorexit. Allen Holub proposed improvements to synchronized that I can wholeheartedly agree with, and Sun made some improvements with Java 1.5 and the java.lang.concurrent package, particularly the ReentrantLock class.

But I can always make improvements later. Right now, I need to focus on advancing my thesis (sadly, I’ll probably miss the deadline), but I keep running into things I should add, like during the last week.

Share
Posted in Concurrent Unit Testing, MS Thesis | Leave a comment

Print This Post Print This Post  

Advantage Over Assertions

One thing that I definitely have to mention is an advantage over the current, classical solution: assertions. Assertions aren’t inherited like my annotations.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Lists are Overused

I think I can really make this really general statement: Lists are overused. We’re using lists all the time. But a list implies an order, and often that order doesn’t matter. What we want many times are sets.

Today I tracked down a bug that had… bugged me for a while, but not seriously enough to warrant a thorough investigation: When I’m instrumenting a file A, I create a file A\_i, and then I want to rename the file A to A~ and A\_i to A. For some files, this was failing.

Today I realized that it was failing because a file A~ was already there. At first I had no idea why, but pretty soon I realized that it was there because I had listed file A twice. I shouldn’t have been using a list of files to instrument, I should have used a set.

I’ve made this observation several times, and have several times already substituted sets for lists. Today I made another effort in this direction.

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

Print This Post Print This Post  

@SuppressSubtypingWarning Implemented

I have now implemented @SuppressSubtypingWarning as far as I am going to, I think. I limited it only to methods and constructors; it can’t be applied to classes or interfaces. I think the impact would have been to unspecific.

There are several ways a method can acquire an annotation:

  • A method is annotated itself.
  • The same method in a superclass is annotated.
  • A class is annotated and the method is first defined in that class or a subclass.

More formally:

Let A be an annotation.
Let m be a method.
Let C, D, S, T be classes.
Let m(C) be the set of methods defined (i.e. introduced or overridden) in class C.
Let a(C) be the set of annotations that are directly attached to class C, i.e. that appear in front of C’s class definition.
Let a(C, m) be the set of annotations that are directly attached to method m in class C, i.e. that appear in front of m’s method definition in the class definition of C.
Finallly, let annotations(C,m) be the set of annotations that are applied to a method m in class C, either because the method was directly annotated or because the annotations were somehow inherited.

A method m in class C has an annotation A if one of the following statements is true: A \in annotations(C,m).

The definition of annotations(C,m) is:

annotations(C,m) = \\\\<br />
\hspace{15mm}\\{ A : A \in a(C, m) \\} \cup \\\\<br />
\hspace{15mm}\\{ A : \exists S \text{ such that } C <: S, A \in a(S, m) \\} \cup \\\\
\hspace{15mm}\\{ A : \\\\
\hspace{30mm}\exists D \text{ such that } C <: D, m \in m(D) \wedge \\\\
\hspace{30mm}\exists S \text{ such that } D <: S, A \in a(S) \wedge \\\\
\hspace{30mm}\not\exists T, T \not = S \text{ such that } S <: T, m \in m(T) \\} The first subset corresponds to a method being directly annotated. The second subset comes into effect if a method in a superclass was annotated. Because of the reflexive property of subtyping <:, this statement actually subsumes the first rule. The third subset contains the annotations that meet the following three criteria: The method exists in the class or a superclass, the class is annotated with the annotation, and the method had not already been introduced in a class higher up. I defined the semantics of @SuppressSubtypingWarning to act only on the specific method that is annotated with it. If it acquires an annotation in any of the three ways above, but the same method in a superclass does not have the annotation, then the subtyping warning that would normally be generated is suppressed. The @SuppressSubtypingWarning does not have any effect on subtyping warnings that methods in superclasses may generate because they may have annotations that super-superclasses lack.

I also decided to not allow annotations of whole classes because the annotation of a class has effects reaching beyond that class itself: It also affects subclasses. If a class is annotated and a subclass introduces a method, then that method will carry the annotation. Therefore, annotating a class with @SuppressSubtypingWarning would suppress annotations for all methods introduced further down in the hierarchy.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Thinking about @SuppressSubtypingWarning

I’m really having problems sleeping lately, so tonight I’ve been doing some thinking about @SuppressSubtypingWarning. At first, I thought I’d just bake it into the PredicateLink and Combine meta-annotations, but then it would mean that an annotation will always suppress subtyping warnings, and I don’t think that’s desired.

So the @SuppressSubtypingWarning annotation has to be a meta-annotation that gets applied to an annotation at the usage site. For example:

@SuppressSubtypingWarning @OnlyEventThread.AfterRealized
private void handleButton() {
System.out.println("Button was pushed");
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() + "'");
}

Unfortunately, Java’s grammar doesn’t let you apply annotations to the usage sites of other annotations, only to their definitions. So this approach isn’t going to work.

I could use a @SuppressSubtypingWarning annotation applied to a class or method to completely disable subtyping warnings for all annotations on that class or method, but I’d rather have it fine-grained. I’ll have to think some more about it.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post