00001 package gov.nasa.arc.ase.jpf.jvm;
00002
00003 import gov.nasa.arc.ase.util.Debug;
00004 import gov.nasa.arc.ase.util.HashData;
00005 import gov.nasa.arc.ase.jpf.InternalErrorException;
00006 import java.io.*;
00007
00008
00009
00010
00011 import java.util.*;
00012
00013
00014
00015
00016
00017
00018
00019
00020 public class Monitor {
00021
00022
00023
00024 private int lockingThread;
00025
00026
00027
00028
00029 private int lockCount;
00030
00031
00032
00033
00034 private int[] waitingThreads;
00035
00036
00037
00038
00039 public Monitor() {
00040 lockingThread = -1;
00041 lockCount = 0;
00042 waitingThreads = new int[0];
00043 }
00044
00045
00046
00047 public boolean canLock(ThreadInfo th) {
00048 if (lockingThread == -1) return true;
00049
00050 return (lockingThread == th.index);
00051 }
00052
00053
00054
00055 public Object clone() {
00056 Monitor m = new Monitor();
00057
00058 m.lockingThread = lockingThread;
00059 m.lockCount = lockCount;
00060 m.waitingThreads = new int[waitingThreads.length];
00061 System.arraycopy(waitingThreads, 0, m.waitingThreads, 0, waitingThreads.length);
00062
00063 return m;
00064 }
00065
00066
00067
00068 public boolean equals(Object o) {
00069 if(o == null) return false;
00070 if(!(o instanceof Monitor)) return false;
00071
00072 Monitor m = (Monitor)o;
00073
00074 if (lockingThread != m.getLockingThread()) return false;
00075 if (lockCount != m.getLockCount()) return false;
00076
00077 int[] w = m.waitingThreads;
00078
00079 if (waitingThreads.length != w.length) return false;
00080
00081 for(int i = 0; i < waitingThreads.length; i++)
00082 if(waitingThreads[i] != w[i]) return false;
00083
00084 return true;
00085 }
00086
00087
00088
00089 public int getLockCount() {
00090 return lockCount;
00091 }
00092
00093
00094
00095 public int getLockingThread() {
00096 return lockingThread;
00097 }
00098
00099
00100
00101 public int[] getWaitingThreads() {
00102 return waitingThreads;
00103 }
00104 public void hash(HashData hd) {
00105 hd.add(lockingThread);
00106 hd.add(lockCount);
00107
00108 for(int i = 0, l = waitingThreads.length; i < l; i++)
00109 hd.add(waitingThreads[i]);
00110 }
00111 public int hashCode() {
00112 HashData hd = new HashData();
00113
00114 hash(hd);
00115
00116 return hd.getValue();
00117 }
00118
00119
00120
00121 public void interrupt(ThreadInfo th) {
00122 remove(th.index);
00123 th.setStatus(ThreadInfo.INTERRUPTED);
00124 }
00125
00126
00127
00128 public void lock(ThreadInfo th, Ref ref) {
00129 if(lockingThread == -1) {
00130 lockingThread = th.index;
00131
00132
00133
00134
00135 } else
00136 if(lockingThread != th.index)
00137 throw new InternalErrorException("lock operation failed");
00138 lockCount++;
00139 }
00140
00141
00142
00143 public void lockNotified(ThreadInfo th, Ref ref) {
00144 if (lockingThread != -1)
00145 throw new InternalErrorException("lock operation failed");
00146
00147 lockingThread = th.index;
00148 lockCount = th.getLockCount();
00149
00150
00151 for(int i = 0; i < waitingThreads.length; i++)
00152 if(waitingThreads[i] == th.index) {
00153 remove(i);
00154 break;
00155 }
00156
00157 th.setStatus(ThreadInfo.RUNNING);
00158 th.setLockCount(0);
00159 }
00160 public void log() {
00161 Debug.println(Debug.MESSAGE, " $lockingThread$: " + lockingThread);
00162 Debug.println(Debug.MESSAGE, " $lockCount$: " + lockCount);
00163 Debug.print(Debug.MESSAGE, " $waitingThreads$: { ");
00164 for(int i = 0, l = waitingThreads.length; i < l; i++) {
00165 if(i != 0) Debug.print(Debug.MESSAGE, ", ");
00166 Debug.print(Debug.MESSAGE, Integer.toString(waitingThreads[i]));
00167 }
00168 Debug.println(Debug.MESSAGE, " }");
00169 }
00170
00171
00172
00173 public void notify(SystemState ss) {
00174 int length = waitingThreads.length;
00175
00176 if(length == 0) return;
00177
00178 int random = ss.random(length);
00179
00180 ss.ks.tl.get(remove(random)).setStatus(ThreadInfo.NOTIFIED);
00181 }
00182
00183
00184
00185 public void notifyAll(SystemState ss) {
00186 for(int i = 0, l = waitingThreads.length; i < l; i++) {
00187 ThreadInfo th = ss.ks.tl.get(waitingThreads[i]);
00188 th.setStatus(ThreadInfo.NOTIFIED);
00189 }
00190
00191 waitingThreads = new int[0];
00192 }
00193 private int remove(int index) {
00194 int r = waitingThreads[index];
00195 int length = waitingThreads.length;
00196
00197 int[] n = new int[length - 1];
00198 System.arraycopy(waitingThreads, 0, n, 0, index);
00199 System.arraycopy(waitingThreads, index+1, n, index, length - index - 1);
00200 waitingThreads = n;
00201
00202 return r;
00203 }
00204 public String toString() {
00205 StringBuffer sb = new StringBuffer();
00206
00207 sb.append("Monitor(");
00208 sb.append("lockingThread=");
00209 sb.append(lockingThread);
00210 sb.append(',');
00211 sb.append("lockCount=");
00212 sb.append(lockCount);
00213 sb.append(',');
00214 sb.append("waitingThreads=");
00215 sb.append('[');
00216 for(int i = 0; i < waitingThreads.length; i++) {
00217 if(i != 0)
00218 sb.append(',');
00219 sb.append(waitingThreads[i]);
00220 }
00221 sb.append(']');
00222 sb.append(')');
00223
00224 return sb.toString();
00225 }
00226
00227
00228
00229
00230 public void unlock(ThreadInfo th, Ref ref) {
00231 lockCount--;
00232
00233 if(lockCount < 0)
00234 throw new InternalErrorException("lock counter can't be negative");
00235
00236 if (lockCount == 0) {
00237 lockingThread = -1;
00238
00239
00240
00241 }
00242 }
00243
00244
00245
00246 public void wait(ThreadInfo th, Ref ref) {
00247 if(lockingThread != th.index)
00248 throw new InternalErrorException("wait on an unlocked monitor");
00249
00250 th.setStatus(ThreadInfo.WAITING);
00251 th.setLockCount(lockCount);
00252
00253 int length = waitingThreads.length;
00254 int[] n = new int[length + 1];
00255 System.arraycopy(waitingThreads, 0, n, 0, length);
00256 waitingThreads = n;
00257 waitingThreads[length] = th.index;
00258
00259 lockingThread = -1;
00260 lockCount = 0;
00261
00262
00263
00264
00265 }
00266 }