KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > gov > nasa > jpf > jvm > Monitor


1 //
2
// Copyright (C) 2005 United States Government as represented by the
3
// Administrator of the National Aeronautics and Space Administration
4
// (NASA). All Rights Reserved.
5
//
6
// This software is distributed under the NASA Open Source Agreement
7
// (NOSA), version 1.3. The NOSA has been approved by the Open Source
8
// Initiative. See the file NOSA-1.3-JPF at the top of the distribution
9
// directory tree for the complete NOSA document.
10
//
11
// THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
12
// KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
13
// LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
14
// SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
15
// A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
16
// THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
17
// DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
18
//
19
package gov.nasa.jpf.jvm;
20
21 import gov.nasa.jpf.JPFException;
22 import gov.nasa.jpf.util.Debug;
23 import gov.nasa.jpf.util.HashData;
24
25 /**
26  * Represents the monitor associate with classes and objects.
27  */

28 public class Monitor {
29   /**
30    * The identifier of the thread locking an object.
31    */

32   private int lockingThread;
33
34   /**
35    * The number of nested locks acquired.
36    */

37   private int lockCount;
38
39   /**
40    * The list of threads waiting to be notified.
41    */

42   private int[] waitingThreads;
43
44   /**
45    * Creates a new empty monitor.
46    */

47   public Monitor () {
48     lockingThread = -1;
49     lockCount = 0;
50     waitingThreads = new int[0];
51   }
52
53   /**
54    * Returns the number of nested locks acquired.
55    */

56   public int getLockCount () {
57     return lockCount;
58   }
59
60   /**
61    * Returns the identifier of the thread holding the lock.
62    */

63   public int getLockingThread () {
64     return lockingThread;
65   }
66
67   /**
68    * Returns the list of waiting threads.
69    */

70   public int[] getWaitingThreads () {
71     return waitingThreads;
72   }
73
74   /**
75    * Returns true if it is possible to lock the monitor.
76    */

77   public boolean canLock (ThreadInfo th) {
78     if (lockingThread == -1) {
79       return true;
80     }
81
82     return (lockingThread == th.index);
83   }
84
85   /**
86    * Creates a clone of the monitor.
87    */

88   public Object JavaDoc clone () {
89     Monitor m = new Monitor();
90
91     m.lockingThread = lockingThread;
92     m.lockCount = lockCount;
93     m.waitingThreads = new int[waitingThreads.length];
94     System.arraycopy(waitingThreads, 0, m.waitingThreads, 0,
95                      waitingThreads.length);
96
97     return m;
98   }
99
100   /**
101    * Compares to another object.
102    */

103   public boolean equals (Object JavaDoc o) {
104     if (o == null) {
105       return false;
106     }
107
108     if (!(o instanceof Monitor)) {
109       return false;
110     }
111
112     Monitor m = (Monitor) o;
113
114     if (lockingThread != m.getLockingThread()) {
115       return false;
116     }
117
118     if (lockCount != m.getLockCount()) {
119       return false;
120     }
121
122     int[] w = m.waitingThreads;
123
124     if (waitingThreads.length != w.length) {
125       return false;
126     }
127
128     for (int i = 0; i < waitingThreads.length; i++) {
129       if (waitingThreads[i] != w[i]) {
130         return false;
131       }
132     }
133
134     return true;
135   }
136
137   public void hash (HashData hd) {
138     hd.add(lockingThread);
139     hd.add(lockCount);
140
141     for (int i = 0, l = waitingThreads.length; i < l; i++) {
142       hd.add(waitingThreads[i]);
143     }
144   }
145
146   public int hashCode () {
147     HashData hd = new HashData();
148
149     hash(hd);
150
151     return hd.getValue();
152   }
153
154   /**
155    * Interrupts one of the threads holding the lock.
156    */

157   public void interrupt (ThreadInfo th) {
158     remove(th.index);
159     th.setStatus(ThreadInfo.INTERRUPTED);
160   }
161
162   /**
163    * Acquires the lock for a given object or class.
164    */

165   public void lock (ThreadInfo th, Ref ref) {
166     // in general, locking is only permitted from the currently running thread
167
// in case the object isn't locked yet.
168

169     if (lockingThread == -1) {
170       lockingThread = th.index;
171
172       th.lock(ref);
173     } else if (lockingThread != th.index) {
174       throw new JPFException("lock operation failed");
175     }
176
177     lockCount++;
178   }
179
180   /**
181    * Tries to re-aquire the lock after being notified.
182    */

183   public void lockNotified (ThreadInfo th, Ref ref) {
184     if (lockingThread != -1) {
185       throw new JPFException("lock operation failed");
186     }
187     
188     lockingThread = th.index;
189     lockCount = th.getLockCount();
190     
191     //** warning: should have been done when interrupted was set. **//
192
for (int i = 0; i < waitingThreads.length; i++) {
193       if (waitingThreads[i] == th.index) {
194         remove(i);
195
196         break;
197       }
198     }
199
200     th.setStatus(ThreadInfo.RUNNING);
201     th.setLockCount(0);
202
203     th.lock(ref);
204   }
205
206   public void log () {
207     Debug.println(Debug.MESSAGE, " $lockingThread$: " + lockingThread);
208     Debug.println(Debug.MESSAGE, " $lockCount$: " + lockCount);
209     Debug.print(Debug.MESSAGE, " $waitingThreads$: { ");
210
211     for (int i = 0, l = waitingThreads.length; i < l; i++) {
212       if (i != 0) {
213         Debug.print(Debug.MESSAGE, ", ");
214       }
215
216       Debug.print(Debug.MESSAGE, Integer.toString(waitingThreads[i]));
217     }
218
219     Debug.println(Debug.MESSAGE, " }");
220   }
221
222   /**
223    * Notifies one of the threads. The thread is chosen non deterministically.
224    */

225   public void notify (SystemState ss) {
226     int length = waitingThreads.length;
227     
228     if (length == 0) {
229       return;
230     }
231
232     int random = ss.random(length);
233
234     ss.ks.tl.get(remove(random)).setStatus(ThreadInfo.NOTIFIED);
235   }
236
237   /**
238    * Notifies all waiting threads.
239    */

240   public void notifyAll (SystemState ss) {
241     for (int i = 0, l = waitingThreads.length; i < l; i++) {
242       ThreadInfo th = ss.ks.tl.get(waitingThreads[i]);
243       th.setStatus(ThreadInfo.NOTIFIED);
244     }
245
246     waitingThreads = new int[0];
247   }
248
249   public int objectHashCode () {
250     return super.hashCode();
251   }
252
253   public String JavaDoc toString () {
254     StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
255
256     sb.append("Monitor(");
257     sb.append("lockingThread=");
258     sb.append(lockingThread);
259     sb.append(',');
260     sb.append("lockCount=");
261     sb.append(lockCount);
262     sb.append(',');
263     sb.append("waitingThreads=");
264     sb.append('[');
265
266     for (int i = 0; i < waitingThreads.length; i++) {
267       if (i != 0) {
268         sb.append(',');
269       }
270
271       sb.append(waitingThreads[i]);
272     }
273
274     sb.append(']');
275     sb.append(')');
276
277     return sb.toString();
278   }
279
280   /**
281    * Releases the lock. The lock can be still held by the thread
282    * if it had been locked more than once.
283    */

284   public void unlock (ThreadInfo th, Ref ref) {
285     // <2do> - might actually be a better way to deal with synced native
286
// methods giving up the lock (join)
287
//if (lockingThread == -1) return;
288

289     lockCount--;
290     
291     if (lockCount < 0) {
292       throw new JPFException("lock counter can't be negative");
293     }
294
295     if (lockCount == 0) {
296       lockingThread = -1;
297       th.unlock(ref);
298     }
299   }
300
301   /**
302    * Waits to be notified. Releases the lock and waits.
303    */

304   public void wait (ThreadInfo th, Ref ref) {
305     if (lockingThread != th.index) {
306       throw new JPFException("wait on an unlocked monitor");
307     }
308
309     th.setStatus(ThreadInfo.WAITING);
310     th.setLockCount(lockCount);
311
312     int length = waitingThreads.length;
313     int[] n = new int[length + 1];
314     System.arraycopy(waitingThreads, 0, n, 0, length);
315     waitingThreads = n;
316     waitingThreads[length] = th.index;
317
318     lockingThread = -1;
319     lockCount = 0;
320
321     th.unlock(ref);
322   }
323
324   private int remove (int index) {
325     int r = waitingThreads[index];
326     int length = waitingThreads.length;
327
328     int[] n = new int[length - 1];
329     System.arraycopy(waitingThreads, 0, n, 0, index);
330     System.arraycopy(waitingThreads, index + 1, n, index, length - index - 1);
331     waitingThreads = n;
332
333     return r;
334   }
335 }
336
Popular Tags