001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
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; either 
008 * version 2.1 of the License, or (at your option) any later version.
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 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package lucee.commons.lock.rw;
020
021import java.util.concurrent.TimeUnit;
022import java.util.concurrent.locks.Lock;
023import java.util.concurrent.locks.ReentrantReadWriteLock;
024
025import lucee.commons.lock.LockException;
026import lucee.commons.lock.LockInterruptedException;
027
028public class RWLock<L> {
029        
030        private final ReentrantReadWriteLock rwl;
031        private final Lock rl;
032    private final Lock wl;
033
034        private L label;
035        private int count;
036        
037        public RWLock(L label) {
038                rwl=new ReentrantReadWriteLock(true);
039                rl = rwl.readLock();
040            wl = rwl.writeLock();
041                this.label=label;
042        }
043
044        
045        public void lock(long timeout, boolean readOnly) throws LockException, LockInterruptedException {
046                if(timeout<=0) throw new LockException("timeout must be a postive number");
047                try {
048                        if(!getLock(readOnly).tryLock(timeout, TimeUnit.MILLISECONDS)){
049                                throw new LockException(timeout);
050                        }
051                } 
052                catch (InterruptedException e) {
053                        throw new LockInterruptedException(e);
054                }
055        }
056
057        synchronized void inc(){
058                count++;
059        }
060        synchronized void dec(){
061                count--;
062        }
063
064
065        public void unlock(boolean readOnly)    {
066                //print.e("unlock:"+readOnly);
067                getLock(readOnly).unlock();
068        }
069
070        private java.util.concurrent.locks.Lock getLock(boolean readOnly) {
071                return readOnly?rl:wl;
072        }
073        
074        /**
075     * Returns an estimate of the number of threads waiting to
076     * acquire this lock.  The value is only an estimate because the number of
077     * threads may change dynamically while this method traverses
078     * internal data structures.  This method is designed for use in
079     * monitoring of the system state, not for synchronization
080     * control.
081     *
082     * @return the estimated number of threads waiting for this lock
083     */
084    public int getQueueLength() {
085                return count;
086        }
087    
088    /**
089     * Queries if the write lock is held by any thread.
090     */
091        public boolean isWriteLocked(){
092                return rwl.isWriteLocked();
093        }
094        
095        /**
096         * Queries if one or more write lock is held by any thread.
097         */
098        public boolean isReadLocked(){
099                return rwl.getReadLockCount()>0;
100        }
101        public L getLabel(){
102                return label;
103        }
104}