001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019: /*
020: * Originally written by Doug Lea and released into the public domain.
021: * This may be used for any purposes whatsoever without acknowledgment.
022: * Thanks for the assistance and support of Sun Microsystems Labs,
023: * and everyone contributing, testing, and using this code.
024: */
025: package org.apache.openjpa.lib.util.concurrent;
026:
027: import java.util.Collection;
028: import java.util.Date;
029:
030: class CondVar implements Condition, java.io.Serializable {
031:
032: /**
033: * The lock
034: */
035: protected final ExclusiveLock lock;
036:
037: /**
038: * Create a new CondVar that relies on the given mutual exclusion lock.
039: * @param lock A non-reentrant mutual exclusion lock.
040: */
041: CondVar(ExclusiveLock lock) {
042: this .lock = lock;
043: }
044:
045: public void awaitUninterruptibly() {
046: int holdCount = lock.getHoldCount();
047: if (holdCount == 0) {
048: throw new IllegalMonitorStateException();
049: }
050: // avoid instant spurious wakeup if thread already interrupted
051: boolean wasInterrupted = Thread.interrupted();
052: try {
053: synchronized (this ) {
054: for (int i = holdCount; i > 0; i--)
055: lock.unlock();
056: while (true) {
057: try {
058: wait();
059: break;
060: } catch (InterruptedException ex) {
061: wasInterrupted = true;
062: // may have masked the signal and there is no way
063: // to tell; defensively propagate the signal
064: notify();
065: }
066: }
067: }
068: } finally {
069: for (int i = holdCount; i > 0; i--)
070: lock.lock();
071: if (wasInterrupted) {
072: Thread.currentThread().interrupt();
073: }
074: }
075: }
076:
077: public void await() throws InterruptedException {
078: int holdCount = lock.getHoldCount();
079: if (holdCount == 0) {
080: throw new IllegalMonitorStateException();
081: }
082: if (Thread.interrupted())
083: throw new InterruptedException();
084: try {
085: synchronized (this ) {
086: for (int i = holdCount; i > 0; i--)
087: lock.unlock();
088: try {
089: wait();
090: } catch (InterruptedException ex) {
091: notify();
092: throw ex;
093: }
094: }
095: } finally {
096: for (int i = holdCount; i > 0; i--)
097: lock.lock();
098: }
099: }
100:
101: public boolean await(long timeout, TimeUnit unit)
102: throws InterruptedException {
103: int holdCount = lock.getHoldCount();
104: if (holdCount == 0) {
105: throw new IllegalMonitorStateException();
106: }
107: if (Thread.interrupted())
108: throw new InterruptedException();
109: long nanos = unit.toNanos(timeout);
110: boolean success = false;
111: try {
112: synchronized (this ) {
113: for (int i = holdCount; i > 0; i--)
114: lock.unlock();
115: try {
116: if (nanos > 0) {
117: long start = Utils.nanoTime();
118: TimeUnit.NANOSECONDS.timedWait(this , nanos);
119: // DK: due to coarse-grained(millis) clock, it seems
120: // preferable to acknowledge timeout(success == false)
121: // when the equality holds(timing is exact)
122: success = Utils.nanoTime() - start < nanos;
123: }
124: } catch (InterruptedException ex) {
125: notify();
126: throw ex;
127: }
128: }
129: } finally {
130: for (int i = holdCount; i > 0; i--)
131: lock.lock();
132: }
133: return success;
134: }
135:
136: // public long awaitNanos(long timeout) throws InterruptedException {
137: // throw new UnsupportedOperationException();
138: // }
139:
140: public boolean awaitUntil(Date deadline)
141: throws InterruptedException {
142: if (deadline == null)
143: throw new NullPointerException();
144: int holdCount = lock.getHoldCount();
145: if (holdCount == 0) {
146: throw new IllegalMonitorStateException();
147: }
148: long abstime = deadline.getTime();
149: if (Thread.interrupted())
150: throw new InterruptedException();
151:
152: boolean success = false;
153: try {
154: synchronized (this ) {
155: for (int i = holdCount; i > 0; i--)
156: lock.unlock();
157: try {
158: long start = System.currentTimeMillis();
159: long msecs = abstime - start;
160: if (msecs > 0) {
161: wait(msecs);
162: // DK: due to coarse-grained(millis) clock, it seems
163: // preferable to acknowledge timeout(success == false)
164: // when the equality holds(timing is exact)
165: success = System.currentTimeMillis() - start < msecs;
166: }
167: } catch (InterruptedException ex) {
168: notify();
169: throw ex;
170: }
171: }
172: } finally {
173: for (int i = holdCount; i > 0; i--)
174: lock.lock();
175: }
176: return success;
177: }
178:
179: public synchronized void signal() {
180: if (!lock.isHeldByCurrentThread()) {
181: throw new IllegalMonitorStateException();
182: }
183: notify();
184: }
185:
186: public synchronized void signalAll() {
187: if (!lock.isHeldByCurrentThread()) {
188: throw new IllegalMonitorStateException();
189: }
190: notifyAll();
191: }
192:
193: protected ExclusiveLock getLock() {
194: return lock;
195: }
196:
197: protected boolean hasWaiters() {
198: throw new UnsupportedOperationException("Use FAIR version");
199: }
200:
201: protected int getWaitQueueLength() {
202: throw new UnsupportedOperationException("Use FAIR version");
203: }
204:
205: protected Collection getWaitingThreads() {
206: throw new UnsupportedOperationException("Use FAIR version");
207: }
208:
209: static interface ExclusiveLock extends Lock {
210:
211: boolean isHeldByCurrentThread();
212:
213: int getHoldCount();
214: }
215: }
|