//jTDS JDBC Driver for Microsoft SQL Server and Sybase
//Copyright (C) 2004 The jTDS Project
//
//This library is free software; you can redistribute it and/or
//modify it under the terms of the GNU Lesser General Public
//License as published by the Free Software Foundation; either
//version 2.1 of the License, or (at your option) any later version.
//
//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
//Lesser General Public License for more details.
//
//You should have received a copy of the GNU Lesser General Public
//License along with this library; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
package net.sourceforge.jtds.jdbc;
/**
* Simple semaphore class used to serialize access requests over the network
* connection.
* <p/>
* Based on the code originally written by Doug Lea. Once JDK 1.5 is the
* standard this class can be replaced by the
* <code>java.util.concurrent.Sempahore</code> class.
*
* @author Mike Hutchinson
* @version $Id: Semaphore.java,v 1.1 2004-12-20 15:51:17 alin_sinpalean Exp $
*/
public class Semaphore {
/**
* Current number of available permits.
*/
protected long permits;
/**
* Create a Semaphore with the given initial number of permits. Using a
* seed of one makes the semaphore act as a mutual exclusion lock. Negative
* seeds are also allowed, in which case no acquires will proceed until the
* number of releases has pushed the number of permits past 0.
*/
public Semaphore(long initialPermits) {
permits = initialPermits;
}
/**
* Wait until a permit is available, and take one.
*/
public void acquire() throws InterruptedException {
if (Thread.interrupted()) {
throw new InterruptedException();
}
synchronized (this) {
try {
while (permits <= 0) {
wait();
}
--permits;
} catch (InterruptedException ex) {
notify();
throw ex;
}
}
}
/**
* Wait at most msecs millisconds for a permit.
*/
public boolean attempt(long msecs) throws InterruptedException {
if (Thread.interrupted()) {
throw new InterruptedException();
}
synchronized (this) {
if (permits > 0) {
--permits;
return true;
} else if (msecs <= 0) {
return false;
} else {
try {
long startTime = System.currentTimeMillis();
long waitTime = msecs;
while (true) {
wait(waitTime);
if (permits > 0) {
--permits;
return true;
} else {
waitTime = msecs - (System.currentTimeMillis() - startTime);
if (waitTime <= 0) {
return false;
}
}
}
} catch (InterruptedException ex) {
notify();
throw ex;
}
}
}
}
/**
* Release a permit.
*/
public synchronized void release() {
++permits;
notify();
}
/**
* Release N permits. <code>release(n)</code> is equivalent in effect to:
* <pre>
* for (int i = 0; i < n; ++i) release();
* </pre>
* <p/>
* But may be more efficient in some semaphore implementations.
*
* @exception IllegalArgumentException if n is negative
*/
public synchronized void release(long n) {
if (n < 0) {
throw new IllegalArgumentException("Negative argument");
}
permits += n;
for (long i = 0; i < n; ++i) {
notify();
}
}
/**
* Return the current number of available permits. Returns an accurate, but
* possibly unstable value, that may change immediately after returning.
*/
public synchronized long permits() {
return permits;
}
}