
org.objectweb.dream.synchro.ReadWriteLockFIFOImpl Maven / Gradle / Ivy
/**
* Dream
* Copyright (C) 2003-2004 INRIA Rhone-Alpes
*
* 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 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
*
* Contact : [email protected]
*
* Initial developer(s): Vivien Quema
* Contributor(s):
*/
package org.objectweb.dream.synchro;
import org.objectweb.dream.dreamannotation.DreamComponent;
import org.objectweb.fractal.fraclet.annotation.annotations.Requires;
/**
* FIFO implementation of the {@link ReadWriteLockItf}interface. Threads contend
* in a First-in/First-out manner for access. This lock is NOT reentrant.
* Current readers and writers should not try to re-obtain locks while holding
* them
*
* Note: Inspired by Doug Lea's implementation.
*/
@DreamComponent(controllerDesc = "dreamUnstoppablePrimitive")
public class ReadWriteLockFIFOImpl
implements
ReadWriteLockItf
{
//----------------------------------------------------------------------------
// Client Interface
//----------------------------------------------------------------------------
/**
* Fair SemaphoreItf serving as a kind of mutual exclusion lock. Writers acquire
* on entry, and hold until rwlock exit. Readers acquire and release only
* during entry (but are blocked from doing so if there is an active writer).
*/
@Requires(name = SemaphoreItf.ITF_NAME)
protected SemaphoreItf entryLock;
/**
* Number of threads that have entered read lock. Note that this is never
* reset to zero. Incremented only during acquisition of read lock while the
* "entryLock" is held, but read elsewhere, so is declared volatile.
*/
protected volatile int readers;
/**
* Number of threads that have exited read lock. Note that this is never reset
* to zero. Accessed only in code protected by synchronized(this). When
* exreaders != readers, the rwlock is being used for reading. Else if the
* entry lock is held, it is being used for writing (or in transition). Else
* it is free. Note: To distinguish these states, we assume that fewer than
* 2^32 reader threads can simultaneously execute.
*/
protected int exreaders;
// ---------------------------------------------------------------------------
// Implementation of the ReadWriteLockItf interface.
// ---------------------------------------------------------------------------
/**
* @see ReadWriteLockItf#acquireRead()
*/
public void acquireRead() throws InterruptedException
{
entryLock.acquire();
++readers;
entryLock.release();
}
/**
* @see org.objectweb.dream.synchro.ReadWriteLockItf#releaseRead()
*/
public synchronized void releaseRead()
{
/*
* If this is the last reader, notify a possibly waiting writer. Because
* waits occur only when entry lock is held, at most one writer can be
* waiting for this notification. Because increments to "readers" aren't
* protected by "this" lock, the notification may be spurious (when an
* incoming reader in in the process of updating the field), but at the
* point tested in acquiring write lock, both locks will be held, thus
* avoiding false alarms. And we will never miss an opportunity to send a
* notification when it is actually needed.
*/
if (++exreaders == readers)
{
notify();
}
}
/**
* @see org.objectweb.dream.synchro.ReadWriteLockItf#acquireWrite()
*/
public void acquireWrite() throws InterruptedException
{
// Acquiring entryLock first forces subsequent entering readers
// (as well as writers) to block.
entryLock.acquire();
// Only read "readers" once now before loop. We know it won't
// change because we hold the entry lock needed to update it.
int r = readers;
try
{
synchronized (this)
{
while (exreaders != r)
{
wait();
}
}
}
catch (InterruptedException ie)
{
entryLock.release();
throw ie;
}
}
/**
* @see org.objectweb.dream.synchro.ReadWriteLockItf#releaseWrite()
*/
public void releaseWrite()
{
entryLock.release();
}
/**
* @see org.objectweb.dream.synchro.ReadWriteLockItf#attemptRead(long)
*/
public boolean attemptRead(long msecs) throws InterruptedException
{
if (!entryLock.attempt(msecs))
{
return false;
}
++readers;
entryLock.release();
return true;
}
/**
* @see org.objectweb.dream.synchro.ReadWriteLockItf#attemptWrite(long)
*/
public boolean attemptWrite(long msecs) throws InterruptedException
{
long startTime = (msecs <= 0) ? 0 : System.currentTimeMillis();
if (!entryLock.attempt(msecs))
{
return false;
}
int r = readers;
try
{
synchronized (this)
{
while (exreaders != r)
{
long timeLeft = (msecs <= 0) ? 0 : msecs
- (System.currentTimeMillis() - startTime);
if (timeLeft <= 0)
{
entryLock.release();
return false;
}
wait(timeLeft);
}
return true;
}
}
catch (InterruptedException ie)
{
entryLock.release();
throw ie;
}
}
}