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]>

Reply via email to