/*
* Copyright (c) 1997-1999 The Java Apache Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the Java Apache
* Project for use in the Apache JServ servlet engine project
*
* As implemented, JServLock works as an actual "lock" object, which * another object will set up and lock and unlock. It blocks incoming * readers if there are waiting writers. *
* There are method that wait only at specified amount of time before * failing with TimeoutException. * * @author Alexei Kosut * @version $Revision: 1.4 $ $Date: 1999/04/26 00:33:55 $ */ public class Lock { private int activeReadLocks = 0; private int waitingReadLocks = 0; private int activeWriteLocks = 0; private int waitingWriteLocks = 0; // We only allow a reader to lock if there are no write locks, // and no waiting writer locks. private boolean allowReadLock() { return activeWriteLocks == 0 && waitingWriteLocks == 0; } // We only allow a writer to lock if there are no active // locks private boolean allowWriteLock() { return activeReadLocks == 0 && activeWriteLocks == 0; } /** * Wait for a read lock. This will wait for all write lock to * be removed before returning. * * @exception InterruptedException if the wait is interrupted. Calling * thread must consider the operation to have failed and stop its * processing. */ public synchronized void readLock() throws InterruptedException { // Register our intent waitingReadLocks++; try { // Wait for a chance to read while (allowReadLock() == false) { wait(); } // Bingo! Switch from a waiting lock to an active lock activeReadLocks++; } finally { //Remove intent to read waitingReadLocks--; } } /** * Wait for a read lock. This will wait for all write lock to * be removed before returning. * * @param timeout the number of millisecond before giving up and failing * with a TimeoutException. * @exception TimeoutException if the lock isn't acquired after the * specified amount of time. * @exception InterruptedException if the wait is interrupted. Calling * thread must consider the operation to have failed and stops its * processing. */ public synchronized void readLock(long timeout) throws InterruptedException, TimeoutException { long waitTill = System.currentTimeMillis() + timeout; // Register our intent waitingReadLocks++; try { // Wait for a chance to read while (allowReadLock() == false) { wait(timeout); // Check to see if was have the lock if (allowReadLock() == false && (timeout = waitTill - System.currentTimeMillis()) < 0 ) { // Timeout without obtaining lock. throw new TimeoutException(); } } // Bingo! Switch from a waiting lock to an active lock activeReadLocks++; } finally { // Remove intent to read. waitingReadLocks--; } } /** * Unlocks a previously acquired read lock. */ public synchronized void readUnlock() { // We're gone activeReadLocks--; // Wake other threads up notifyAll(); } /** * Wait for a read lock. This will wait until all read lock have been * removed and no other write lock are active. * * @exception InterruptedException if the wait is interrupted. Calling * thread must consider the operation to have failed and stops its * processing. */ public synchronized void writeLock() throws InterruptedException { // Register our intent waitingWriteLocks++; try { // Wait for a chance to write while (allowWriteLock() == false) { wait(); } // Bingo! Switch from a waiting lock to an active lock activeWriteLocks++; } finally { // Remove intent lock waitingWriteLocks--; } } /** * Wait for a read lock. This will wait until all read lock have been * removed and no other write lock are active. * * @param timeout the number of millisecond before giving up and failing * with a TimeoutException. * @exception TimeoutException if the lock isn't acquired after the * specified amount of time. * @exception InterruptedException if the wait is interrupted. Calling * thread must consider the operation to have failed and stops its * processing. */ public synchronized void writeLock(long timeout) throws InterruptedException, TimeoutException { long waitTill = System.currentTimeMillis() + timeout; // Register our intent waitingWriteLocks++; try { // Wait for a chance to write if (allowWriteLock() == false) { wait(timeout); if (allowWriteLock() == false && (timeout = waitTill - System.currentTimeMillis()) < 0 ) { // Timeout, we failed to acquire the lock throw new TimeoutException(); } } // Bingo! Switch from a waiting lock to an active lock activeWriteLocks++; } finally { waitingWriteLocks--; } } /** * Unlock a previously acquired write lock. */ public synchronized void writeUnlock() { // We're gone activeWriteLocks--; // Wake other threads up notifyAll(); } }