#68106: Mutex starvation fixed - enable another reader to proceed chained mutex in case readers have got it before.
1.1 --- a/openide.util/src/org/openide/util/Mutex.java Fri May 26 07:38:45 2006 +0000
1.2 +++ b/openide.util/src/org/openide/util/Mutex.java Fri May 26 15:00:50 2006 +0000
1.3 @@ -138,6 +138,9 @@
1.4
1.5 /** granted mode */
1.6 private int grantedMode = NONE;
1.7 +
1.8 + /** The mode the mutex was in before it started chaining */
1.9 + private int origMode;
1.10
1.11 /** protects internal data structures */
1.12 private /*final*/ Object LOCK;
1.13 @@ -189,15 +192,6 @@
1.14 }
1.15 }
1.16
1.17 - /** Decides whether two locks are compatible.?
1.18 - * @param granted?
1.19 - * @param requested?
1.20 - * @return <tt>true</tt> iff they are compatible?
1.21 - */
1.22 - private static boolean compatibleLocks(int granted, int requested) {
1.23 - return cmatrix[requested][granted];
1.24 - }
1.25 -
1.26 /** Initiates this Mutex */
1.27 private void init(Object lock) {
1.28 this.LOCK = lock;
1.29 @@ -605,7 +599,7 @@
1.30 info.rsnapshot = info.counts[S];
1.31
1.32 if (grantedMode == S) {
1.33 - grantedMode = X;
1.34 + setGrantedMode(X);
1.35 } else if (grantedMode == X) {
1.36 // defensive
1.37 throw new IllegalStateException();
1.38 @@ -630,7 +624,7 @@
1.39 } else { // first acquisition
1.40
1.41 if (isCompatible(requested)) { // NONE -> S,X or S -> S
1.42 - grantedMode = requested;
1.43 + setGrantedMode(requested);
1.44 registeredThreads.put(t, info = new ThreadInfo(t, requested));
1.45
1.46 if (requested == S) {
1.47 @@ -646,7 +640,7 @@
1.48 return false;
1.49 }
1.50
1.51 - grantedMode = CHAIN;
1.52 + setGrantedMode(CHAIN);
1.53 cell = chain(requested, t, 0);
1.54 }
1.55 // sync
1.56 @@ -655,7 +649,7 @@
1.57 }
1.58 // for
1.59 }
1.60 -
1.61 +
1.62 /** privilegedEnter serves for processing posted requests */
1.63 private boolean reenter(Thread t, int mode) {
1.64 boolean log = LOG.isLoggable(Level.FINE);
1.65 @@ -707,7 +701,7 @@
1.66 readersNo += 2;
1.67
1.68 // prevent from new readers
1.69 - grantedMode = CHAIN;
1.70 + setGrantedMode(CHAIN);
1.71
1.72 return true;
1.73 }
1.74 @@ -735,7 +729,7 @@
1.75 // always chain this thread
1.76 // since there can be another one
1.77 // in the queue with higher priority
1.78 - grantedMode = CHAIN;
1.79 + setGrantedMode(CHAIN);
1.80 cell = chain(mode, t, Integer.MAX_VALUE);
1.81
1.82 if (readersNo == 0) { // seems I may enter
1.83 @@ -746,7 +740,7 @@
1.84
1.85 return;
1.86 } else {
1.87 - grantedMode = NONE;
1.88 + setGrantedMode(NONE);
1.89 wakeUpOthers();
1.90 }
1.91 }
1.92 @@ -875,9 +869,11 @@
1.93
1.94 // downgrade the lock
1.95 if (info.counts[S] > 0) {
1.96 - info.mode = grantedMode = S;
1.97 + info.mode = S;
1.98 + setGrantedMode(S);
1.99 } else {
1.100 - info.mode = grantedMode = NONE;
1.101 + info.mode = NONE;
1.102 + setGrantedMode(NONE);
1.103 registeredThreads.remove(info.t);
1.104 }
1.105
1.106 @@ -937,7 +933,7 @@
1.107 // set grantedMode to NONE
1.108 // and then wakeUp others - either immediately
1.109 // or in privelegedEnter()
1.110 - grantedMode = NONE;
1.111 + setGrantedMode(NONE);
1.112
1.113 if (info.getRunnableCount(X) > 0) {
1.114 return X;
1.115 @@ -968,7 +964,7 @@
1.116 }
1.117
1.118 if (waiters.size() == 1) {
1.119 - grantedMode = X;
1.120 + setGrantedMode(X);
1.121 }
1.122 // else let CHAIN
1.123
1.124 @@ -1061,10 +1057,10 @@
1.125 continue;
1.126 }
1.127
1.128 - if (compatibleLocks(grantedMode, qc.mode)) { // woken S -> should I wake X? -> no
1.129 + if (isCompatible(qc.mode)) { // woken S -> should I wake X? -> no
1.130 waiters.remove(i--);
1.131 qc.wakeMeUp();
1.132 - grantedMode = qc.mode;
1.133 + setGrantedMode(qc.mode);
1.134
1.135 if (getThreadInfo(qc.t) == null) {
1.136 // force to have a record since recorded threads
1.137 @@ -1079,7 +1075,7 @@
1.138 registeredThreads.put(qc.t, ti);
1.139 }
1.140 } else {
1.141 - grantedMode = CHAIN;
1.142 + setGrantedMode(CHAIN);
1.143
1.144 break;
1.145 }
1.146 @@ -1109,7 +1105,7 @@
1.147 if (qc.mode == S) { // readers only
1.148 waiters.remove(i--);
1.149 qc.wakeMeUp();
1.150 - grantedMode = S;
1.151 + setGrantedMode(S);
1.152
1.153 if (getThreadInfo(qc.t) == null) {
1.154 // force to have a record since recorded threads
1.155 @@ -1181,7 +1177,9 @@
1.156 * @return <tt>true</tt> if and only if current mode and requested mode are compatible
1.157 */
1.158 private boolean isCompatible(int requested) {
1.159 - return compatibleLocks(grantedMode, requested);
1.160 + // allow next reader in even in chained mode, if it was read access before
1.161 + if (requested == S && grantedMode == CHAIN && origMode == S) return true;
1.162 + return cmatrix[requested][grantedMode];
1.163 }
1.164
1.165 private ThreadInfo getThreadInfo(Thread t) {
1.166 @@ -1523,4 +1521,11 @@
1.167 parent.leave(Thread.currentThread());
1.168 }
1.169 }
1.170 +
1.171 + private void setGrantedMode(int mode) {
1.172 + if (grantedMode != CHAIN && mode == CHAIN) {
1.173 + origMode = grantedMode;
1.174 + }
1.175 + grantedMode = mode;
1.176 + }
1.177 }