Working With Hiccups

During the night I meditated over the question of how to insert the header code for synchronized methods changed to synchronized blocks correctly. In the case I was considering, it was obvious that the instructions needed to be inserted before the instruction that was originally first, and that references to that instruction had to be relocated to still point to it. However, I wasn’t sure if that was always true, and I didn’t know if the exit code before ?return opcodes was correct.

I’m now pretty sure that in all cases, the header code needs to be inserted before the first opcode, and that references need to be relocated. Here’s my reasoning: Before, grabbing the lock was implicitly done by the JVM. Now, the method does it itself, but there’s no reason it should ever be done again. For the remainder of the method, it should still be as implicit as possible.

I also believe that the exit code should be inserted in the place of ?return opcodes, and references to it not be relocated. That’s what I was doing already. Again, my reasoning is that things need to still appear implicit to the rest of the method, and that means in this case the exit code needs to be executed whenever the method returns, so jumps should not go to the ?return instruction itself, but to the beginning of the exit code that precedes it.

I changed the instrumentor accordingly, and now the programs load and run. That’s good.

But when they’re running in the JPDA monitor, quite often they hang. I don’t know why. I keep getting the message “slave VM in edu.rice.cs.cunit.tm.syncPoints.SyncPointRecorder.add. postponing update”. I put that message there. I know when it’s supposed to occur. It just doesn’t make sense to me. I’ve also seen this behavior more often on the computer at work than at home.

Whenever the JPDA monitor is trying to make an update, i.e. read and clear the list the slave maintains, it checks if the slave is just in the process of adding to that list. If that’s the case, it postpones the update. If it went ahead and cleared the list, a race condition could cause the slave to throw a NullPointerException. However, the function is so short, I don’t know why it would be spending so much time in it. I also don’t know if it’s not returning or just calling it so often and at such a high frequency that it appears stuck in there.

Here’s the code for SyncPointRecorder:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
 * Class that records synchronization points.
 *
 * @author Mathias Ricken
 */

@IncludeInRuntime
public class SyncPointRecorder {
    /**
     * List of synchronization points.
     */

    private static volatile ArrayList<ISyncPoint> _syncPoints =
        new ArrayList<ISyncPoint>();

    /**
     * Adds a synchronization point to the list.
     * Note: This method has to be synchronized,
     * but it may NOT be instrumented as such!
     * An infinite recursion would be the result.
     * The monitor application has to check that
     * no thread is currently holding the lock on
     * SyncPointerRecorder.class.
     * Only then may it clear the list.
     * @param sp synchronization point to add.
     */

    public static synchronized void add(ISyncPoint sp) {
        if (_syncPoints==null) {
            _syncPoints = new ArrayList<ISyncPoint>();
        }
        _syncPoints.add(sp);
    }
}

This isn’t an optimal solution, but it should work. It might make sense to change this to a custom data structure, maybe a resizeable ring buffer, but I don’t think that’s what’s causing the program to hang.

I have the frightening feeling that completeness and robustness are inversely proportional, with a very disadvantageous proportionality constant…

Share

About Mathias

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

Leave a Reply