All,
Avi Drissman ([EMAIL PROTECTED]) pointed out a problem with the current
implementation of org.apache.avalon.excalibur.concurrent.ReadWriteLock: If
you hold a read lock, and a thread waiting for a write lock is interrupted,
there is no way to aquire a read lock again.
This patch fixes the problem, and a syntactic error in build.xml.
/LS
cvs server: Diffing .
Index: build.xml
===================================================================
RCS file: /home/cvspublic/jakarta-avalon-excalibur/build.xml,v
retrieving revision 1.70
diff -u -r1.70 build.xml
--- build.xml 2001/10/30 22:03:49 1.70
+++ build.xml 2001/10/31 08:26:09
@@ -169,9 +169,6 @@
</available>
<available property="servlet.present" classname="javax.servlet.Servlet">
<classpath refid="project.class.path"/>
- <available property="jaxen.present" classname="org.jaxen.dom.XPath">
- <classpath refid="project.class.path"/>
- </available>
</available>
<available property="jms.present" classname="javax.jms.Queue">
<classpath refid="project.class.path"/>
cvs server: Diffing lib
cvs server: Diffing src
cvs server: Diffing src/java
cvs server: Diffing src/java/org
cvs server: Diffing src/java/org/apache
cvs server: Diffing src/java/org/apache/avalon
cvs server: Diffing src/java/org/apache/avalon/excalibur
cvs server: Diffing src/java/org/apache/avalon/excalibur/cli
cvs server: Diffing src/java/org/apache/avalon/excalibur/collections
cvs server: Diffing src/java/org/apache/avalon/excalibur/component
cvs server: Diffing src/java/org/apache/avalon/excalibur/concurrent
Index: src/java/org/apache/avalon/excalibur/concurrent/ReadWriteLock.java
===================================================================
RCS file:
/home/cvspublic/jakarta-avalon-excalibur/src/java/org/apache/avalon/excalibur/concurrent/ReadWriteLock.java,v
retrieving revision 1.4
diff -u -r1.4 ReadWriteLock.java
--- src/java/org/apache/avalon/excalibur/concurrent/ReadWriteLock.java
2001/08/10 17:12:52 1.4
+++ src/java/org/apache/avalon/excalibur/concurrent/ReadWriteLock.java
2001/10/31 08:26:10
@@ -79,12 +79,18 @@
synchronized ( m_lock )
{
m_numWaitingForWrite++;
- while ( m_numReadLocksHeld != 0 )
+ try
{
- m_lock.wait();
+ while ( m_numReadLocksHeld != 0 )
+ {
+ m_lock.wait();
+ }
+ m_numReadLocksHeld = -1;
}
- m_numReadLocksHeld = -1;
- m_numWaitingForWrite--;
+ finally
+ {
+ m_numWaitingForWrite--;
+ }
}
}
cvs server: Diffing src/java/org/apache/avalon/excalibur/datasource
cvs server: Diffing src/java/org/apache/avalon/excalibur/i18n
cvs server: Diffing src/java/org/apache/avalon/excalibur/io
cvs server: Diffing src/java/org/apache/avalon/excalibur/logger
cvs server: Diffing src/java/org/apache/avalon/excalibur/logger/factory
cvs server: Diffing src/java/org/apache/avalon/excalibur/monitor
cvs server: Diffing src/java/org/apache/avalon/excalibur/naming
cvs server: Diffing src/java/org/apache/avalon/excalibur/naming/memory
cvs server: Diffing src/java/org/apache/avalon/excalibur/naming/rmi
cvs server: Diffing src/java/org/apache/avalon/excalibur/naming/rmi/server
cvs server: Diffing src/java/org/apache/avalon/excalibur/pool
cvs server: Diffing src/java/org/apache/avalon/excalibur/property
cvs server: Diffing src/java/org/apache/avalon/excalibur/proxy
cvs server: Diffing src/java/org/apache/avalon/excalibur/testcase
cvs server: Diffing src/java/org/apache/avalon/excalibur/xml
cvs server: Diffing src/java/org/apache/avalon/excalibur/xml/xpath
cvs server: Diffing src/scratchpad
cvs server: Diffing src/scratchpad/org
cvs server: Diffing src/scratchpad/org/apache
cvs server: Diffing src/scratchpad/org/apache/avalon
cvs server: Diffing src/scratchpad/org/apache/avalon/excalibur
cvs server: Diffing src/scratchpad/org/apache/avalon/excalibur/cache
cvs server: Diffing src/scratchpad/org/apache/avalon/excalibur/cache/doc-files
cvs server: Diffing src/scratchpad/org/apache/avalon/excalibur/cache/test
cvs server: Diffing src/scratchpad/org/apache/avalon/excalibur/catalog
cvs server: Diffing src/scratchpad/org/apache/avalon/excalibur/container
cvs server: Diffing src/scratchpad/org/apache/avalon/excalibur/extension
cvs server: Diffing src/scratchpad/org/apache/avalon/excalibur/extension/test
cvs server: Diffing src/scratchpad/org/apache/avalon/excalibur/i18n
cvs server: Diffing src/scratchpad/org/apache/avalon/excalibur/i18n/test
cvs server: cannot find
src/scratchpad/org/apache/avalon/excalibur/i18n/test/XMLResourceBundleTestCase.java
cvs server: Diffing src/scratchpad/org/apache/avalon/excalibur/i18n/util
cvs server: Diffing src/scratchpad/org/apache/avalon/excalibur/lang
cvs server: Diffing src/scratchpad/org/apache/avalon/excalibur/pipeline
cvs server: Diffing src/scratchpad/org/apache/avalon/excalibur/thread
cvs server: Diffing src/scratchpad/org/apache/avalon/excalibur/thread/impl
cvs server: Diffing src/scratchpad/org/apache/avalon/excalibur/util
cvs server: Diffing src/scratchpad/org/apache/avalon/excalibur/util/test
cvs server: Diffing src/scratchpad/org/apache/avalon/excalibur/vfs
cvs server: Diffing src/test
cvs server: Diffing src/test/org
cvs server: Diffing src/test/org/apache
cvs server: Diffing src/test/org/apache/avalon
cvs server: Diffing src/test/org/apache/avalon/excalibur
cvs server: Diffing src/test/org/apache/avalon/excalibur/cli
cvs server: Diffing src/test/org/apache/avalon/excalibur/cli/test
cvs server: Diffing src/test/org/apache/avalon/excalibur/collections
cvs server: Diffing src/test/org/apache/avalon/excalibur/collections/test
cvs server: Diffing src/test/org/apache/avalon/excalibur/concurrent
cvs server: Diffing src/test/org/apache/avalon/excalibur/concurrent/test
Index:
src/test/org/apache/avalon/excalibur/concurrent/test/ReadWriteLockTestCase.java
===================================================================
RCS file:
/home/cvspublic/jakarta-avalon-excalibur/src/test/org/apache/avalon/excalibur/concurrent/test/ReadWriteLockTestCase.java,v
retrieving revision 1.4
diff -u -r1.4 ReadWriteLockTestCase.java
---
src/test/org/apache/avalon/excalibur/concurrent/test/ReadWriteLockTestCase.java
2001/10/25 16:00:48 1.4
+++
src/test/org/apache/avalon/excalibur/concurrent/test/ReadWriteLockTestCase.java
2001/10/31 08:26:15
@@ -28,17 +28,17 @@
{
protected ReadWriteLock m_lock;
protected boolean m_success = false;
-
+
public TriesWriteLock(ReadWriteLock lock)
{
m_lock = lock;
}
-
+
public boolean hasSuccess()
{
return m_success;
}
-
+
public void run ()
{
try
@@ -53,7 +53,7 @@
}
}
}
-
+
/**
* Worker thread that attempts to
* aquire a read lock. Start it, wait a little while
@@ -64,17 +64,17 @@
{
protected ReadWriteLock m_lock;
protected boolean m_success = false;
-
+
public TriesReadLock( final ReadWriteLock lock )
{
m_lock = lock;
}
-
+
public boolean hasSuccess()
{
return m_success;
}
-
+
public void run ()
{
try
@@ -89,11 +89,11 @@
}
}
}
-
+
public ReadWriteLockTestCase (String name) {
super (name);
}
-
+
/**
* Attempt to aquire and release read and write locks from
* different threads.
@@ -104,23 +104,23 @@
final ReadWriteLock lock = new ReadWriteLock();
final TriesWriteLock wl = new TriesWriteLock( lock );
final TriesReadLock rl = new TriesReadLock( lock );
-
+
rl.start ();
Thread.currentThread().sleep( 100 );
assertTrue( "Attempted to aquire read lock.", rl.hasSuccess () );
-
+
wl.start ();
Thread.currentThread().sleep( 100 );
assertTrue( "Attempted to aquire write lock.", !wl.hasSuccess () );
-
+
lock.release();
-
+
Thread.currentThread().sleep( 100 );
assertTrue( "Attempted to aquire write lock after releasing read
lock.",
- wl.hasSuccess () );
-
+ wl.hasSuccess () );
+
lock.release();
-
+
//
// And see that the write lock is released properly.
//
@@ -128,10 +128,10 @@
r2.start ();
Thread.currentThread().sleep( 100 );
assertTrue( "Attempted to aquire read lock.", r2.hasSuccess () );
-
+
lock.release();
}
-
+
/**
* Test that the lock throws an IllegalStateException when
* one attempts to release an already released lock.
@@ -149,7 +149,7 @@
// OK, we should receive this one.
}
}
-
+
/**
* Tests that attempts to aquire a write lock
* are given higher priority than attempts
@@ -162,23 +162,23 @@
TriesReadLock rlb = new TriesReadLock( lock );
TriesWriteLock wla = new TriesWriteLock( lock );
TriesWriteLock wlb = new TriesWriteLock( lock );
-
+
rla.start ();
Thread.currentThread().sleep( 100 );
assertTrue( "Attempted to aquire read lock.", rla.hasSuccess () );
-
+
wla.start ();
wlb.start ();
-
+
//
// Give the write lock threads some time to attempt
// to aquire a lock.
//
Thread.currentThread().sleep( 100 );
-
+
rlb.start ();
Thread.currentThread().sleep( 100 );
-
+
//
// Two write locks queued up, one read lock queued up.
//
@@ -187,15 +187,15 @@
// rlb -> (has waiting write locks)
//
assertTrue( "Attempted to aquire write lock, and succeeded even though
it shouldn't be possible (rla has the lock).",
- !wla.hasSuccess() && !wlb.hasSuccess() &&
!rlb.hasSuccess() );
-
+ !wla.hasSuccess() && !wlb.hasSuccess() && !rlb.hasSuccess() );
+
//
// Upon releasing the lock, the write lock attempt should succeed,
while the read
// lock should still be waiting.
//
lock.release();
Thread.currentThread().sleep( 100 );
-
+
//
// One write lock queued up, one read lock queued up.
//
@@ -204,15 +204,15 @@
// rlb -> (has waiting write lock)
//
assertTrue( "Attempted to aquire write lock after releasing read
lock.",
- (wla.hasSuccess () || wlb.hasSuccess () ) &&
!rlb.hasSuccess ()
- && !(wla.hasSuccess () && wlb.hasSuccess () ));
-
+ (wla.hasSuccess () || wlb.hasSuccess () ) && !rlb.hasSuccess ()
+ && !(wla.hasSuccess () && wlb.hasSuccess () ));
+
//
// Release write lock again. The other one of wla and wlb should grab
the lock.
//
lock.release();
Thread.currentThread().sleep( 100 );
-
+
//
// Two write locks queued up, one read lock queued up.
//
@@ -220,17 +220,17 @@
// rlb -> (write lock is held)
//
assertTrue( "Attempted to aquire write lock after releasing read
lock.",
- wla.hasSuccess () && wlb.hasSuccess () && !rlb.hasSuccess
() );
-
+ wla.hasSuccess () && wlb.hasSuccess () && !rlb.hasSuccess () );
+
//
// Release the lock - the waiting read lock should grab it.
//
lock.release();
Thread.currentThread().sleep( 100 );
assertTrue( "Attempted to aquire write lock after releasing read
lock.",
- wla.hasSuccess () && wlb.hasSuccess () && rlb.hasSuccess
() );
+ wla.hasSuccess () && wlb.hasSuccess () && rlb.hasSuccess () );
}
-
+
/**
* Tests that the lock behaves correctly when
* multiple read locks are obtained.
@@ -241,28 +241,28 @@
TriesReadLock rla = new TriesReadLock( lock );
TriesReadLock rlb = new TriesReadLock( lock );
TriesWriteLock wla = new TriesWriteLock( lock );
-
+
rla.start ();
rlb.start ();
Thread.currentThread().sleep( 100 );
assertTrue( "Attempted to aquire read multiple read locks.",
- rla.hasSuccess () && rlb.hasSuccess () );
-
+ rla.hasSuccess () && rlb.hasSuccess () );
+
wla.start ();
Thread.currentThread().sleep( 100 );
assertTrue( "Write lock aquired even though read locks are held.",
!wla.hasSuccess () );
-
+
lock.release ();
Thread.currentThread().sleep( 100 );
assertTrue( "Write lock aquired even though read locks are held.
(There should be one read lock left)",
- !wla.hasSuccess () );
-
+ !wla.hasSuccess () );
+
lock.release ();
Thread.currentThread().sleep( 100 );
assertTrue( "Write lock not aquired even though lock should be
released.",
- wla.hasSuccess () );
+ wla.hasSuccess () );
}
-
+
/**
* Tests the tryAquireXXX methods.
*/
@@ -273,7 +273,7 @@
TriesReadLock rlb = new TriesReadLock( lock );
TriesWriteLock wla = new TriesWriteLock( lock );
TriesWriteLock wlb = new TriesWriteLock( lock );
-
+
//
// Grab a read lock, try to aquire one more (should work),
// and try aquiring a write lock (should not work).
@@ -281,18 +281,18 @@
rla.start ();
Thread.currentThread().sleep( 100 );
assertTrue( "Could not aquire a read lock.", rla.hasSuccess() );
-
+
assertTrue( "Could not aquire a read lock, even though only a read
lock is held.",
- lock.tryAquireRead() );
-
+ lock.tryAquireRead() );
+
assertTrue( "Could aquire a write lock.", !lock.tryAquireWrite() );
-
+
//
// Release both locks.
//
lock.release();
lock.release();
-
+
//
// Try aquiring a write lock (should work), a read
// lock (should fail) and another write lock (should fail).
@@ -300,14 +300,71 @@
assertTrue( "Could not aquire a write lock.", lock.tryAquireWrite() );
assertTrue( "Could aquire a read lock.", !lock.tryAquireRead() );
assertTrue( "Could aquire a write lock.", !lock.tryAquireWrite() );
-
+
//
// Release the write lock.
//
lock.release();
-
+
assertTrue( "Could not aquire a write lock after releasing the lock.",
- lock.tryAquireWrite() );
+ lock.tryAquireWrite() );
+ }
+
+ /**
+ * Tests a condition pointed out to me (L.Sutic) by Avi Drissman
+ * <a href="[EMAIL PROTECTED]">[EMAIL PROTECTED]</a>. If you hold
+ * a read lock, and a thread waiting for a write lock is interrupted,
+ * there is no way to aquire a read lock again.
+ *
+ * (This condition is fixed, 2001-10-31.)
+ */
+ public void testDeadLock () throws Exception {
+ ReadWriteLock lock = new ReadWriteLock();
+ TriesReadLock rla = new TriesReadLock( lock );
+ TriesReadLock rlb = new TriesReadLock( lock );
+ TriesWriteLock wla = new TriesWriteLock( lock );
+ TriesWriteLock wlb = new TriesWriteLock( lock );
+
+ //
+ // Grab a read lock.
+ //
+ rla.start();
+ Thread.currentThread().sleep( 100 );
+ assertTrue( rla.hasSuccess() );
+
+ //
+ // Try to grab a write lock. (The attempt stalls,
+ // because we are holding a read lock.)
+ //
+ wla.start();
+ Thread.currentThread().sleep( 100 );
+ assertTrue( !wla.hasSuccess() );
+
+ //
+ // Interupt the thread waiting for the write lock...
+ //
+ wla.interrupt();
+
+ //
+ // ...and release the read lock.
+ //
+ lock.release();
+
+ //
+ // Right, we are in the condition described by Drissman.
+ // Now try to aquire, in turn, a read and a write lock.
+ // Before the fix, the assertion immediately below
+ // would fail.
+ //
+ rlb.start();
+ Thread.currentThread().sleep( 100 );
+ assertTrue( rlb.hasSuccess() );
+ lock.release();
+
+ wlb.start();
+ Thread.currentThread().sleep( 100 );
+ assertTrue( wlb.hasSuccess() );
+ lock.release();
}
}
cvs server: Diffing src/test/org/apache/avalon/excalibur/datasource
cvs server: Diffing src/test/org/apache/avalon/excalibur/datasource/test
cvs server: Diffing src/test/org/apache/avalon/excalibur/i18n
cvs server: Diffing src/test/org/apache/avalon/excalibur/i18n/test
cvs server: Diffing src/test/org/apache/avalon/excalibur/io
cvs server: Diffing src/test/org/apache/avalon/excalibur/io/test
cvs server: Diffing src/test/org/apache/avalon/excalibur/logger
cvs server: Diffing src/test/org/apache/avalon/excalibur/logger/test
cvs server: Diffing src/test/org/apache/avalon/excalibur/monitor
cvs server: Diffing src/test/org/apache/avalon/excalibur/monitor/test
cvs server: Diffing src/test/org/apache/avalon/excalibur/naming
cvs server: Diffing src/test/org/apache/avalon/excalibur/naming/memory
cvs server: Diffing src/test/org/apache/avalon/excalibur/naming/memory/test
cvs server: Diffing src/test/org/apache/avalon/excalibur/naming/rmi
cvs server: Diffing src/test/org/apache/avalon/excalibur/naming/rmi/test
cvs server: Diffing src/test/org/apache/avalon/excalibur/naming/test
cvs server: Diffing src/test/org/apache/avalon/excalibur/pool
cvs server: Diffing src/test/org/apache/avalon/excalibur/pool/test
cvs server: Diffing src/test/org/apache/avalon/excalibur/property
cvs server: Diffing src/test/org/apache/avalon/excalibur/property/test
cvs server: Diffing src/test/org/apache/avalon/excalibur/test
cvs server: Diffing src/xdocs
cvs server: Diffing src/xdocs/dtd
cvs server: Diffing src/xdocs/images
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>