This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.
Build: NetBeans IDE Dev (Build 201211120001) VM: Java HotSpot(TM) 64-Bit Server VM, 23.5-b02, Java(TM) SE Runtime Environment, 1.7.0_09-b05 OS: Windows 7 Stacktrace: java.lang.NullPointerException at org.openide.util.Mutex.leaveImpl(Mutex.java:860) at org.openide.util.Mutex.leave(Mutex.java:841) at org.openide.util.Mutex$Privileged.exitReadAccess(Mutex.java:1683) at org.openide.nodes.EntrySupportDefault.getNodes(EntrySupportDefault.java:132) at org.openide.nodes.EntrySupportDefault.getNodes(EntrySupportDefault.java:172) at org.openide.nodes.EntrySupportDefault.getNodesCount(EntrySupportDefault.java:176)
Created attachment 127670 [details] stacktrace
Enforcing synchronization with getters and setters: # This patch file was generated by NetBeans IDE # It uses platform neutral UTF-8 encoding and \n newlines. --- Base (BASE) +++ Locally Modified (Based On LOCAL) @@ -173,10 +173,14 @@ { true, false, false, false },{ true, false, false, true } }; - /** granted mode */ + /** granted mode + * @GuardedBy("LOCK") + */ private int grantedMode = NONE; - /** The mode the mutex was in before it started chaining */ + /** The mode the mutex was in before it started chaining + * @GuardedBy("LOCK") + */ private int origMode; /** protects internal data structures */ @@ -185,15 +189,19 @@ /** wrapper, if any */ private final Executor wrapper; - /** threads that - owns or waits for this mutex */ - private /*final*/ Map<Thread,ThreadInfo> registeredThreads; + /** threads that - owns or waits for this mutex + * @GuardedBy("LOCK") + */ + private Map<Thread,ThreadInfo> registeredThreads; - /** number of threads that holds S mode (readersNo == "count of threads in registeredThreads that holds S") */ - - // NOI18N + /** number of threads that holds S mode (readersNo == "count of threads in registeredThreads that holds S") + * @GuardedBy("LOCK") + */ private int readersNo = 0; - /** a queue of waiting threads for this mutex */ + /** a queue of waiting threads for this mutex + * @GuardedBy("LOCK") + */ private List<QueueCell> waiters; /** identification of the mutex */ @@ -598,10 +606,10 @@ StringBuilder sbuff = new StringBuilder(512); synchronized (LOCK) { - sbuff.append("threads: ").append(registeredThreads).append(newline); // NOI18N + sbuff.append("threads: ").append(getRegisteredThreads()).append(newline); // NOI18N sbuff.append("readersNo: ").append(readersNo).append(newline); // NOI18N - sbuff.append("waiters: ").append(waiters).append(newline); // NOI18N - sbuff.append("grantedMode: ").append(grantedMode).append(newline); // NOI18N + sbuff.append("waiters: ").append(getWaiters()).append(newline); // NOI18N + sbuff.append("grantedMode: ").append(getGrantedMode()).append(newline); // NOI18N } return sbuff.toString(); @@ -651,15 +659,15 @@ ThreadInfo info = getThreadInfo(t); if (info != null) { - if (grantedMode == NONE) { + if (getGrantedMode() == NONE) { // defensive throw new IllegalStateException(); } // reenters // requested == S -> always succeeds // info.mode == X -> always succeeds - if (((info.mode == S) && (grantedMode == X)) || - ((info.mode == X) && (grantedMode == S))) { + if (((info.mode == S) && (getGrantedMode() == X)) || + ((info.mode == X) && (getGrantedMode() == S))) { // defensive throw new IllegalStateException(); } @@ -692,9 +700,9 @@ info.mode = X; info.counts[requested]++; info.rsnapshot = info.counts[S]; - if (grantedMode == S) { + if (getGrantedMode() == S) { setGrantedMode(X); - } else if (grantedMode == X) { + } else if (getGrantedMode() == X) { // defensive throw new IllegalStateException(); } @@ -711,7 +719,7 @@ } else { if (isCompatible(requested)) { setGrantedMode(requested); - registeredThreads.put(t, + getRegisteredThreads().put(t, info = new ThreadInfo(t, requested)); if (requested == S) { readersNo++; @@ -748,7 +756,7 @@ private boolean reenterImpl(Thread t, int mode) { // from leaveX -> grantedMode is NONE or S if (mode == S) { - if ((grantedMode != NONE) && (grantedMode != S)) { + if ((getGrantedMode() != NONE) && (getGrantedMode() != S)) { throw new IllegalStateException(this.toString()); } @@ -759,10 +767,10 @@ // assert (mode == X) ThreadInfo tinfo = getThreadInfo(t); - boolean chainFromLeaveX = ((grantedMode == CHAIN) && (tinfo != null) && (tinfo.counts[X] > 0)); + boolean chainFromLeaveX = ((getGrantedMode() == CHAIN) && (tinfo != null) && (tinfo.counts[X] > 0)); // process grantedMode == X or CHAIN from leaveX OR grantedMode == NONE from leaveS - if ((grantedMode == X) || (grantedMode == NONE) || chainFromLeaveX) { + if ((getGrantedMode() == X) || (getGrantedMode() == NONE) || chainFromLeaveX) { enter(mode, t, true); return false; @@ -773,7 +781,7 @@ } ThreadInfo info = new ThreadInfo(t, mode); - registeredThreads.put(t, info); + getRegisteredThreads().put(t, info); // prevent from grantedMode == NONE (another thread - leaveS) readersNo += 2; @@ -812,8 +820,8 @@ if (readersNo == 0) { // seems I may enter // no one has higher prio? - if (waiters.get(0) == cell) { - waiters.remove(0); + if (getWaiters().get(0) == cell) { + getWaiters().remove(0); setGrantedMode(mode); @@ -835,13 +843,12 @@ /** Leaves this mutex */ final void leave(Thread t) { boolean log = LOG.isLoggable(Level.FINER); - - if (log) doLog("Leaving {0}", grantedMode); // NOI18N - + synchronized (LOCK) { + if (log) doLog("Leaving {0}", getGrantedMode()); // NOI18N leaveImpl(t); - - if (log) doLog("Leaving exit: {0}", grantedMode); // NOI18N + if (log) doLog("Leaving exit: {0}", getGrantedMode()); // NOI18N } + } private void leaveImpl(Thread t) { ThreadInfo info; @@ -851,7 +858,7 @@ synchronized (LOCK) { info = getThreadInfo(t); - switch (grantedMode) { + switch (getGrantedMode()) { case NONE: throw new IllegalStateException(); @@ -953,7 +960,7 @@ } else { info.mode = NONE; setGrantedMode(NONE); - registeredThreads.remove(info.t); + getRegisteredThreads().remove(info.t); } if (info.getRunnableCount(S) > 0) { @@ -999,7 +1006,7 @@ if (info.counts[S] == 0) { // remove the thread info.mode = NONE; - registeredThreads.remove(info.t); + getRegisteredThreads().remove(info.t); // downsize readersNo if (readersNo <= 0) { @@ -1021,14 +1028,14 @@ wakeUpOthers(); } else if (info.getRunnableCount(X) > 0) { return X; - } else if ((grantedMode == CHAIN) && (readersNo == 1)) { + } else if ((getGrantedMode() == CHAIN) && (readersNo == 1)) { // can be the mode advanced from CHAIN? Examine first item of waiters! - for (int i = 0; i < waiters.size(); i++) { - QueueCell qc = waiters.get(i); + for (int i = 0; i < getWaiters().size(); i++) { + QueueCell qc = getWaiters().get(i); synchronized (qc) { if (qc.isGotOut()) { - waiters.remove(i--); + getWaiters().remove(i--); continue; } @@ -1042,13 +1049,13 @@ throw new IllegalStateException(); } - if (waiters.size() == 1) { + if (getWaiters().size() == 1) { setGrantedMode(X); } // else let CHAIN tinfo.mode = X; - waiters.remove(i); + getWaiters().remove(i); qc.wakeMeUp(); } } @@ -1084,21 +1091,21 @@ //qc.timeout = timeout; qc.priority2 = priority; - final int size = waiters.size(); + final int size = getWaiters().size(); if (size == 0) { - waiters.add(qc); + getWaiters().add(qc); } else if (qc.getPriority() == Integer.MAX_VALUE) { - waiters.add(0, qc); + getWaiters().add(0, qc); } else { QueueCell cursor; int i = 0; do { - cursor = waiters.get(i); + cursor = getWaiters().get(i); if (cursor.getPriority() < qc.getPriority()) { - waiters.add(i, qc); + getWaiters().add(i, qc); break; } @@ -1107,7 +1114,7 @@ } while (i < size); if (i == size) { - waiters.add(qc); + getWaiters().add(qc); } } @@ -1116,28 +1123,28 @@ /** Scans through waiters and wakes up them */ private void wakeUpOthers() { - if ((grantedMode == X) || (grantedMode == CHAIN)) { + if ((getGrantedMode() == X) || (getGrantedMode() == CHAIN)) { // defensive throw new IllegalStateException(); } - if (waiters.isEmpty()) { + if (getWaiters().isEmpty()) { return; } - for (int i = 0; i < waiters.size(); i++) { - QueueCell qc = waiters.get(i); + for (int i = 0; i < getWaiters().size(); i++) { + QueueCell qc = getWaiters().get(i); synchronized (qc) { if (qc.isGotOut()) { // bogus waiter - waiters.remove(i--); + getWaiters().remove(i--); continue; } if (isCompatible(qc.mode)) { // woken S -> should I wake X? -> no - waiters.remove(i--); + getWaiters().remove(i--); qc.wakeMeUp(); setGrantedMode(qc.mode); @@ -1151,7 +1158,7 @@ readersNo++; } - registeredThreads.put(qc.t, ti); + getRegisteredThreads().put(qc.t, ti); } } else { setGrantedMode(CHAIN); @@ -1164,25 +1171,25 @@ } private void wakeUpReaders() { - assert (grantedMode == NONE) || (grantedMode == S); + assert (getGrantedMode() == NONE) || (getGrantedMode() == S); - if (waiters.isEmpty()) { + if (getWaiters().isEmpty()) { return; } - for (int i = 0; i < waiters.size(); i++) { - QueueCell qc = waiters.get(i); + for (int i = 0; i < getWaiters().size(); i++) { + QueueCell qc = getWaiters().get(i); synchronized (qc) { if (qc.isGotOut()) { // bogus waiter - waiters.remove(i--); + getWaiters().remove(i--); continue; } if (qc.mode == S) { // readers only - waiters.remove(i--); + getWaiters().remove(i--); qc.wakeMeUp(); setGrantedMode(S); @@ -1192,7 +1199,7 @@ ThreadInfo ti = new ThreadInfo(qc.t, qc.mode); ti.forced = true; readersNo++; - registeredThreads.put(qc.t, ti); + getRegisteredThreads().put(qc.t, ti); } } } @@ -1277,12 +1284,13 @@ */ private boolean isCompatible(int requested) { // allow next reader in even in chained mode, if it was read access before - if (requested == S && grantedMode == CHAIN && origMode == S) return true; - return cmatrix[requested][grantedMode]; + if (requested == S && getGrantedMode() == CHAIN && getOrigMode() == S) return true; + return cmatrix[requested][getGrantedMode()]; } private ThreadInfo getThreadInfo(Thread t) { - return registeredThreads.get(t); + assert Thread.holdsLock(LOCK); + return getRegisteredThreads().get(t); } private boolean canUpgrade(int threadGranted, int requested) { @@ -1471,6 +1479,25 @@ return ret; } + private int getOrigMode() { + Thread.holdsLock(LOCK); + return origMode; + } + + private void setOrigMode(int origMode) { + Thread.holdsLock(LOCK); + this.origMode = origMode; + } + + private Map<Thread,ThreadInfo> getRegisteredThreads() { + Thread.holdsLock(LOCK); + return registeredThreads; + } + + private List<QueueCell> getWaiters() { + return waiters; + } + // --------------------------------------------- END OF EVENT METHODS ------------------------------ /** Action to be executed in a mutex without throwing any checked exceptions. @@ -1689,9 +1716,14 @@ } private void setGrantedMode(int mode) { + assert Thread.holdsLock(LOCK); if (grantedMode != CHAIN && mode == CHAIN) { - origMode = grantedMode; + setOrigMode(grantedMode); } grantedMode = mode; } + private int getGrantedMode() { + assert Thread.holdsLock(LOCK); + return grantedMode; } +}
jardo, can you apply the patch, then?
ergonomics#737fe6774c90
Integrated into 'main-silver', will be available in build *201307162300* on http://bits.netbeans.org/dev/nightly/ (upload may still be in progress) Changeset: http://hg.netbeans.org/main-silver/rev/737fe6774c90 User: Jaroslav Tulach <jtulach@netbeans.org> Log: #222006: Guard access to internal mutable variables via assert Thread.holdsLock