ozeigermann    2005/01/13 08:44:03

  Modified:    transaction/src/java/org/apache/commons/transaction/locking
                        GenericLockManager.java
               transaction/src/test/org/apache/commons/transaction/locking
                        GenericLockTest.java
  Log:
  Fixed deadlock hazard in deadlock detection caused by interleaving access
  to locks set of an owner and added test case that revealed it
  
  Revision  Changes    Path
  1.20      +14 -9     
jakarta-commons/transaction/src/java/org/apache/commons/transaction/locking/GenericLockManager.java
  
  Index: GenericLockManager.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-commons/transaction/src/java/org/apache/commons/transaction/locking/GenericLockManager.java,v
  retrieving revision 1.19
  retrieving revision 1.20
  diff -u -r1.19 -r1.20
  --- GenericLockManager.java   9 Jan 2005 19:33:53 -0000       1.19
  +++ GenericLockManager.java   13 Jan 2005 16:44:03 -0000      1.20
  @@ -281,12 +281,17 @@
       protected void releaseAllNoTimeOutReset(Object ownerId) {
           Set locks = (Set) globalOwners.get(ownerId);
           if (locks != null) {
  +            Collection locksCopy;
  +            // need to copy in order not to interfere with wouldDeadlock
  +            // possibly called by
  +            // other threads
               synchronized (locks) {
  -                for (Iterator it = locks.iterator(); it.hasNext();) {
  -                    GenericLock lock = (GenericLock) it.next();
  -                    lock.release(ownerId);
  -                    it.remove();
  -                }
  +                locksCopy = new ArrayList(locks);
  +            }
  +            for (Iterator it = locksCopy.iterator(); it.hasNext();) {
  +                GenericLock lock = (GenericLock) it.next();
  +                lock.release(ownerId);
  +                it.remove();
               }
           }
       }
  
  
  
  1.12      +77 -6     
jakarta-commons/transaction/src/test/org/apache/commons/transaction/locking/GenericLockTest.java
  
  Index: GenericLockTest.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-commons/transaction/src/test/org/apache/commons/transaction/locking/GenericLockTest.java,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- GenericLockTest.java      8 Jan 2005 18:56:03 -0000       1.11
  +++ GenericLockTest.java      13 Jan 2005 16:44:03 -0000      1.12
  @@ -262,6 +262,9 @@
   
           sLogger.logInfo("\n\nChecking detection of indirect deadlock \n\n");
   
  +        final String jamowner1 = "jamowner1";
  +        final String jamowner2 = "jamowner2";
  +
           final String owner1 = "owner1";
           final String owner2 = "owner2";
           final String owner3 = "owner3";
  @@ -274,7 +277,7 @@
           final ReadWriteLockManager manager = new 
ReadWriteLockManager(sLogger,
                   TIMEOUT);
   
  -        final RendezvousBarrier restart = new RendezvousBarrier("restart", 
3, TIMEOUT, sLogger);
  +        final RendezvousBarrier restart = new RendezvousBarrier("restart", 
5, TIMEOUT, sLogger);
   
           final TurnBarrier cb = new TurnBarrier("cb1", TIMEOUT, sLogger, 1);
   
  @@ -282,6 +285,74 @@
               
               System.out.print(".");
   
  +            // thread that accesses lock of res1 just to cause interference 
and
  +            // possibly detect concurrency problems
  +            Thread jamThread1 = new Thread(new Runnable() {
  +                public void run() {
  +                    try {
  +                        for (int i = 0; i < 10; i++) {
  +                            manager.readLock(jamowner1, res1);
  +                            Thread.sleep(10);
  +                            manager.releaseAll(jamowner1);
  +                            Thread.sleep(10);
  +                            manager.writeLock(jamowner1, res1);
  +                            Thread.sleep(10);
  +                            manager.releaseAll(jamowner1);
  +                            Thread.sleep(10);
  +                        }
  +                    } catch (LockException le) {
  +                        fail("Jam Thread should not fail");
  +                    } catch (InterruptedException ie) {
  +                    } finally {
  +                        manager.releaseAll(jamowner1);
  +                        synchronized (restart) {
  +                            try {
  +                                synchronized (restart) {
  +                                    restart.meet();
  +                                    restart.reset();
  +                                }
  +                                } catch (InterruptedException ie) {}
  +                        }
  +                    }
  +                }
  +            }, "Jam Thread #1");
  +
  +            jamThread1.start();
  +
  +            // thread that accesses lock of res1 just to cause interference 
and
  +            // possibly detect concurrency problems
  +            Thread jamThread2 = new Thread(new Runnable() {
  +                public void run() {
  +                    try {
  +                        for (int i = 0; i < 10; i++) {
  +                            manager.writeLock(jamowner2, res1);
  +                            Thread.sleep(10);
  +                            manager.releaseAll(jamowner2);
  +                            Thread.sleep(10);
  +                            manager.readLock(jamowner2, res1);
  +                            Thread.sleep(10);
  +                            manager.releaseAll(jamowner2);
  +                            Thread.sleep(10);
  +                        }
  +                    } catch (LockException le) {
  +                        fail("Jam Thread should not fail");
  +                    } catch (InterruptedException ie) {
  +                    } finally {
  +                        manager.releaseAll(jamowner2);
  +                        synchronized (restart) {
  +                            try {
  +                                synchronized (restart) {
  +                                    restart.meet();
  +                                    restart.reset();
  +                                }
  +                                } catch (InterruptedException ie) {}
  +                        }
  +                    }
  +                }
  +            }, "Jam Thread #2");
  +
  +            jamThread2.start();
  +
               Thread t1 = new Thread(new Runnable() {
                   public void run() {
                       try {
  @@ -368,7 +439,7 @@
               // XXX in special scenarios the current implementation might 
cause more than one
               // owner to be a deadlock victim
               if (deadlockCnt != 1) {
  -                sLogger.logWarning("More than one thread was deadlock 
victim!");
  +                sLogger.logWarning("\nMore than one thread was deadlock 
victim!\n");
               }
               assertTrue(deadlockCnt >= 1);
               deadlockCnt = 0;
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to