*** empty log message ***
authornavid <navid>
Wed, 4 Feb 2009 03:27:52 +0000 (03:27 +0000)
committernavid <navid>
Wed, 4 Feb 2009 03:27:52 +0000 (03:27 +0000)
60 files changed:
Robust/Transactions/TransactionalIO/src/TransactionalIO/benchmarks/benchmark.java
Robust/Transactions/TransactionalIO/src/TransactionalIO/core/ExtendedTransaction.java
Robust/Transactions/TransactionalIO/src/TransactionalIO/core/TransactionalFile.java
Robust/Transactions/dstm2/src/dstm2/Defaults.java
Robust/Transactions/dstm2/src/dstm2/SpecialLock.java [new file with mode: 0644]
Robust/Transactions/dstm2/src/dstm2/SpecialTransactionalFile.java [new file with mode: 0644]
Robust/Transactions/dstm2/src/dstm2/Thread.java
Robust/Transactions/dstm2/src/dstm2/manager/SpecialManager.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/EnteredMonitor.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/EventListener.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/EventListenerIfc.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/JavaAgent.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/LockIdGenerator.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/LockingContextIdCache.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/StaticEventListener.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/ThreadLocalEnteredMonitors.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/instrument/ClassTransformer.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/instrument/InstrumentConfig.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/instrument/InstrumentationUtilities.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/instrument/InstrumentedAttribute.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/instrument/MonitorEnterMethodAdapter.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/instrument/SimulateMethodSyncMethodAdapter.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/instrument/StackAnalyzeMethodVisitor.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/analyzer/Analyzer.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/analyzer/Cycle.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/analyzer/CycleDetector.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/analyzer/DuplicatedEdgesHandler.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/analyzer/GraphvizGenerator.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/analyzer/LockEdge.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/analyzer/LockGraphBuilder.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/analyzer/LockNode.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/common/Lock.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/common/LockingContext.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/common/contexts/ContextFileReader.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/common/contexts/ContextFileWriter.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/common/contexts/ContextMemory.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/common/contexts/ContextReaderIfc.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/common/contexts/ContextWriterIfc.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/common/events/EventFileReader.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/common/events/EventFileWriter.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/common/events/LockEventListenerIfc.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/transactionalinterfaces/Bool.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/transactionalinterfaces/HashMap.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/transactionalinterfaces/Intif.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/transactionalinterfaces/bytebuffer.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/transactionalinterfaces/jcbuffer.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/transactionalinterfaces/trEventListener.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/transactionalinterfaces/trHashMap.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/transactionalinterfaces/trLockingContext.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/util/BuildInformation.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/util/Counter.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/util/IdentityWeakHashMap.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/util/InvalidOptionException.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/util/MaxValueCounter.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/util/OptionFormatter.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/util/OptionParser.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/util/TransactionalCounter.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/util/logging/AppendableHandler.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/util/logging/Handler.java [new file with mode: 0644]
Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/util/logging/Logger.java [new file with mode: 0644]

index 4d9702317ff9e46624b17a54aa246b2716a89178..894f2123cb68d905ec52677b7dfc809f1d357199 100644 (file)
@@ -51,12 +51,12 @@ public class benchmark {
         try {
             byte[] data = new byte[1];
             char[] name = new char[20];
-            /*RandomAccessFile file = new RandomAccessFile("/scratch/TransactionalIO/FinancialTransactionBenchmarkFiles/namelist.text", "rw");
+            RandomAccessFile file = new RandomAccessFile("/scratch/TransactionalIO/FinancialTransactionBenchmarkFiles/namelist.text", "rw");
             RandomAccessFile file2 = new RandomAccessFile("/scratch/TransactionalIO/FinancialTransactionBenchmarkFiles/financialtransaction.text", "rw");
-            RandomAccessFile file3 = new RandomAccessFile("/scratch/TransactionalIO/FinancialTransactionBenchmarkFiles/accountbalance.text", "rw");*/
-            RandomAccessFile file = new RandomAccessFile("/home/navid/namelist.text", "rw");
+            RandomAccessFile file3 = new RandomAccessFile("/scratch/TransactionalIO/FinancialTransactionBenchmarkFiles/accountbalance.text", "rw");
+            /*RandomAccessFile file = new RandomAccessFile("/home/navid/namelist.text", "rw");
             RandomAccessFile file2 = new RandomAccessFile("/home/navid/financialtransaction.text", "rw");
-            RandomAccessFile file3 = new RandomAccessFile("/home/navid/accountbalance.text", "rw");
+            RandomAccessFile file3 = new RandomAccessFile("/home/navid/accountbalance.text", "rw");*/
             
             
            
@@ -199,56 +199,68 @@ public class benchmark {
             preparenamelist();
             count = 0;
             m = Collections.synchronizedMap(TransactionalFiles);
-            TransactionalFile tr = new TransactionalFile("/home/navid/randomwords.text", "rw");
+            //TransactionalFile tr = new TransactionalFile("/home/navid/randomwords.text", "rw");
+            TransactionalFile tr = new TransactionalFile("/scratch/TransactionalIO/PureIOBenchmarkFiles/randomwords.text", "rw");
             m.put(String.valueOf(count), tr);
             count++;
+            //TransactionalFile tr2 = new TransactionalFile("/home/navid/input.text", "rw");
             TransactionalFile tr2 = new TransactionalFile("/home/navid/input.text", "rw");
             m.put(String.valueOf(count), tr2);
             count++;
-            TransactionalFile tr3 = new TransactionalFile("/home/navid/iliad.text", "rw");
+            //TransactionalFile tr3 = new TransactionalFile("/home/navid/iliad.text", "rw");
+            TransactionalFile tr3 = new TransactionalFile("/scratch/TransactionalIO/WordCunterBenchmarkFiles/iliad.text", "rw");
             m.put(String.valueOf(count), tr3);
             count++;
-            TransactionalFile tr4 = new TransactionalFile("/home/navid/counter_benchmark_output.text", "rw");
-            m.put(String.valueOf(count), tr4);
+            //TransactionalFile tr4 = new TransactionalFile("/home/navid/counter_benchmark_output.text", "rw");
+            TransactionalFile tr4 = new TransactionalFile("/scratch/TransactionalIO/WordCunterBenchmarkFiles/counter_benchmark_output.text", "rw");
+            m.put("counteroutput", tr4);
+            //m.put(String.valueOf(count), tr4);
             count++;
 
-            TransactionalFile tr5 = new TransactionalFile("/home/navid/financialtransaction.text", "rw");
+            //TransactionalFile tr5 = new TransactionalFile("/home/navid/financialtransaction.text", "rw");
+            TransactionalFile tr5 = new TransactionalFile("/scratch/TransactionalIO/FinancialTransactionBenchmarkFiles/financialtransaction.text", "rw");
             m.put(String.valueOf(count), tr5);
 
             count++;
 
-            TransactionalFile tr6 = new TransactionalFile("/home/navid/accountbalance.text", "rw");
-            m.put(String.valueOf(count), tr6);
+            //TransactionalFile tr6 = new TransactionalFile("/home/navid/accountbalance.text", "rw");
+            TransactionalFile tr6 = new TransactionalFile("/scratch/TransactionalIO/FinancialTransactionBenchmarkFiles/accountbalance.text", "rw");
+            m.put("accountbalance", tr6);
+            //m.put(String.valueOf(count), tr6);
 
             count++;
 
-            TransactionalFile tr7 = new TransactionalFile("/home/navid/financialtransactionlog.text", "rw");
+            //TransactionalFile tr7 = new TransactionalFile("/home/navid/financialtransactionlog.text", "rw");
+            TransactionalFile tr7 = new TransactionalFile("/scratch/TransactionalIO/FinancialTransactionBenchmarkFiles/financialtransactionlog.text", "rw");
+            m.put("financialtransactionlog", tr7);
             m.put(String.valueOf(count), tr7);
-
             count++;
 
-            RandomAccessFile tr8 = new RandomAccessFile("/home/navid/accountbalance.text", "rw");
-            m.put(String.valueOf(count), tr8);
+            //RandomAccessFile tr8 = new RandomAccessFile("/home/navid/accountbalance.text", "rw");
+            RandomAccessFile tr8 = new RandomAccessFile("/scratch/TransactionalIO/FinancialTransactionBenchmarkFiles/accountbalance.text", "rw");
+            //m.put(String.valueOf(count), tr8);
+            m.put("accountbalancerandom", tr8);
 //
             count++;
 
-            RandomAccessFile tr9 = new RandomAccessFile("/home/navid/financialtransactionlog.text", "rw");
-            m.put(String.valueOf(count), tr9);
-
+            //RandomAccessFile tr9 = new RandomAccessFile("/home/navid/financialtransactionlog.text", "rw");
+            RandomAccessFile tr9 = new RandomAccessFile("/scratch/TransactionalIO/FinancialTransactionBenchmarkFiles/financialtransactionlog.text", "rw");
+            //m.put(String.valueOf(count), tr9);
+            m.put("financialtransactionlograndom", tr9);
             count++;
 
             int index = 97;
             for (int i = 0; i < 26; i++) {
-                     
-                //m.put(String.valueOf((char) (index+i)), new RandomAccessFile("/home/navid/" + String.valueOf((char) (index+i)) + ".text", "rw"));
-           
-                      m.put(String.valueOf((char) (index+i)), new TransactionalFile("/home/navid/" + String.valueOf((char) (index+i)) + ".text", "rw"));
-
-                           count++;
+                      m.put(String.valueOf((char) (index+i))+"random", new RandomAccessFile("/home/navid/" + String.valueOf((char) (index+i)) + ".text", "rw"));
+                      //m.put(String.valueOf((char) (index+i)), new TransactionalFile("/home/navid/" + String.valueOf((char) (index+i)) + ".text", "rw"));
+                      m.put(String.valueOf((char) (index+i)), new TransactionalFile("/scratch/TransactionalIO/PureIOBenchmarkFiles/" + String.valueOf((char) (index+i)) + ".text", "rw"));
+                      count++;
             }
                  
                
-            m.put(100, new RandomAccessFile("/home/navid/counter_benchmark_output.text", "rw"));   
+            //m.put(100, new RandomAccessFile("/home/navid/counter_benchmark_output.text", "rw"));   
+            m.put("counterdstm2output", new RandomAccessFile("/scratch/TransactionalIO/WordCunterBenchmarkFiles/counter_benchmark_output.text", "rw"));   
+            //m.put(100, new RandomAccessFile("/scratch/TransactionalIO/WordCunterBenchmarkFiles/counter_benchmark_output.text", "rw"));   
             /*count = 0;
             m = Collections.synchronizedMap(TransactionalFiles);
             TransactionalFile tr = new TransactionalFile("/scratch/TransactionalIO/PureIOBenchmarkFiles/randomwords.text", "rw");
@@ -322,6 +334,12 @@ public class benchmark {
             m2.put(Integer.valueOf(count), "masterfully");
             count++;
             m2.put(Integer.valueOf(count), "unweariable");
+            count++;
+        //    m2.put(Integer.valueOf(count), "Atreus");
+         //    count++;
+          //  m2.put(Integer.valueOf(count), "Olympus");
+        
+            
         } catch (FileNotFoundException ex) {
             Logger.getLogger(benchmark.class.getName()).log(Level.SEVERE, null, ex);
         }
index 5770302b5ce52ae55297a6d31654146513cbd43b..9f53876564dcb947e5725bc0d71c4fb030990066 100644 (file)
@@ -44,6 +44,7 @@ public class ExtendedTransaction implements TransactionStatu {
     {
         System.load("/home/navid/libkooni.so");
     }
+    
     private boolean flag = true;
     public TransactionStatu memorystate;
     private PropertyChangeSupport changes = new PropertyChangeSupport(this);
index a6e9e4633a467e1c3c889695c09c315324923499..f025376d863f58340843d9ef0e8f5f48f44c6338 100644 (file)
@@ -421,7 +421,7 @@ public class TransactionalFile implements Comparable {
                 int c, char2, char3;
                 int count = 0;
                 int chararr_count = 0;
-
+               // System.out.println("size " +bytearr);
                 read(bytearr);
 
                 while (count < utflen) {
index a5dae56e59d2d81af4bb3953e1da4fa9da57e143..1295e01797c48bf3087968a93025ce8b2e08ea45 100644 (file)
@@ -52,7 +52,7 @@ public class Defaults {
   /**
    * fully-qualified contention manager name
    **/
-  public static final String MANAGER = "dstm2.manager.BackoffManager";
+  public static final String MANAGER = "dstm2.manager.SpecialManager";
   /**
    * fully-qualified factory name
    **/
diff --git a/Robust/Transactions/dstm2/src/dstm2/SpecialLock.java b/Robust/Transactions/dstm2/src/dstm2/SpecialLock.java
new file mode 100644 (file)
index 0000000..33841af
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package dstm2;
+
+
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ *
+ * @author navid
+ */
+public class SpecialLock extends ReentrantLock{
+    private static SpecialLock instance = null;
+    private Transaction ownerTransaction = null;
+
+    private SpecialLock() {
+    }
+    
+    
+    public synchronized void lock(Transaction tr){
+        super.lock();
+        setOwnerTransaction(ownerTransaction);
+    }
+    
+    public synchronized void unlock(Transaction tr){
+        super.unlock();
+        setOwnerTransaction(null);
+    }
+    
+    public synchronized void setOwnerTransaction(Transaction tr){
+        ownerTransaction = tr;
+    }
+    
+    public synchronized Transaction getOwnerTransaction(){
+        return ownerTransaction;
+    }
+    
+    public synchronized static SpecialLock getSpecialLock(){
+        if (instance == null){ 
+            instance = new SpecialLock();
+            return instance;
+        }
+        else
+            return instance;    
+        
+    }
+
+}
diff --git a/Robust/Transactions/dstm2/src/dstm2/SpecialTransactionalFile.java b/Robust/Transactions/dstm2/src/dstm2/SpecialTransactionalFile.java
new file mode 100644 (file)
index 0000000..68e53da
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package dstm2;
+
+import TransactionalIO.core.Wrapper;
+import TransactionalIO.exceptions.AbortedException;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+/**
+ *
+ * @author navid
+ */
+public class SpecialTransactionalFile{
+    
+    RandomAccessFile raFile;
+    
+    public SpecialTransactionalFile(File arg0, String arg1) throws FileNotFoundException {
+        raFile = new RandomAccessFile(arg0, arg1);
+    }
+
+    public SpecialTransactionalFile(String arg0, String arg1) throws FileNotFoundException {
+        raFile = new RandomAccessFile(arg0, arg1);
+    }
+
+    
+    private void checkConsisteny(){
+        Transaction me = Thread.getTransaction();
+        if (!me.isActive()) {
+                throw new AbortedException();
+        }
+        if (me != SpecialLock.getSpecialLock().getOwnerTransaction())
+            SpecialLock.getSpecialLock().lock(me);
+        
+        if (!me.isActive()) {
+                SpecialLock.getSpecialLock().unlock(me);
+                throw new AbortedException();
+        }
+        
+    }
+    
+    
+    public void close() throws IOException {
+        checkConsisteny();
+        raFile.close();
+    }
+
+    
+    public long getFilePointer() throws IOException {
+        checkConsisteny();
+        return raFile.getFilePointer();
+    }
+
+    
+    public long length() throws IOException {
+        checkConsisteny();
+        return raFile.length();
+    }
+
+    
+    public int read() throws IOException {
+        checkConsisteny();
+        return raFile.read();
+    }
+
+    
+    public int read(byte[] arg0, int arg1, int arg2) throws IOException {
+        checkConsisteny();
+        return raFile.read(arg0, arg1, arg2);
+    }
+
+    
+    public int read(byte[] arg0) throws IOException {
+        checkConsisteny();
+        return raFile.read(arg0);
+    }
+
+    
+    public void seek(long arg0) throws IOException {
+        checkConsisteny();
+        raFile.seek(arg0);
+    }
+
+    
+    public void setLength(long arg0) throws IOException {
+        checkConsisteny();
+        raFile.setLength(arg0);
+    }
+
+    
+    public int skipBytes(int arg0) throws IOException {
+        checkConsisteny();
+        return raFile.skipBytes(arg0);
+    }
+
+    
+    public void write(int arg0) throws IOException {
+        checkConsisteny();
+        raFile.write(arg0);
+    }
+
+    
+    public void write(byte[] arg0) throws IOException {
+        checkConsisteny();
+        raFile.write(arg0);
+    }
+
+    
+    public void write(byte[] arg0, int arg1, int arg2) throws IOException {
+        checkConsisteny();
+        raFile.write(arg0, arg1, arg2);
+    }
+    
+    public final void writeInt(int integer) throws IOException{
+        checkConsisteny();
+        raFile.writeInt(integer);
+    }
+    
+    public final int readInt() throws IOException{
+        checkConsisteny();
+        return raFile.readInt();
+    }
+    
+    public final void writeBoolean(boolean bool) throws IOException{
+        checkConsisteny();
+        raFile.writeBoolean(bool);
+    }
+    
+    public final boolean readBoolean() throws IOException{
+        checkConsisteny();
+        return raFile.readBoolean();
+    }
+    
+    public final void writeUTF(String val) throws IOException{
+        checkConsisteny();
+        raFile.writeUTF(val);
+    }
+    
+    public final String readUTF() throws IOException{
+        checkConsisteny();
+        return raFile.readUTF();
+    }
+    
+    public final void writeShort(short val) throws IOException{
+        checkConsisteny();
+        raFile.writeShort(val);
+    }
+    
+    public final short readShort() throws IOException{
+        checkConsisteny();
+        return raFile.readShort();
+    }
+    
+      public final void writeByte(byte arg0) throws IOException{
+        checkConsisteny();
+        raFile.writeByte(arg0);
+    }
+    
+    public final byte readByte() throws IOException{
+        checkConsisteny();
+        return raFile.readByte();
+    }
+    
+    public final void writeChar(int val) throws IOException{
+        checkConsisteny();
+        raFile.writeChar(val);
+    }
+    
+    public final char readChar() throws IOException{
+        checkConsisteny();
+        return raFile.readChar();
+    }
+    
+    public final void writeBytes(String val) throws IOException{
+        checkConsisteny();
+        raFile.writeBytes(val);
+    }
+    
+      public final void writeLong(long val) throws IOException{
+        checkConsisteny();
+        raFile.writeLong(val);
+    }
+    
+    public final long readLong() throws IOException{
+        checkConsisteny();
+        return raFile.readLong();
+    }
+    
+      public final void writeDouble(double arg0) throws IOException{
+        checkConsisteny();
+        raFile.writeDouble(arg0);
+    }
+    
+    public final double readDouble() throws IOException{
+        checkConsisteny();
+        return raFile.readDouble();
+    }
+    
+    public final void writeFloat(float val) throws IOException{
+        checkConsisteny();
+        raFile.writeFloat(val);
+    }
+    
+    public final float readFloat() throws IOException{
+        checkConsisteny();
+        return raFile.readFloat();
+    }
+    
+  
+    
+    
+    
+
+   
+    
+}
index ce56db126fd9c5092fcb99ac91bbbb1add0e3549..00bb5569cf7dc731abe09c02c95876f6b58f05fa 100644 (file)
@@ -42,6 +42,7 @@ import TransactionalIO.exceptions.PanicException;
 import dstm2.factory.AtomicFactory;
 import dstm2.factory.Factory;
 import TransactionalIO.benchmarks.benchmark;
+import dstm2.SpecialLock;
 import TransactionalIO.core.TransactionalFile;
 import TransactionalIO.core.Wrapper;
 import java.lang.reflect.Constructor;
@@ -286,7 +287,7 @@ public class Thread extends java.lang.Thread{
         }
         catch(AbortedException ex){
             threadState.depth--;
-          //  System.out.println("aborted");
+           // System.out.println(Thread.currentThread() + " aborted");
            // Wrapper.getTransaction().unlockAllLocks();
         }
         catch (Exception e) {
@@ -297,6 +298,8 @@ public class Thread extends java.lang.Thread{
             
             
             Wrapper.getTransaction().unlockAllLocks();
+            if (Thread.getTransaction() == SpecialLock.getSpecialLock().getOwnerTransaction())
+                SpecialLock.getSpecialLock().unlock(Thread.getTransaction());
             if  (flag == true)
                 break;
         }
diff --git a/Robust/Transactions/dstm2/src/dstm2/manager/SpecialManager.java b/Robust/Transactions/dstm2/src/dstm2/manager/SpecialManager.java
new file mode 100644 (file)
index 0000000..6f50871
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package dstm2.manager;
+
+import dstm2.SpecialLock;
+import dstm2.Transaction;
+
+/**
+ *
+ * @author navid
+ */
+public class SpecialManager extends PriorityManager{
+    
+    public void resolveConflict(Transaction me, Transaction other) {
+        if (me == SpecialLock.getSpecialLock().getOwnerTransaction())
+            other.abort();
+        else if (other == SpecialLock.getSpecialLock().getOwnerTransaction())
+            me.abort();
+
+        else 
+            super.resolveConflict(me, other);
+      }
+
+      public long getPriority() {
+        throw new UnsupportedOperationException();
+      }
+
+      public void setPriority(long value) {
+        throw new UnsupportedOperationException();
+      }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/EnteredMonitor.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/EnteredMonitor.java
new file mode 100644 (file)
index 0000000..35b0772
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.agent;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Each instance of this class represents an entered monitor.
+ *
+ * The reference to the monitor object is kept as a WeakReference internally in
+ * this class and won't prevent the monitor from being garbage collected.
+ *
+ * TODO Add basic test for the WeakReference handling.
+ */
+final class EnteredMonitor {
+    private final WeakReference mMonitorRef;
+    private final int mLockingContextId;
+    private final int mLockId;
+
+    EnteredMonitor(Object monitor,
+                   int lockId,
+                   int lockingContextId) {
+        mLockId = lockId;
+        mLockingContextId = lockingContextId;
+        mMonitorRef = new WeakReference<Object>(monitor);
+    }
+
+    Object getMonitorIfStillHeld() {
+        final Object monitor = mMonitorRef.get();
+        /*
+         * TODO The call to Thread.holdsLock takes long time. It would be
+         * interesting to test how the performance would be affected if this
+         * code is removed and replaced by an event for each MonitorExit and
+         * each finished synchronized method.
+         */
+        if (monitor != null && Thread.holdsLock(monitor)) {
+            return monitor;
+        } else {
+            return null;
+        }
+    }
+
+    int getLockingContextId() {
+        return mLockingContextId;
+    }
+
+    int getLockId() {
+        return mLockId;
+    }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/EventListener.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/EventListener.java
new file mode 100644 (file)
index 0000000..214dd4c
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.agent;
+
+import static com.enea.jcarder.common.contexts.ContextFileReader.EVENT_DB_FILENAME;
+import static com.enea.jcarder.common.contexts.ContextFileReader.CONTEXTS_DB_FILENAME;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Iterator;
+
+//import net.jcip.annotations.ThreadSafe;
+
+import com.enea.jcarder.common.LockingContext;
+import com.enea.jcarder.common.contexts.ContextFileWriter;
+import com.enea.jcarder.common.contexts.ContextWriterIfc;
+import com.enea.jcarder.common.events.EventFileWriter;
+import com.enea.jcarder.common.events.LockEventListenerIfc;
+import com.enea.jcarder.transactionalinterfaces.trEventListener;
+import com.enea.jcarder.util.Counter;
+//import com.enea.jcarder.util.TransactionalCounter;
+import com.enea.jcarder.util.TransactionalCounter;
+import com.enea.jcarder.util.logging.Logger;
+
+import dstm2.Thread;
+
+//@ThreadSafe
+import java.util.Vector;
+import java.util.concurrent.Callable;
+import java.util.logging.Level;
+final class EventListener implements EventListenerIfc {
+    trEventListener listener;
+    private final ThreadLocalEnteredMonitors mEnteredMonitors;
+    private final LockEventListenerIfc mLockEventListener;
+    private final LockIdGenerator mLockIdGenerator;
+    private final LockingContextIdCache mContextCache;
+    private final Logger mLogger;
+    //private final Counter mNumberOfEnteredMonitors;
+    private final TransactionalCounter trmNumberOfEnteredMonitors;
+
+    public static EventListener create(Logger logger, File outputdir)
+    throws IOException {
+        EventFileWriter eventWriter =
+            new EventFileWriter(logger,
+                                new File(outputdir, EVENT_DB_FILENAME));
+        ContextFileWriter contextWriter =
+            new ContextFileWriter(logger,
+                                  new File(outputdir, CONTEXTS_DB_FILENAME));
+        return new EventListener(logger, eventWriter, contextWriter);
+    }
+
+    public EventListener(Logger logger,
+                         LockEventListenerIfc lockEventListener,
+                         /*ContextWriterIfc contextWriter*/ContextFileWriter contextWriter) {
+        
+          mLogger = logger;
+        mEnteredMonitors = new ThreadLocalEnteredMonitors();
+        mLockEventListener = lockEventListener;
+        mLockIdGenerator = new LockIdGenerator(mLogger, contextWriter);
+        mContextCache = new LockingContextIdCache(mLogger, contextWriter);
+       // mNumberOfEnteredMonitors =
+       //     new Counter("Entered Monitors", mLogger, 100000);
+        
+        trmNumberOfEnteredMonitors =
+            new TransactionalCounter("Entered Monitors", mLogger, 100000);
+        
+  /*      listener = new trEventListener();
+        listener.atmoicfileds = trEventListener.factory.create();
+        this.listener.atmoicfileds.setCCByteBuffer(this.getMContextCache().getMContextWriter().getMbuff().mbuffer);
+        listener.atmoicfileds.setCCPosiiton(getMContextCache().getMContextWriter().getTest().pos);
+        listener.atmoicfileds.setCCShutdown(getMContextCache().getMContextWriter().getShutdownHookExecuted().boolif);
+
+      
+        listener.atmoicfileds.setHMap1Capacity(getMContextCache().getMCache().capacity);
+        listener.atmoicfileds.setHMap1Position(getMContextCache().getMCache().position);
+        listener.atmoicfileds.setHMap1Values(getMContextCache().getMCache().values);
+       
+        listener.atmoicfileds.setELNumberofMonitors(getTrmNumberOfEnteredMonitors().mValue);
+      
+        listener.atmoicfileds.setLIGByteBuffer(getMLockIdGenerator().getMContextWriter().getMbuff().mbuffer);
+        listener.atmoicfileds.setLIGPosiiton(getMLockIdGenerator().getMContextWriter().getTest().pos);
+        listener.atmoicfileds.setLIGShutdown(getMLockIdGenerator().getMContextWriter().getShutdownHookExecuted().boolif);
+      
+        listener.atmoicfileds.setHMap2Capacity(getMLockIdGenerator().getMIdMap().capacity);
+        listener.atmoicfileds.setHMap2Position(getMLockIdGenerator().getMIdMap().position);
+        listener.atmoicfileds.setHMap2Values(getMLockIdGenerator().getMIdMap().values);
+      
+        listener.atmoicfileds.setEFWByteBuffer(((EventFileWriter)this.getMLockEventListener()).getMbuff().mbuffer);
+        listener.atmoicfileds.setEFWShutdown(((EventFileWriter)this.getMLockEventListener()).getShutdownHookExecuted().boolif);
+        listener.atmoicfileds.setEFWCounter(((EventFileWriter)this.getMLockEventListener()).getTrmWrittenLockEvents().mValue);*/
+      
+      
+    }
+    
+    
+      public EventListener(EventListener other) {
+        this.mLogger = other.mLogger;
+        this.mEnteredMonitors = other.mEnteredMonitors;
+        this.trmNumberOfEnteredMonitors = other.trmNumberOfEnteredMonitors;
+        //this.trmNumberOfEnteredMonitors.mValue.setPosition(other.trmNumberOfEnteredMonitors.mValue.getPosition());
+        this.mContextCache = new LockingContextIdCache(other.mContextCache);
+        this.mLockIdGenerator =new LockIdGenerator(other.mLockIdGenerator);
+        this.mLockEventListener = new EventFileWriter((EventFileWriter) (other.mLockEventListener));
+    }
+
+    public void beforeMonitorEnter(Object monitor, LockingContext context)
+    throws Exception {
+        mLogger.finest("EventListener.beforeMonitorEnter");
+        Iterator<EnteredMonitor> iter = mEnteredMonitors.getIterator();
+        while (iter.hasNext()) {
+            Object previousEnteredMonitor = iter.next().getMonitorIfStillHeld();
+            if (previousEnteredMonitor == null) {
+                iter.remove();
+            } else if (previousEnteredMonitor == monitor) {
+                return; // Monitor already entered.
+            }
+        }
+        //enteringNewMonitor(monitor, context);
+        enteringNewMonitor(monitor, context);
+        
+    }
+
+ /*   private synchronized  void enteringNewMonitor(Object monitor,
+                                                 LockingContext context)
+    throws Exception {
+        mNumberOfEnteredMonitors.increment();
+        int newLockId = mLockIdGenerator.acquireLockId(monitor);
+        System.out.println("monitor " + monitor.getClass());
+        int newContextId = mContextCache.acquireContextId(context);
+        
+        EnteredMonitor lastMonitor = mEnteredMonitors.getFirst();
+        if (lastMonitor != null) {
+            java.lang.Thread performingThread = Thread.currentThread();
+            mLockEventListener.onLockEvent(newLockId,
+                                           newContextId,
+                                           lastMonitor.getLockId(),
+                                           lastMonitor.getLockingContextId(),
+                                           performingThread.getId());
+        }
+        mEnteredMonitors.addFirst(new EnteredMonitor(monitor,
+                                                     newLockId,
+                                                     newContextId));
+        
+    }*/
+    
+    private void trenteringNewMonitor(Vector arguments)
+    throws Exception {
+        
+        trmNumberOfEnteredMonitors.increment();
+        final int newLockId = mLockIdGenerator.acquireLockId((Object)arguments.get(1));
+        final int newContextId = mContextCache.acquireContextId((LockingContext)arguments.get(0));
+        arguments.add(newLockId);
+        arguments.add(newContextId);
+        
+        EnteredMonitor lastMonitor = mEnteredMonitors.getFirst();
+        if (lastMonitor != null) {
+            java.lang.Thread performingThread = Thread.currentThread();
+            Vector args = new Vector();
+            
+            
+            
+            args.add(newLockId);
+            args.add(newContextId);
+            args.add(lastMonitor.getLockId());
+            args.add(lastMonitor.getLockingContextId());
+            args.add(performingThread.getId());
+            
+            mLockEventListener.tronLockEvent(args);
+        }
+      //  mEnteredMonitors.addFirst(new EnteredMonitor((Object)context.get(1),
+      //                                               newLockId,
+        //                                             newContextId));
+        
+    }
+    
+    
+    
+   private synchronized void enteringNewMonitor(Object monitor,
+                                                 LockingContext context)
+    throws Exception {
+         final Vector arguments = new Vector();
+         arguments.add(context);
+         arguments.add(monitor);
+         Thread.doIt(new Callable<Boolean>() {
+          public Boolean call() throws Exception {
+                trenteringNewMonitor(arguments);
+                
+                return true;
+          }
+        });
+      //  System.out.println(arguments.size());
+        mEnteredMonitors.addFirst(new EnteredMonitor(monitor, ((Integer)(arguments.get(2))).intValue(), ((Integer)(arguments.get(3))).intValue()));
+        
+        arguments.clear();
+       
+    }
+
+    public LockingContextIdCache getMContextCache() {
+        return mContextCache;
+    }
+
+    public ThreadLocalEnteredMonitors getMEnteredMonitors() {
+        return mEnteredMonitors;
+    }
+
+    public LockEventListenerIfc getMLockEventListener() {
+        return mLockEventListener;
+    }
+
+    public LockIdGenerator getMLockIdGenerator() {
+        return mLockIdGenerator;
+    }
+
+    public Logger getMLogger() {
+        return mLogger;
+    }
+
+    public TransactionalCounter getTrmNumberOfEnteredMonitors() {
+        return trmNumberOfEnteredMonitors;
+    }
+   
+   
+   
+   
+   
+  
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/EventListenerIfc.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/EventListenerIfc.java
new file mode 100644 (file)
index 0000000..3872f98
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.agent;
+
+import com.enea.jcarder.common.LockingContext;
+import dstm2.AtomicSuperClass;
+
+public interface EventListenerIfc extends AtomicSuperClass{
+
+    void beforeMonitorEnter(Object monitor,
+                            LockingContext context) throws Exception;
+
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/JavaAgent.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/JavaAgent.java
new file mode 100644 (file)
index 0000000..a37c652
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.agent;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.lang.instrument.Instrumentation;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+
+import com.enea.jcarder.agent.instrument.ClassTransformer;
+import com.enea.jcarder.agent.instrument.InstrumentConfig;
+import com.enea.jcarder.util.BuildInformation;
+import com.enea.jcarder.util.logging.AppendableHandler;
+import com.enea.jcarder.util.logging.Handler;
+import com.enea.jcarder.util.logging.Logger;
+import dstm2.Init;
+
+/**
+ * This is the main class of the JCarder Java agent. It will initialize JCarder
+ * and register a ClassTransformer that is called by the JVM each time a class
+ * is loaded.
+ */
+public final class JavaAgent {
+
+    private static final String DUMP_PROPERTY = "jcarder.dump";
+    private static final String LOGLEVEL_PROPERTY = "jcarder.loglevel";
+    private static final String LOG_FILENAME = "jcarder.log";
+
+    private final InstrumentConfig mConfig = new InstrumentConfig();
+    private Logger mLogger;
+    PrintWriter mLogWriter;
+    private File mOutputDir;
+    private Logger.Level mLogLevel;
+    private static final String OUTPUTDIR_PROPERTY = "jcarder.outputdir";
+
+    private JavaAgent() { }
+
+    /**
+     * This method is called by the JVM when the JVM is started with the
+     * -javaagent command line parameter.
+     */
+    public static void premain(final String args,
+                               final Instrumentation instrumentation)
+    throws Exception {
+         Init.init();
+        JavaAgent javaAgent = new JavaAgent();
+        javaAgent.init(instrumentation);
+    }
+
+    private void init(Instrumentation instrumentation)
+    throws Exception {
+        handleProperties();
+        initLogger();
+        mLogger.info("Starting " + BuildInformation.getShortInfo() + " agent");
+        logJvmInfo();
+        EventListener listener = EventListener.create(mLogger, mOutputDir);
+        ClassTransformer classTransformer =
+            new ClassTransformer(mLogger, mOutputDir, mConfig);
+        instrumentation.addTransformer(classTransformer);
+        StaticEventListener.setListener(listener);
+        mLogger.info("JCarder agent initialized\n");
+    }
+
+    private void initLogger() {
+        File logFile = new File(mOutputDir, LOG_FILENAME);
+        if (logFile.exists()) {
+            logFile.delete();
+        }
+        FileWriter fileWriter;
+        try {
+            fileWriter = new FileWriter(logFile);
+        } catch (IOException e) {
+            System.err.println("Failed to open log file \""
+                               + logFile + "\": " + e.getMessage());
+            return;
+        }
+        mLogWriter = new PrintWriter(new BufferedWriter(fileWriter));
+        AppendableHandler fileHandler = new AppendableHandler(mLogWriter);
+        AppendableHandler consoleHandler =
+            new AppendableHandler(System.err, Logger.Level.INFO, "{message}\n");
+
+        Thread hook = new Thread() {
+            public void run() {
+                mLogWriter.flush();
+            }
+        };
+        Runtime.getRuntime().addShutdownHook(hook);
+
+        Collection<Handler> handlers = new ArrayList<Handler>();
+        handlers.add(fileHandler);
+        handlers.add(consoleHandler);
+        mLogger = new Logger(handlers, mLogLevel);
+    }
+
+    private void logJvmInfo() {
+        Enumeration<?> properties = System.getProperties().propertyNames();
+        while (properties.hasMoreElements()) {
+            String key = (String) properties.nextElement();
+            if (key.startsWith("java.vm.")) {
+                mLogger.config(key + ": " + System.getProperty(key));
+            }
+        }
+    }
+
+    private void handleProperties() throws IOException {
+        handleDumpProperty();
+        handleLogLevelProperty();
+        handleOutputDirProperty();
+    }
+
+    private void handleDumpProperty() {
+        mConfig.setDumpClassFiles(Boolean.getBoolean(DUMP_PROPERTY));
+    }
+
+    private void handleLogLevelProperty() {
+        String logLevelValue = System.getProperty(LOGLEVEL_PROPERTY, "fine");
+        Logger.Level logLevel = Logger.Level.fromString(logLevelValue);
+        if (logLevel != null) {
+            mLogLevel = logLevel;
+        } else {
+            System.err.print("Bad loglevel; should be one of ");
+            System.err.println(Logger.Level.getEnumeration());
+            System.err.println();
+            System.exit(1);
+        }
+    }
+
+    private void handleOutputDirProperty() throws IOException {
+        final String property = System.getProperty(OUTPUTDIR_PROPERTY, ".");
+        mOutputDir = new File(property).getCanonicalFile();
+        if (!mOutputDir.isDirectory()) {
+            mOutputDir.mkdirs();
+        }
+    }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/LockIdGenerator.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/LockIdGenerator.java
new file mode 100644 (file)
index 0000000..847e3d1
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.agent;
+
+import java.io.IOException;
+//import net.jcip.annotations.NotThreadSafe;
+
+import com.enea.jcarder.common.Lock;
+import com.enea.jcarder.common.contexts.ContextFileWriter;
+import com.enea.jcarder.common.contexts.ContextWriterIfc;
+//import com.enea.jcarder.transactionalinterfaces.trHashMap;
+import com.enea.jcarder.util.IdentityWeakHashMap;
+import com.enea.jcarder.util.logging.Logger;
+import dstm2.util.IntHashMap;
+import com.enea.jcarder.transactionalinterfaces.Intif;
+//import java.util.HashMap;
+import sun.misc.VM;
+
+/**
+ * This class is responsible for generating unique IDs for objects.
+ *
+ * We cannot use System.identityHashCode(o) since it returns random numbers,
+ * which are not guaranteed to be unique.
+ *
+ * TODO Add basic tests for this class.
+ */
+//@NotThreadSafe
+final class LockIdGenerator {
+    //private final IdentityWeakHashMap<Integer> mIdMap;
+   // private final HashMap<Intif.positionif> mIdMap;
+    private final IntHashMap mIdMap;
+    //private final ContextWriterIfc mContextWriter;
+    private final ContextFileWriter mContextWriter;
+    private final Logger mLogger;
+
+    /**
+     * Create a LockIdGenerator backed by a ContextWriterIfc
+     */
+    public LockIdGenerator(LockIdGenerator other){
+        this.mIdMap = other.mIdMap;
+       // this.mIdMap.values.setValues(other.mIdMap.values.getValues());
+       // this.mIdMap.position.setPosition(other.mIdMap.position.getPosition());
+       // this.mIdMap.capacity.setPosition(other.mIdMap.capacity.getPosition());
+        //this.mIdMap.keys = other.mIdMap.keys;
+        this.mContextWriter = other.mContextWriter;
+        this.mLogger = other.mLogger;
+        
+        
+    }
+    
+    public LockIdGenerator(Logger logger, /*ContextWriterIfc writer*/ContextFileWriter writer) {
+        mLogger = logger;
+       // mIdMap = new IdentityWeakHashMap<Integer>();
+//        mIdMap = new HashMap<Intif.positionif>();
+        mIdMap = new IntHashMap();
+        mContextWriter = writer;
+
+    }
+
+    /**
+     * Return an ID for a given object.
+     *
+     * If the method is invoked with the same object instance more than once it
+     * is guaranteed that the same ID is returned each time. Two objects that
+     * are not identical (as compared with "==") will get different IDs.
+     */
+    public int acquireLockId(Object o) throws IOException {
+        assert o != null;
+        Integer id = (Integer)mIdMap.get(System.identityHashCode(o));
+     //   if (mIdMap.get(HashMap.hash(o)) == null){
+        if (id == null){
+            id = mContextWriter.writeLock(new Lock(o));        
+           // Intif.positionif tmp = Intif.factory.create();
+           // tmp.setPosition(id);
+           // mIdMap.put(HashMap.hash(o), tmp);
+             //mIdMap.put(o, tmp);
+            mIdMap.put(System.identityHashCode(o), id);
+            mLogger.finest("Created new lock ID: " + id);        
+        }
+       // else 
+     //       id = mIdMap.get(HashMap.hash(o)).getPosition();
+       
+      /* if (id == null) {
+            id = mContextWriter.writeLock(new Lock(o));
+            tmp.setPosition(id);
+            mIdMap.put(System.identityHashCode(o), tmp);
+            mLogger.finest("Created new lock ID: " + id);
+        }*/
+        return id;
+    }
+
+    public ContextFileWriter getMContextWriter() {
+        return mContextWriter;
+    }
+
+
+
+    public Logger getMLogger() {
+        return mLogger;
+    }
+    
+    
+    
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/LockingContextIdCache.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/LockingContextIdCache.java
new file mode 100644 (file)
index 0000000..aa82b91
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.agent;
+
+import java.io.IOException;
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
+
+
+//import dstm2.util.HashMap;
+//import net.jcip.annotations.NotThreadSafe;
+
+import com.enea.jcarder.common.LockingContext;
+import com.enea.jcarder.common.contexts.ContextFileWriter;
+import com.enea.jcarder.common.contexts.ContextWriterIfc;
+import com.enea.jcarder.transactionalinterfaces.Intif;
+import com.enea.jcarder.transactionalinterfaces.trHashMap;
+import com.enea.jcarder.util.logging.Logger;
+import dstm2.util.IntHashMap;
+//import dstm2.util.HashMap;
+
+/**
+ * This class is responsible for mapping LockingContext instances to locking
+ * context IDs. It maintains a cache to be able to return the same ID again if
+ * an ID is requested for the same or equal LockingContext more than once.
+ *
+ * This class is similar to the java.util.WeakHashMap but uses soft references
+ * instead of weak references in order to try to keep the entries in the cache
+ * as long as there is enough memory available.
+ *
+ * TODO An alternative implementation to consider could be to only store the
+ * hashCode in a map and perform a comparison with the Context file file
+ * (possibly memory mapped). I don't know how that would affect the performance.
+ * Another option to consider would be to use a plain HashMap without
+ * SoftReferences and accept the potential memory problem as a trade-of for
+ * better performance (?) and to avoid getting different IDs for duplicated
+ * LockingContexts.
+ *
+ * TODO Add basic tests for this class.
+ */
+//@NotThreadSafe
+final class LockingContextIdCache {
+    //private final HashMap<EqualsComparableKey, Integer> mCache;
+    //private final HashMap<Intif.positionif> mCache;
+    private final IntHashMap mCache;
+    //private final ReferenceQueue<Object> mReferenceQueue;
+    //private final ContextWriterIfc mContextWriter;
+    private final ContextFileWriter mContextWriter;
+    private final Logger mLogger;
+    
+
+    /**
+     * Create a LockingContextIdCache backed by a ContextWriterIfc.
+     */
+    public LockingContextIdCache(LockingContextIdCache other){
+        this.mCache = other.mCache;
+       // this.mCache.values.setValues(other.mCache.values.getValues());
+       //this.mCache.position.setPosition(other.mCache.position.getPosition());
+       //this.mCache.capacity.setPosition(other.mCache.capacity.getPosition());
+       //this.mCache.keys = other.mCache.keys;;
+        this.mContextWriter = other.mContextWriter;
+        this.mLogger = other.mLogger;
+        
+    }
+    
+    public LockingContextIdCache(Logger logger, ContextWriterIfc writer) {
+        mLogger = logger;
+        //mCache = new HashMap<EqualsComparableKey, Integer>();
+//       mCache = new HashMap<Intif.positionif>();
+       mCache = new IntHashMap();
+     //   mReferenceQueue = new ReferenceQueue<Object>();
+        mContextWriter = (ContextFileWriter) writer;
+    }
+
+    /**
+     * Acquire a unique ID for the provided LockingContext. The ID will be
+     * cached. If a provided LockingContext is equal to a previously provided
+     * LockingContext that is still in the cache, the same ID will be returned.
+     *
+     * The equality is checked with the LockingContext.equals(Object other)
+     * method.
+     */
+    public int acquireContextId(LockingContext context) throws IOException {
+        assert context != null;
+       // removeGarbageCollectedKeys();
+        //Integer id = mCache.get(new StrongKey(context));
+        Integer id = mCache.get(context.hashCode());
+      //  if (mCache.get(HashMap.hash(context)) == null) {
+        if (id == null){
+            mLogger.finest("Creating new context ID");
+            id = mContextWriter.writeContext(context);
+           //mCache.put((new SoftKey(context, mReferenceQueue)), id);
+         //   Intif.positionif tmp =  Intif.factory.create();
+           // tmp.setPosition(id);
+            //intval.setPosition(id);
+          //  mCache.put(HashMap.hash(context),tmp);
+            mCache.put(context.hashCode(),id);
+        }   
+        //else 
+          //  id = mCache.get(HashMap.hash(context)).getPosition();
+        return id;
+    }
+
+    public IntHashMap getMCache() {
+        return mCache;
+    }
+
+    public ContextFileWriter getMContextWriter() {
+        return mContextWriter;
+    }
+
+    public Logger getMLogger() {
+        return mLogger;
+    }
+    
+    
+
+ /*   private void removeGarbageCollectedKeys() {
+        Reference e;
+        while ((e = mReferenceQueue.poll()) != null) {
+            mLogger.finest("Removing garbage-collected cached context");
+            mCache.remove(e);
+        }
+    }
+
+    private static interface EqualsComparableKey {
+        Object get();
+        boolean equals(Object obj);
+        int hashCode();
+    }
+
+    private static class StrongKey implements EqualsComparableKey {
+        private final Object mReferent;
+
+        StrongKey(Object referent) {
+            assert referent != null;
+            mReferent = referent;
+        }
+
+        public Object get() {
+            return mReferent;
+        }
+
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            try {
+                EqualsComparableKey reference = (EqualsComparableKey) obj;
+                return mReferent.equals(reference.get());
+            } catch (ClassCastException e) {
+                return false;
+            }
+        }
+
+        public int hashCode() {
+            return mReferent.hashCode();
+        }
+    }
+
+    private static class SoftKey extends SoftReference<LockingContext>
+    implements EqualsComparableKey {
+        private final int mHash;
+
+        SoftKey(LockingContext referent, ReferenceQueue<Object> queue) {
+            super(referent, queue);
+            assert referent != null;
+            mHash = referent.hashCode();
+        }
+
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            try {
+                Object otherReferent = ((EqualsComparableKey) obj).get();
+                Object thisReferent = get();
+                return (thisReferent != null
+                        && otherReferent != null
+                        && thisReferent.equals(otherReferent));
+            } catch (ClassCastException e) {
+                return false;
+            }
+        }
+
+        public int hashCode() {
+            return mHash;
+        }
+    }*/
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/StaticEventListener.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/StaticEventListener.java
new file mode 100644 (file)
index 0000000..727312d
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.agent;
+
+//import net.jcip.annotations.ThreadSafe;
+import com.enea.jcarder.common.LockingContext;
+import com.enea.jcarder.common.events.EventFileWriter;
+import com.enea.jcarder.transactionalinterfaces.trEventListener;
+import dstm2.AtomicSuperClass;
+import java.util.concurrent.Callable;
+import dstm2.Thread;
+import java.util.HashMap;
+import java.util.Vector;
+
+/**
+ * This class provides static methods that are supposed to be invoked directly
+ * from the instrumented classes.
+ */
+//@ThreadSafe
+public final class StaticEventListener{
+
+    private StaticEventListener() { }
+    //private static EventListenerIfc smListener;
+    private static EventListenerIfc smListener;
+    private static HashMap map= new HashMap();
+    
+
+    //public synchronized static void setListener(EventListenerIfc listener) {
+      //  smListener = (EventListener)listener;
+    //}
+    
+    public  static void trsetListener(Vector listener) {
+        //smListener = ((EventListener)(arg.get(0)));
+        smListener = (EventListenerIfc)listener.get(0);
+    //  smListener = new EventListener((EventListener)(arg.get(0)));
+   //   smListener.listener = new trEventListener();
+     // smListener.listener.atmoicfileds = trEventListener.factory.create();
+    //  smListener.listener.atmoicfileds = ((EventListener)(arg.get(0))).listener.atmoicfileds;
+      
+      /*smListener2.atmoicfileds.setCCByteBuffer(((EventListener)(arg.get(0))).getMContextCache().getMContextWriter().getMbuff().mbuffer);
+      smListener2.atmoicfileds.setCCPosiiton(((EventListener)(arg.get(0))).getMContextCache().getMContextWriter().getTest().pos);
+      smListener2.atmoicfileds.setCCShutdown(((EventListener)(arg.get(0))).getMContextCache().getMContextWriter().getShutdownHookExecuted().boolif);
+      
+      
+      
+      smListener2.atmoicfileds.setHMap1Capacity(((EventListener)(arg.get(0))).getMContextCache().getMCache().capacity);
+      smListener2.atmoicfileds.setHMap1Position(((EventListener)(arg.get(0))).getMContextCache().getMCache().position);
+      smListener2.atmoicfileds.setHMap1Values(((EventListener)(arg.get(0))).getMContextCache().getMCache().values);
+      
+      smListener2.atmoicfileds.setELNumberofMonitors(((EventListener)(arg.get(0))).getTrmNumberOfEnteredMonitors().mValue);
+      
+      smListener2.atmoicfileds.setLIGByteBuffer(((EventListener)(arg.get(0))).getMLockIdGenerator().getMContextWriter().getMbuff().mbuffer);
+      smListener2.atmoicfileds.setLIGPosiiton(((EventListener)(arg.get(0))).getMLockIdGenerator().getMContextWriter().getTest().pos);
+      smListener2.atmoicfileds.setLIGShutdown(((EventListener)(arg.get(0))).getMLockIdGenerator().getMContextWriter().getShutdownHookExecuted().boolif);
+      
+      smListener2.atmoicfileds.setHMap2Capacity(((EventListener)(arg.get(0))).getMLockIdGenerator().getMIdMap().capacity);
+      smListener2.atmoicfileds.setHMap2Position(((EventListener)(arg.get(0))).getMLockIdGenerator().getMIdMap().position);
+      smListener2.atmoicfileds.setHMap2Values(((EventListener)(arg.get(0))).getMLockIdGenerator().getMIdMap().values);
+      
+      smListener2.atmoicfileds.setEFWByteBuffer(((EventFileWriter)((EventListener)(arg.get(0))).getMLockEventListener()).getMbuff().mbuffer);
+      smListener2.atmoicfileds.setEFWShutdown(((EventFileWriter)((EventListener)(arg.get(0))).getMLockEventListener()).getShutdownHookExecuted().boolif);
+      smListener2.atmoicfileds.setEFWCounter(((EventFileWriter)((EventListener)(arg.get(0))).getMLockEventListener()).getTrmWrittenLockEvents().mValue);*/
+      
+    }
+    
+    public  static void setListener(EventListenerIfc listener) {
+         final Vector arg = new Vector();
+         arg.add(listener);
+         Thread.doIt(new Callable<Boolean>() {
+          public Boolean call() throws Exception {
+                trsetListener(arg);
+                return true;
+          }
+        });
+    }
+        
+   // }
+
+    public static EventListenerIfc trgetListener() {
+    /*  
+        ((EventListener)smListener).getMContextCache().getMCache().capacity.getPosition();
+        ((EventListener)smListener).getMContextCache().getMCache().position.getPosition();
+        ((EventListener)smListener).getMContextCache().getMCache().values.getValues();
+        ((EventListener)smListener).getTrmNumberOfEnteredMonitors().mValue.getPosition();
+        ((EventListener)smListener).getMLockIdGenerator().getMIdMap().capacity.getPosition();
+        ((EventListener)smListener).getMLockIdGenerator().getMIdMap().position.getPosition();
+        ((EventListener)smListener).getMLockIdGenerator().getMIdMap().values.getValues();*/
+        return smListener;
+    }
+    
+    public  static EventListenerIfc getListener() {
+        return Thread.doIt(new Callable<EventListenerIfc>() {
+          public EventListenerIfc call() throws Exception {
+                return trgetListener();
+          }
+        });
+        
+    }
+
+    /**
+     * This method is expected to be called from the instrumented classes.
+     *
+     * @param monitor
+     *            The monitor object that was acquired. This value is allowed to
+     *            be null.
+     *
+     * @param lockReference
+     *            A textual description of how the lock object was addressed.
+     *            For example: "this", "com.enea.jcarder.Foo.mBar" or
+     *            "com.enea.jcarder.Foo.getLock()".
+     *
+     * @param methodWithClass
+     *            The method that acquired the lock, on the format
+     *            "com.enea.jcarder.Foo.bar()".
+     */
+    public static void beforeMonitorEnter(Object monitor,
+                                          String lockReference,
+                                          String methodWithClass) {
+        try {
+            EventListenerIfc listener = getListener();
+            if (listener != null) {
+                final LockingContext lockingContext =
+                    new LockingContext(Thread.currentThread(),
+                                       lockReference,
+                                       methodWithClass);
+                listener.beforeMonitorEnter(monitor,
+                                            lockingContext);
+            }
+        } catch (Throwable t) {
+            handleError(t);
+        }
+       // System.out.println("here finito");
+    }
+
+    private static void handleError(Throwable t) {
+        setListener(null);
+        t.printStackTrace();
+    }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/ThreadLocalEnteredMonitors.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/ThreadLocalEnteredMonitors.java
new file mode 100644 (file)
index 0000000..e54e5d2
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.agent;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+//import net.jcip.annotations.ThreadSafe;
+
+/**
+ * Each instance of this class keeps a list of entered monitors for a thread.
+ *
+ * Note that this class is a ThreadLocal and therefore each thread will have its
+ * own instance.
+ */
+
+//@ThreadSafe
+final class ThreadLocalEnteredMonitors
+extends ThreadLocal<ArrayList<EnteredMonitor>> {
+
+    public ArrayList<EnteredMonitor> initialValue() {
+        return new ArrayList<EnteredMonitor>();
+    }
+
+    Iterator<EnteredMonitor> getIterator() {
+        return get().iterator();
+    }
+
+    EnteredMonitor getFirst() {
+        ArrayList<EnteredMonitor> list = get();
+        if (list.isEmpty()) {
+            return null;
+        } else {
+            return list.get(0);
+        }
+    }
+
+    void addFirst(EnteredMonitor enteredMonitor) {
+        get().add(0, enteredMonitor);
+    }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/instrument/ClassTransformer.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/instrument/ClassTransformer.java
new file mode 100644 (file)
index 0000000..9782d20
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.agent.instrument;
+
+import com.enea.jcarder.org.objectweb.asm.ClassReader;
+import com.enea.jcarder.org.objectweb.asm.ClassVisitor;
+import com.enea.jcarder.org.objectweb.asm.ClassWriter;
+import com.enea.jcarder.org.objectweb.asm.util.CheckClassAdapter;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.lang.instrument.ClassFileTransformer;
+import java.lang.instrument.IllegalClassFormatException;
+import java.security.ProtectionDomain;
+
+
+import com.enea.jcarder.util.logging.Logger;
+
+/**
+ * This class is responsible for all instrumentations and handles related issues
+ * with class loaders.
+ *
+ * TODO Add basic test for this class.
+ */
+public class ClassTransformer implements ClassFileTransformer {
+    private static final String ORIGINAL_CLASSES_DIRNAME =
+        "jcarder_original_classes";
+    private static final String INSTRUMENTED_CLASSES_DIRNAME =
+        "jcarder_instrumented_classes";
+    private final Logger mLogger;
+    private final ClassLoader mAgentClassLoader;
+    private final InstrumentConfig mInstrumentConfig;
+    private File mOriginalClassesDir;
+    private File mInstrumentedClassesDir;
+
+    public ClassTransformer(Logger logger,
+                            File outputDirectory,
+                            InstrumentConfig config) {
+        mLogger = logger;
+        mOriginalClassesDir =
+            new File(outputDirectory, ORIGINAL_CLASSES_DIRNAME);
+        mInstrumentedClassesDir =
+            new File(outputDirectory, INSTRUMENTED_CLASSES_DIRNAME);
+        mInstrumentConfig = config;
+        mAgentClassLoader = getClass().getClassLoader();
+        mLogger.fine("JCarder loaded with "
+                     + getClassLoaderName(mAgentClassLoader) + ".");
+        if (mAgentClassLoader == null) {
+            mLogger.info("Will instrument AWT and Swing classes");
+        } else {
+            mLogger.info("Not instrumenting standard library classes "
+                         + "(AWT, Swing, etc.)");
+        }
+        deleteDirRecursively(mInstrumentedClassesDir);
+        deleteDirRecursively(mOriginalClassesDir);
+    }
+
+    public byte[] transform(final ClassLoader classLoader,
+                            final String jvmInternalClassName,
+                            final Class<?> classBeingRedefined,
+                            final ProtectionDomain protectionDomain,
+                            final byte[] originalClassBuffer)
+    throws IllegalClassFormatException {
+        String className = jvmInternalClassName.replace('/', '.');
+        try {
+            return instrument(classLoader, originalClassBuffer, className);
+        } catch (Throwable t) {
+            mLogger.severe("Failed to transform the class "
+                           + className + ": " + t.getMessage());
+            dumpClassToFile(originalClassBuffer,
+                            mOriginalClassesDir,
+                            className);
+            return null;
+        }
+    }
+
+    private byte[] instrument(final ClassLoader classLoader,
+                              final byte[] originalClassBuffer,
+                              final String className) {
+        if (className.startsWith("com.enea.jcarder")
+            && !className.startsWith("com.enea.jcarder.testclasses")) {
+            return null; // Don't instrument ourself.
+        }
+        final String reason = isInstrumentable(className);
+        if (reason != null) {
+            mLogger.finest(
+                "Won't instrument class " + className + ": " + reason);
+            return null;
+        }
+        if (!isCompatibleClassLoader(classLoader)) {
+            mLogger.finest("Can't instrument class " + className
+                           + " loaded with " + getClassLoaderName(classLoader));
+            return null;
+        }
+        final ClassReader reader = new ClassReader(originalClassBuffer);
+        final ClassWriter writer = new ClassWriter(true);
+        ClassVisitor visitor = writer;
+        if (mInstrumentConfig.getValidateTransfomedClasses()) {
+            visitor = new CheckClassAdapter(visitor);
+        }
+        visitor = new ClassAdapter(mLogger, visitor, className);
+        reader.accept(visitor, false);
+        byte[] instrumentedClassfileBuffer = writer.toByteArray();
+        if (mInstrumentConfig.getDumpClassFiles()) {
+            dumpClassToFile(originalClassBuffer,
+                            mOriginalClassesDir,
+                            className);
+            dumpClassToFile(instrumentedClassfileBuffer,
+                            mInstrumentedClassesDir,
+                            className);
+        }
+        return instrumentedClassfileBuffer;
+    }
+
+    /**
+     * Instrumented classes must use the same static members in the
+     * com.ena.jcarder.agent.StaticEventListener class as the Java agent and
+     * therefore they must be loaded with the same class loader as the agent was
+     * loaded with, or with a class loader that has the agent's class loader as
+     * a parent or ancestor.
+     *
+     * Note that the agentLoader may have been loaded with the bootstrap class
+     * loader (null) and then "null" is a compatible class loader.
+     */
+    private boolean isCompatibleClassLoader(final ClassLoader classLoader) {
+        ClassLoader c = classLoader;
+        while (c != mAgentClassLoader) {
+            if (c == null) {
+                return false;
+            }
+            c = c.getParent();
+        }
+        return true;
+    }
+
+    private static String getClassLoaderName(final ClassLoader loader) {
+        if (loader == null) {
+            return "the bootstrap class loader";
+        } else if (loader == ClassLoader.getSystemClassLoader()) {
+            return "the system class loader";
+        } else {
+            return "the class loader \"" + loader + "\"";
+        }
+    }
+
+    /**
+     * Check whether we want to instrument a class.
+     *
+     * @param className Name of the class, including package.
+     * @return null if the class should be instrumented, otherwise a
+     * string containing the reason of why the class shouldn't be
+     * instrumented.
+     */
+    private static String isInstrumentable(String className) {
+        // AWK and Swing classes are OK.
+        if (className.startsWith("java.awt.")
+            || className.startsWith("javax.swing.")) {
+            return null;
+        }
+
+        // Other standard library classes are not.
+        if (className.startsWith("java.")
+            || className.startsWith("javax.")
+            || className.startsWith("sun.") 
+            || className.startsWith("dstm2") || className.startsWith("org")) {
+            return "standard library class";
+        }
+
+        // All other classes should be instrumented.
+        return null;
+    }
+
+    private static boolean deleteDirRecursively(File dir) {
+        if (dir.isDirectory()) {
+            String[] children = dir.list();
+            for (int i = 0; i < children.length; i++) {
+                boolean success =
+                    deleteDirRecursively(new File(dir, children[i]));
+                if (!success) {
+                    return false;
+                }
+            }
+        }
+        return dir.delete();
+    }
+
+    /**
+     * The dumped file can be decompiled with javap or with gnu.bytecode.dump.
+     * The latter also prints detailed information about the constant pool,
+     * something which javap does not.
+     */
+    private void dumpClassToFile(byte[] content,
+                                 File baseDir,
+                                 String className) {
+        try {
+            String separator = System.getProperty("file.separator");
+            File file = new File(baseDir + separator
+                                 + className.replace(".", separator)
+                                 + ".class");
+            file.getParentFile().mkdirs();
+            FileOutputStream fos = new FileOutputStream(file);
+            fos.write(content);
+            fos.close();
+        } catch (IOException e) {
+            mLogger.severe("Failed to dump class to file: " + e.getMessage());
+        }
+    }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/instrument/InstrumentConfig.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/instrument/InstrumentConfig.java
new file mode 100644 (file)
index 0000000..8b2f420
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.agent.instrument;
+
+// TODO Is this config class needed?
+public final class InstrumentConfig {
+
+    private final boolean mValidateTransfomedClasses = true;
+    private boolean mDumpClassFiles;
+
+    public InstrumentConfig() {
+        mDumpClassFiles = false;
+    }
+
+    public void setDumpClassFiles(boolean dumpClassFiles) {
+        mDumpClassFiles = dumpClassFiles;
+    }
+
+    public boolean getDumpClassFiles() {
+        return mDumpClassFiles;
+    }
+
+    public boolean getValidateTransfomedClasses() {
+        return mValidateTransfomedClasses;
+    }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/instrument/InstrumentationUtilities.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/instrument/InstrumentationUtilities.java
new file mode 100644 (file)
index 0000000..0751f59
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.agent.instrument;
+
+import com.enea.jcarder.org.objectweb.asm.MethodVisitor;
+import com.enea.jcarder.org.objectweb.asm.Opcodes;
+
+
+public final class InstrumentationUtilities {
+
+    private InstrumentationUtilities() { }
+
+    public static void pushClassReferenceToStack(MethodVisitor mv,
+                                                 String className) {
+        /*
+         * It is not possible to use:
+         *
+         *     mv.visitLdcInsn(RuleType.getType(mClassName));
+         *
+         * for class versions before 49.0 (introduced with java 1.5). Therefore
+         * we use Class.forName instead.
+         *
+         * TODO It might be possible to do this more efficiently by caching the
+         * result from Class.forName. But note that adding a new field (where
+         * the cached class object can be stored) is only possible if the class
+         * has not already been loaded by the JVM.
+         */
+        mv.visitLdcInsn(className);
+        mv.visitMethodInsn(Opcodes.INVOKESTATIC,
+                           "java/lang/Class",
+                           "forName",
+                           "(Ljava/lang/String;)Ljava/lang/Class;");
+    }
+
+    public static String getInternalName(Class c) {
+        return c.getName().replace('.', '/');
+    }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/instrument/InstrumentedAttribute.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/instrument/InstrumentedAttribute.java
new file mode 100644 (file)
index 0000000..a135ebc
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.agent.instrument;
+
+import com.enea.jcarder.org.objectweb.asm.Attribute;
+import com.enea.jcarder.org.objectweb.asm.ByteVector;
+import com.enea.jcarder.org.objectweb.asm.ClassWriter;
+
+
+public final class InstrumentedAttribute extends Attribute {
+    private static final String PREFIX = "com.enea.jcarder.instrumented";
+
+    public InstrumentedAttribute() {
+        super(PREFIX);
+    }
+
+    public InstrumentedAttribute(String attributeType) {
+        super(PREFIX + "." + attributeType);
+    }
+
+    public static boolean matchAttribute(Attribute a) {
+        return a.type.startsWith(PREFIX);
+    }
+
+    protected ByteVector write(ClassWriter arg0,
+                               byte[] arg1,
+                               int arg2,
+                               int arg3,
+                               int arg4) {
+        return new ByteVector();
+    }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/instrument/MonitorEnterMethodAdapter.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/instrument/MonitorEnterMethodAdapter.java
new file mode 100644 (file)
index 0000000..595ce5b
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.agent.instrument;
+
+import net.jcip.annotations.NotThreadSafe;
+
+
+import com.enea.jcarder.agent.StaticEventListener;
+
+import com.enea.jcarder.org.objectweb.asm.MethodAdapter;
+import com.enea.jcarder.org.objectweb.asm.MethodVisitor;
+import com.enea.jcarder.org.objectweb.asm.Opcodes;
+import static com.enea.jcarder.agent.instrument.InstrumentationUtilities.getInternalName;
+
+@NotThreadSafe
+class MonitorEnterMethodAdapter extends MethodAdapter {
+    private static final String CALLBACK_CLASS_NAME =
+        getInternalName(StaticEventListener.class);
+    private final String mClassAndMethodName;
+    private final String mClassName;
+    private StackAnalyzeMethodVisitor mStack;
+
+    MonitorEnterMethodAdapter(final MethodVisitor visitor,
+                          final String className,
+                          final String methodName) {
+        super(visitor);
+        mClassAndMethodName = className + "." + methodName + "()";
+        mClassName = className;
+    }
+
+    public void visitInsn(int inst) {
+        if (inst == Opcodes.MONITORENTER) {
+            mv.visitInsn(Opcodes.DUP);
+            mv.visitLdcInsn(convertFromJvmInternalNames(mStack.peek()));
+            mv.visitLdcInsn(mClassAndMethodName);
+            mv.visitMethodInsn(Opcodes.INVOKESTATIC,
+                               CALLBACK_CLASS_NAME,
+                               "beforeMonitorEnter",
+                   "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)V");
+        }
+        super.visitInsn(inst);
+    }
+
+    private String convertFromJvmInternalNames(String s) {
+        if (s == null) {
+            assert false;
+            return "null???";
+        } else {
+            final String name = s.replace('/', '.');
+            if (name.equals(mClassName + ".class")) {
+                return "class";
+            } else {
+                return name;
+            }
+        }
+    }
+
+    void setStackAnalyzer(StackAnalyzeMethodVisitor stack) {
+        mStack = stack;
+    }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/instrument/SimulateMethodSyncMethodAdapter.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/instrument/SimulateMethodSyncMethodAdapter.java
new file mode 100644 (file)
index 0000000..99392c1
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.agent.instrument;
+
+import com.enea.jcarder.org.objectweb.asm.Label;
+import com.enea.jcarder.org.objectweb.asm.MethodAdapter;
+import com.enea.jcarder.org.objectweb.asm.MethodVisitor;
+import com.enea.jcarder.org.objectweb.asm.Opcodes;
+import net.jcip.annotations.NotThreadSafe;
+
+/**
+ * This Method Adapter simulates a synchronized declaration on a method by
+ * adding a MonitorEnter and MonitorExits.
+ */
+//@NotThreadSafe
+class SimulateMethodSyncMethodAdapter extends MethodAdapter {
+    private final String mClassName;
+    private final boolean mIsStatic;
+    private final Label mTryLabel = new Label();
+    private final Label mFinallyLabel = new Label();
+
+    SimulateMethodSyncMethodAdapter(final MethodVisitor visitor,
+                                    final String className,
+                                    final boolean isStatic) {
+        super(visitor);
+        mClassName = className;
+        mIsStatic = isStatic;
+    }
+
+    public void visitCode() {
+        super.visitCode();
+        /*
+         * This MethodAdapter will only be applied to synchronized methods, and
+         * constructors are not allowed to be declared synchronized. Therefore
+         * we can add instructions at the beginning of the method and do not
+         * have to find the place after the initial constructor byte codes:
+         *
+         *     ALOAD 0 : this
+         *     INVOKESPECIAL Object.<init>() : void
+         *
+         */
+        putMonitorObjectReferenceOnStack();
+        mv.visitInsn(Opcodes.MONITORENTER);
+        mv.visitLabel(mTryLabel);
+    }
+
+    /**
+     * This method is called just after the last code in the method.
+     */
+    public void visitMaxs(int arg0, int arg1) {
+        /*
+         * This finally block is needed in order to exit the monitor even when
+         * the method exits by throwing an exception.
+         */
+        mv.visitLabel(mFinallyLabel);
+        putMonitorObjectReferenceOnStack();
+        mv.visitInsn(Opcodes.MONITOREXIT);
+        mv.visitInsn(Opcodes.ATHROW);
+        mv.visitTryCatchBlock(mTryLabel,
+                              mFinallyLabel,
+                              mFinallyLabel,
+                              null);
+        super.visitMaxs(arg0, arg1);
+    }
+
+    public void visitInsn(int inst) {
+        switch (inst) {
+        case Opcodes.IRETURN:
+        case Opcodes.LRETURN:
+        case Opcodes.FRETURN:
+        case Opcodes.DRETURN:
+        case Opcodes.ARETURN:
+        case Opcodes.RETURN:
+            putMonitorObjectReferenceOnStack();
+            mv.visitInsn(Opcodes.MONITOREXIT);
+            break;
+        default:
+            // Do nothing.
+        }
+        super.visitInsn(inst);
+    }
+
+    private void putMonitorObjectReferenceOnStack() {
+        if (mIsStatic) {
+            InstrumentationUtilities.pushClassReferenceToStack(mv, mClassName);
+        } else {
+            mv.visitVarInsn(Opcodes.ALOAD, 0);
+        }
+    }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/instrument/StackAnalyzeMethodVisitor.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/instrument/StackAnalyzeMethodVisitor.java
new file mode 100644 (file)
index 0000000..761733a
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.agent.instrument;
+
+import com.enea.jcarder.org.objectweb.asm.AnnotationVisitor;
+import com.enea.jcarder.org.objectweb.asm.Attribute;
+import com.enea.jcarder.org.objectweb.asm.Label;
+import com.enea.jcarder.org.objectweb.asm.MethodVisitor;
+import com.enea.jcarder.org.objectweb.asm.Opcodes;
+import com.enea.jcarder.org.objectweb.asm.Type;
+import java.util.Stack;
+import net.jcip.annotations.NotThreadSafe;
+
+
+
+import com.enea.jcarder.util.logging.Logger;
+
+/**
+ * This class tries to keep track of what is currently on the operand stack. It
+ * does not keep track of the actual values but from where the values
+ * originates. A value may for example originate from a specific field member in
+ * the class, a local variable, a return value from a specific method or
+ * something else.
+ *
+ * The analysis is done during the instrumentation.
+ */
+@NotThreadSafe
+class StackAnalyzeMethodVisitor implements MethodVisitor {
+    private static final TextualDescription UNKOWN_VALUE =
+        new TextualDescription("???");
+    private final Logger mLogger;
+    private final Stack<Object> mStack = new Stack<Object>();
+    private final MethodVisitor mMethodVisitor;
+    private final boolean mIsStatic;
+
+    StackAnalyzeMethodVisitor(final Logger logger,
+                              final MethodVisitor methodVisitor,
+                              final boolean isStatic) {
+        mLogger = logger;
+        mMethodVisitor = methodVisitor;
+        mIsStatic = isStatic;
+    }
+
+    private static class TextualDescription {
+        private final String mDescription;
+
+        TextualDescription(String description) {
+            mDescription = description;
+        }
+
+        public String toString() {
+            return mDescription;
+        }
+    }
+
+    /**
+     * @return A textual description of from where the current value of the
+     *         stack originates. The string "???" is returned if the origin is
+     *         unknown.
+     */
+    String peek() {
+        if (mStack.isEmpty()) {
+            return UNKOWN_VALUE.toString();
+        } else {
+            return mStack.peek().toString();
+        }
+    }
+
+    private String pop() {
+        return popObject().toString();
+    }
+
+    private Object popObject() {
+        if (mStack.isEmpty()) {
+            return UNKOWN_VALUE;
+        } else {
+            return mStack.pop();
+        }
+    }
+
+    private void pushTextualDescription(String s) {
+        mStack.push(new TextualDescription(s));
+    }
+
+    private void pushStringObject(String s) {
+        mStack.push(s);
+    }
+
+    private void clear() {
+        mLogger.finest("Invalidating stack");
+        mStack.clear();
+    }
+
+    public void visitCode() {
+        mMethodVisitor.visitCode();
+        clear();
+    }
+
+    public void visitEnd() {
+        mMethodVisitor.visitEnd();
+        clear();
+    }
+
+    public void visitFieldInsn(int opCode,
+                               String owner,
+                               String name,
+                               String desc) {
+        mMethodVisitor.visitFieldInsn(opCode, owner, name, desc);
+        switch (opCode) {
+        case Opcodes.GETFIELD:
+            pop();
+            pushTextualDescription(owner + "." + name);
+            break;
+        case Opcodes.GETSTATIC:
+            pushTextualDescription(owner + "." + name);
+            break;
+        default:
+            clear();
+        }
+    }
+
+    public void visitIincInsn(int arg0, int arg1) {
+        mMethodVisitor.visitIincInsn(arg0, arg1);
+        clear();
+    }
+
+    public void visitInsn(int opCode) {
+        mMethodVisitor.visitInsn(opCode);
+        switch (opCode) {
+        case Opcodes.DUP:
+            pushTextualDescription(peek());
+            break;
+        default:
+            clear();
+        }
+    }
+
+    public void visitIntInsn(int opCode, int arg1) {
+        mMethodVisitor.visitIntInsn(opCode, arg1);
+        clear();
+    }
+
+    public void visitJumpInsn(int opCode, Label arg1) {
+        mMethodVisitor.visitJumpInsn(opCode, arg1);
+        clear();
+    }
+
+    public void visitLabel(Label arg0) {
+        mMethodVisitor.visitLabel(arg0);
+        // We have to invalidate the stack since we don't know how we arrived
+        // at this label. We might have jumped to this place from anywhere.
+        clear();
+    }
+
+    public void visitLdcInsn(Object cst) {
+        mMethodVisitor.visitLdcInsn(cst);
+        if (cst instanceof Type) {
+            Type t = (Type) cst;
+            pushTextualDescription(t.getClassName() + ".class");
+        } else if (cst instanceof String) {
+            pushStringObject((String) cst);
+        } else {
+            clear();
+        }
+    }
+
+    public void visitLineNumber(int arg0, Label arg1) {
+        mMethodVisitor.visitLineNumber(arg0, arg1);
+    }
+
+    public void visitLocalVariable(String name,
+                                   String desc,
+                                   String signature,
+                                   Label start,
+                                   Label end,
+                                   int index) {
+        mMethodVisitor.visitLocalVariable(name,
+                                          desc,
+                                          signature,
+                                          start,
+                                          end,
+                                          index);
+    }
+
+    public void visitLookupSwitchInsn(Label arg0, int[] arg1, Label[] arg2) {
+        mMethodVisitor.visitLookupSwitchInsn(arg0, arg1, arg2);
+        clear();
+    }
+
+    // TODO refactor this method
+    public void visitMethodInsn(int opCode,
+                                String owner,
+                                String name,
+                                String desc) {
+        mMethodVisitor.visitMethodInsn(opCode, owner, name, desc);
+        switch (opCode) {
+        case Opcodes.INVOKEVIRTUAL:
+            // pass through to next case.
+        case Opcodes.INVOKESPECIAL:
+            // pass through to next case.
+        case Opcodes.INVOKESTATIC:
+            if ("forName".equals(name)
+                && "java/lang/Class".equals(owner)
+                && "(Ljava/lang/String;)Ljava/lang/Class;".equals(desc)) {
+                Object stackObject = popObject();
+                if (stackObject instanceof String) {
+                    String classDescription = ((String) stackObject) + ".class";
+                    pushTextualDescription(classDescription);
+                    break;
+                }
+            }
+            // pass through to next case.
+        case Opcodes.INVOKEINTERFACE:
+            clear();
+            if (isNonVoidMethod(name, desc)) {
+                pushTextualDescription(owner + "." + name + "()");
+            }
+            break;
+        default:
+            clear();
+        }
+    }
+
+    private static boolean isNonVoidMethod(String name, String desc) {
+        return Type.getReturnType(desc) != Type.VOID_TYPE
+               || name.equals("<init>");
+    }
+
+    public void visitMultiANewArrayInsn(String arg0, int arg1) {
+        mMethodVisitor.visitMultiANewArrayInsn(arg0, arg1);
+        clear();
+    }
+
+    public AnnotationVisitor visitParameterAnnotation(int arg0,
+                                                      String arg1,
+                                                      boolean arg2) {
+        return mMethodVisitor.visitParameterAnnotation(arg0, arg1, arg2);
+    }
+
+    public void visitTableSwitchInsn(int arg0,
+                                     int arg1,
+                                     Label arg2,
+                                     Label[] arg3) {
+        mMethodVisitor.visitTableSwitchInsn(arg0, arg1, arg2, arg3);
+        clear();
+    }
+
+    public void visitTryCatchBlock(Label arg0,
+                                   Label arg1,
+                                   Label arg2,
+                                   String arg3) {
+        mMethodVisitor.visitTryCatchBlock(arg0, arg1, arg2, arg3);
+        clear();
+    }
+
+    public void visitTypeInsn(int opCode, String desc) {
+        mMethodVisitor.visitTypeInsn(opCode, desc);
+    }
+
+    public void visitVarInsn(int opCode, int index) {
+        mMethodVisitor.visitVarInsn(opCode, index);
+        switch (opCode) {
+        case Opcodes.ALOAD:
+            if (index == 0 && !mIsStatic) {
+                pushTextualDescription("this");
+            } else {
+                /*
+                 * TODO Translate the index to a local variable name. To be able
+                 * to do that we probably have to analyze the class in two steps
+                 * since the visit method visitLocalVariable is not called until
+                 * after all calls to visitVarInsn.
+                 */
+                pushTextualDescription("<localVariable" + index + ">");
+            }
+            break;
+        case Opcodes.ASTORE:
+            pop();
+            break;
+        default:
+            clear();
+        }
+    }
+
+    public AnnotationVisitor visitAnnotation(String arg0, boolean arg1) {
+        return mMethodVisitor.visitAnnotation(arg0, arg1);
+    }
+
+    public AnnotationVisitor visitAnnotationDefault() {
+        return mMethodVisitor.visitAnnotationDefault();
+    }
+
+    public void visitAttribute(Attribute arg0) {
+        mMethodVisitor.visitAttribute(arg0);
+    }
+
+    public void visitMaxs(int arg0, int arg1) {
+        mMethodVisitor.visitMaxs(arg0, arg1);
+    }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/analyzer/Analyzer.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/analyzer/Analyzer.java
new file mode 100644 (file)
index 0000000..ada5483
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.analyzer;
+
+import static com.enea.jcarder.common.contexts.ContextFileReader.CONTEXTS_DB_FILENAME;
+import static com.enea.jcarder.common.contexts.ContextFileReader.EVENT_DB_FILENAME;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import com.enea.jcarder.common.LockingContext;
+import com.enea.jcarder.common.contexts.ContextFileReader;
+import com.enea.jcarder.common.contexts.ContextReaderIfc;
+import com.enea.jcarder.common.events.EventFileReader;
+import com.enea.jcarder.util.BuildInformation;
+import com.enea.jcarder.util.InvalidOptionException;
+import com.enea.jcarder.util.OptionParser;
+import com.enea.jcarder.util.logging.AppendableHandler;
+import com.enea.jcarder.util.logging.Handler;
+import com.enea.jcarder.util.logging.Logger;
+import com.enea.jcarder.util.logging.Logger.Level;
+
+/**
+ * The main class of the JCarder analyzer.
+ */
+public final class Analyzer {
+
+    enum OutputMode { INCLUDE_ALL,
+                      INCLUDE_CYCLES,
+                      INCLUDE_ONLY_MULTI_THREADED_CYCLES };
+
+    /*
+     * Cycles with only one thread can never cause a deadlock, but it might be
+     * possible that basic tests of a single class are very simplified and use
+     * only a single thread where a real program might invoke the methods from
+     * several different threads. Therefore single-threaded cycles are also
+     * interesting to detect and include by default.
+     */
+    private OutputMode mOutputMode = OutputMode.INCLUDE_CYCLES;
+    private boolean mIncludePackages = false;
+    private boolean mPrintDetails = false;
+    private Logger mLogger;
+    final private Level mLogLevel = Logger.Level.INFO;
+    private String mInputDirectory = ".";
+
+    public static void main(String[] args) {
+        new Analyzer().start(args);
+    }
+
+    public void start(String[] args) {
+        parseArguments(args);
+        initLogger();
+        LockGraphBuilder graphBuilder = new LockGraphBuilder();
+        final ContextReaderIfc contextReader;
+
+        try {
+            contextReader =
+                new ContextFileReader(mLogger, new File(mInputDirectory,
+                                                        CONTEXTS_DB_FILENAME));
+
+            EventFileReader eventReader = new EventFileReader(mLogger);
+            eventReader.parseFile(new File(mInputDirectory, EVENT_DB_FILENAME),
+                                  graphBuilder);
+        }
+        catch (IOException e) {
+            mLogger.severe("Error while reading result database: "
+                           + e.getMessage());
+            return;
+        }
+        printInitiallyLoadedStatistics(graphBuilder.getAllLocks());
+
+        CycleDetector cycleDetector = new CycleDetector(mLogger);
+        cycleDetector.analyzeLockNodes(graphBuilder.getAllLocks());
+        printCycleAnalysisStatistics(cycleDetector);
+
+        if (mOutputMode == OutputMode.INCLUDE_ALL) {
+            printDetailsIfEnabled(cycleDetector.getCycles(), contextReader);
+            try {
+                generatGraphvizFileForAllNodes(graphBuilder, contextReader);
+            } catch (IOException e) {
+                mLogger.severe("Error while generating Graphviz file: "
+                               + e.getMessage());
+            }
+        } else {
+            if (mOutputMode == OutputMode.INCLUDE_ONLY_MULTI_THREADED_CYCLES) {
+                cycleDetector.removeSingleThreadedCycles();
+            }
+            if (cycleDetector.getCycles().isEmpty()) {
+                System.out.println("No cycles found!");
+                return;
+            }
+            graphBuilder.clear(); // Help GC.
+            /*
+             * TODO Also clear all references in LockNode.mOutgoingEdges to
+             * avoid keeping references to a lot of LockEdge and LockNode
+             * objects in order to release as much memory as possible for the
+             * memory mapped file?
+             *
+             * It is not necessary to use the DuplicateEdgeshandler since those
+             * duplicates are removed anyway when cycles that are alike are
+             * removed.
+             */
+            cycleDetector.removeAlikeCycles(contextReader);
+
+            printDetailsIfEnabled(cycleDetector.getCycles(), contextReader);
+            try {
+                generateGraphvizFilesForCycles(contextReader, cycleDetector);
+            } catch (IOException e) {
+                mLogger.severe("Error while generating Graphviz file: "
+                               + e.getMessage());
+            }
+        }
+    }
+
+    private void initLogger() {
+        Collection<Handler> handlers = new ArrayList<Handler>();
+        handlers.add(new AppendableHandler(System.out,
+                                           Logger.Level.CONFIG,
+                                           "{message}\n"));
+        mLogger = new Logger(handlers, mLogLevel);
+    }
+
+    private void generateGraphvizFilesForCycles(ContextReaderIfc reader,
+                                                CycleDetector cycleDetector)
+    throws IOException {
+        System.out.println();
+        int index = 0;
+        Collection<HashSet<LockEdge>> cycles =
+            cycleDetector.mergeCyclesWithIdenticalLocks();
+        for (HashSet<LockEdge> edges : cycles) {
+            if (index >= 100) {
+                System.out.println("Aborting. Too many cycles!");
+                break;
+            }
+            GraphvizGenerator graphvizGenerator = new GraphvizGenerator();
+            createGraphvizFile(graphvizGenerator.generate(edges,
+                                                          reader,
+                                                          mIncludePackages),
+                                                          index++);
+        }
+    }
+
+    private void  printCycleAnalysisStatistics(CycleDetector cycleDetector) {
+        System.out.println("\nCycle analysis result: ");
+        System.out.println("   Cycles:          "
+                           + cycleDetector.getCycles().size());
+        System.out.println("   Edges in cycles: "
+                           + cycleDetector.getNumberOfEdges());
+        System.out.println("   Nodes in cycles: "
+                           + cycleDetector.getNumberOfNodes());
+        System.out.println("   Max cycle depth: "
+                           + cycleDetector.getMaxCycleDepth());
+        System.out.println("   Max graph depth: "
+                           + cycleDetector.getMaxDepth());
+        System.out.println();
+    }
+
+    private void generatGraphvizFileForAllNodes(LockGraphBuilder graphBuilder,
+                                                ContextReaderIfc reader)
+    throws IOException {
+        DuplicatedEdgesHandler.mergeDuplicatedEdges(graphBuilder.getAllLocks(),
+                                                    reader);
+        // TODO Print statistics about removed duplicates?
+        LinkedList<LockEdge> allEdges = new LinkedList<LockEdge>();
+        for (LockNode node : graphBuilder.getAllLocks()) {
+            allEdges.addAll(node.getOutgoingEdges());
+        }
+        GraphvizGenerator graphvizGenerator = new GraphvizGenerator();
+        createGraphvizFile(graphvizGenerator.generate(allEdges,
+                                                      reader,
+                                                      mIncludePackages),
+                                                      0);
+    }
+
+    private void parseArguments(String[] args) {
+        OptionParser op = new OptionParser();
+        configureOptionParser(op);
+
+        try {
+            op.parse(args);
+        } catch (InvalidOptionException e) {
+            handleBadOption(op, e.getMessage());
+        }
+
+        handleOptions(op);
+    }
+
+    private void configureOptionParser(OptionParser op) {
+        /*
+         * TODO Add parameters for filtering (including & excluding) specific
+         * locks and edges for example by specifying thread names, object
+         * classes, method names or packages?
+         */
+
+        op.addOption("-help",
+                     "Print this help text");
+        op.addOption("-d <directory>",
+                     "Read results to analyze from <directory> (default:"
+                     + " current directory)");
+        op.addOption("-includepackages",
+                     "Include packages (not only class names) in graph");
+        op.addOption("-outputmode <mode>",
+                     "Set output mode to <mode> (one of ALL, CYCLES, MTCYCLES);"
+                     + " ALL: include everything;"
+                     + " CYCLES: only include cycles (this is the default);"
+                     + " MTCYCLES: only include multi-thread cycles");
+        op.addOption("-printdetails",
+                     "Print details");
+        op.addOption("-version",
+                     "Print program version");
+    }
+
+    private void handleOptions(OptionParser op) {
+        Map<String, String> options = op.getOptions();
+        for (String option : options.keySet()) {
+            if (option.equals("-help")) {
+                printHelpText(System.out, op);
+                System.exit(0);
+            } else if (option.equals("-i")) {
+                mInputDirectory = options.get(option);
+            } else if (option.equals("-includepackages")) {
+                mIncludePackages = true;
+            } else if (option.equals("-outputmode")) {
+                String value = options.get(option);
+                if (value.equalsIgnoreCase("all")) {
+                    mOutputMode = OutputMode.INCLUDE_ALL;
+                } else if (value.equalsIgnoreCase("cycles")) {
+                    mOutputMode = OutputMode.INCLUDE_CYCLES;
+                } else if (value.equalsIgnoreCase("mtcycles")) {
+                    mOutputMode = OutputMode.INCLUDE_ONLY_MULTI_THREADED_CYCLES;
+                } else {
+                    handleBadOption(op, "bad output mode");
+                }
+            } else if (option.equals("-printdetails")) {
+                mPrintDetails = true;
+            } else if (option.equals("-version")) {
+                BuildInformation.printLongBuildInformation();
+                System.exit(0);
+            }
+        }
+    }
+
+    private void printHelpText(PrintStream stream, OptionParser op) {
+        stream.print("Usage: java -jar jcarder.jar [options]\n\n");
+        stream.print("Options:\n");
+        stream.print(op.getOptionHelp());
+    }
+
+    private void handleBadOption(OptionParser optionParser, String message) {
+        System.err.println("JCarder: " + message);
+        printHelpText(System.err, optionParser);
+        System.exit(1);
+    }
+
+    private void printDetailsIfEnabled(Iterable<Cycle> cycles,
+                                       ContextReaderIfc reader) {
+        if (!mPrintDetails) {
+            return;
+        }
+        SortedSet<String> threads = new TreeSet<String>();
+        SortedSet<String> methods = new TreeSet<String>();
+        for (Cycle cycle : cycles) {
+            for (LockEdge edge : cycle.getEdges()) {
+                LockingContext source =
+                    reader.readContext(edge.getSourceLockingContextId());
+                LockingContext target =
+                    reader.readContext(edge.getTargetLockingContextId());
+                threads.add(source.getThreadName());
+                threads.add(target.getThreadName());
+                methods.add(source.getMethodWithClass());
+                methods.add(target.getMethodWithClass());
+            }
+        }
+        System.out.println();
+        System.out.println("Threads involved in cycles:");
+        for (String thread : threads) {
+            System.out.println("   " + thread);
+        }
+        System.out.println();
+        System.out.println("Methods involved in cycles:");
+        for (String method : methods) {
+            System.out.println("   " + method);
+        }
+        System.out.println();
+    }
+
+
+    private void printInitiallyLoadedStatistics(Iterable<LockNode> locks) {
+        int numberOfNodes = 0;
+        int numberOfUniqueEdges = 0;
+        int numberOfDuplicatedEdges = 0;
+        for (LockNode lock : locks) {
+            numberOfNodes++;
+            numberOfUniqueEdges += lock.numberOfUniqueEdges();
+            numberOfDuplicatedEdges += lock.numberOfDuplicatedEdges();
+        }
+        System.out.println("\nLoaded from database files:");
+        System.out.println("   Nodes: " + numberOfNodes);
+        System.out.println("   Edges: " + numberOfUniqueEdges
+                           + " (excluding " + numberOfDuplicatedEdges
+                           + " duplicated)");
+    }
+
+    private void createGraphvizFile(String s, int index) throws IOException {
+        File file = new File("jcarder_result_" + index + ".dot");
+        System.out.println("Writing Graphviz file: " + file.getAbsolutePath());
+        FileWriter fw = new FileWriter(file);
+        fw.write(s);
+        fw.flush();
+        fw.close();
+    }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/analyzer/Cycle.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/analyzer/Cycle.java
new file mode 100644 (file)
index 0000000..81fc0e0
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.analyzer;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import com.enea.jcarder.common.contexts.ContextReaderIfc;
+
+/**
+ * An instance of this class represents a single cycle of edges. The edges must
+ * form a single circle witout any alternative paths. If there are alternative
+ * paths in a graph cycle, those cycles will be split into separate Cycle
+ * objects.
+ *
+ * TODO Write basic tests.
+ */
+class Cycle {
+    final HashSet<LockEdge> mEdgesInCycle = new HashSet<LockEdge>();
+
+    Cycle(Collection<LockEdge> edgesInTheCycle) {
+        mEdgesInCycle.addAll(edgesInTheCycle);
+        assert mEdgesInCycle.size() >= 2;
+    }
+
+    HashSet<LockEdge> getEdges() {
+        return mEdgesInCycle;
+    }
+
+    HashSet<LockNode> getNodes() {
+        HashSet<LockNode> nodes = new HashSet<LockNode>();
+        for (LockEdge edge : mEdgesInCycle) {
+            /*
+             * All sources will be included if we get all the targets, since it
+             * is a cycle.
+             */
+            nodes.add(edge.getTarget());
+        }
+        return nodes;
+    }
+
+    void updateNodeCycleStatus() {
+        final LockNode.CycleType type;
+        if (isSingleThreaded()) {
+            type = LockNode.CycleType.SINGLE_THREADED_CYCLE;
+        } else {
+            type = LockNode.CycleType.CYCLE;
+        }
+        for (LockEdge edge : mEdgesInCycle) {
+            edge.getSource().raiseCycleType(type);
+            edge.getTarget().raiseCycleType(type);
+        }
+    }
+
+    boolean isSingleThreaded() {
+        // TODO Cache the result to improve performance?
+        final Iterator<LockEdge> iter = mEdgesInCycle.iterator();
+        if (iter.hasNext()) {
+            final long firstThreadId = iter.next().getThreadId();
+            while (iter.hasNext()) {
+                if (firstThreadId != iter.next().getThreadId()) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    boolean alike(Cycle other, ContextReaderIfc reader) {
+        if (this.equals(other)) {
+            return true;
+        }
+        if (mEdgesInCycle.size() != other.mEdgesInCycle.size()) {
+            return false;
+        }
+        if (isSingleThreaded() != other.isSingleThreaded()) {
+            return false;
+        }
+        LinkedList<LockEdge> otherEdges =
+            new LinkedList<LockEdge>(other.mEdgesInCycle);
+        // TODO Refactor the following code?
+        outerLoop:
+        for (LockEdge edge : mEdgesInCycle) {
+            Iterator<LockEdge> iter = otherEdges.iterator();
+            while (iter.hasNext()) {
+                if (edge.alike(iter.next(), reader)) {
+                    iter.remove();
+                    continue outerLoop;
+                }
+            }
+            return false;
+        }
+        return true;
+    }
+
+    public boolean equals(Object obj) {
+        try {
+            Cycle other = (Cycle) obj;
+            return mEdgesInCycle.equals(other.mEdgesInCycle);
+        } catch (ClassCastException e) {
+            return false;
+        }
+    }
+
+    public int hashCode() {
+        return mEdgesInCycle.hashCode();
+    }
+
+
+    public String toString() {
+        return mEdgesInCycle.toString();
+    }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/analyzer/CycleDetector.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/analyzer/CycleDetector.java
new file mode 100644 (file)
index 0000000..84edea9
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.analyzer;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+
+import net.jcip.annotations.NotThreadSafe;
+
+import com.enea.jcarder.common.contexts.ContextReaderIfc;
+import com.enea.jcarder.util.Counter;
+import com.enea.jcarder.util.MaxValueCounter;
+import com.enea.jcarder.util.logging.Logger;
+
+/**
+ * This class is responsible for finding and managing cycles.
+ *
+ * TODO Add possibility to ignore cycles guarded by a common lock.
+ *
+ * TODO Add possibility to ignore cycles created by two threads that cannot
+ * possibly run at the same time. Is it possible to achieve that by tracking
+ * Thread.start() and Thread.join()?
+ *
+ * TODO Add more basic tests for this class.
+ */
+@NotThreadSafe
+class CycleDetector {
+    private final HashSet<Cycle> mCycles;
+    private final Logger mLogger;
+    private final MaxValueCounter mMaxDepth;
+    private final MaxValueCounter mMaxCycleDepth;
+    private final MaxValueCounter mNoOfCycles;
+    private final Counter mNoOfCreatedCycleObjects;
+
+    CycleDetector(Logger logger) {
+        mLogger = logger;
+        mCycles = new HashSet<Cycle>();
+        mMaxDepth = new MaxValueCounter("Graph Depth", mLogger);
+        mMaxCycleDepth = new MaxValueCounter("Cycle Depth", mLogger);
+        mNoOfCycles = new MaxValueCounter("Found cycles", mLogger);
+        mNoOfCreatedCycleObjects = new Counter("Created cycle objects",
+                                               mLogger,
+                                               100000);
+    }
+
+    /**
+     * Analyze a set of LockNodes and LockEdges. All cycles they form will be
+     * stored within this class.
+     */
+    void analyzeLockNodes(final Iterable<LockNode> nodes) {
+        ArrayList<LockNode> nodesOnStack = new ArrayList<LockNode>(10);
+        ArrayList<LockEdge> edgesOnStack = new ArrayList<LockEdge>(10);
+        HashSet<LockNode> visitedNodes = new HashSet<LockNode>();
+        HashSet<LockEdge> visitedEdges = new HashSet<LockEdge>();
+        for (LockNode lock : nodes) {
+            if (!visitedNodes.contains(lock)) {
+                analyzeNode(lock, nodesOnStack, edgesOnStack, visitedNodes,
+                            visitedEdges);
+            }
+        }
+        for (Cycle cycle : mCycles) {
+            cycle.updateNodeCycleStatus();
+        }
+    }
+
+    MaxValueCounter getMaxDepth() {
+        return mMaxDepth;
+    }
+
+    MaxValueCounter getMaxCycleDepth() {
+        return mMaxCycleDepth;
+    }
+
+    private void analyzeNode(final LockNode node,
+                             final ArrayList<LockNode> nodesOnStack,
+                             final ArrayList<LockEdge> edgesOnStack,
+                             final HashSet<LockNode> visitedNodes,
+                             final HashSet<LockEdge> visitedEdges) {
+        visitedNodes.add(node);
+        nodesOnStack.add(node);
+        for (LockEdge edge : node.getOutgoingEdges()) {
+            edgesOnStack.add(edge);
+            analyzeEdge(edge, nodesOnStack, edgesOnStack, visitedNodes,
+                        visitedEdges);
+            edgesOnStack.remove(edgesOnStack.size() - 1);
+        }
+        nodesOnStack.remove(nodesOnStack.size() - 1);
+    }
+
+    private void analyzeEdge(final LockEdge edge,
+                             final ArrayList<LockNode> nodesOnStack,
+                             final ArrayList<LockEdge> edgesOnStack,
+                             final HashSet<LockNode> visitedNodes,
+                             final HashSet<LockEdge> visitedEdges) {
+        if (!visitedEdges.contains(edge)) {
+            mMaxDepth.set(nodesOnStack.size());
+            final int index = nodesOnStack.indexOf(edge.getTarget());
+            if (index >= 0) {
+                final List<LockEdge> edgesInCycle =
+                    edgesOnStack.subList(index, edgesOnStack.size());
+                mNoOfCreatedCycleObjects.increment();
+                mMaxCycleDepth.set(edgesInCycle.size());
+                mCycles.add(new Cycle(edgesInCycle));
+                mNoOfCycles.set(mCycles.size());
+                /*
+                 * Keeping the first edge from the cycle in the visitedEdges
+                 * list is an optimization that avoids unnecessary (as I
+                 * believe) repeated checks. The other edges have to be removed,
+                 * otherwise all cycles won't be found. See the testcases for
+                 * examples of such cases.
+                 */
+                List<LockEdge> edgesToRemove =
+                    edgesInCycle.subList(1, edgesInCycle.size());
+                visitedEdges.removeAll(edgesToRemove);
+            } else {
+                visitedEdges.add(edge);
+                analyzeNode(edge.getTarget(),
+                            nodesOnStack,
+                            edgesOnStack,
+                            visitedNodes,
+                            visitedEdges);
+            }
+        }
+    }
+
+
+    HashSet<Cycle> getCycles() {
+        return mCycles;
+    }
+
+    private static boolean containsAlike(Cycle cycle, Iterable<Cycle> others,
+                                         ContextReaderIfc reader) {
+        for (Cycle other : others) {
+            if (cycle.alike(other, reader)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Reducing the number of cycles by ignoring those that are duplicates (very
+     * similar) to another cycle.
+     */
+    void removeAlikeCycles(ContextReaderIfc reader) {
+        int removedCycles = 0;
+        ArrayList<Cycle> uniqueCycles = new ArrayList<Cycle>();
+        Iterator<Cycle> iter = mCycles.iterator();
+        while (iter.hasNext()) {
+            final Cycle cycle = iter.next();
+            if (containsAlike(cycle, uniqueCycles, reader)) {
+                iter.remove();
+                removedCycles++;
+            } else {
+                uniqueCycles.add(cycle);
+            }
+        }
+        mLogger.info("Ignoring " + removedCycles
+                     + " almost identical cycle(s).");
+        assert uniqueCycles.equals(new ArrayList<Cycle>(mCycles));
+    }
+
+    /**
+     * Remove cycles that are formed by a only one thread.
+     */
+    void removeSingleThreadedCycles() {
+        int removedCycles = 0;
+        Iterator<Cycle> iter = mCycles.iterator();
+        while (iter.hasNext()) {
+            final Cycle cycle = iter.next();
+            if (cycle.isSingleThreaded()) {
+                iter.remove();
+                removedCycles++;
+            }
+        }
+        mLogger.info("Ignoring "
+                     + removedCycles
+                     + " single threaded cycle(s).");
+    }
+
+    /**
+     * Get the total number of edges in all known cycles.
+     */
+    int getNumberOfEdges() {
+        HashSet<LockEdge> edges = new HashSet<LockEdge>();
+        for (Cycle cycle : mCycles) {
+            edges.addAll(cycle.getEdges());
+        }
+        return edges.size();
+    }
+
+    /**
+     * Get the total number of nodes in all known cycles.
+     */
+    int getNumberOfNodes() {
+        HashSet<LockNode> nodes = new HashSet<LockNode>();
+        for (Cycle cycle : mCycles) {
+            for (LockEdge edge : cycle.getEdges()) {
+                nodes.add(edge.getSource());
+                nodes.add(edge.getTarget());
+            }
+        }
+        return nodes.size();
+    }
+
+    /**
+     * Find out the cycles that consist of identical locks and group them
+     * together. Then return all edges in each group.
+     *
+     * The data structure in the CycleDetector class is unaffected.
+     */
+    Collection<HashSet<LockEdge>> mergeCyclesWithIdenticalLocks() {
+        /*
+         * TODO Refactor this method? The temporary data structure is too
+         * complex?
+         */
+        HashMap<HashSet<LockNode>, HashSet<LockEdge>> setOfNodesToEdgesMap =
+            new HashMap<HashSet<LockNode>, HashSet<LockEdge>>();
+        for (Cycle cycle : mCycles) {
+            final HashSet<LockNode> nodes = cycle.getNodes();
+            HashSet<LockEdge> edges = setOfNodesToEdgesMap.get(nodes);
+            if (edges == null) {
+                edges = new HashSet<LockEdge>();
+                setOfNodesToEdgesMap.put(nodes, edges);
+            }
+            edges.addAll(cycle.getEdges());
+        }
+        return setOfNodesToEdgesMap.values();
+    }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/analyzer/DuplicatedEdgesHandler.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/analyzer/DuplicatedEdgesHandler.java
new file mode 100644 (file)
index 0000000..0cba0aa
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.analyzer;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.TreeSet;
+
+import com.enea.jcarder.common.LockingContext;
+import com.enea.jcarder.common.contexts.ContextReaderIfc;
+
+/**
+ * This class contains functionality for merging edges that have the same source
+ * and target nodes and identical thread IDs and locking contexts content, but
+ * different locking context IDs.
+ *
+ * Such a merge might be desirable since the producer of the context file is not
+ * required to guarantee that identical locking contexts always get the same
+ * IDs.
+ *
+ * @TODO Add basic tests for this class.
+ */
+public final class DuplicatedEdgesHandler {
+    private final Iterable<LockNode> mLockNodes;
+    private final Map<Integer, Integer> mContextIdTranslation;
+    private final Map<LockingContext, TreeSet<Integer>> mContextToIdMap;
+
+    /**
+     * The constructor is made private to prevent that someone creates an
+     * instance of this class and then forgets to release the reference to it.
+     * That would be undesirable since the mContextToIdMap structure in this
+     * class might be very large and should be garbage collected as soon as
+     * possible.
+     *
+     * @see DuplicatedEdgesHandler.mergeDuplicatedEdges() instead.
+     */
+    private DuplicatedEdgesHandler(Iterable<LockNode> lockNodes,
+                                   ContextReaderIfc reader) {
+        mLockNodes = lockNodes;
+        mContextIdTranslation = populateTranslationMap();
+        mContextToIdMap = createContextToIdMap(reader);
+    }
+
+    public static void mergeDuplicatedEdges(Iterable<LockNode> lockNodes,
+                                            ContextReaderIfc reader) {
+        DuplicatedEdgesHandler handler = new DuplicatedEdgesHandler(lockNodes,
+                                                                    reader);
+        handler.updateContextIdTranslationMap();
+        handler.updateEdgesWithTranslationMap();
+    }
+
+    private void updateEdgesWithTranslationMap() {
+        for (LockNode node : mLockNodes) {
+            node.translateContextIds(mContextIdTranslation);
+        }
+    }
+
+    private Map<Integer, Integer> populateTranslationMap() {
+        final HashMap<Integer, Integer> contextIds =
+            new HashMap<Integer, Integer>();
+        for (LockNode node : mLockNodes) {
+            node.populateContextIdTranslationMap(contextIds);
+        }
+        return contextIds;
+    }
+
+    private Map<LockingContext, TreeSet<Integer>>
+    createContextToIdMap(ContextReaderIfc reader) {
+        final Map<LockingContext, TreeSet<Integer>> contextToId =
+            new HashMap<LockingContext, TreeSet<Integer>>();
+        for (Integer id : mContextIdTranslation.values()) {
+            LockingContext context = reader.readContext(id);
+            TreeSet<Integer> ids = contextToId.get(context);
+            if (ids == null) {
+                ids = new TreeSet<Integer>();
+                contextToId.put(context, ids);
+            }
+            ids.add(id);
+        }
+        return contextToId;
+    }
+
+    private void updateContextIdTranslationMap() {
+        for (TreeSet<Integer> ids : mContextToIdMap.values()) {
+            if (ids.size() > 1) {
+                Iterator<Integer> iter = ids.iterator();
+                Integer firstId = iter.next();
+                while (iter.hasNext()) {
+                    mContextIdTranslation.put(iter.next(), firstId);
+                }
+            }
+        }
+    }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/analyzer/GraphvizGenerator.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/analyzer/GraphvizGenerator.java
new file mode 100644 (file)
index 0000000..4d49009
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.analyzer;
+
+import java.util.HashSet;
+
+import com.enea.jcarder.common.LockingContext;
+import com.enea.jcarder.common.contexts.ContextReaderIfc;
+
+/**
+ * This class can be used to generate a Graphviz <http://www.graphviz.org> graph
+ * as a string.
+ *
+ * TODO Add tooltips to the graph? The tooltips might for example contain the
+ * package names of classes.
+ *
+ * TODO If there are to many edges, merge them together in the graph and add an
+ * href link to an html page that describes them all?
+ *
+ * TODO Optionaly merge edges that are identical except for the threads?
+ */
+final class GraphvizGenerator {
+    private static final String EDGE_LABEL_FORMAT =
+        " [fontsize=10, label=<\n" +
+        "     <table align=\"left\" border=\"0\" cellborder=\"0\"\n" +
+        "            cellspacing=\"0\" cellpadding=\"0\">\n" +
+        "       <tr>\n" +
+        "         <td align=\"left\">  </td>\n" +
+        "         <td align=\"left\" colspan=\"2\">" +
+        "Thread: %1$s<br align=\"left\"/>" +
+        "</td>\n" +
+        "       </tr>\n" +
+        "       <tr>\n" +
+        "         <td align=\"left\">  </td>\n" +
+        "         <td align=\"left\" colspan=\"2\">" +
+        "holding: %2$s<br align=\"left\"/>" +
+        "</td>\n" +
+        "       </tr>\n" +
+        "       <tr>\n" +
+        "         <td align=\"left\">  </td>\n" +
+        "         <td align=\"left\">  </td>\n" +
+        "         <td align=\"left\">" +
+        "in: %3$s<br align=\"left\"/>" +
+        "</td>\n" +
+        "       </tr>\n" +
+        "       <tr>\n" +
+        "         <td align=\"left\">  </td>\n" +
+        "         <td align=\"left\" colspan=\"2\">" +
+        "taking: %4$s<br align=\"left\"/>" +
+        "</td>\n" +
+        "       </tr> \n" +
+        "       <tr>\n" +
+        "         <td align=\"left\">  </td>\n" +
+        "         <td align=\"left\">  </td>\n" +
+        "         <td align=\"left\">" +
+        "in: %5$s<br align=\"left\"/>" +
+        "</td>\n" +
+        "       </tr>\n" +
+        "     </table>\n" +
+        "    >]";
+
+    public String generate(Iterable<LockEdge> edgesToBePrinted,
+                           ContextReaderIfc reader,
+                           boolean includePackages) {
+        StringBuffer sb = new StringBuffer();
+        sb.append("digraph G {\n");
+        sb.append("  node [shape=ellipse, style=filled, fontsize=12];\n");
+        final HashSet<LockNode> alreadyAppendedNodes = new HashSet<LockNode>();
+        for (LockEdge edge : edgesToBePrinted) {
+            appendNodeIfNotAppended(reader,
+                                    sb,
+                                    alreadyAppendedNodes,
+                                    edge.getSource());
+            appendNodeIfNotAppended(reader,
+                                    sb,
+                                    alreadyAppendedNodes,
+                                    edge.getTarget());
+            sb.append("  " + edge.getSource().toString() + "");
+            sb.append(" -> " + edge.getTarget().toString() + "");
+            sb.append(createEdgeLabel(reader, edge, includePackages));
+            sb.append(";\n");
+        }
+        sb.append("}\n");
+        return sb.toString();
+    }
+
+    private String createEdgeLabel(ContextReaderIfc reader,
+                                   LockEdge edge,
+                                   boolean includePackages) {
+        final LockingContext source =
+            reader.readContext(edge.getSourceLockingContextId());
+        final LockingContext target =
+            reader.readContext(edge.getTargetLockingContextId());
+        return String.format(EDGE_LABEL_FORMAT,
+                             escape(handlePackage(target.getThreadName(),
+                                                  includePackages)),
+                             escape(handlePackage(source.getLockReference(),
+                                                  includePackages)),
+                             escape(handlePackage(source.getMethodWithClass(),
+                                                  includePackages)),
+                             escape(handlePackage(target.getLockReference(),
+                                                  includePackages)),
+                             escape(handlePackage(target.getMethodWithClass(),
+                                                  includePackages)));
+    }
+
+    private String handlePackage(String s,
+                                 boolean includePackages) {
+        String[] parts = s.split("\\.");
+        if (parts.length >= 2 && !includePackages) {
+            return parts[parts.length - 2] + "." + parts[parts.length - 1];
+        } else {
+            return s;
+        }
+    }
+
+    private static String escape(String s) {
+        return s.replace("&", "&amp;")
+                .replace("<", "&lt;")
+                .replace(">", "&gt;")
+                .replace("\"", "&quot;")
+                .replace("\'", "&#039;");
+    }
+
+    private String getLockNodeString(LockNode node,
+                                     ContextReaderIfc reader) {
+        final String color;
+        switch (node.getCycleType()) {
+        case CYCLE:
+            color = "firebrick1";
+            break;
+        case SINGLE_THREADED_CYCLE:
+            color = "yellow";
+            break;
+        default:
+            color = "white";
+        }
+        return "  " + node.toString() + " [label = \""
+               + escape(reader.readLock(node.getLockId()).toString())
+               + "\" , fillcolor=" + color + "];\n";
+    }
+
+    private void appendNodeIfNotAppended(ContextReaderIfc reader,
+                                         StringBuffer sb,
+                                         HashSet<LockNode> alreadyAppendedNodes,
+                                         LockNode node) {
+        if (!alreadyAppendedNodes.contains(node)) {
+            alreadyAppendedNodes.add(node);
+            sb.append(getLockNodeString(node, reader));
+        }
+    }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/analyzer/LockEdge.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/analyzer/LockEdge.java
new file mode 100644 (file)
index 0000000..c317573
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.analyzer;
+
+import java.util.Map;
+
+import net.jcip.annotations.NotThreadSafe;
+
+import com.enea.jcarder.common.LockingContext;
+import com.enea.jcarder.common.contexts.ContextReaderIfc;
+
+/**
+ * A LockEdge instance represents a directed edge from a source LockNode to a
+ * target LockNode.
+ */
+@NotThreadSafe
+class LockEdge {
+    private final LockNode mSource;
+    private final LockNode mTarget;
+    private final long mThreadId; // The thread that did the synchronization.
+    private int mSourceContextId;
+    private int mTargetContextId;
+    private long mNumberOfDuplicates;
+
+    LockEdge(LockNode source,
+             LockNode target,
+             long threadId,
+             int sourceLockingContextId,
+             int targetLockingContextId) {
+        mSource = source;
+        mTarget = target;
+        mThreadId = threadId;
+        mSourceContextId = sourceLockingContextId;
+        mTargetContextId = targetLockingContextId;
+        mNumberOfDuplicates = 0;
+    }
+
+    void merge(LockEdge other) {
+        assert this.equals(other);
+        mNumberOfDuplicates += (other.mNumberOfDuplicates + 1);
+    }
+
+    long getDuplicates() {
+        return mNumberOfDuplicates;
+    }
+
+    boolean alike(LockEdge other, ContextReaderIfc reader) {
+        /*
+         * TODO Some kind of cache to improve performance? Note that the context
+         * IDs are not declared final.
+         */
+        LockingContext thisSourceContext =
+            reader.readContext(mSourceContextId);
+        LockingContext otherSourceContext =
+            reader.readContext(other.mSourceContextId);
+        LockingContext thisTargetContext =
+            reader.readContext(mTargetContextId);
+        LockingContext otherTargetContext =
+            reader.readContext(other.mTargetContextId);
+        return thisSourceContext.alike(otherSourceContext)
+               && thisTargetContext.alike(otherTargetContext)
+               && mSource.alike(other.mSource, reader)
+               && mTarget.alike(other.mTarget, reader);
+    }
+
+    public boolean equals(Object obj) {
+        /*
+         * TODO It might be a potential problem to use LockEdges in HashMaps
+         * since they are mutable and this equals method depends on them?
+         */
+        try {
+            LockEdge other = (LockEdge) obj;
+            return (mTarget.getLockId() == other.mTarget.getLockId())
+            && (mSource.getLockId() == other.mSource.getLockId())
+            && (mThreadId == other.mThreadId)
+            && (mSourceContextId == other.mSourceContextId)
+            && (mTargetContextId == other.mTargetContextId);
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
+    public int hashCode() {
+        // TODO Improve hashCode algorithm to improve performance?
+        return mTarget.getLockId() + mSource.getLockId();
+    }
+
+    LockNode getTarget() {
+        return mTarget;
+    }
+
+    LockNode getSource() {
+        return mSource;
+    }
+
+    int getSourceLockingContextId() {
+        return mSourceContextId;
+    }
+
+    int getTargetLockingContextId() {
+        return mTargetContextId;
+    }
+
+    /**
+     * Translate the source and target context ID according to a translation
+     * map.
+     */
+    void translateContextIds(Map<Integer, Integer> translation) {
+        final Integer newSourceId = translation.get(mSourceContextId);
+        if (newSourceId != null && newSourceId != mSourceContextId) {
+            mSourceContextId = newSourceId;
+        }
+        final Integer newTargetId = translation.get(mTargetContextId);
+        if (newTargetId != null && newSourceId != mTargetContextId) {
+            mTargetContextId = newTargetId;
+        }
+    }
+
+    long getThreadId() {
+        return mThreadId;
+    }
+
+    public String toString() {
+        return "  " + mSource + "->" + mTarget;
+    }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/analyzer/LockGraphBuilder.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/analyzer/LockGraphBuilder.java
new file mode 100644 (file)
index 0000000..1da9af7
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.analyzer;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+import java.util.Vector;
+import net.jcip.annotations.NotThreadSafe;
+
+import com.enea.jcarder.common.events.LockEventListenerIfc;
+
+/**
+ * This class is responsible for constructing a structure of LockNode and
+ * LockEdge objects from incoming lock events.
+ *
+ * TODO Add basic tests for this class.
+ */
+@NotThreadSafe
+class LockGraphBuilder implements LockEventListenerIfc {
+    private HashMap<Integer, LockNode> mLocks =
+        new HashMap<Integer, LockNode>();
+
+    LockNode getLockNode(int lockId) {
+        LockNode lockNode = mLocks.get(lockId);
+        if (lockNode == null) {
+            lockNode = new LockNode(lockId);
+            mLocks.put(lockId, lockNode);
+        }
+        return lockNode;
+    }
+
+    public void onLockEvent(int lockId,
+                            int lockingContextId,
+                            int lastTakenLockId,
+                            int lastTakenLockingContectId,
+                            long threadId) {
+        if (lastTakenLockId >= 0) {
+            final LockNode sourceLock = getLockNode(lastTakenLockId);
+            final LockNode targetLock = getLockNode(lockId);
+            final LockEdge edge = new LockEdge(sourceLock,
+                                               targetLock,
+                                               threadId,
+                                               lastTakenLockingContectId,
+                                               lockingContextId);
+            sourceLock.addOutgoingEdge(edge);
+        }
+    }
+
+    void clear() {
+        mLocks.clear();
+    }
+
+    Iterable<LockNode> getAllLocks() {
+        return mLocks.values();
+    }
+
+    public void tronLockEvent(Vector srgs) throws IOException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/analyzer/LockNode.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/analyzer/LockNode.java
new file mode 100644 (file)
index 0000000..06d3e72
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.analyzer;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import net.jcip.annotations.NotThreadSafe;
+
+import com.enea.jcarder.common.contexts.ContextReaderIfc;
+
+/**
+ * A LockNode instance represents a lock in a graph.
+ */
+@NotThreadSafe
+class LockNode {
+    enum CycleType { NO_CYCLE, SINGLE_THREADED_CYCLE, CYCLE };
+
+    private final int mLockId;
+    private Map<LockEdge, LockEdge> mOutgoingEdges;
+    private CycleType mCycleType = CycleType.NO_CYCLE;
+
+    LockNode(final int lockId) {
+        mLockId = lockId;
+        mOutgoingEdges = new HashMap<LockEdge, LockEdge>();
+    }
+
+    int getLockId() {
+        return mLockId;
+    }
+
+    CycleType getCycleType() {
+        return mCycleType;
+    }
+
+    void raiseCycleType(CycleType newCycleType) {
+        if (newCycleType.compareTo(mCycleType) > 0) {
+            mCycleType = newCycleType;
+        }
+    }
+
+    void addOutgoingEdge(LockEdge newEdge) {
+        LockEdge existingEdge = mOutgoingEdges.get(newEdge);
+        if (existingEdge == null) {
+            mOutgoingEdges.put(newEdge, newEdge);
+        } else {
+            existingEdge.merge(newEdge);
+        }
+    }
+
+    void populateContextIdTranslationMap(Map<Integer, Integer> translationMap) {
+        for (LockEdge edge : mOutgoingEdges.values()) {
+            translationMap.put(edge.getSourceLockingContextId(),
+                               edge.getSourceLockingContextId());
+            translationMap.put(edge.getTargetLockingContextId(),
+                               edge.getTargetLockingContextId());
+        }
+    }
+
+    void translateContextIds(Map<Integer, Integer> translation) {
+        Map<LockEdge, LockEdge> oldEdges = mOutgoingEdges;
+        mOutgoingEdges = new HashMap<LockEdge, LockEdge>(oldEdges.size());
+        for (LockEdge edge : oldEdges.values()) {
+            edge.translateContextIds(translation);
+            addOutgoingEdge(edge);
+        }
+    }
+
+    Set<LockEdge> getOutgoingEdges() {
+        return mOutgoingEdges.keySet();
+    }
+
+    public String toString() {
+        return "L_" + mLockId;
+    }
+
+    long numberOfUniqueEdges() {
+        return mOutgoingEdges.size();
+    }
+
+    long numberOfDuplicatedEdges() {
+        long numberOfDuplicatedEdges = 0;
+        for (LockEdge edge : mOutgoingEdges.values()) {
+            numberOfDuplicatedEdges += edge.getDuplicates();
+        }
+        return numberOfDuplicatedEdges;
+    }
+
+    boolean alike(LockNode other, ContextReaderIfc reader) {
+        // TODO Maybe introduce some kind of cache to improve performance?
+        String thisClassName = reader.readLock(mLockId).getClassName();
+        String otherClassName = reader.readLock(other.mLockId).getClassName();
+        return thisClassName.equals(otherClassName);
+    }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/common/Lock.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/common/Lock.java
new file mode 100644 (file)
index 0000000..114997b
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.common;
+
+//import net.jcip.annotations.ThreadSafe;
+
+/**
+ * A Lock instance represents a Java monitor object.
+ */
+//@ThreadSafe
+public final class Lock {
+    private final String mClassName;
+    private final int mObjectId;
+
+    public Lock(Object lock) {
+        mClassName = lock.getClass().getName();
+        mObjectId = System.identityHashCode(lock);
+    }
+
+    public Lock(String className, int objectId) {
+        mClassName = className;
+        mObjectId = objectId;
+    }
+
+    public String toString() {
+        return mClassName + '@' + Integer.toHexString(mObjectId).toUpperCase();
+    }
+
+    public int getObjectId() {
+        return mObjectId;
+    }
+
+    public String getClassName() {
+        return mClassName;
+    }
+
+    public int hashCode() {
+        return mObjectId;
+    }
+
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        final Lock other = (Lock) obj;
+        return mObjectId == other.mObjectId
+               && mClassName.equals(other.mClassName);
+    }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/common/LockingContext.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/common/LockingContext.java
new file mode 100644 (file)
index 0000000..7d5ed8a
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.common;
+
+//import net.jcip.annotations.ThreadSafe;
+
+/**
+ * An instance of this class represents the context for the acquiring of a lock.
+ */
+//@ThreadSafe
+public final class LockingContext {
+    /**
+     * The name of the thread that acquired the lock.
+     */
+    private final String mThreadName;
+
+    /**
+     * A textual description of how the lock object was addressed. For example:
+     * "this", "com.enea.jcarder.Foo.mBar" or "com.enea.jcarder.Foo.getLock()"
+     */
+    private final String mLockReference;
+
+    /**
+     * The method that acquired a lock, on the
+     * format "com.enea.jcarder.Foo.bar()".
+     */
+    private final String mMethodWithClass;
+    // TODO Include row number in MethodWithClass?
+
+    public LockingContext(String threadName,
+                          String lockReference,
+                          String methodWithClass) {
+        mThreadName = threadName;
+        mLockReference = lockReference;
+        mMethodWithClass = methodWithClass;
+    }
+
+    public LockingContext(Thread thread,
+                          String lockReference,
+                          String methodWithClass) {
+        this(thread.getName(), lockReference, methodWithClass);
+    }
+
+    public String getLockReference() {
+        return mLockReference;
+    }
+
+    public String getMethodWithClass() {
+        return mMethodWithClass;
+    }
+
+    public String getThreadName() {
+        return mThreadName;
+    }
+
+    public boolean alike(LockingContext other) {
+        return mLockReference.equals(other.mLockReference)
+               && mMethodWithClass.equals(other.mMethodWithClass);
+    }
+
+    public boolean equals(Object other) {
+        try {
+            if (other == null) {
+                return false;
+            }
+            // TODO Maybe use interned strings to improve performance?
+            final LockingContext otherContext = (LockingContext) other;
+            return mThreadName.equals(otherContext.mThreadName)
+                   && mLockReference.equals(otherContext.mLockReference)
+                   && mMethodWithClass.equals(otherContext.mMethodWithClass);
+        } catch (ClassCastException e) {
+            return false;
+        }
+    }
+
+    public int hashCode() {
+        return mThreadName.hashCode()
+               + mMethodWithClass.hashCode()
+               + mLockReference.hashCode();
+    }
+
+    public String toString() {
+        return "Thread: " + mThreadName
+               + " LockRef: " + mLockReference
+               + " Method:  " + mMethodWithClass;
+    }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/common/contexts/ContextFileReader.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/common/contexts/ContextFileReader.java
new file mode 100644 (file)
index 0000000..8afad30
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.common.contexts;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.charset.Charset;
+
+//import net.jcip.annotations.NotThreadSafe;
+
+import com.enea.jcarder.common.Lock;
+import com.enea.jcarder.common.LockingContext;
+import com.enea.jcarder.util.logging.Logger;
+
+//@NotThreadSafe
+public final class ContextFileReader
+implements ContextReaderIfc {
+    // TODO Make the directory of the database files configurable?
+    public static final String EVENT_DB_FILENAME = "jcarder_events.db";
+    public static final String CONTEXTS_DB_FILENAME = "jcarder_contexts.db";
+    static final long MAGIC_COOKIE = 3927194112434171438L;
+    static final int MAJOR_VERSION = 1;
+    static final int MINOR_VERSION = 0;
+    static final Charset CHARSET = Charset.forName("UTF-8");
+    private final Logger mLogger;
+    private final ByteBuffer mBuffer;
+
+    public ContextFileReader(Logger logger, File file) throws IOException {
+        mLogger = logger;
+        RandomAccessFile raFile = new RandomAccessFile(file, "r");
+        final String path = file.getCanonicalPath();
+        mLogger.info("Opening for reading: " + path);
+        FileChannel roChannel = raFile.getChannel();
+        if (roChannel.size() > Integer.MAX_VALUE) {
+            throw new IOException("File too large: " + path);
+        }
+        mBuffer = roChannel.map(FileChannel.MapMode.READ_ONLY,
+                                0,
+                                (int) roChannel.size());
+        roChannel.close();
+        raFile.close();
+        validateHeader(path);
+    }
+
+    private void validateHeader(String filename) throws IOException {
+        mBuffer.rewind();
+        if (MAGIC_COOKIE != mBuffer.getLong()) {
+            throw new IOException("Invalid file contents in: " + filename);
+        }
+        final int majorVersion = mBuffer.getInt();
+        final int minorVersion = mBuffer.getInt();
+        if (majorVersion != MAJOR_VERSION) {
+            throw new IOException("Incompatible version: "
+                                  + majorVersion + "." + minorVersion
+                                  + " in: " + filename);
+        }
+    }
+
+    private String readString() {
+        final int stringBytes = mBuffer.getInt();
+        mBuffer.limit(stringBytes + mBuffer.position());
+        final String result = CHARSET.decode(mBuffer).toString();
+        mBuffer.limit(mBuffer.capacity());
+        return result;
+    }
+
+    public LockingContext readContext(int id) {
+        mBuffer.position(id);
+        return new LockingContext(readString(),
+                                  readString(),
+                                  readString());
+    }
+
+    public Lock readLock(int id) {
+        mBuffer.position(id);
+        String className = readString();
+        int objectId = mBuffer.getInt();
+        return new Lock(className, objectId);
+    }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/common/contexts/ContextFileWriter.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/common/contexts/ContextFileWriter.java
new file mode 100644 (file)
index 0000000..9bf1b6d
--- /dev/null
@@ -0,0 +1,517 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.common.contexts;
+
+
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+
+//import net.jcip.annotations.ThreadSafe;
+
+import com.enea.jcarder.common.Lock;
+import com.enea.jcarder.common.LockingContext;
+import com.enea.jcarder.transactionalinterfaces.Bool;
+import com.enea.jcarder.transactionalinterfaces.Intif;
+import com.enea.jcarder.transactionalinterfaces.bytebuffer;
+import com.enea.jcarder.transactionalinterfaces.jcbuffer;
+import com.enea.jcarder.util.Counter;
+import com.enea.jcarder.util.logging.Logger;
+import dstm2.Init;
+import dstm2.atomic;
+import dstm2.Thread;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.nio.LongBuffer;
+import java.util.Vector;
+import java.util.concurrent.Callable;
+
+import dstm2.AtomicArray;
+
+//@ThreadSafe
+import java.util.logging.Level;
+public final class ContextFileWriter
+implements ContextWriterIfc {
+   
+
+    private final Logger mLogger;
+    RandomAccessFile raFile;
+
+    private bytebuffer mbuff;
+    private Intif test;
+    private Bool ShutdownHookExecuted; 
+    ;
+    
+    
+ //   private boolean mShutdownHookExecuted = false;
+
+    public ContextFileWriter(Logger logger, File file) throws IOException {
+        mbuff = new bytebuffer();
+        mbuff.allocateDirect(8192);
+
+        test = new Intif();
+        test.init();
+        ShutdownHookExecuted = new Bool();
+        ShutdownHookExecuted.init();;
+        mLogger = logger;
+        mLogger.info("Opening for writing: " + file.getAbsolutePath());
+        raFile = new RandomAccessFile(file, "rw");
+         raFile.setLength(0);
+        System.out.println(file.getAbsolutePath());
+       
+        ShutdownHookExecuted.init();
+       
+        
+       
+//        mChannel = raFile.getChannel();
+
+        
+        writeHeader();
+
+        Runtime.getRuntime().addShutdownHook(new Thread() {
+            public void run() { shutdownHook(); }
+        });
+    }
+
+  
+    
+     private synchronized void shutdownHook() {
+      //  System.out.println(Thread.currentThread() + " ashut ddddddborted in committing");
+        
+        Thread.doIt(new Callable<Boolean>() {
+         
+            public Boolean call() {
+            
+                try {
+                    if (raFile.getChannel().isOpen()) {
+                        writeBuffer();
+                    
+                }
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+                
+                ShutdownHookExecuted.set(true);
+                return true;
+            }
+       });
+      
+     }
+
+  
+    
+    private void writeBuffer() throws IOException {
+        mbuff.flip();
+        raFile.write(mbuff.getBytes());
+        
+        while (mbuff.hasRemaining()) {
+            Thread.yield();
+            raFile.write(mbuff.getBytes());
+       }
+        mbuff.clear();
+    }
+
+  
+    
+    private void writeHeader() throws IOException {
+     //   System.out.println("head");
+        ByteBuffer mBuffer = ByteBuffer.allocateDirect(16);
+        mBuffer.putLong(ContextFileReader.MAGIC_COOKIE);
+        mBuffer.putInt(ContextFileReader.MAJOR_VERSION);
+        mBuffer.putInt(ContextFileReader.MINOR_VERSION);
+        mBuffer.rewind();
+        mbuff.put(mBuffer);
+        test.increment(8+4+4);
+        //filePosition.increment(8+4+4);
+    }
+
+
+    
+    public synchronized void close() throws IOException {
+      //  System.out.println("clo");
+        
+            Thread.doIt(new Callable<Boolean>() {
+                
+            public Boolean call() {
+                try {
+                  //  System.out.println(Thread.currentThread() + " closeaborted in committing");
+                      writeBuffer();
+                      raFile.close();  
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+                
+                return true;
+            };
+       });
+        
+    }
+
+  
+    
+    private void writeString(String s) throws IOException {
+     //   System.out.println("str");
+        ByteBuffer encodedString = ContextFileReader.CHARSET.encode(s);
+        final int length = encodedString.remaining();
+        assureBufferCapacity(4 + length);
+        ByteBuffer mBuffer = ByteBuffer.allocateDirect(length +4);
+        mBuffer.putInt(length);
+        mBuffer.put(encodedString);
+        mBuffer.rewind();
+        mbuff.put(mBuffer);
+        
+        //for (int j=0; j<4+length; j++){
+        //       mbuff.factory2.create();
+        //}
+        //mbuff.put(mBuffer.get());
+        test.increment(4+length);
+        //
+
+    }
+
+    
+    private void writeInteger(int i) throws IOException {
+        assureBufferCapacity(4);
+        ByteBuffer mBuffer = ByteBuffer.allocateDirect(4);
+        mBuffer.putInt(i);
+        mBuffer.rewind();
+        mbuff.put(mBuffer);
+        //for (int j=0; j<4; j++){
+           // mbuff.factory2.create();
+               //mbuff.put(mBuffer.get());
+        //}
+        test.increment(4);
+    }
+
+  
+    
+    private void assureBufferCapacity(int size) throws IOException {
+        if (mbuff.remaining() < size){// || ShutdownHookExecuted.isTrue()) {
+            writeBuffer();
+        }
+
+        // Grow buffer if it can't hold the requested size.
+        while (mbuff.capacity() < size) {
+            mbuff = mbuff.allocateDirect(2 * mbuff.capacity());
+        }
+    }
+    
+    
+    
+
+   
+    
+    public int writeLock(Lock lock) throws IOException {
+        int startPosition = test.get();
+        writeString(lock.getClassName());
+        writeInteger(lock.getObjectId());
+        
+     //   ByteBuffer encodedString = ContextFileReader.CHARSET.encode(((Lock)arg.get(0)).getClassName());
+     //   final int length = encodedString.remaining();
+      //  ByteBuffer mBuffer = ByteBuffer.allocateDirect(8+ length);
+     //   mBuffer.putInt(length);
+     //   mBuffer.put(encodedString);
+      //  mBuffer.putInt(((Lock)arg.get(0)).getObjectId());
+       // mBuffer.rewind();
+       // assureBufferCapacity(8+length);
+       // for (int j=0; j<(8+length); j++){
+        //    byte value = mBuffer.get();
+         //   mbuff.put(value);
+       // }
+    //    mbuff.put(mBuffer);
+       // test.increment(8+length);
+        flushBufferIfNeeded();
+        return startPosition;
+        
+    }
+    
+ /*   public int writeLockWrapper(Lock lock) throws IOException {
+      //  System.out.println("lock");
+            int result = 0;
+            try{
+            final Vector arg = new Vector() ;
+            arg.add(lock);
+            result = Thread.doIt(new Callable<Integer>() {
+       
+               public Integer call() {
+                       try {
+              //              System.out.println(Thread.currentThread() + " alockborted in committing");
+                            return writeLock(arg);
+                          //  System.out.println(Thread.currentThread() + " NO???? alockborted in committing");
+                       } catch (IOException ex) {
+                            java.util.logging.Logger.getLogger(ContextFileWriter.class.getName()).log(Level.SEVERE, null, ex);
+                        }
+                       return -1;
+               }
+            }); 
+            
+            }catch(GracefulException e){
+           System.out.println(Thread.currentThread() + "lock graceful exc");
+           
+            }finally{
+                return result;
+            }
+    }*/
+
+  
+    
+     public int writeContext(LockingContext context)
+    throws IOException {
+        int startPosition = test.get();
+        writeString(context.getThreadName());
+        writeString(context.getLockReference());
+        writeString(context.getMethodWithClass());
+        
+     //   ByteBuffer encodedString = ContextFileReader.CHARSET.encode(context.getThreadName());
+      //  final int length = encodedString.remaining();
+      //  ByteBuffer encodedString2 = ContextFileReader.CHARSET.encode(context.getLockReference());
+      //  final int length2 = encodedString2.remaining();
+     //   ByteBuffer encodedString3 = ContextFileReader.CHARSET.encode(context.getMethodWithClass());
+     //   final int length3 = encodedString3.remaining();
+      //  ByteBuffer mBuffer = ByteBuffer.allocateDirect(12+length+length2+length3);
+        
+      //  mBuffer.putInt(length);
+      //  mBuffer.put(encodedString);
+      //  mBuffer.putInt(length2);
+      //  mBuffer.put(encodedString2);
+      //  mBuffer.putInt(length3);
+      //  mBuffer.put(encodedString3);
+      //  mBuffer.rewind();
+
+        
+        
+       // assureBufferCapacity(12 + length + length2 + length3);
+       //for (int j=0;j<(12+length +length2 +length3);j++){
+       //       byte value = mBuffer.get();
+        //      mbuff.put(value);
+      // }
+     //   mbuff.put(mBuffer);
+       
+        //test.increment(12+length +length2 +length3);
+        flushBufferIfNeeded();
+        
+        return startPosition;
+       // mbuff.put((byte)2);
+       // return -1;
+    }
+
+/*   public int writeContext(LockingContext context)
+    {
+       int startPosition = -2;
+       try{
+        final LockingContext c = context;  
+        startPosition = Thread.doIt(new Callable<Integer>() {
+                
+               public Integer call() throws IOException {
+                                return trwriteContext(c); 
+               }
+               
+        });
+         
+        
+
+        }catch(GracefulException e){
+           System.out.println(Thread.currentThread() + " context graceful exc");
+       }
+       finally{
+ //        System.out.println(Thread.currentThread() + " con");
+  //       Throwable t = new Throwable();
+//StackTraceElement[] es = t.getStackTrace();
+//for ( int i=0; i<es.length; i++ )
+   //{
+   //StackTraceElement e = es[i];
+   //System.out.println( " in class:" + e.getClassName()
+          //             + " in source file:" + e.getFileName()
+         //              + " in method:" + e.getMethodName()
+       //                + " at line:" + e.getLineNumber()
+     //                  + " " + ( e.isNativeMethod() ? "native" : "" ) );
+   //}
+         
+        return startPosition;
+       }
+    }*/
+   
+     private void flushBufferIfNeeded() throws IOException {
+        if (ShutdownHookExecuted.isTrue()) {
+       //     System.out.println("fdddlush");
+            writeBuffer();
+        }
+    }
+
+    public Bool getShutdownHookExecuted() {
+        return ShutdownHookExecuted;
+    }
+
+    public void setShutdownHookExecuted(Bool ShutdownHookExecuted) {
+        this.ShutdownHookExecuted = ShutdownHookExecuted;
+    }
+
+   
+
+    public bytebuffer getMbuff() {
+        return mbuff;
+    }
+
+    public void setMbuff(bytebuffer mbuff) {
+        this.mbuff = mbuff;
+    }
+
+    public RandomAccessFile getRaFile() {
+        return raFile;
+    }
+
+    public void setRaFile(RandomAccessFile raFile) {
+        this.raFile = raFile;
+    }
+
+    public Intif getTest() {
+        return test;
+    }
+
+    public void setTest(Intif test) {
+        this.test = test;
+    }
+
+    public RandomAccessFile getTrraFile() {
+        return raFile;
+    }
+
+    public void setTrraFile(RandomAccessFile trraFile) {
+        this.raFile = trraFile;
+    }
+     
+     
+       
+      
+ /*       private void writeString(String s) throws IOException {
+        ByteBuffer encodedString = ContextFileReader.CHARSET.encode(s);
+        final int length = encodedString.remaining();
+     
+        assureBufferCapacity(4 + length);
+        mBuffer.putInt(length);
+        mBuffer.put(encodedString);
+        for (int j =0; j<4+length; j++)
+            mbuff.put(mBuffer.get());
+         //   datastindex++;
+        //}
+        
+        mNextFilePosition += 4 + length;
+    }
+      
+      private synchronized void shutdownHook() {
+        System.out.println("shut");
+        try {
+            if (mChannel.isOpen()) {
+                  System.out.println("shut");
+                writeBuffer();
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        mShutdownHookExecuted = true;
+    }
+    
+  
+    
+        public synchronized void close() throws IOException {
+        writeBuffer();
+        mChannel.close();
+    }
+    
+       private void writeInteger(int i) throws IOException {
+        assureBufferCapacity(4);
+        mBuffer.putInt(i);
+        System.out.println("ffff");
+        for (int j =0; j<4; j++)
+            mbuff.put(mBuffer.get());
+  //          data[dataendindex+i] = mBuffer.get();
+//            datastindex++;
+    //    }
+        mNextFilePosition += 4;
+        
+    }
+      private void assureBufferCapacity(int size) throws IOException {
+        if (mBuffer.remaining() < size || mShutdownHookExecuted) {
+            writeBuffer();
+        }
+
+        // Grow buffer if it can't hold the requested size.
+        while (mBuffer.capacity() < size) {
+            System.out.println("be ga raftam");
+            mBuffer = ByteBuffer.allocateDirect(2 * mBuffer.capacity());
+        }
+    }
+    
+     public synchronized int writeLock(Lock lock) throws IOException {
+        final int startPosition = mNextFilePosition;
+        writeString(lock.getClassName());
+        writeInteger(lock.getObjectId());
+        flushBufferIfNeeded();
+        return startPosition;
+    }
+    
+    public synchronized int writeContext(LockingContext context)
+    throws IOException {
+        final int startPosition = mNextFilePosition;
+        writeString(context.getThreadName());
+        writeString(context.getLockReference());
+        writeString(context.getMethodWithClass());
+        flushBufferIfNeeded();
+       System.out.println(Thread.currentThread() + " con");
+        return startPosition;
+    }
+    
+    private void flushBufferIfNeeded() throws IOException {
+        if (mShutdownHookExecuted) {
+            writeBuffer();
+      //      System.out.println("sssskk");
+        }
+    }
+      
+        private void writeBuffer() throws IOException {
+            mBuffer.flip();
+            int rem = mBuffer.remaining();
+            int i = 0;
+            //while (mBuffer.hasRemaining()) {
+            while (i< rem) {
+                Thread.yield();
+                raFile.write(data);
+               // int written = mChannel.write(mBuffer);
+                i++;
+             //   mBuffer.position(mBuffer.position() + written);
+                        
+            }
+            mBuffer.clear();
+        } 
+        private void writeHeader() throws IOException {
+            mBuffer.putLong(ContextFileReader.MAGIC_COOKIE);
+            mBuffer.putInt(ContextFileReader.MAJOR_VERSION);
+            mBuffer.putInt(ContextFileReader.MINOR_VERSION);
+            mNextFilePosition += 8 + 4 + 4;
+
+    }*/
+    }
+    
+   
+                  
+
+
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/common/contexts/ContextMemory.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/common/contexts/ContextMemory.java
new file mode 100644 (file)
index 0000000..80fb988
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.common.contexts;
+
+import java.util.LinkedList;
+//import net.jcip.annotations.NotThreadSafe;
+import com.enea.jcarder.common.Lock;
+import com.enea.jcarder.common.LockingContext;
+
+//@NotThreadSafe
+public final class ContextMemory
+implements ContextWriterIfc, ContextReaderIfc {
+
+    private final LinkedList<Lock> mLocks = new LinkedList<Lock>();
+    private final LinkedList<LockingContext> mLockingContexts =
+        new LinkedList<LockingContext>();
+
+    public int writeLock(Lock lock) {
+        mLocks.addLast(lock);
+        return mLocks.size() - 1;
+    }
+
+    public int writeContext(LockingContext context) {
+        mLockingContexts.addLast(context);
+        return mLockingContexts.size() - 1;
+    }
+
+    public Lock readLock(int id) {
+        return mLocks.get(id);
+    }
+
+    public LockingContext readContext(int id) {
+        return mLockingContexts.get(id);
+    }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/common/contexts/ContextReaderIfc.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/common/contexts/ContextReaderIfc.java
new file mode 100644 (file)
index 0000000..1dfb1e4
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.common.contexts;
+
+import com.enea.jcarder.common.Lock;
+import com.enea.jcarder.common.LockingContext;
+
+public interface ContextReaderIfc {
+    LockingContext readContext(int id);
+    Lock readLock(int id);
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/common/contexts/ContextWriterIfc.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/common/contexts/ContextWriterIfc.java
new file mode 100644 (file)
index 0000000..2999990
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.common.contexts;
+
+import java.io.IOException;
+
+import com.enea.jcarder.common.Lock;
+import com.enea.jcarder.common.LockingContext;
+
+public interface ContextWriterIfc {
+
+    int writeLock(Lock lock) throws IOException;
+
+    int writeContext(LockingContext context) throws IOException;
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/common/events/EventFileReader.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/common/events/EventFileReader.java
new file mode 100644 (file)
index 0000000..c4a9851
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.common.events;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+
+import com.enea.jcarder.util.logging.Logger;
+
+public final class EventFileReader {
+    private static final int INT_LENGTH = 4;
+    private static final int LONG_LENGTH = 8;
+    private final Logger mLogger;
+    static final int EVENT_LENGTH = (INT_LENGTH * 4) + LONG_LENGTH;
+    static final long MAGIC_COOKIE = 2153191828159737167L;
+    static final int MAJOR_VERSION = 1;
+    static final int MINOR_VERSION = 0;
+
+    public EventFileReader(Logger logger) {
+        mLogger = logger;
+    }
+
+    public void parseFile(File file,
+                          LockEventListenerIfc eventReceiver)
+    throws IOException {
+        int numberOfParsedEvents = 0;
+        FileInputStream fis = new FileInputStream(file);
+        final String path = file.getCanonicalPath();
+        mLogger.info("Opening for reading: " + path);
+        FileChannel fileChannel = fis.getChannel();
+        validateHeader(fileChannel, path);
+        final ByteBuffer buffer = ByteBuffer.allocate(EVENT_LENGTH);
+        while (fileChannel.read(buffer) == EVENT_LENGTH) {
+            buffer.rewind();
+            parseLockEvent(buffer, eventReceiver);
+            buffer.rewind();
+            numberOfParsedEvents++;
+        }
+        mLogger.fine("Loaded " + numberOfParsedEvents
+                     + " lock events from file.");
+    }
+
+    private void validateHeader(FileChannel channel,
+                                String filename) throws IOException {
+        final ByteBuffer buffer = ByteBuffer.allocate(8 + 4 + 4);
+        channel.read(buffer);
+        buffer.flip();
+        if (MAGIC_COOKIE != buffer.getLong()) {
+            throw new IOException("Invalid file contents in: " + filename);
+        }
+        final int majorVersion = buffer.getInt();
+        final int minorVersion = buffer.getInt();
+        if (majorVersion != MAJOR_VERSION) {
+            throw new IOException("Incompatible version: "
+                                  + majorVersion + "." + minorVersion
+                                  + " in: " + filename);
+        }
+    }
+
+    private static void parseLockEvent(ByteBuffer lockEventBuffer,
+                                       LockEventListenerIfc eventReceiver)
+    throws IOException {
+        final int lockId                    = lockEventBuffer.getInt();
+        final int lockingContextId          = lockEventBuffer.getInt();
+        final int lastTakenLockId           = lockEventBuffer.getInt();
+        final int lastTakenLockingContextId = lockEventBuffer.getInt();
+        final long threadId                 = lockEventBuffer.getLong();
+        eventReceiver.onLockEvent(lockId,
+                                  lockingContextId,
+                                  lastTakenLockId,
+                                  lastTakenLockingContextId,
+                                  threadId);
+    }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/common/events/EventFileWriter.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/common/events/EventFileWriter.java
new file mode 100644 (file)
index 0000000..300b3bf
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.common.events;
+
+
+import TransactionalIO.exceptions.GracefulException;
+import com.enea.jcarder.transactionalinterfaces.Bool;
+import com.enea.jcarder.transactionalinterfaces.bytebuffer;
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+//import net.jcip.annotations.ThreadSafe;
+
+import com.enea.jcarder.util.Counter;
+import com.enea.jcarder.util.TransactionalCounter;
+import com.enea.jcarder.util.logging.Logger;
+
+import java.util.concurrent.Callable;
+import static com.enea.jcarder.common.events.EventFileReader.EVENT_LENGTH;
+
+import dstm2.Thread;
+
+//@ThreadSafe
+import java.util.Vector;
+public final class EventFileWriter implements LockEventListenerIfc {
+//    private final ByteBuffer mBuffer =
+ //   ByteBuffer.allocateDirect(EVENT_LENGTH * 1024);
+ //   private final FileChannel mFileChannel;
+    private final Logger mLogger;
+//    private final Counter mWrittenLockEvents;
+//    private boolean mShutdownHookExecuted = false;
+    
+    private bytebuffer mbuff;
+    private Bool ShutdownHookExecuted; 
+    private RandomAccessFile traf; 
+    private TransactionalCounter trmWrittenLockEvents;
+
+    public EventFileWriter(EventFileWriter other){
+        this.ShutdownHookExecuted = other.ShutdownHookExecuted;
+        this.ShutdownHookExecuted.boolif.setValue(other.ShutdownHookExecuted.boolif.getValue());
+        this.mLogger = other.mLogger;
+        this.mbuff = other.mbuff;
+     //   this.mbuff.mbuffer.setByteHolder(other.mbuff.mbuffer.getByteHolder());
+        this.traf = other.traf;
+        this.trmWrittenLockEvents = other.trmWrittenLockEvents;
+        this.trmWrittenLockEvents.mValue.setPosition(other.trmWrittenLockEvents.mValue.getPosition());
+    }
+    
+    public EventFileWriter(Logger logger, File file) throws IOException {
+        
+        
+        
+        mLogger = logger;
+        mLogger.info("Opening for writing: " + file.getAbsolutePath());
+        traf = new RandomAccessFile(file, "rw");
+        traf.setLength(0);
+    //    mFileChannel = raFile.getChannel();
+    //    mWrittenLockEvents = new Counter("Written Lock Events",
+       //                                  mLogger,
+        //                                 100000);
+        
+        mbuff = new bytebuffer();
+        mbuff.allocateDirect(8192);
+        
+        ShutdownHookExecuted = new Bool();
+        ShutdownHookExecuted.init();
+        trmWrittenLockEvents = new TransactionalCounter("Written Lock Events",
+                                         mLogger,
+                                         100000);
+        
+        writeHeader();
+        Runtime.getRuntime().addShutdownHook(new Thread() {
+            public void run() { shutdownHook(); }
+        });
+    }
+
+  /*  private void writeHeader() throws IOException {
+        mBuffer.putLong(EventFileReader.MAGIC_COOKIE);
+        mBuffer.putInt(EventFileReader.MAJOR_VERSION);
+        mBuffer.putInt(EventFileReader.MINOR_VERSION);
+        writeBuffer();
+    }*/
+    
+    private void writeHeader() throws IOException {
+        ByteBuffer mBuffer = ByteBuffer.allocateDirect(16);
+        mBuffer.putLong(EventFileReader.MAGIC_COOKIE);
+        mBuffer.putInt(EventFileReader.MAJOR_VERSION);
+        mBuffer.putInt(EventFileReader.MINOR_VERSION);
+        mBuffer.rewind();
+        
+        /*for (int i=0; i<16; i++){
+            mbuff.put(mBuffer.get());
+        }*/
+         
+        mbuff.put(mBuffer);
+        writeBuffer();
+    }
+
+    /*public synchronized void onLockEvent(int lockId,
+                                         int lockingContextId,
+                                         int lastTakenLockId,
+                                         int lastTakenLockingContextId,
+                                         long threadId) throws IOException {
+        
+        mBuffer.putInt(lockId);
+        mBuffer.putInt(lockingContextId);
+        mBuffer.putInt(lastTakenLockId);
+        mBuffer.putInt(lastTakenLockingContextId);
+        mBuffer.putLong(threadId);
+        mWrittenLockEvents.increment();
+        if (mBuffer.remaining() < EVENT_LENGTH || mShutdownHookExecuted) {
+            writeBuffer();
+        }
+    }*/
+    
+    public void tronLockEvent(Vector arg) throws IOException {
+       
+            ByteBuffer mBuffer = ByteBuffer.allocateDirect(24);
+            mBuffer.putInt((Integer)arg.get(0));
+            mBuffer.putInt((Integer)arg.get(1));
+            mBuffer.putInt((Integer)arg.get(2));
+            mBuffer.putInt((Integer)arg.get(3));
+            mBuffer.putLong((Long)arg.get(4));
+            mBuffer.rewind();
+        
+            //for (int i=0; i<24; i++){
+              //  mbuff.put(mBuffer.get());
+            //}
+            
+            mbuff.put(mBuffer);
+        
+            trmWrittenLockEvents.increment();
+            if (mbuff.remaining() < EVENT_LENGTH || ShutdownHookExecuted.isTrue()) {
+                writeBuffer();
+            }
+    }
+            
+    public void onLockEvent(int lockId,
+                                         int lockingContextId,
+                                         int lastTakenLockId,
+                                         int lastTakenLockingContextId,
+                                         long threadId) throws IOException{
+            
+        
+            final Vector arg = new Vector();
+            arg.add(Integer.valueOf(lockId));
+            arg.add(Integer.valueOf(lockingContextId));
+            arg.add(Integer.valueOf(lastTakenLockId));
+            arg.add(Integer.valueOf(lastTakenLockingContextId));
+            arg.add(Long.valueOf(threadId));
+            Thread.doIt(new Callable<Boolean>() {
+                
+            public Boolean call() throws IOException {
+                tronLockEvent(arg);
+                return true;
+            }
+            
+          });
+        
+    }        
+
+   /* private void writeBuffer() throws IOException {
+        mBuffer.flip();
+        mFileChannel.write(mBuffer);
+        while (mBuffer.hasRemaining()) {
+            Thread.yield();
+            mFileChannel.write(mBuffer);
+        }
+        mBuffer.clear();
+    }*/
+    
+    
+    private void writeBuffer() throws IOException {
+        mbuff.flip();
+        traf.write(mbuff.getBytes());
+        while (mbuff.hasRemaining()) {
+            Thread.yield();
+            traf.write(mbuff.getBytes());
+        }
+        mbuff.clear();
+    }
+
+
+    /*public synchronized void close() throws IOException {
+        
+        writeBuffer();
+        mFileChannel.close();
+    }*/
+    
+     public synchronized void close() throws IOException {
+      //  System.out.println("clo");
+        try{
+            Thread.doIt(new Callable<Boolean>() {
+                
+            public Boolean call() {
+                try {
+                  //  System.out.println(Thread.currentThread() + " closeaborted in committing");
+                      writeBuffer();
+                      traf.close();  
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+                
+                return true;
+            };
+       });
+        }catch(GracefulException e){
+                    System.out.println(Thread.currentThread() + " close graceful exc");
+        }
+    }
+
+  /*  private synchronized void shutdownHook() {
+        try {
+            if (mFileChannel.isOpen()) {
+                writeBuffer();
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        mShutdownHookExecuted = true;
+    }*/
+    
+    
+   private synchronized void shutdownHook() {
+        
+        try{ 
+        Thread.doIt(new Callable<Boolean>() {
+         
+            public Boolean call() {
+            
+                try {
+                    if (traf.getChannel().isOpen()) {
+                        writeBuffer();
+                    
+                }
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+                
+                ShutdownHookExecuted.set(true);
+                return true;
+            }
+       });
+       }catch(GracefulException e){
+           System.out.println(Thread.currentThread() + " shut graceful exc");
+       }
+     }
+
+    public Bool getShutdownHookExecuted() {
+        return ShutdownHookExecuted;
+    }
+
+    public void setShutdownHookExecuted(Bool ShutdownHookExecuted) {
+        this.ShutdownHookExecuted = ShutdownHookExecuted;
+    }
+
+    public bytebuffer getMbuff() {
+        return mbuff;
+    }
+
+    public void setMbuff(bytebuffer mbuff) {
+        this.mbuff = mbuff;
+    }
+
+    public RandomAccessFile getTraf() {
+        return traf;
+    }
+
+    public void setTraf(RandomAccessFile traf) {
+        this.traf = traf;
+    }
+
+    public TransactionalCounter getTrmWrittenLockEvents() {
+        return trmWrittenLockEvents;
+    }
+
+    public void setTrmWrittenLockEvents(TransactionalCounter trmWrittenLockEvents) {
+        this.trmWrittenLockEvents = trmWrittenLockEvents;
+    }
+   
+   
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/common/events/LockEventListenerIfc.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/common/events/LockEventListenerIfc.java
new file mode 100644 (file)
index 0000000..263054a
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.common.events;
+
+import java.io.IOException;
+import java.util.Vector;
+
+public interface LockEventListenerIfc {
+
+    void onLockEvent(int lockId,
+                     int lockingContextId,
+                     int lastTakenLockId,
+                     int lastTakenLockingContextId,
+                     long threadId)throws IOException;
+    
+    void tronLockEvent(Vector srgs)throws IOException;
+}
+
+
+
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/transactionalinterfaces/Bool.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/transactionalinterfaces/Bool.java
new file mode 100644 (file)
index 0000000..7187c78
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package com.enea.jcarder.transactionalinterfaces;
+
+/**
+ *
+ * @author navid
+ */
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+
+
+import dstm2.AtomicArray;
+import dstm2.atomic;
+import dstm2.Thread;
+import dstm2.factory.Factory;
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+/**
+ *
+ * @author navid
+ */
+public class Bool{
+    
+   
+    static Factory<boolif> factory = Thread.makeFactory(boolif.class);
+    public boolif boolif;
+    
+    public void init(){
+        boolif = factory.create();
+        boolif.setValue(false);
+    }
+    
+    public void set(boolean v){
+        boolif.setValue(v);
+    }
+    
+    public boolean isTrue(){
+        return boolif.getValue();
+    }
+     
+    
+     
+     @atomic public interface boolif{
+         boolean getValue();
+         void setValue(boolean value);
+         
+       //  void setLong(long value);   
+     }
+     
+    
+
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/transactionalinterfaces/HashMap.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/transactionalinterfaces/HashMap.java
new file mode 100644 (file)
index 0000000..f1f619e
--- /dev/null
@@ -0,0 +1,897 @@
+package com.enea.jcarder.transactionalinterfaces;
+
+import java.io.IOException;
+import java.util.AbstractSet;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import dstm2.Thread;
+import dstm2.atomic;
+import dstm2.factory.Factory;
+
+public class HashMap<V extends dstm2.AtomicSuperClass> implements Iterable<V>{
+       
+    /**
+     * The default initial capacity - MUST be a power of two.
+     */
+    static final int DEFAULT_INITIAL_CAPACITY = 16;
+
+    /**
+     * The maximum capacity, used if a higher value is implicitly specified
+     * by either of the constructors with arguments.
+     * MUST be a power of two <= 1<<30.
+     */
+    static final int MAXIMUM_CAPACITY = 1 << 30;
+
+    /**
+     * The load factor used when none specified in constructor.
+     **/
+    static final float DEFAULT_LOAD_FACTOR = 0.75f;
+
+    /**
+     * The table, resized as necessary. Length MUST Always be a power of two.
+     */
+    //transient TEntry<V>[] table;
+    dstm2.AtomicArray<TEntry> table;
+    final private Factory<TEntry> factory;
+       
+    //transient Entry<K, V>[] table;
+
+    /**
+     * The number of key-value mappings contained in this identity hash map.
+     */
+    //transient int size;
+    
+    java.util.concurrent.atomic.AtomicInteger size;
+    
+    /*
+     * The capacity of the table
+     */
+    transient int capacity;
+  
+    /**
+     * The next size value at which to resize (capacity * load factor).
+     * @serial
+     */
+    int threshold;
+  
+    /**
+     * The load factor for the hash table.
+     *
+     * @serial
+     */
+    final float loadFactor;
+
+    /**
+     * The number of times this HashMap has been structurally modified
+     * Structural modifications are those that change the number of mappings in
+     * the HashMap or otherwise modify its internal structure (e.g.,
+     * rehash).  This field is used to make iterators on Collection-views of
+     * the HashMap fail-fast.  (See ConcurrentModificationException).
+     */
+    transient volatile int modCount;
+
+    /**
+     * Constructs an empty <tt>HashMap</tt> with the specified initial
+     * capacity and load factor.
+     *
+     * @param  initialCapacity The initial capacity.
+     * @param  loadFactor      The load factor.
+     * @throws IllegalArgumentException if the initial capacity is negative
+     *         or the load factor is nonpositive.
+     */
+    
+      @atomic public interface TEntry<V> {
+       int getHash();
+       V getValue();
+       TEntry<V> getNext();
+       void setHash(int h);
+       void setValue(V v);
+       void setNext(TEntry<V> n);
+       
+    }
+    
+    public HashMap(int initialCapacity, float loadFactor) {
+       size = new AtomicInteger(0);
+       factory = Thread.makeFactory(TEntry.class);
+        if (initialCapacity < 0)
+            throw new IllegalArgumentException("Illegal initial capacity: " +
+                                               initialCapacity);
+        if (initialCapacity > MAXIMUM_CAPACITY)
+            initialCapacity = MAXIMUM_CAPACITY;
+        if (loadFactor <= 0 || Float.isNaN(loadFactor))
+            throw new IllegalArgumentException("Illegal load factor: " +
+                                               loadFactor);
+
+        // Find a power of 2 >= initialCapacity
+        int capacity = 1;
+        while (capacity < initialCapacity) 
+            capacity <<= 1;
+    
+        this.capacity = capacity;
+        this.loadFactor = loadFactor;
+        threshold = (int)(capacity * loadFactor);
+        table = new dstm2.AtomicArray<TEntry>(TEntry.class, capacity);
+//        for(int i = 0; i < capacity; i++) {
+//             table[i] = factory.create();
+//        }
+        //table = new Entry[capacity];
+        init();
+    }
+  
+    /**
+     * Constructs an empty <tt>HashMap</tt> with the specified initial
+     * capacity and the default load factor (0.75).
+     *
+     * @param  initialCapacity the initial capacity.
+     * @throws IllegalArgumentException if the initial capacity is negative.
+     */
+    public HashMap(int initialCapacity) {
+        this(initialCapacity, DEFAULT_LOAD_FACTOR);
+    }
+
+    /**
+     * Constructs an empty <tt>HashMap</tt> with the default initial capacity
+     * (16) and the default load factor (0.75).
+     */
+    public HashMap() {
+       this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
+    }
+
+    /**
+     * Constructs a new <tt>HashMap</tt> with the same mappings as the
+     * specified <tt>Map</tt>.  The <tt>HashMap</tt> is created with
+     * default load factor (0.75) and an initial capacity sufficient to
+     * hold the mappings in the specified <tt>Map</tt>.
+     *
+     * @param   m the map whose mappings are to be placed in this map.
+     * @throws  NullPointerException if the specified map is null.
+     */
+    public HashMap(HashMap<? extends V> m) {
+        this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
+                      DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);
+        putAllForCreate(m);
+    }
+
+    // internal utilities
+
+    /**
+     * Initialization hook for subclasses. This method is called
+     * in all constructors and pseudo-constructors (clone, readObject)
+     * after HashMap has been initialized but before any entries have
+     * been inserted.  (In the absence of this method, readObject would
+     * require explicit knowledge of subclasses.)
+     */
+    void init() {
+    }
+    public dstm2.AtomicArray<TEntry> getBuckets() {
+       return table;
+    }
+    /**
+     * Value representing null keys inside tables.
+     */
+    static final Object NULL_KEY = new Object();
+
+    /**
+     * Returns internal representation for key. Use NULL_KEY if key is null.
+     */
+    static <T> T maskNull(T key) {
+        return key == null ? (T)NULL_KEY : key;
+    }
+
+    /**
+     * Returns key represented by specified internal representation.
+     */
+    static <T> T unmaskNull(T key) {
+        return (key == NULL_KEY ? null : key);
+    }
+
+    /**
+     * Whether to prefer the old supplemental hash function, for
+     * compatibility with broken applications that rely on the
+     * internal hashing order.
+     *
+     * Set to true only by hotspot when invoked via
+     * -XX:+UseNewHashFunction or -XX:+AggressiveOpts
+     */
+    private static final boolean useNewHash;
+    static { useNewHash = false; }
+
+    private static int oldHash(int h) {
+        h += ~(h << 9);
+        h ^=  (h >>> 14);
+        h +=  (h << 4);
+        h ^=  (h >>> 10);
+        return h;
+    }
+
+    private static int newHash(int h) {
+        // This function ensures that hashCodes that differ only by
+        // constant multiples at each bit position have a bounded
+        // number of collisions (approximately 8 at default load factor).
+        h ^= (h >>> 20) ^ (h >>> 12);
+        return h ^ (h >>> 7) ^ (h >>> 4);
+    }
+
+    /**
+     * Applies a supplemental hash function to a given hashCode, which
+     * defends against poor quality hash functions.  This is critical
+     * because HashMap uses power-of-two length hash tables, that
+     * otherwise encounter collisions for hashCodes that do not differ
+     * in lower bits.
+     */
+    public static int hash(int h) {
+       return useNewHash ? newHash(h) : oldHash(h);
+    }
+
+    static int hash(Object key) {
+       return hash(key.hashCode());
+    }
+
+    /** 
+     * Check for equality of non-null reference x and possibly-null y. 
+     */
+    static boolean eq(Object x, Object y) {
+        return x == y || x.equals(y);
+    }
+
+    /**
+     * Returns index for hash code h. 
+     */
+    public static int indexFor(int h, int length) {
+        return h & (length-1);
+    }
+    /**
+     * Returns the number of key-value mappings in this map.
+     *
+     * @return the number of key-value mappings in this map.
+     */
+    public int size() {
+        return size.get();
+    }
+  
+    /**
+     * Returns <tt>true</tt> if this map contains no key-value mappings.
+     *
+     * @return <tt>true</tt> if this map contains no key-value mappings.
+     */
+    public boolean isEmpty() {
+        return size.get() == 0;
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped in this identity
+     * hash map, or <tt>null</tt> if the map contains no mapping for this key.
+     * A return value of <tt>null</tt> does not <i>necessarily</i> indicate
+     * that the map contains no mapping for the key; it is also possible that
+     * the map explicitly maps the key to <tt>null</tt>. The
+     * <tt>containsKey</tt> method may be used to distinguish these two cases.
+     *
+     * @param   key the key whose associated value is to be returned.
+     * @return  the value to which this map maps the specified key, or
+     *          <tt>null</tt> if the map contains no mapping for this key.
+     * @see #put(Object, Object)
+     */
+    public V get(int key) {
+//             if (key == null)
+//                 return getForNullKey();
+        int hash = hash(key);
+        for (TEntry<V> e = table.get(indexFor(hash, capacity));
+             e != null;
+             e = e.getNext()) {
+            Object k;
+            if (e.getHash() == hash)
+                return e.getValue();
+        }
+        return null;
+    }
+
+//    private V getForNullKey() {
+//        int hash = hash(NULL_KEY.hashCode());
+//        int i = indexFor(hash, capacity);
+//        TEntry<K,V> e = table[i];
+//        //Entry<K,V> e = table[i];
+//        while (true) {
+//            if (e == null)
+//                return null;
+//            if (e.getKey() == NULL_KEY)
+//                return e.getValue();
+//            e = e.getNext();
+//        }
+//    }
+
+    /**
+     * Returns <tt>true</tt> if this map contains a mapping for the
+     * specified key.
+     *
+     * @param   key   The key whose presence in this map is to be tested
+     * @return <tt>true</tt> if this map contains a mapping for the specified
+     * key.
+     */
+    public boolean containsKey(int key) {
+        Object k = maskNull(key);
+        int hash = hash(k);
+        int i = indexFor(hash, capacity);
+        TEntry<V> e = table.get(i); 
+        while (e != null) {
+            if (e.getHash() == hash) 
+                return true;
+            e = e.getNext();
+        }
+        return false;
+    }
+
+    /**
+     * Returns the entry associated with the specified key in the
+     * HashMap.  Returns null if the HashMap contains no mapping
+     * for this key.
+     */
+    TEntry<V> getEntry(int key) {
+        int hash = hash(key);
+        int i = indexFor(hash, capacity);
+        TEntry<V> e = table.get(i); 
+        while (e != null && !(e.getHash() == hash))
+            e = e.getNext();
+        return e;
+    }
+  
+    /**
+     * Associates the specified value with the specified key in this map.
+     * If the map previously contained a mapping for this key, the old
+     * value is replaced.
+     *
+     * @param key key with which the specified value is to be associated.
+     * @param value value to be associated with the specified key.
+     * @return previous value associated with specified key, or <tt>null</tt>
+     *        if there was no mapping for key.  A <tt>null</tt> return can
+     *        also indicate that the HashMap previously associated
+     *        <tt>null</tt> with the specified key.
+     */
+    public V put(int key, V value) {
+        int hash = hash(key);
+        int i = indexFor(hash, capacity);
+        for (TEntry<V> e = table.get(i); e != null; e = e.getNext()) {
+            if (e.getHash() == hash) {
+                V oldValue = e.getValue();
+                e.setValue(value);
+//                e.recordAccess(this);
+                return oldValue;
+            }
+        }
+        modCount++;
+        addEntry(hash, value, i);
+        return null;
+    }
+
+
+
+    /**
+     * This method is used instead of put by constructors and
+     * pseudoconstructors (clone, readObject).  It does not resize the table,
+     * check for comodification, etc.  It calls createEntry rather than
+     * addEntry.
+     */
+    private void putForCreate(int key, V value) {
+        int hash = hash(key);
+        int i = indexFor(hash, capacity);
+
+        /**
+         * Look for preexisting entry for key.  This will never happen for
+         * clone or deserialize.  It will only happen for construction if the
+         * input Map is a sorted map whose ordering is inconsistent w/ equals.
+         */
+        for (TEntry<V> e = table.get(i); e != null; e = e.getNext()) {
+            if (e.getHash() == hash) {
+                e.setValue(value);
+                return;
+            }
+        }
+
+        createEntry(hash, value, i);
+    }
+
+    void putAllForCreate(HashMap<? extends V> m) {
+        for (Iterator<? extends HashMap.TEntry<? extends V>> i = m.entrySet().iterator(); i.hasNext(); ) {
+            HashMap.TEntry<? extends V> e = i.next();
+            putForCreate(e.getHash(), e.getValue());
+        }
+    }
+
+    /**
+     * Rehashes the contents of this map into a new array with a
+     * larger capacity.  This method is called automatically when the
+     * number of keys in this map reaches its threshold.
+     *
+     * If current capacity is MAXIMUM_CAPACITY, this method does not
+     * resize the map, but sets threshold to Integer.MAX_VALUE.
+     * This has the effect of preventing future calls.
+     *
+     * @param newCapacity the new capacity, MUST be a power of two;
+     *        must be greater than current capacity unless current
+     *        capacity is MAXIMUM_CAPACITY (in which case value
+     *        is irrelevant).
+     */
+    void resize(int newCapacity) {
+        dstm2.AtomicArray<TEntry> oldTable = table;
+        int oldCapacity = capacity;
+        if (oldCapacity == MAXIMUM_CAPACITY) {
+            threshold = Integer.MAX_VALUE;
+            return;
+        }
+
+        dstm2.AtomicArray<TEntry> newTable = new dstm2.AtomicArray<TEntry>(TEntry.class, newCapacity);
+        transfer(newTable, newCapacity);
+        table = newTable;
+        threshold = (int)(newCapacity * loadFactor);
+        capacity = newCapacity;
+    }
+
+    /** 
+     * Transfer all entries from current table to newTable.
+     */
+    void transfer(dstm2.AtomicArray<TEntry> newTable, int nc) {
+       dstm2.AtomicArray<TEntry> src = table;
+        int newCapacity = nc;
+        for (int j = 0; j < capacity; j++) {
+            TEntry<V> e = src.get(j);
+            if (e != null) {
+                src.set(j, null);
+                do {
+                    TEntry<V> next = e.getNext();
+                    int i = indexFor(e.getHash(), newCapacity);  
+                    e.setNext(newTable.get(i));
+                    newTable.set(i, e);
+                    e = next;
+                } while (e != null);
+            }
+        }
+    }
+
+    /**
+     * Copies all of the mappings from the specified map to this map
+     * These mappings will replace any mappings that
+     * this map had for any of the keys currently in the specified map.
+     *
+     * @param m mappings to be stored in this map.
+     * @throws NullPointerException if the specified map is null.
+     */
+    public void putAll(HashMap<? extends V> m) {
+        int numKeysToBeAdded = m.size();
+        if (numKeysToBeAdded == 0)
+            return;
+
+        /*
+         * Expand the map if the map if the number of mappings to be added
+         * is greater than or equal to threshold.  This is conservative; the
+         * obvious condition is (m.size() + size) >= threshold, but this
+         * condition could result in a map with twice the appropriate capacity,
+         * if the keys to be added overlap with the keys already in this map.
+         * By using the conservative calculation, we subject ourself
+         * to at most one extra resize.
+         */
+        if (numKeysToBeAdded > threshold) {
+            int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1);
+            if (targetCapacity > MAXIMUM_CAPACITY)
+                targetCapacity = MAXIMUM_CAPACITY;
+            int newCapacity = capacity;
+            while (newCapacity < targetCapacity)
+                newCapacity <<= 1;
+            if (newCapacity > capacity)
+                resize(newCapacity);
+        }
+
+        for (Iterator<? extends HashMap.TEntry<? extends V>> i = m.entrySet().iterator(); i.hasNext(); ) {
+            HashMap.TEntry<? extends V> e = i.next();
+            put(e.getHash(), e.getValue());
+        }
+    }
+  
+    /**
+     * Removes the mapping for this key from this map if present.
+     *
+     * @param  key key whose mapping is to be removed from the map.
+     * @return previous value associated with specified key, or <tt>null</tt>
+     *        if there was no mapping for key.  A <tt>null</tt> return can
+     *        also indicate that the map previously associated <tt>null</tt>
+     *        with the specified key.
+     */
+    public V remove(int key) {
+        TEntry<V> e = removeEntryForKey(key);
+        return (e == null ? null : e.getValue());
+    }
+
+    /**
+     * Removes and returns the entry associated with the specified key
+     * in the HashMap.  Returns null if the HashMap contains no mapping
+     * for this key.
+     */
+    TEntry<V> removeEntryForKey(int key) {
+        int hash = hash(key);
+        int i = indexFor(hash, capacity);
+        TEntry<V> prev = table.get(i);
+        TEntry<V> e = prev;
+
+        while (e != null) {
+            TEntry<V> next = e.getNext();
+            if (e.getHash() == hash) {
+                modCount++;
+                size.decrementAndGet();
+                if (prev == e) 
+                    table.set(i, next);
+                else
+                    prev.setNext(next);
+//                e.recordRemoval(this);
+                return e;
+            }
+            prev = e;
+            e = next;
+        }
+   
+        return e;
+    }
+
+    /**
+     * Special version of remove for EntrySet.
+     */
+    TEntry<V> removeMapping(TEntry<V> o) {
+
+        TEntry<V> entry = o;
+        int hash = hash(o.getHash());
+        int i = indexFor(hash, capacity);
+        TEntry<V> prev = table.get(i);
+        TEntry<V> e = prev;
+
+        while (e != null) {
+            TEntry<V> next = e.getNext();
+            if (e.getHash() == hash) {
+                modCount++;
+                size.decrementAndGet();
+                if (prev == e) 
+                       table.set(i,  next);
+                else
+                    prev.setNext(next);
+//                e.recordRemoval(this);
+                return e;
+            }
+            prev = e;
+            e = next;
+        }
+   
+        return e;
+    }
+
+    /**
+     * Removes all mappings from this map.
+     */
+    public void clear() {
+        modCount++;
+        dstm2.AtomicArray<TEntry> tab = table;
+        for (int i = 0; i < capacity; i++) 
+               table.set(i, null);
+        size.set(0);
+    }
+
+    /**
+     * Returns <tt>true</tt> if this map maps one or more keys to the
+     * specified value.
+     *
+     * @param value value whose presence in this map is to be tested.
+     * @return <tt>true</tt> if this map maps one or more keys to the
+     *         specified value.
+     */
+    public boolean containsValue(Object value) {
+       if (value == null) 
+            return containsNullValue();
+
+       dstm2.AtomicArray<TEntry> tab = table;
+        for (int i = 0; i < capacity; i++)
+            for (TEntry e = tab.get(i); e != null ; e = e.getNext())
+                if (value.equals(e.getValue()))
+                    return true;
+       return false;
+    }
+
+    /**
+     * Special-case code for containsValue with null argument
+     **/
+    private boolean containsNullValue() {
+       dstm2.AtomicArray<TEntry> tab = table;
+        for (int i = 0; i < capacity ; i++)
+            for (TEntry e = tab.get(i) ; e != null ; e = e.getNext())
+                if (e.getValue() == null)
+                    return true;
+       return false;
+    }
+
+  
+    
+
+    /**
+     * Add a new entry with the specified key, value and hash code to
+     * the specified bucket.  It is the responsibility of this 
+     * method to resize the table if appropriate.
+     *
+     * Subclass overrides this to alter the behavior of put method.
+     */
+    void addEntry(int hash, V value, int bucketIndex) {
+       TEntry<V> e = table.get(bucketIndex);
+       TEntry<V> n = factory.create();
+        n.setHash(hash);
+        n.setValue(value);
+        n.setNext(e);
+       table.set(bucketIndex, n);
+        if (size.incrementAndGet() >= threshold) {
+               synchronized(this) {
+                       if(size.get() >= threshold)
+                               resize(2 * capacity);
+               }
+        }
+    }
+
+    /**
+     * Like addEntry except that this version is used when creating entries
+     * as part of Map construction or "pseudo-construction" (cloning,
+     * deserialization).  This version needn't worry about resizing the table.
+     *
+     * Subclass overrides this to alter the behavior of HashMap(Map),
+     * clone, and readObject.
+     */
+    void createEntry(int hash, V value, int bucketIndex) {
+       TEntry<V> e = table.get(bucketIndex);
+       TEntry<V> n = factory.create();
+        n.setHash(hash);
+        n.setValue(value);
+        n.setNext(e);
+       table.set(bucketIndex, n);
+        size.incrementAndGet();
+    }
+
+    private abstract class HashIterator<E> implements Iterator<E> {
+        TEntry<V> next;        // next entry to return
+        int expectedModCount;  // For fast-fail 
+        int index;             // current slot 
+        TEntry<V> current;     // current entry
+
+        HashIterator() {
+            expectedModCount = modCount;
+            dstm2.AtomicArray<TEntry> t = table;
+            int i = capacity;
+            TEntry<V> n = null;
+            if (size.get() != 0) { // advance to first entry
+                while (i > 0 && (n = t.get(--i)) == null)
+                    ;
+            }
+            next = n;
+            index = i;
+        }
+
+        public boolean hasNext() {
+            return next != null;
+        }
+
+        TEntry<V> nextEntry() { 
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            TEntry<V> e = next;
+            if (e == null) 
+                throw new NoSuchElementException();
+                
+            TEntry<V> n = e.getNext();
+            dstm2.AtomicArray<TEntry> t = table;
+            int i = index;
+            while (n == null && i > 0)
+                n = t.get(--i);
+            index = i;
+            next = n;
+            return current = e;
+        }
+
+        public void remove() {
+            if (current == null)
+                throw new IllegalStateException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            int k = current.getHash();
+            current = null;
+            HashMap.this.removeEntryForKey(k);
+            expectedModCount = modCount;
+        }
+
+    }
+
+    private class ValueIterator extends HashIterator<V> {
+        public V next() {
+            return nextEntry().getValue();
+        }
+    }
+
+    private class KeyIterator extends HashIterator<Integer> {
+        public Integer next() {
+            return nextEntry().getHash();
+        }
+    }
+
+//    private class EntryIterator extends HashIterator<Map.Entry<K,V>> {
+//        public Map.Entry<K,V> next() {
+//            return nextEntry();
+//        }
+//    }
+
+    // Subclass overrides these to alter behavior of views' iterator() method
+    public Iterator<Integer> newKeyIterator()   {
+        return new KeyIterator();
+    }
+    public Iterator<V> newValueIterator()   {
+        return new ValueIterator();
+    }
+//    Iterator<Map.Entry<K,V>> newEntryIterator()   {
+//        return new EntryIterator();
+//    }
+
+
+    // Views
+
+    private transient Set<HashMap.TEntry<V>> entrySet = null;
+
+
+
+    private class KeySet extends AbstractSet<Integer> {
+        public Iterator<Integer> iterator() {
+            return newKeyIterator();
+        }
+        public int size() {
+            return size.get();
+        }
+        public boolean contains(Integer o) {
+            return containsKey(o);
+        }
+        public boolean remove(Integer o) {
+            return HashMap.this.removeEntryForKey(o) != null;
+        }
+        public void clear() {
+            HashMap.this.clear();
+        }
+    }
+
+
+
+    /**
+     * Returns a collection view of the mappings contained in this map.  Each
+     * element in the returned collection is a <tt>Map.Entry</tt>.  The
+     * collection is backed by the map, so changes to the map are reflected in
+     * the collection, and vice-versa.  The collection supports element
+     * removal, which removes the corresponding mapping from the map, via the
+     * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
+     * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations.
+     * It does not support the <tt>add</tt> or <tt>addAll</tt> operations.
+     *
+     * @return a collection view of the mappings contained in this map.
+     * @see Map.Entry
+     */
+    public Set<HashMap.TEntry<V>> entrySet() {
+        Set<HashMap.TEntry<V>> es = entrySet;
+        return (es != null ? es : (entrySet = (Set<HashMap.TEntry<V>>) (Set) new EntrySet()));
+    }
+
+    private class EntrySet {//extends AbstractSet/*<Map.Entry<K,V>>*/ {
+//        public Iterator/*<Map.Entry<K,V>>*/ iterator() {
+//            return newEntryIterator();
+//        }
+        public boolean contains(HashMap.TEntry<V> o) {
+            HashMap.TEntry<V> e = (HashMap.TEntry<V>) o;
+            TEntry<V> candidate = getEntry(e.getHash());
+            return candidate != null && candidate.equals(e);
+        }
+        public boolean remove(HashMap.TEntry<V> o) {
+            return removeMapping(o) != null;
+        }
+        public int size() {
+            return size.get();
+        }
+        public void clear() {
+            HashMap.this.clear();
+        }
+    }
+
+    /**
+     * Save the state of the <tt>HashMap</tt> instance to a stream (i.e.,
+     * serialize it).
+     *
+     * @serialData The <i>capacity</i> of the HashMap (the length of the
+     *            bucket array) is emitted (int), followed  by the
+     *            <i>size</i> of the HashMap (the number of key-value
+     *            mappings), followed by the key (Object) and value (Object)
+     *            for each key-value mapping represented by the HashMap
+     *             The key-value mappings are emitted in the order that they
+     *             are returned by <tt>entrySet().iterator()</tt>.
+     * 
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws IOException
+    {
+       Iterator<HashMap.TEntry<V>> i = entrySet().iterator();
+
+       // Write out the threshold, loadfactor, and any hidden stuff
+       s.defaultWriteObject();
+
+       // Write out number of buckets
+       s.writeInt(capacity);
+
+       // Write out size (number of Mappings)
+       s.writeInt(size.get());
+
+        // Write out keys and values (alternating)
+       while (i.hasNext()) { 
+            HashMap.TEntry<V> e = i.next();
+            s.writeObject(e.getHash());
+            s.writeObject(e.getValue());
+        }
+    }
+
+    private static final long serialVersionUID = 362498820763181265L;
+
+    /**
+     * Reconstitute the <tt>HashMap</tt> instance from a stream (i.e.,
+     * deserialize it).
+     */
+    private void readObject(java.io.ObjectInputStream s)
+         throws IOException, ClassNotFoundException
+    {
+       // Read in the threshold, loadfactor, and any hidden stuff
+       s.defaultReadObject();
+
+       // Read in number of buckets and allocate the bucket array;
+       int numBuckets = s.readInt();
+       table = new dstm2.AtomicArray(TEntry.class, numBuckets);
+
+        init();  // Give subclass a chance to do its thing.
+
+       // Read in size (number of Mappings)
+       int size = s.readInt();
+
+       // Read the keys and values, and put the mappings in the HashMap
+       for (int i=0; i<size; i++) {
+           int key = (Integer) s.readObject();
+           V value = (V) s.readObject();
+           putForCreate(key, value);
+       }
+    }
+
+    // These methods are used when serializing HashSets
+    int   capacity()     { return capacity; }
+    float loadFactor()   { return loadFactor;   }
+
+       public int getCapacity() {
+               return capacity;
+       }
+
+       
+         public Iterator<V> iterator() {
+           return new Iterator<V>() {
+             int tableIndex = 0;
+             public TEntry<V> cursor = table.get(tableIndex);
+             public boolean hasNext() {
+               return cursor != null;
+             }
+             public V next() {
+               TEntry<V> node = cursor;
+               cursor = cursor.getNext();
+               while(cursor==null) {
+                       tableIndex++;
+                       if(tableIndex < capacity) {
+                               cursor = table.get(tableIndex);
+                       }
+               }
+               return node.getValue();
+             }
+             public void remove() {
+               throw new UnsupportedOperationException();
+             }
+             
+           };
+         }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/transactionalinterfaces/Intif.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/transactionalinterfaces/Intif.java
new file mode 100644 (file)
index 0000000..8b7c775
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package com.enea.jcarder.transactionalinterfaces;
+
+import dstm2.AtomicSuperClass;
+import dstm2.atomic;
+import dstm2.Thread;
+import dstm2.factory.Factory;
+
+/**
+ *
+ * @author navid
+ */
+public class Intif {
+      
+      public static Factory<positionif> factory = Thread.makeFactory(positionif.class);
+      
+      public positionif pos;
+      
+      public void init(){
+          
+          pos = factory.create();
+          //pos.setPosition(0);
+      }
+      
+      public void increment(int offset){
+          pos.setPosition(pos.getPosition() + offset);
+          
+      }
+      
+      public int get(){
+          return pos.getPosition();
+      }
+      
+      @atomic public interface positionif extends AtomicSuperClass{
+        public int getPosition();
+        public void setPosition(int pos);
+    }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/transactionalinterfaces/bytebuffer.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/transactionalinterfaces/bytebuffer.java
new file mode 100644 (file)
index 0000000..9d47fa5
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package com.enea.jcarder.transactionalinterfaces;
+
+//import com.enea.jcarder.transactionalinterfaces.bytebuffer.byteholder;
+import com.enea.jcarder.util.Counter;
+import dstm2.AtomicArray;
+import dstm2.AtomicByteArray;
+import dstm2.atomic;
+import dstm2.Thread;
+import dstm2.factory.Factory;
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+/**
+ *
+ * @author navid
+ */
+public class bytebuffer {
+    
+   
+    static Factory<bytebufferif> factory = Thread.makeFactory(bytebufferif.class);
+//    public static Factory<byteholder> factory2 = Thread.makeFactory(byteholder.class);
+   
+    
+    public bytebufferif mbuffer;
+    
+    public int capacity(){
+        return mbuffer.getCapacity();
+    }
+    
+    public int position(){
+        return mbuffer.getPosition();
+    }
+    
+    public bytebufferif flip(){
+        mbuffer.setLimit(mbuffer.getPosition());
+        mbuffer.setPosition(0);
+        return mbuffer;
+    }
+    
+    public final bytebufferif clear(){
+        mbuffer.setPosition(0);
+        mbuffer.setLimit(mbuffer.getCapacity());
+        return mbuffer;
+    }
+    
+    public final boolean hasRemaining(){
+        return mbuffer.getPosition() < mbuffer.getLimit();
+    }
+    
+    public final int remaining(){
+        return mbuffer.getLimit() - mbuffer.getPosition();
+    }
+    
+    public void put(byte value){
+
+         AtomicByteArray ar = mbuffer.getByteHolderar();
+
+         ar.set(mbuffer.getPosition(),value);
+         mbuffer.setPosition(mbuffer.getPosition()+1);
+         
+    }
+    
+   
+    
+    public void put(ByteBuffer value){
+        
+        if (remaining() < value.remaining())
+            throw new BufferOverflowException();
+        
+         /*AtomicArray<byteholder> ar = mbuffer.getByteHolder();
+         while(value.hasRemaining()){
+            byteholder bh = mbuffer.getByteHolder().get(mbuffer.getPosition());
+            if ((bh = mbuffer.getByteHolder().get(mbuffer.getPosition())) ==  null){
+                bh = factory2.create();
+            }
+            bh.setByte(value.get());
+            ar.set(mbuffer.getPosition(),bh);
+            mbuffer.setPosition(mbuffer.getPosition()+1);
+         }*/
+        AtomicByteArray ar = mbuffer.getByteHolderar();
+         while(value.hasRemaining()){
+            
+            
+            ar.set(mbuffer.getPosition(),Byte.valueOf(value.get()));
+            mbuffer.setPosition(mbuffer.getPosition()+1);
+         }
+       // while(value.hasRemaining()){
+        //    if (mbuffer.getByteHolder().get(mbuffer.getPosition()) ==  null)
+         //       mbuffer.getByteHolder().set(mbuffer.getPosition(), factory2.create());
+        //   mbuffer.getByteHolder.set((mbuffer.getPosition()), value.get());
+         //   mbuffer.setPosition(mbuffer.getPosition()+1);
+            //System.out.println("sss");
+        //}
+    }
+    
+
+    
+    public bytebuffer allocateDirect(int capacity){
+        System.out.println("allocate " + capacity);
+        mbuffer = factory.create();
+        mbuffer.setByteHolderar(new AtomicByteArray(Byte.class,capacity));
+        mbuffer.setPosition(0);
+        mbuffer.setLimit(capacity);
+        mbuffer.setCapacity(capacity);
+     //   for (int i=0; i<capacity; i++){
+          //  ar.set(i, factory2.create());
+        //}
+      //  for (int i=0; i<capacity; i++)
+        //    mbuffer.getByteHolder().set(i, factory2.create());
+       // mbuffer.getByteHolder().set(0, factory2.create());
+       // mbuffer.getByteHolder().get(0).setByte((byte)2);
+        return this;
+    }
+    
+    public byte[] getBytes(){
+     //   System.out.println("getbytes");
+        int length = remaining();
+        byte[] result = new byte[length];
+        int i = 0;
+       /* while (hasRemaining()) {
+            result[i] = mbuffer.getByteHolder().get(mbuffer.getPosition()).getByte();
+            mbuffer.setPosition(mbuffer.getPosition()+1);
+            i++;
+        }*/
+        while (hasRemaining()) {
+            result[i] =  mbuffer.getByteHolderar().get(mbuffer.getPosition()).byteValue();
+            mbuffer.setPosition(mbuffer.getPosition()+1);
+            i++;
+        }
+        return result;
+    }
+     
+     @atomic public interface bytebufferif{
+        int getLimit();
+        void setLimit(int value);
+        int getPosition();
+        void setPosition(int value);
+        int getCapacity();
+        void setCapacity(int value);
+        AtomicByteArray getByteHolderar();
+        void setByteHolderar(AtomicByteArray bytes);
+
+     }
+     
+    
+
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/transactionalinterfaces/jcbuffer.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/transactionalinterfaces/jcbuffer.java
new file mode 100644 (file)
index 0000000..ee712df
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package com.enea.jcarder.transactionalinterfaces;
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+/**
+ *
+ * @author navid
+ */
+public class jcbuffer {
+
+    jcbytebufferif mbuffer;
+    
+    public int capacity(){
+        return mbuffer.getCapacity();
+    }
+    
+    public int position(){
+        return mbuffer.getPosition();
+    }
+    
+    public jcbytebufferif flip(){
+        mbuffer.setLimit(mbuffer.getPosition());
+        mbuffer.setPosition(0);
+        return mbuffer;
+    }
+    
+    public final jcbytebufferif clear(){
+        mbuffer.setPosition(0);
+        mbuffer.setLimit(mbuffer.getCapacity());
+        return mbuffer;
+    }
+    
+    public final boolean hasRemaining(){
+        return mbuffer.getPosition() < mbuffer.getLimit();
+    }
+    
+    public final int remaining(){
+        return mbuffer.getLimit() - mbuffer.getPosition();
+    }
+    
+    public void put(byte value){
+
+         jcbyteholder[] ar = mbuffer.getByteHolder();
+         jcbyteholder bh;
+         if (mbuffer.getByteHolder()[mbuffer.getPosition()] ==  null){
+            bh = new jcbyteholder();
+            
+         }
+         else 
+             bh = mbuffer.getByteHolder()[mbuffer.getPosition()];
+         bh.setByte(value);
+         ar[mbuffer.getPosition()] = bh;
+         mbuffer.setPosition(mbuffer.getPosition()+1);
+         
+    }
+    
+   
+    
+    public void put(ByteBuffer value){
+        
+        if (remaining() < value.remaining())
+            throw new BufferOverflowException();
+        
+         jcbyteholder[] ar = mbuffer.getByteHolder();
+         while(value.hasRemaining()){
+            jcbyteholder bh = mbuffer.getByteHolder()[mbuffer.getPosition()];
+            if (mbuffer.getByteHolder()[mbuffer.getPosition()] ==  null){
+                bh = new jcbyteholder();
+            }
+            else 
+                bh = mbuffer.getByteHolder()[mbuffer.getPosition()];
+            bh.setByte(value.get());
+            ar[mbuffer.getPosition()] = bh;
+            mbuffer.setPosition(mbuffer.getPosition()+1);
+         }
+        
+       // while(value.hasRemaining()){
+        //    if (mbuffer.getByteHolder().get(mbuffer.getPosition()) ==  null)
+         //       mbuffer.getByteHolder().set(mbuffer.getPosition(), factory2.create());
+        //   mbuffer.getByteHolder.set((mbuffer.getPosition()), value.get());
+         //   mbuffer.setPosition(mbuffer.getPosition()+1);
+            //System.out.println("sss");
+        //}
+    }
+    
+
+    
+    public jcbuffer allocateDirect(int capacity){
+        System.out.println("allocate " + capacity);
+        mbuffer = new jcbytebufferif();
+        mbuffer.setByteHolder(new jcbyteholder[capacity]);
+        mbuffer.setPosition(0);
+        mbuffer.setLimit(capacity);
+        mbuffer.setCapacity(capacity);
+        jcbyteholder[] ar = mbuffer.getByteHolder();
+     //   for (int i=0; i<capacity; i++){
+          //  ar.set(i, factory2.create());
+        //}
+      //  for (int i=0; i<capacity; i++)
+      //      mbuffer.getByteHolder().set(i, factory2.create());
+       // mbuffer.getByteHolder().set(0, factory2.create());
+       // mbuffer.getByteHolder().get(0).setByte((byte)2);
+        return this;
+    }
+    
+    public byte[] getBytes(){
+     //   System.out.println("getbytes");
+        int length = remaining();
+        byte[] result = new byte[length];
+        int i = 0;
+        while (hasRemaining()) {
+            result[i] = mbuffer.getByteHolder()[mbuffer.getPosition()].getByte();
+            mbuffer.setPosition(mbuffer.getPosition()+1);
+            i++;
+        }
+        return result;
+    }
+    
+       class jcbytebufferif{
+        jcbyteholder[] bytes;
+        int limit;
+        int position;
+        int capacity;
+        int getLimit(){
+            return limit;
+        }
+        void setLimit(int value){
+            limit = value;
+        }
+        int getPosition(){
+            return position;
+        }
+        void setPosition(int value){
+            position = value;
+        }
+        int getCapacity(){
+            return capacity;
+        }
+        void setCapacity(int value){
+            capacity = value;
+        }
+        jcbyteholder[] getByteHolder(){
+            return bytes;
+        }
+        void setByteHolder(jcbyteholder[] bytes){
+            this.bytes =  bytes;
+        }
+        
+      //  AtomicArray<Byte> getByteHolderar();
+      //  void setByteHolderar(Byte[] bytes);
+     }
+     
+     class jcbyteholder{
+         byte val;
+         byte getByte(){
+             return val;
+         };
+         void setByte(byte value){
+             val = value;
+         }
+     }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/transactionalinterfaces/trEventListener.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/transactionalinterfaces/trEventListener.java
new file mode 100644 (file)
index 0000000..9709ff3
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package com.enea.jcarder.transactionalinterfaces;
+
+import com.enea.jcarder.util.Counter;
+import com.enea.jcarder.util.TransactionalCounter;
+import dstm2.atomic;
+import dstm2.Thread;
+import dstm2.factory.Factory;
+
+/**
+ *
+ * @author navid
+ */
+public class trEventListener{
+    public static Factory<trAtomicFieldsEventListener> factory = Thread.makeFactory(trAtomicFieldsEventListener.class); 
+    public trAtomicFieldsEventListener atmoicfileds;
+    
+    
+    
+    @atomic public interface trAtomicFieldsEventListener {
+    public bytebuffer.bytebufferif getCCByteBuffer();
+    public void setCCByteBuffer(bytebuffer.bytebufferif val);
+    public Bool.boolif getCCShutdown();
+    public void setCCShutdown(Bool.boolif val);
+    public Intif.positionif getCCPosiiton();
+    public void setCCPosiiton(Intif.positionif val);
+    
+    public Intif.positionif getHMap1Capacity();
+    public void setHMap1Capacity(Intif.positionif val);
+    public Intif.positionif getHMap1Position();
+    public void setHMap1Position(Intif.positionif val);
+    public trHashMap.valueHolder getHMap1Values();
+    public void setHMap1Values(trHashMap.valueHolder val);
+    
+    
+    public Intif.positionif getELNumberofMonitors();
+    public void setELNumberofMonitors(Intif.positionif val);
+    
+    public bytebuffer.bytebufferif getLIGByteBuffer();
+    public void setLIGByteBuffer(bytebuffer.bytebufferif val);
+    public Bool.boolif getLIGShutdown();
+    public void setLIGShutdown(Bool.boolif val);
+    public Intif.positionif getLIGPosiiton();
+    public void setLIGPosiiton(Intif.positionif val);
+    
+   public Intif.positionif getHMap2Capacity();
+    public void setHMap2Capacity(Intif.positionif val);
+    public Intif.positionif getHMap2Position();
+    public void setHMap2Position(Intif.positionif val);
+    public trHashMap.valueHolder getHMap2Values();
+    public void setHMap2Values(trHashMap.valueHolder val);
+
+    
+    public bytebuffer.bytebufferif getEFWByteBuffer();
+    public void setEFWByteBuffer(bytebuffer.bytebufferif val);
+    public Bool.boolif getEFWShutdown();
+    public void setEFWShutdown(Bool.boolif val);
+    public Intif.positionif getEFWCounter();
+    public void setEFWCounter(Intif.positionif val);
+    
+    
+    }
+}
+
+
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/transactionalinterfaces/trHashMap.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/transactionalinterfaces/trHashMap.java
new file mode 100644 (file)
index 0000000..68c99a1
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package com.enea.jcarder.transactionalinterfaces;
+
+import dstm2.AtomicArray;
+import dstm2.AtomicIntArray;
+import dstm2.AtomicSuperClass;
+import dstm2.atomic;
+import dstm2.factory.Factory;
+import dstm2.Thread;
+import java.util.HashMap;
+import java.util.Map.Entry;
+
+/**
+ *
+ * @author navid
+ */
+public class trHashMap implements Intif.positionif{
+    
+    
+    public static Factory<Intif.positionif> factory = Thread.makeFactory(Intif.positionif.class); 
+    public static Factory<valueHolder> factory2 = Thread.makeFactory(valueHolder.class);
+    public static Factory<trLockingContext.holder> factory3 = Thread.makeFactory(trLockingContext.holder.class);
+    public static Factory<keyHolder> factory4 = Thread.makeFactory(keyHolder.class);
+    public valueHolder values;
+    public Object[] keys;
+    AtomicIntArray intkeys = new AtomicIntArray(Integer.class, 10);
+    public keyHolder keys2;
+    public Intif.positionif position;
+    public Intif.positionif capacity;
+    
+    public trHashMap() {
+        keys = new Object[15];
+        position = factory.create();
+        capacity = factory.create();
+        values = factory2.create();
+        keys2 = factory4.create();
+        
+        position.setPosition(0);
+        capacity.setPosition(15);
+        values.setValues(new AtomicIntArray(Integer.class, 15));
+        keys2.setKeys(new AtomicArray<trLockingContext.holder>(trLockingContext.holder.class, 15));
+    }
+    
+    
+    int indexFor(int h, int length) {
+                return h & (length - 1);
+    }
+    
+    public void put(Object key, int value){
+      //  int hash = System.identityHashCode(key);
+    /*    System.out.println("key " + key + " value " + value);
+        if (map.containsKey(key)){
+            System.out.println("-------hmap-----------------");
+                System.out.println("value replaced " + key);
+                System.out.println("-------hmap-------------------");
+        }
+        map.put(key, value);*/
+                
+            
+        for (int i=0; i<position.getPosition(); i++){
+      //      System.out.println("Key " + key + " value " + value + " keys[i] " +keys[i]);
+            if ((key.equals(keys[i])) || (key == keys[i])){
+                System.out.println("-----------tr-------------");
+                System.out.println("value replaced " + key);
+                System.out.println("-------------tr-------------");
+                values.getValues().set(i, value);
+                keys[i] = key;
+                return;
+            }
+        }
+        if (position.getPosition()  == capacity.getPosition()){
+            System.out.println("expanding");
+            capacity.setPosition(capacity.getPosition()*2);
+            AtomicIntArray ar = new AtomicIntArray(Integer.class, capacity.getPosition());
+            Object[] tmp = new Object[capacity.getPosition()];
+            
+            for (int i=0; i<capacity.getPosition(); i++){
+                ar.set(i, values.getValues().get(i));
+                tmp[i] = keys[i];
+            }
+            keys = new Object[capacity.getPosition()];
+            System.arraycopy(tmp, 0, keys, 0, capacity.getPosition()/2);
+            values.setValues(ar);
+        }
+        
+        keys[position.getPosition()] = key;
+        values.getValues().set(position.getPosition(), value);
+        position.setPosition(position.getPosition()+1);
+        System.out.println("tr key " + keys[position.getPosition()-1] + " tr value " + values.getValues().get(position.getPosition()-1));
+    }
+    
+    public Integer get(Object key){
+       boolean flag  = false;
+       int i;
+       for (i=0; i<position.getPosition(); i++){
+            if (key == keys[i] || key.equals(keys[i])){
+                flag = true;
+                break;
+            }
+       }
+       if (flag)
+           return values.getValues().get(i);
+       return null;
+     //   if (map.containsKey(key)){
+       //     return (Integer)map.get(key);
+            
+        //}
+        //return null;
+       //return (Integer)map.get(key);
+    }
+    
+      public void put2(Object key, int value){
+      //  int hash = System.identityHashCode(key);
+    /*    System.out.println("key " + key + " value " + value);
+        if (map.containsKey(key)){
+            System.out.println("-------hmap-----------------");
+                System.out.println("value replaced " + key);
+                System.out.println("-------hmap-------------------");
+        }
+        map.put(key, value);*/
+                
+            
+        for (int i=0; i<position.getPosition(); i++){
+      //      System.out.println("Key " + key + " value " + value + " keys[i] " +keys[i]);
+            if ((key.equals(keys[i])) || (key == keys[i])){
+                System.out.println("-----------tr-------------");
+                System.out.println("value replaced " + key);
+                System.out.println("-------------tr-------------");
+                values.getValues().set(i, value);
+                keys[i] = key;
+                return;
+            }
+        }
+        if (position.getPosition()  == capacity.getPosition()){
+            System.out.println("expanding");
+            capacity.setPosition(capacity.getPosition()*2);
+            AtomicIntArray ar = new AtomicIntArray(Integer.class, capacity.getPosition());
+            Object[] tmp = new Object[capacity.getPosition()];
+            
+            for (int i=0; i<capacity.getPosition(); i++){
+                ar.set(i, values.getValues().get(i));
+                tmp[i] = keys[i];
+            }
+            keys = new Object[capacity.getPosition()];
+            System.arraycopy(tmp, 0, keys, 0, capacity.getPosition()/2);
+            values.setValues(ar);
+        }
+        
+        keys[position.getPosition()] = key;
+        values.getValues().set(position.getPosition(), value);
+        position.setPosition(position.getPosition()+1);
+        System.out.println("tr key " + keys[position.getPosition()-1] + " tr value " + values.getValues().get(position.getPosition()-1));
+    }
+    
+    public Integer get2(Object key){
+       boolean flag  = false;
+       int i;
+       for (i=0; i<position.getPosition(); i++){
+            if (key == keys[i] || key.equals(keys[i])){
+                flag = true;
+                break;
+            }
+       }
+       if (flag)
+           return values.getValues().get(i);
+       return null;
+     //   if (map.containsKey(key)){
+       //     return (Integer)map.get(key);
+            
+        //}
+        //return null;
+       //return (Integer)map.get(key);
+    }
+    
+    
+    
+  /*  public Integer get(Object key) {
+        if (key == null) {
+            return getForNullKey();
+        }
+        int hash = hash(key.hashCode());
+        for (Entry<Object, Integer> e = table[indexFor(hash, table.length)]; e != null; e = e.next) {
+            Object k;
+            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
+                return e.value;
+            }
+        }
+        return null
+
+    }*/
+    
+ /*   private Object getForNullKey() {
+        table.
+        for (Entry e = table[0]; e != null; e = ) {
+            if (e.getKey() == null)
+              return e.getValue();
+        }
+        return null;
+    }
+
+      static int hash(int h) {
+           h ^= (h >>> 20) ^ (h >>> 12);
+          return h ^ (h >>> 7) ^ (h >>> 4);
+      }*/
+       
+    
+/*    public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            try {
+                Object otherReferent = ((EqualsComparableKey) obj).get();
+                Object thisReferent = get();
+                return (thisReferent != null
+                        && otherReferent != null
+                        && thisReferent.equals(otherReferent));
+            } catch (ClassCastException e) {
+                return false;
+            }
+    }*/
+    public void remove(){
+        
+    }
+    
+    
+    @atomic public interface valueHolder extends AtomicSuperClass{
+        AtomicIntArray getValues();
+        void setValues(AtomicIntArray values);
+     
+    }
+    
+    @atomic public interface keyHolder{
+        AtomicArray<trLockingContext.holder> getKeys();
+        void setKeys(AtomicArray<trLockingContext.holder> values);
+
+    }
+
+    public int getPosition() {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public void setPosition(int pos) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+    
+    
+    
+
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/transactionalinterfaces/trLockingContext.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/transactionalinterfaces/trLockingContext.java
new file mode 100644 (file)
index 0000000..904f8a7
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package com.enea.jcarder.transactionalinterfaces;
+
+import dstm2.atomic;
+
+/**
+ *
+ * @author navid
+ */
+public class trLockingContext {
+    
+    
+    @atomic public interface holder{
+        public String getThreadName();
+        public void setThreadName(String name);
+        public String getMethodName();
+        public void setMethodName(String method);
+        public String getLockRef();
+        public void setLockRef(String name);
+    }
+
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/util/BuildInformation.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/util/BuildInformation.java
new file mode 100644 (file)
index 0000000..a3494a8
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.util;
+
+import java.io.IOException;
+import java.util.Properties;
+
+public final class BuildInformation {
+
+    private BuildInformation() { }
+
+    public static String getShortInfo() {
+        try {
+            Properties props = loadBuildProperties();
+            return "JCarder ("
+                   + props.getProperty("build.version")
+                   + "/"
+                   + props.getProperty("build.number")
+                   + ")";
+        } catch (IOException e) {
+            e.printStackTrace();
+            return "JCarder";
+        }
+    }
+
+    public static void printLongBuildInformation() {
+        Properties props;
+        try {
+            props = loadBuildProperties();
+        } catch (IOException e) {
+            e.printStackTrace();
+            return;
+        }
+        StringBuffer sb = new StringBuffer();
+        sb.append("JCarder -- cards Java programs to keep threads"
+                  + " disentangled\n");
+        sb.append("\nCopyright (C) 2006-2007 Enea AB\n");
+        sb.append("Copyright (C) 2007 Ulrik Svensson\n");
+        sb.append("Copyright (C) 2007 Joel Rosdahl\n");
+        sb.append("\nVersion: " + props.getProperty("build.version"));
+        sb.append("\nBuild  : " + props.getProperty("build.number"));
+        sb.append("\nAt     : " + props.getProperty("build.timestamp"));
+        sb.append("\nBy     : " + props.getProperty("build.user.name"));
+        sb.append("\nOn     : " + props.getProperty("build.os.name"));
+        System.out.println(sb.toString());
+    }
+
+    private static Properties loadBuildProperties() throws IOException {
+        Properties props = new Properties();
+        ClassLoader classLoader = ClassLoader.getSystemClassLoader();
+        props.load(classLoader.getResourceAsStream("build.properties"));
+       // return null;
+        return props;
+    }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/util/Counter.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/util/Counter.java
new file mode 100644 (file)
index 0000000..9410522
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.util;
+
+import com.enea.jcarder.util.logging.Logger;
+
+//import net.jcip.annotations.NotThreadSafe;
+
+//@NotThreadSafe
+public final class Counter {
+    final int mLogIntervall;
+    final String mName;
+    final Logger mLogger;
+    int mValue = 0;
+
+    
+    public Counter(String name, Logger logger, int logInterval) {
+        mName = name;
+        mLogger = logger;
+        mLogIntervall = logInterval;
+    }
+
+    public void increment() {
+        mValue++;
+        if ((mValue % mLogIntervall) == 0) {
+            mLogger.fine(mName + ": " + mValue);
+        } else if (mLogger.isLoggable(Logger.Level.FINEST)) {
+            mLogger.finest(mName + ": " + mValue);
+        }
+    }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/util/IdentityWeakHashMap.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/util/IdentityWeakHashMap.java
new file mode 100644 (file)
index 0000000..3727054
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.util;
+
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
+//import net.jcip.annotations.NotThreadSafe;
+
+/**
+ * This class is similar to the java.util.WeakHashMap but compares objects with
+ * the == operator instead of with the Object.equals method.
+ *
+ * TODO Add basic tests for this class.
+ */
+//@NotThreadSafe
+public final class IdentityWeakHashMap<V> {
+    private final HashMap<IdentityComparableKey, V> mHashMap;
+    private final ReferenceQueue<Object> mReferenceQueue;
+    private final StrongKey mStrongKey = new StrongKey();
+    private Object mLastKey = null; // Cache to improve performance.
+    private V mLastValue = null; // Cache to improve performance.
+    private int mPutCounter = 0;
+
+    public IdentityWeakHashMap() {
+        mHashMap = new HashMap<IdentityComparableKey, V>();
+        mReferenceQueue = new ReferenceQueue<Object>();
+    }
+
+    public V get(Object key) {
+        /*
+         * Avoid calls to removeGarbageCollectedKeys in this method in order to
+         * improve performance.
+         */
+        if (key == mLastKey) {
+            return mLastValue;
+        }
+        mLastKey = key;
+        mStrongKey.setReferent(key);
+        mLastValue = mHashMap.get(mStrongKey);
+        return mLastValue;
+    }
+
+    public void put(Object key, V value) {
+        assert value != null;
+        mLastKey = key;
+        mLastValue = value;
+        if (mPutCounter > 1000) {
+            // Don't call to often in order to improve performance.
+            removeGarbageCollectedKeys();
+            mPutCounter = 0;
+        } else {
+            mPutCounter++;
+        }
+        mHashMap.put((new WeakKey(key, mReferenceQueue)), value);
+    }
+
+    private void removeGarbageCollectedKeys() {
+        Reference e;
+        int noOfCollectedLocks = 0;
+        while ((e = mReferenceQueue.poll()) != null) {
+            noOfCollectedLocks++;
+            mHashMap.remove(e);
+        }
+    }
+
+    private static interface IdentityComparableKey {
+        Object get();
+        boolean equals(Object obj);
+        int hashCode();
+    }
+
+    private static class StrongKey implements IdentityComparableKey {
+        private Object mReferent;
+
+        void setReferent(Object referent) {
+            assert referent != null;
+            mReferent = referent;
+        }
+
+        public Object get() {
+            return mReferent;
+        }
+
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            try {
+                IdentityComparableKey reference = (IdentityComparableKey) obj;
+                return (reference.get() == get());
+            } catch (ClassCastException e) {
+                return false;
+            }
+        }
+
+        public int hashCode() {
+            return System.identityHashCode(mReferent);
+        }
+    }
+
+    private static class WeakKey extends WeakReference<Object>
+    implements IdentityComparableKey {
+        private final int mHash;
+
+        WeakKey(Object referent, ReferenceQueue<Object> queue) {
+            super(referent, queue);
+            assert referent != null;
+            mHash = System.identityHashCode(referent);
+        }
+
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            try {
+                IdentityComparableKey reference = (IdentityComparableKey) obj;
+                Object referent = reference.get();
+                return (referent != null) &&  (referent == get());
+            } catch (ClassCastException e) {
+                return false;
+            }
+        }
+
+        public int hashCode() {
+            return mHash;
+        }
+    }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/util/InvalidOptionException.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/util/InvalidOptionException.java
new file mode 100644 (file)
index 0000000..e1b2d5b
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.util;
+
+public class InvalidOptionException extends Exception {
+    public InvalidOptionException(String message) {
+        super(message);
+    }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/util/MaxValueCounter.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/util/MaxValueCounter.java
new file mode 100644 (file)
index 0000000..0f17bdf
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.util;
+
+import com.enea.jcarder.util.logging.Logger;
+
+//import net.jcip.annotations.NotThreadSafe;
+
+//@NotThreadSafe
+public final class MaxValueCounter {
+    final String mName;
+    final Logger mLogger;
+    int mValue = 0;
+    int mMaxValue = 0;
+
+    public MaxValueCounter(String name, Logger logger) {
+        mName = name;
+        mLogger = logger;
+    }
+
+    public void set(int value) {
+        mValue = value;
+        if (mValue > mMaxValue) {
+            mMaxValue = mValue;
+            mLogger.fine("New " + mName + ": " + mMaxValue);
+        }
+    }
+
+    public String toString() {
+        return String.valueOf(mMaxValue);
+    }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/util/OptionFormatter.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/util/OptionFormatter.java
new file mode 100644 (file)
index 0000000..3085e6b
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This is a helper class for an OptionParser.
+ */
+class OptionFormatter {
+    private final int mOptionIndent;
+    private final int mDescrIndent;
+    private final int mMaxWidth;
+
+    public OptionFormatter(int optionIndent, int descrIndent, int maxWidth) {
+        mOptionIndent = optionIndent;
+        mDescrIndent = descrIndent;
+        mMaxWidth = maxWidth;
+    }
+
+    public void format(StringBuilder sb, String option, String descr) {
+        addSpace(sb, mOptionIndent);
+        sb.append(option);
+        final int firstIndent;
+        if (mOptionIndent + option.length() >= mDescrIndent) {
+            sb.append("\n");
+            firstIndent = mDescrIndent;
+        } else {
+            firstIndent = mDescrIndent - (mOptionIndent + option.length());
+        }
+        if (descr == null) {
+            sb.append('\n');
+        } else {
+            List<String> descrLines = wrapText(descr, mMaxWidth - mDescrIndent);
+            indentText(sb, descrLines, mDescrIndent, firstIndent);
+        }
+    }
+
+    static void addSpace(StringBuilder sb, int n) {
+        for (int i = 0; i < n; ++i) {
+            sb.append(' ');
+        }
+    }
+
+    static List<String> wrapText(String text, int maxWidth) {
+        ArrayList<String> result = new ArrayList<String>();
+        int pos = 0;
+        StringBuilder sb = new StringBuilder();
+
+        for (String word : text.split("\\s+")) {
+            if (sb.length() > 0 && word.length() + 1 > maxWidth - sb.length()) {
+                result.add(sb.toString());
+                sb.setLength(0);
+                sb.append(word);
+                pos = word.length();
+            } else {
+                if (sb.length() > 0) {
+                    sb.append(' ');
+                }
+                sb.append(word);
+                pos += word.length();
+            }
+        }
+        if (sb.length() > 0) {
+            result.add(sb.toString());
+        }
+
+        return result;
+    }
+
+    static void indentText(StringBuilder sb,
+                           List<String> lines,
+                           int indent,
+                           int firstIndent) {
+        boolean first = true;
+        addSpace(sb, firstIndent);
+        for (String line : lines) {
+            if (first) {
+                first = false;
+            } else {
+                addSpace(sb, indent);
+            }
+            sb.append(line);
+            sb.append('\n');
+        }
+    }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/util/OptionParser.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/util/OptionParser.java
new file mode 100644 (file)
index 0000000..a032f82
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This class parses command-line options.
+ */
+public class OptionParser {
+    private class OptionData {
+        String valueName;
+        String description;
+    }
+
+    private final List<String> mArguments = new ArrayList<String>();
+    private final Map<String, String> mParsedOptions =
+        new HashMap<String, String>();
+    private final Map<String, OptionData> mValidOptions =
+        new HashMap<String, OptionData>();
+
+    public OptionParser() {
+    }
+
+    /**
+     * Tell the parser to recognize a new option.
+     *
+     * Options can be given on the following forms:
+     *
+     * <ul>
+     * <li>-option</li>
+     * <li>-option foo</li>
+     * </ul>
+     *
+     * The first form specifies an option without a value and the second
+     * specifies an option with a value.
+     *
+     * @param option
+     *            The option.
+     * @param description
+     *            Description of the option.
+     */
+    public void addOption(String option, String description) {
+        final int spacePos = option.indexOf(' ');
+        final String flag;
+        final String valueName;
+        if (spacePos == -1) {
+            flag = option;
+            valueName = null;
+        } else {
+            flag = option.substring(0, spacePos);
+            valueName = option.substring(spacePos + 1);
+        }
+        OptionData data = new OptionData();
+        data.valueName = valueName;
+        data.description = description;
+        mValidOptions.put(flag, data);
+    }
+
+    /**
+     * Get arguments remaining after options (and their values) have been
+     * parsed.
+     *
+     * @return The arguments.
+     */
+    public List<String> getArguments() {
+        return mArguments;
+    }
+
+    /**
+     * Get a string containing help text describing available options.
+     *
+     * @return The help text.
+     */
+    public String getOptionHelp() {
+        StringBuilder sb = new StringBuilder();
+        OptionFormatter formatter = new OptionFormatter(2, 23, 79);
+        ArrayList<String> options = new ArrayList<String>();
+        options.addAll(mValidOptions.keySet());
+        Collections.sort(options);
+        for (String option : options) {
+            final OptionData data = mValidOptions.get(option);
+            final String optAndVal;
+            if (data.valueName == null) {
+                optAndVal = option;
+            } else {
+                optAndVal = option + " " + data.valueName;
+            }
+            formatter.format(sb, optAndVal, data.description);
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Get parsed options.
+     *
+     * The map is keyed on option and the values are the option values (null if
+     * no parameter was expected).
+     *
+     * @return The option map.
+     */
+    public Map<String, String> getOptions() {
+        return mParsedOptions;
+    }
+
+    /**
+     * Parse arguments.
+     *
+     * @param arguments
+     *            The arguments to parse.
+     * @throws InvalidOptionException
+     *             If an invalid option is encountered.
+     */
+    public void parse(String[] arguments) throws InvalidOptionException {
+        mArguments.clear();
+        boolean reachedNonOption = false;
+        for (int i = 0; i < arguments.length; ++i) {
+            if (!reachedNonOption
+                    && (arguments[i].length() == 0
+                            || arguments[i].charAt(0) != '-')) {
+                reachedNonOption = true;
+            }
+            if (reachedNonOption) {
+                mArguments.add(arguments[i]);
+            } else {
+                String option = arguments[i];
+                if (mValidOptions.containsKey(option)) {
+                    OptionData data = mValidOptions.get(option);
+                    String optionArgument;
+                    if (data.valueName != null) {
+                        ++i;
+                        if (i < arguments.length) {
+                            optionArgument = arguments[i];
+                        } else {
+                            String message = "value missing to flag " + option;
+                            throw new InvalidOptionException(message);
+                        }
+                    } else {
+                        optionArgument = null;
+                    }
+                    mParsedOptions.put(option, optionArgument);
+                } else {
+                    throw new InvalidOptionException("invalid flag: "
+                                                     + arguments[i]);
+                }
+            }
+        }
+    }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/util/TransactionalCounter.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/util/TransactionalCounter.java
new file mode 100644 (file)
index 0000000..ae1a3f0
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package com.enea.jcarder.util;
+
+import com.enea.jcarder.transactionalinterfaces.Intif;
+import com.enea.jcarder.util.logging.Logger;
+
+
+/**
+ *
+ * @author navid
+ */
+public class TransactionalCounter {
+
+    public final int mLogIntervall;
+    public final String mName;
+    public final Logger mLogger;
+    public Intif.positionif mValue;
+
+    public TransactionalCounter(String name, Logger logger, int logInterval) {
+        mValue = Intif.factory.create();
+        mValue.setPosition(0);
+        mName = name;
+        mLogger = logger;
+        mLogIntervall = logInterval;
+    }
+
+    public void increment() {
+        mValue.setPosition(mValue.getPosition()+1);
+        if (((mValue.getPosition()) % mLogIntervall) == 0) {
+            mLogger.fine(mName + ": " + mValue);
+        } else if (mLogger.isLoggable(Logger.Level.FINEST)) {
+            mLogger.finest(mName + ": " + mValue);
+        }
+    }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/util/logging/AppendableHandler.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/util/logging/AppendableHandler.java
new file mode 100644 (file)
index 0000000..20d788a
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.util.logging;
+
+import java.io.IOException;
+
+import com.enea.jcarder.util.logging.Logger.Level;
+
+/**
+ * This class acts as a log handler for classes that that implement the
+ * Appendable interface.
+ *
+ * The Appendable does not need to be thread-safe; AppendableHandler
+ * synchronizes calls to Appendable's methods.
+ */
+public class AppendableHandler implements Handler {
+    private final Appendable mDestination;
+    private final Level mLevel;
+    private final String mMessageFormat;
+
+    /**
+     * Constructor.
+     *
+     * The default log level is FINEST and the default message format is
+     * "{level}: {message}\n"
+     *
+     * @param destination
+     *            Destination of the log messages.
+     */
+    public AppendableHandler(Appendable destination) {
+        this(destination, Logger.Level.FINEST);
+    }
+
+    /**
+     * Constructor.
+     *
+     * The default message format is "{level}: {message}\n"
+     *
+     * @param destination
+     *            Destination of the log messages.
+     * @param logLevel
+     *            Log level.
+     */
+    public AppendableHandler(Appendable destination, Logger.Level logLevel) {
+        this(destination, logLevel, "{level}: {message}\n");
+    }
+
+    /**
+     * Constructor.
+     *
+     * Substrings like {keyword} are expanded in the message format string.
+     *
+     * Currently supported keywords:
+     *
+     * - {message} -- the message
+     * - {level} -- the log level
+     *
+     * @param destination Destination of the log messages.
+     * @param logLevel Log level.
+     * @param messageFormat Message format.
+     */
+    public AppendableHandler(Appendable destination,
+                             Logger.Level logLevel,
+                             String messageFormat) {
+        mDestination = destination;
+        mLevel = logLevel;
+        mMessageFormat = messageFormat;
+    }
+
+
+    public void publish(Level level, String message) {
+        if (level.compareTo(mLevel) <= 0) {
+            try {
+                String formattedMessage = mMessageFormat
+                    .replace("{level}", level.toString())
+                    .replace("{message}", message);
+                synchronized (mDestination) {
+                    mDestination.append(formattedMessage);
+                }
+            } catch (IOException e) {
+                // Ignore.
+            }
+        }
+    }
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/util/logging/Handler.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/util/logging/Handler.java
new file mode 100644 (file)
index 0000000..74ac348
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.util.logging;
+
+import com.enea.jcarder.util.logging.Logger.Level;
+
+/**
+ * This interface must be implemented by classes that handles log messages from
+ * the Logger class.
+ */
+public interface Handler {
+    /**
+     * Handle a published message.
+     *
+     * This method is called by a Logger class each time it receives a message
+     * to be logged.
+     *
+     * @param level Log level of the message.
+     * @param message The message.
+     */
+    void publish(Level level, String message);
+}
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/util/logging/Logger.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/util/logging/Logger.java
new file mode 100644 (file)
index 0000000..29042a9
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package com.enea.jcarder.util.logging;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * A simple logging framework.
+ *
+ * We use our own simple Logging framework for several reasons:
+ *  - To avoid interfering with logging from the user application. Even if we
+ * were using Log4J instead of java.util.Logging.*, JCarder might interfere with
+ * for example Log4J system properties.
+ *  - The default java.util.logging.LogManager is reset by a shutdown hook and
+ * there is no fixed order in which the shutdown hooks are executed.
+ *  - Minimizing the usage of the Java standard library improves performance and
+ * minimizes the risk of deadlock if the standard library is instrumented by
+ * JCarder.
+ */
+public final class Logger {
+    public static enum Level {
+        SEVERE,
+        WARNING,
+        INFO,
+        CONFIG,
+        FINE,
+        FINER,
+        FINEST;
+
+        /**
+         * Parse a string and return the corresponding log level.
+         *
+         * @param string The string to parse.
+         * @return
+         */
+        public static Level fromString(String string) {
+            for (Level level : values()) {
+                if (string.equalsIgnoreCase(level.toString())) {
+                    return level;
+                }
+            }
+            return null;
+        }
+
+        public static String getEnumeration() {
+            StringBuffer sb = new StringBuffer();
+            boolean first = true;
+            for (Level level : values()) {
+                if (first) {
+                    first = false;
+                } else {
+                    sb.append(", ");
+                }
+                sb.append(level.toString());
+            }
+            return sb.toString();
+        }
+    }
+
+    final Collection<Handler> mHandlers;
+    final Level mLevel;
+
+    /**
+     * Constructor setting default value of log level.
+     *
+     * The default is to log everything, i.e., log level FINEST.
+     *
+     * @param handlers Log handlers. null means no handlers.
+     */
+    public Logger(Collection<Handler> handlers) {
+        this(handlers, Level.FINEST);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param handlers Log handlers. null means no handlers.
+     * @param logLevel Log level.
+     */
+    public Logger(Collection<Handler> handlers, Level logLevel) {
+        mLevel = logLevel;
+        mHandlers = new ArrayList<Handler>();
+        if (handlers != null) {
+            // Create a copy of the provided collection instead of sharing
+            // it, in order to make sure that mHandlers is immutable and
+            // thread safe.
+            mHandlers.addAll(handlers);
+        }
+    }
+
+    /**
+     * Check whether a message with a certain level would be logged.
+     *
+     * @param level The level.
+     * @return True if the message would be logged, otherwise false.
+     */
+    public boolean isLoggable(Level level) {
+        return level.compareTo(mLevel) <= 0;
+    }
+
+    /**
+     * Log a message with level SEVERE.
+     *
+     * @param message The message.
+     */
+    public void severe(String message) {
+        publishLog(Level.SEVERE, message);
+    }
+
+
+    /**
+     * Log a message with level WARNING.
+     *
+     * @param message The message.
+     */
+    public void warning(String message) {
+        publishLog(Level.WARNING, message);
+    }
+
+
+    /**
+     * Log a message with level INFO.
+     *
+     * @param message The message.
+     */
+    public void info(String message) {
+        publishLog(Level.INFO, message);
+    }
+
+
+    /**
+     * Log a message with level CONFIG.
+     *
+     * @param message The message.
+     */
+    public void config(String message) {
+        publishLog(Level.CONFIG, message);
+    }
+
+
+    /**
+     * Log a message with level FINE.
+     *
+     * @param message The message.
+     */
+    public void fine(String message) {
+        publishLog(Level.FINE, message);
+    }
+
+
+    /**
+     * Log a message with level FINER.
+     *
+     * @param message The message.
+     */
+    public void finer(String message) {
+        publishLog(Level.FINER, message);
+    }
+
+    /**
+     * Log a message with level FINEST.
+     *
+     * @param message The message.
+     */
+    public void finest(String message) {
+        publishLog(Level.FINEST, message);
+    }
+
+    private void publishLog(Level level, String message) {
+        if (isLoggable(level)) {
+            for (Handler handler : mHandlers) {
+                handler.publish(level, message);
+            }
+        }
+    }
+}