/*
* $Id$
*
* Copyright (c) 2009-2010 by Joel Uckelman
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License (LGPL) as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, copies are available
* at http://www.opensource.org.
*/
package VASSAL.tools.concurrent;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* A {@link ReadWriteLock} which counts locks held.
*
* Locks are not associated with particular threads as with
* {@link ReentrantReadWriteLock}, so can be released from threads other
* than the the ones which acquired them.
*
* @since 3.2.0
* @author Joel Uckelman
*/
public class CountingReadWriteLock implements ReadWriteLock {
/** {@inheritDoc} */
public Lock readLock() { return r; }
/** {@inheritDoc} */
public Lock writeLock() { return w; }
protected final ReadLock r = new ReadLock();
protected final WriteLock w = new WriteLock();
protected final Sync sync = new Sync();
protected abstract class BaseLock implements Lock {
public void lockInterruptibly() {
throw new UnsupportedOperationException();
}
public Condition newCondition() {
throw new UnsupportedOperationException();
}
}
protected class ReadLock extends BaseLock {
public void lock() { sync.acquireShared(0); }
public void unlock() { sync.releaseShared(0); }
public boolean tryLock() { return sync.tryAcquireShared(0) >= 0; }
public boolean tryLock(long time, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(0, unit.toNanos(time));
}
}
protected class WriteLock extends BaseLock {
public void lock() { sync.acquire(0); }
public void unlock() { sync.release(0); }
public boolean tryLock() { return sync.tryAcquire(0); }
public boolean tryLock(long time, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(0, unit.toNanos(time));
}
}
// Read states are positive, the write state is -1.
// State 0 means that no locks are held.
protected static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 1L;
@Override
protected boolean tryAcquire(int dummy) {
return compareAndSetState(0, -1);
}
@Override
protected boolean tryRelease(int dummy) {
if (getState() != -1) throw new IllegalMonitorStateException();
return compareAndSetState(-1, 0);
}
@Override
protected int tryAcquireShared(int dummy) {
final int s = getState();
return s >= 0 && compareAndSetState(s, s+1) ? 1 : -1;
}
@Override
protected boolean tryReleaseShared(int dummy) {
final int s = getState();
if (s < 1) throw new IllegalMonitorStateException();
return compareAndSetState(s, s-1);
}
}
}