2 * Copyright (C) 2014, United States Government, as represented by the
3 * Administrator of the National Aeronautics and Space Administration.
6 * The Java Pathfinder core (jpf-core) platform is licensed under the
7 * Apache License, Version 2.0 (the "License"); you may not use this file except
8 * in compliance with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0.
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 package gov.nasa.jpf.vm;
20 import gov.nasa.jpf.util.HashData;
22 import java.io.PrintWriter;
23 import java.util.Arrays;
26 * Represents the variable, hash-collapsed pooled data associated with an object
27 * that is not related to the object values (->Fields), but to the use of the
28 * object for synchronization purposes (locks and signals).
31 public class Monitor implements Cloneable {
33 static ThreadInfo[] emptySet = new ThreadInfo[0];
35 /** the thread owning the lock */
36 private ThreadInfo lockingThread;
38 /** the nesting level for recursive lock acquisition */
39 private int lockCount;
42 * the list of threads that try to acquire the lock (can be in blocked, waiting,
43 * interrupted or running state).
45 ThreadInfo[] lockedThreads;
48 * Creates a new empty monitor.
53 lockedThreads = emptySet;
56 private Monitor (ThreadInfo locking, int count, ThreadInfo[] locked) {
57 lockingThread = locking;
59 lockedThreads = locked.clone();
60 Arrays.sort(lockedThreads);
63 public void printFields (PrintWriter pw) {
68 if (lockingThread != null) {
69 pw.print( "locked by: ");
70 pw.print( lockingThread.getName());
72 pw.print( "unlocked");
75 pw.print(", lockCount: ");
78 pw.print(", locked: {");
79 for (i=0; i<lockedThreads.length; i++) {
80 if (i > 0) pw.print(',');
81 pw.print(lockedThreads[i].getName());
83 pw.print(lockedThreads[i].getStateName());
88 // for debugging purposes
90 PrintWriter pw = new PrintWriter(System.out);
95 Monitor cloneWithLocked (ThreadInfo ti) {
96 return new Monitor(lockingThread, lockCount, add(lockedThreads, ti));
99 Monitor cloneWithoutLocked (ThreadInfo ti) {
100 return new Monitor(lockingThread, lockCount, remove(lockedThreads, ti));
104 public Monitor clone () {
106 // no need to clone the empty set (which should be the majority of cases)
107 Monitor m = (Monitor) super.clone();
108 if (lockedThreads != emptySet) {
109 m.lockedThreads = lockedThreads.clone();
113 } catch (CloneNotSupportedException cnsx) {
114 throw new InternalError("should not happen");
120 * Compares to another object.
123 public boolean equals (Object o) {
128 if (!(o instanceof Monitor)) {
132 Monitor m = (Monitor) o;
134 if (lockingThread != m.getLockingThread()) {
138 if (lockCount != m.getLockCount()) {
142 ThreadInfo[] list = m.lockedThreads;
143 if (lockedThreads.length != list.length) {
147 for (int i = 0; i < lockedThreads.length; i++) {
148 if (lockedThreads[i] != list[i]) {
157 public void hash (HashData hd) {
158 if (lockingThread != null) {
159 hd.add(lockingThread.getId());
164 for (int i = 0; i < lockedThreads.length; i++) {
165 hd.add(lockedThreads[i].getId());
171 public int hashCode () {
172 HashData hd = new HashData();
174 return hd.getValue();
179 * Returns the number of nested locks acquired.
181 public int getLockCount () {
187 * Returns the identifier of the thread holding the lock.
189 public ThreadInfo getLockingThread () {
190 return lockingThread;
195 * Returns the list of locked threads
197 public ThreadInfo[] getLockedThreads() {
198 return lockedThreads;
202 public boolean hasLockedThreads () {
203 return (lockedThreads.length > 0);
206 public boolean hasWaitingThreads () {
207 for (int i=0; i<lockedThreads.length; i++) {
208 if (lockedThreads[i].isWaiting()) {
216 public int getNumberOfWaitingThreads() {
219 for (ThreadInfo ti : lockedThreads){
229 public ThreadInfo[] getWaitingThreads() {
230 int n = getNumberOfWaitingThreads();
233 ThreadInfo[] list = new ThreadInfo[n];
235 for (int j=0; j<lockedThreads.length && i<n; j++){
236 ThreadInfo ti = lockedThreads[j];
249 public int getNumberOfBlockedThreads() {
252 for (ThreadInfo ti : lockedThreads){
262 public ThreadInfo[] getBlockedThreads() {
263 int n = getNumberOfBlockedThreads();
266 ThreadInfo[] list = new ThreadInfo[n];
268 for (int j=0; j<lockedThreads.length && i<n; j++){
269 ThreadInfo ti = lockedThreads[j];
283 public int getNumberOfBlockedOrWaitingThreads() {
286 for (ThreadInfo ti : lockedThreads){
287 if (ti.isBlocked() || ti.isWaiting()){
296 public ThreadInfo[] getBlockedOrWaitingThreads() {
297 int n = getNumberOfBlockedThreads();
300 ThreadInfo[] list = new ThreadInfo[n];
302 for (int j=0; j<lockedThreads.length && i<n; j++){
303 ThreadInfo ti = lockedThreads[j];
304 if (ti.isBlocked() || ti.isWaiting()){
318 * Returns true if it is possible to lock the monitor.
320 public boolean canLock (ThreadInfo th) {
321 if (lockingThread == null) {
325 return (lockingThread == th);
329 void setLockingThread (ThreadInfo ti) {
334 void incLockCount () {
339 void decLockCount () {
340 assert lockCount > 0 : "negative lockCount";
345 void setLockCount (int lc) {
346 assert lc >= 0 : "attempt to set negative lockCount";
350 public int objectHashCode () {
351 return super.hashCode();
354 void resetLockedThreads () {
355 lockedThreads = emptySet;
358 public boolean isLocking(ThreadInfo ti){
359 if (lockedThreads != null){
360 for (ThreadInfo lti : lockedThreads){
371 static boolean containsLocked(ThreadInfo[] list, ThreadInfo ti){
372 int len = list.length;
374 for (int i=0; i<len; i++){
383 static ThreadInfo[] add (ThreadInfo[] list, ThreadInfo ti) {
384 int len = list.length;
386 //--- first, check if its already there
387 if (containsLocked(list, ti)){
388 // this is required because interrupted parks/joins can try to
389 // re-park/join from their respective handlers (they don't hold locks)
393 ThreadInfo[] newList = new ThreadInfo[len+1];
396 for (; pos < len && ti.compareTo(list[pos]) > 0; pos++) {
397 newList[pos] = list[pos];
401 for (; pos < len; pos++) {
402 newList[pos+1] = list[pos];
408 void addLocked (ThreadInfo ti) {
409 lockedThreads = add(lockedThreads, ti);
412 static ThreadInfo[] remove (ThreadInfo[] list, ThreadInfo ti) {
413 int len = list.length;
415 if (len == 0) { // nothing to remove from
418 } else if (len == 1) { // one element list optimization
426 //--- first, check if its already there
427 if (!containsLocked(list, ti)) {
428 // no known case yet, but we keep it symmetric
429 // <2do> maybe worth a warning
433 for (int i=0; i<len; i++) {
436 ThreadInfo[] newList = new ThreadInfo[newLen];
438 System.arraycopy(list, 0, newList, 0, i);
441 System.arraycopy(list, i+1, newList, i, newLen-i);
446 // else, not in list:
451 void removeLocked (ThreadInfo ti) {
452 lockedThreads = remove(lockedThreads, ti);