content: // Spatial Index Library
  //
  // Copyright (C) 2002  Navel Ltd.
  //
  // 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 aint with this library; if not, write to the Free Software
  // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  //
  // Contact information:
  //  Mailing address:
  //    Marios Hadjieleftheriou
  //    University of California, Riverside
  //    Department of Computer Science
  //    Surge Building, Room 310
  //    Riverside, CA 92521
  //
  //  Email:
  //    marioh@cs.ucr.edu
  
  // Readers/Writers lock by Allen Holub
  
  package sil.spatialindex;
  
  import java.util.*;
  
  public class RWLock
  {
  	private int active_readers;
  	private int waiting_readers;
  	private int active_writers;
  
  	private final LinkedList writer_locks = new LinkedList();
  
  	public synchronized void read_lock()
  	{
  		if (active_writers == 0 && writer_locks.size() == 0)
  			++active_readers;
  		else
  		{
  			++waiting_readers;
  			try{ wait(); } catch (InterruptedException e) {}
  		}
  	}
  
  	public synchronized boolean read_lock_noblock()
  	{
  		if (active_writers == 0 && writer_locks.size() == 0)
  		{
  			++active_readers;
  			return true;
  		}
  		return false;
  	}
  
  	public synchronized void read_unlock()
  	{
  		if (--active_readers == 0) notify_writers();
  	}
  
  	public void write_lock()
  	{
  		Object lock = new Object();
  		synchronized(lock)
  		{
  			synchronized(this)
  			{
  				boolean okay_to_write = writer_locks.size() == 0 && active_readers == 0 && active_writers == 0;
  				if (okay_to_write)
  				{
  					++active_writers;
  					return; // the "return" jumps over the "wait" call
  				}
  
  				writer_locks.addLast(lock);
  			}
  			try { lock.wait(); } catch (InterruptedException e) {}
  		}
  	}
  
  	synchronized public boolean write_lock_noblock()
  	{
  		if (writer_locks.size() == 0  && active_readers == 0 && active_writers == 0)
  		{
  			++active_writers;
  			return true;
  		}
  		return false;
  	}
  
  	public synchronized void write_unlock()
  	{
  		 --active_writers;
  		 if (waiting_readers > 0)   // priority to waiting readers
  			 notify_readers();
  		 else
  			 notify_writers();
  	}
  
  	private void notify_readers()       // must be accessed from a
  	{                                   //  synchronized method
  		active_readers  += waiting_readers;
  		waiting_readers = 0;
  		notifyAll();
  	}
  
  	private void notify_writers()       // must be accessed from a
  	{                                   //  synchronized method
  		if (writer_locks.size() > 0)
  		{
  			Object oldest = writer_locks.removeFirst();
  			++active_writers;
  			synchronized(oldest) { oldest.notify(); }
  		}
  	}
  }
  