Java Path Finder

Java Path Finder(JPF) is a model checker for Java programs and can check concurrent programs for deadlocks and data races which are more serious in muti-core environments. Java threads used by concurrent programs are context switched by the OS scheduler at run-time when we ‘yield’ a thread or due to some other reason. Even though it might be possible to test these scenarios extensively by profiling a few possible combinations of thread interleavings, it is quite tedious. So JPF tests this type of code by exploring all the code using algorithms to find errors.

JPF has quite a number of plug points and gov.nasa.jpf.jvm.VMListener is one such interface. I have implemented it to get data about the number of BLOCKED threads that the System Under Test(SUT) has and the monitor that they are blocked at. The data is still not clear but it is reasonable. I am not able to get clear data showing how many threads are blocked for a particular monitor to be released at a point in time. I think the code has to be refined.

JPF can be downloaded from http://babelfish.arc.nasa.gov/trac/jpf/ by using a mercurial eclipse plugin and it is quite easy to build and use.

I implemented gov.nasa.jpf.jvm.VMListener and added the classpath entry pointing to the class file to jpf-core.native_classpath

gov.nasa.jpf.jvm.VMListener based on JPF source code

public class LockContentionListener implements VMListener{


	@Override
	public void threadStarted(JVM vm) {
		printLocks( vm );
	}


	/**
	 * Thread and lock status.
	 * @param vm
	 */

	    private void printLocks( JVM jvm ){

		StringBuffer locksAndThreads = new StringBuffer();

		for ( ThreadInfo tf : jvm.getThreadList().getThreads()) {

		    ElementInfo ei = tf.getLockObject();
		    if (ei != null) {
		      if (tf.getState() == ThreadInfo.State.WAITING ||
				  tf.getState() == ThreadInfo.State.BLOCKED ) {
			  locksAndThreads.append( "\n");
			  locksAndThreads.append(tf.getStateDescription());
			  locksAndThreads.append(ei);
			  locksAndThreads.append(" \n Lock Count (" +                 ei.getMonitor().getNumberOfBlockedThreads()+ ")");

			    LinkedList locks = tf.getLockedObjects();
			    if (locks.isEmpty()) {
				locksAndThreads.append("  call stack:");
				    for (StackFrame frame : tf){
				      if (!frame.isDirectCallFrame()) {
					  locksAndThreads.append("\tat \n ");
					  locksAndThreads.append(frame.getStackTraceInfo());
				      }
				    }
			    }
				System.out.println( "Locks owned by Threads[ " + locksAndThreads + " \n ]");

		  }
		 }
		}
	    }

SUT

public class LockContention{
	
	private static final int NUM_THREADS = 2;
	
	
	public  static void main( String... argv ) throws InterruptedException {
		
		Thread[] readThreads = new Thread[ NUM_THREADS ];

		Locker locker = new Locker();
		
		for(  int i = 0 ; i < readThreads.length; i ++ ){
			
			readThreads[ i ] = new Thread( new ReadLockContention( locker ) ){
				
				public String getName(){
					return "LockContention (Reader)[ " + getId() + " ]";
				}
				
				
			};
		}

		Thread[] writeThreads = new Thread[ NUM_THREADS ];

		for( int i = 0 ; i < writeThreads.length; i ++ ){
			writeThreads[ i ] = new Thread( new WriteLockContention( locker ) ){

				public String getName(){
					return "LockContention (Writer)[" + getId() + " ]";
				}
				
			};
		}
		
		for( Thread t : readThreads ){
			t.start();
		}
		for( Thread t : writeThreads ){
			t.start();
		}
		for( Thread t : readThreads ){
			t.join();
		}

		for( Thread t : writeThreads ){
			t.join();
		}
		
	}


}

class ReadLockContention implements Runnable{
	
	private Locker locker;
	
	public ReadLockContention( Locker locker ){
		this.locker = locker;
	}

	@Override
	public void run() {
		locker.contendForReadLock();
		
	}

}

class WriteLockContention implements Runnable{
	
	private Locker locker;
	
	public WriteLockContention( Locker locker ){
		this.locker = locker;
	}

	@Override
	public void run() {
		locker.contendForWriteLock();
		
	}

}

class Locker{
	
	private final String lock = new String();

	/**
	 * Consider this as a read lock
	 */
	void contendForReadLock(){
			synchronized( lock ){
				try {
					Thread.sleep(50000);
				} catch (InterruptedException e) {
					System.out.println( "InterruptedException" );
			    }
				
			}
	}
	
	/**
	 * Consider this as a write lock
	 */
	void contendForWriteLock(){
			synchronized( lock ){
				
			}
	}
	
}

Output

The command

jpf +listener+=LockContentionListener LockContention.jpf

produces

Threads blocked on Locks[
thread id=2,name=Thread-2,status=BLOCKED,priority=5,lockCount=0,suspendCount=0java.lang.String@137
Lock Count (1) call stack: at
Locker.contendForReadLock(LockContention.java:97) at
ReadLockContention.run(LockContention.java:67)
]
Threads blocked on Locks[
thread id=1,name=Thread-1,status=BLOCKED,priority=5,lockCount=0,suspendCount=0java.lang.String@137
Lock Count (1) call stack: at
Locker.contendForReadLock(LockContention.java:97) at
ReadLockContention.run(LockContention.java:67)
]

The monitor is shown in bold. I want to know how many threads are blocked for a lock to be released.
It seems that these messages indicate that two threads(Thread-1,Thread-2) are blocked on the same monitor but I think this has to be investigated further. There is no reply to my forum question about this.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s

%d bloggers like this: