001: /* uDig - User Friendly Desktop Internet GIS client
002: * http://udig.refractions.net
003: * (C) 2004, Refractions Research Inc.
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation;
008: * version 2.1 of the License.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: */
015: package net.refractions.udig.ui;
016:
017: import java.util.Date;
018: import java.util.HashSet;
019: import java.util.Set;
020: import java.util.concurrent.TimeUnit;
021: import java.util.concurrent.locks.Condition;
022:
023: import org.eclipse.swt.widgets.Display;
024:
025: class UDIGDisplaySafeCondition implements Condition {
026: /** SafeCondition owningLock field */
027: private final UDIGDisplaySafeLock owningLock;
028: private final Condition nonDisplayCondition;
029: private final Condition displayCondition;
030: private volatile Set<Thread> displayNotified = new HashSet<Thread>();
031:
032: UDIGDisplaySafeCondition(UDIGDisplaySafeLock lock) {
033: if (lock == null)
034: throw new NullPointerException("Lock cannot be null"); //$NON-NLS-1$
035: owningLock = lock;
036:
037: nonDisplayCondition = owningLock.internalLock.newCondition();
038: displayCondition = owningLock.internalLock.newCondition();
039: }
040:
041: public void await() throws InterruptedException {
042: doAwait(-1, null, true);
043: }
044:
045: /**
046: * @param wait
047: * @param unit
048: * @param allowInterrupts
049: * @return see {@linkplain Condition#await(long, TimeUnit)}
050: * @throws InterruptedException
051: */
052: boolean doAwait(long wait, TimeUnit unit, boolean allowInterrupts)
053: throws InterruptedException {
054: owningLock.internalLock.lock();
055: try {
056: checkState();
057: owningLock.unlock();
058:
059: if (Display.getCurrent() == null) {
060: if (!allowInterrupts) {
061: // findbugs note: this is correct behaviour. I know its not in a while loop
062: nonDisplayCondition.awaitUninterruptibly();
063: return true;
064: } else {
065: if (unit == null) {
066: nonDisplayCondition.await();
067: return true;
068: } else
069: return nonDisplayCondition.await(wait, unit);
070: }
071: } else {
072: return displayAwait(wait, unit, allowInterrupts) <= 0;
073: }
074: } finally {
075: // findbugs note: this is correct behaviour.
076: owningLock.lock();
077: owningLock.internalLock.unlock();
078: }
079: }
080:
081: private long displayAwait(long time, TimeUnit unit,
082: boolean allowInterrupts) throws InterruptedException {
083: long remaining;
084: displayNotified.add(Thread.currentThread());
085: long start = System.nanoTime();
086:
087: if (unit != null) {
088: remaining = TimeUnit.NANOSECONDS.convert(time, unit);
089: } else {
090: remaining = -1;
091: }
092:
093: long nextInterval = TimeUnit.NANOSECONDS.convert(100,
094: TimeUnit.MILLISECONDS);
095: ;
096: Display current = Display.getCurrent();
097: while (nextInterval > 0
098: && displayNotified.contains(Thread.currentThread())) {
099: if (unit != null) {
100: nextInterval = Math.min(nextInterval, remaining);
101: }
102: // unlock while running display events.
103: owningLock.internalLock.unlock();
104: boolean readAndDispatch = current.readAndDispatch();
105:
106: // findbugs note: this is correct behaviour. It is closed outside this method
107: owningLock.internalLock.lock();
108: if (!readAndDispatch) {
109: try {
110: displayCondition.await(nextInterval,
111: TimeUnit.NANOSECONDS);
112: } catch (InterruptedException e) {
113: if (allowInterrupts)
114: throw e;
115: }
116: }
117: remaining -= System.nanoTime() - start;
118: }
119: return remaining;
120: }
121:
122: public boolean await(long time, TimeUnit unit)
123: throws InterruptedException {
124: return doAwait(time, unit, true);
125: }
126:
127: public long awaitNanos(long nanosTimeout)
128: throws InterruptedException {
129: long remaining;
130: if (Display.getCurrent() == null) {
131: remaining = nonDisplayCondition.awaitNanos(nanosTimeout);
132: } else {
133: remaining = displayAwait(nanosTimeout,
134: TimeUnit.NANOSECONDS, true);
135: }
136: return remaining;
137: }
138:
139: public void awaitUninterruptibly() {
140: try {
141: doAwait(-1, null, false);
142: } catch (InterruptedException e) {
143: throw new Error("This should not be permitted to happen", e); //$NON-NLS-1$
144: }
145: }
146:
147: public boolean awaitUntil(Date deadline)
148: throws InterruptedException {
149: checkState();
150: long waitTime = deadline.getTime() - System.currentTimeMillis();
151:
152: return doAwait(waitTime, TimeUnit.MILLISECONDS, true);
153: }
154:
155: public void signal() {
156: owningLock.internalLock.lock();
157: try {
158: checkState();
159:
160: if (!displayNotified.isEmpty()) {
161: Thread next = displayNotified.iterator().next();
162: displayNotified.remove(next);
163: displayCondition.signal();
164: } else {
165: nonDisplayCondition.signal();
166: }
167: } finally {
168: owningLock.internalLock.unlock();
169: }
170: }
171:
172: public void signalAll() {
173: owningLock.internalLock.lock();
174: try {
175: checkState();
176: if (!displayNotified.isEmpty()) {
177: displayNotified.clear();
178: displayCondition.signalAll();
179: }
180: nonDisplayCondition.signalAll();
181: } finally {
182: owningLock.internalLock.unlock();
183: }
184: }
185:
186: private void checkState() {
187: if (!owningLock.isHeldByCurrentThread())
188: throw new IllegalStateException(
189: "current thread does not own lock!!!"); //$NON-NLS-1$
190: }
191:
192: public int getWaitQueueLength() {
193:
194: int count = displayNotified.size();
195:
196: int i = count
197: + owningLock.internalLock
198: .getWaitQueueLength(this .nonDisplayCondition);
199: return i;
200: }
201:
202: public boolean isOwner(UDIGDisplaySafeLock lock) {
203: return owningLock == lock;
204: }
205:
206: }
|