You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by ay...@apache.org on 2007/05/15 12:02:37 UTC

svn commit: r538117 - in /harmony/enhanced/classlib/trunk/modules/awt/src: main/java/common/org/apache/harmony/awt/wtk/Synchronizer.java test/api/java/common/org/apache/harmony/awt/wtk/SynchronizerTest.java

Author: ayza
Date: Tue May 15 03:02:33 2007
New Revision: 538117

URL: http://svn.apache.org/viewvc?view=rev&rev=538117
Log:
Applying patch from HARMONY-3601 ([classlib][awt][drlvm][netbeans] ToolkitImpl.createImage() throws RTE: Not owner can't unlock resource)

Modified:
    harmony/enhanced/classlib/trunk/modules/awt/src/main/java/common/org/apache/harmony/awt/wtk/Synchronizer.java
    harmony/enhanced/classlib/trunk/modules/awt/src/test/api/java/common/org/apache/harmony/awt/wtk/SynchronizerTest.java

Modified: harmony/enhanced/classlib/trunk/modules/awt/src/main/java/common/org/apache/harmony/awt/wtk/Synchronizer.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/awt/src/main/java/common/org/apache/harmony/awt/wtk/Synchronizer.java?view=diff&rev=538117&r1=538116&r2=538117
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/awt/src/main/java/common/org/apache/harmony/awt/wtk/Synchronizer.java (original)
+++ harmony/enhanced/classlib/trunk/modules/awt/src/main/java/common/org/apache/harmony/awt/wtk/Synchronizer.java Tue May 15 03:02:33 2007
@@ -20,8 +20,8 @@
  */
 package org.apache.harmony.awt.wtk;
 
-import java.util.Hashtable;
-import java.util.LinkedList;
+import java.util.IdentityHashMap;
+import java.util.Map;
 
 import org.apache.harmony.awt.internal.nls.Messages;
 
@@ -36,7 +36,6 @@
 
 public class Synchronizer {
     //TODO: think about java.util.concurrent use for faster blocking/awaking operations
-    //TODO: think about all synchronized methods. Is there need to synchronize everything?
 
     /**
      * This field holds the counter of lock operation.
@@ -53,18 +52,24 @@
     protected Thread owner;
 
     /**
-     * This field holds the wait queue.
-     * Wait queue is a queue where thread wait for synchronizer access.
-     * Empty when synchronizer is free.
-     */
-    protected final LinkedList<Thread> waitQueue = new LinkedList<Thread>();
-
-    /**
      * The event dispatch thread
      */
     protected Thread dispatchThread;
-
-    private final Hashtable<Thread, Integer> storedStates = new Hashtable<Thread, Integer>();
+    
+    /**
+     * Indicates whether the event dispatch thread, which has the highest 
+     * priority, is waiting to acquire the lock.
+     */
+    private boolean isDispatchThreadWaiting;
+    
+    /**
+     * This object is used for threads locking. A locked thread could be 
+     * unlocked only in one of two ways: the unlock() method of this class has 
+     * been invoked; the thread has been interrupted from another thread.
+     */
+    private final Object lock = new Object();
+    
+    private final Map<Thread, Integer> storedStates = new IdentityHashMap<Thread, Integer>();
 
     /**
      * Acquire the lock for this synchronizer. Nested lock is supported.
@@ -74,60 +79,51 @@
      * Supposed to be used in Toolkit.lockAWT() only.
      */
     public void lock() {
-        synchronized (this) {
-            Thread curThread = Thread.currentThread();
+        final Thread curThread = Thread.currentThread();
 
-            if (acquestCounter == 0) {
-                acquestCounter = 1;
+        synchronized (lock) {
+            if (owner == null) {
                 owner = curThread;
-            } else {
-                if (owner == curThread) {
-                    acquestCounter++;
-                } else {
-                    if (curThread == dispatchThread) {
-                        waitQueue.addFirst(curThread);
-                    } else {
-                        waitQueue.addLast(curThread);
-                    }
-                    try {
-                        wait();
-                    } catch (InterruptedException e) {
-                        if (owner != curThread) {
-                            waitQueue.remove(curThread);
-                            // awt.1F=Waiting for resource access thread interrupted not from unlock method.
-                            throw new RuntimeException(Messages
-                                    .getString("awt.1F")); //$NON-NLS-1$
-                        }
-                    }
-                }
-            }
+                acquestCounter = 1;
+                return;
+            } else if (owner == curThread) {
+                acquestCounter++;
+                return;
+            }
+            
+            isDispatchThreadWaiting = (curThread == dispatchThread);
+            park(curThread);
         }
     }
-
+    
     /**
      * Release the lock for this synchronizer.
      * If wait queue is not empty the first waiting thread acquires the lock.
      * Supposed to be used in Toolkit.unlockAWT() only.
      */
     public void unlock() {
-        synchronized (this) {
-            if (acquestCounter == 0) {
+        synchronized (lock) {
+            if (owner == null) {
                 // awt.20=Can't unlock not locked resource.
                 throw new RuntimeException(Messages.getString("awt.20")); //$NON-NLS-1$
             }
+
             if (owner != Thread.currentThread()) {
                 // awt.21=Not owner can't unlock resource.
                 throw new RuntimeException(Messages.getString("awt.21")); //$NON-NLS-1$
             }
 
             acquestCounter--;
+
             if (acquestCounter == 0) {
-                if (waitQueue.size() > 0) {
+                if (isDispatchThreadWaiting) {
+                    isDispatchThreadWaiting = false;
+                    owner = dispatchThread;
                     acquestCounter = 1;
-                    owner = waitQueue.removeFirst();
-                    owner.interrupt();
+                    dispatchThread.interrupt();
                 } else {
                     owner = null;
+                    lock.notify();
                 }
             }
         }
@@ -140,22 +136,21 @@
      * Do not call it directly.
      */
     public void storeStateAndFree() {
-        synchronized (this) {
-            Thread curThread = Thread.currentThread();
+        final Thread curThread = Thread.currentThread();
 
-            if (owner != curThread) {
-                // awt.22=Not owner can't free resource.
-                throw new RuntimeException(Messages.getString("awt.22")); //$NON-NLS-1$
-            }
-            if (storedStates.containsKey(curThread)) {
-                // awt.23=One thread can't store state several times in a row.
-                throw new RuntimeException(Messages.getString("awt.23")); //$NON-NLS-1$
-            }
+        if (owner != curThread) {
+            // awt.22=Not owner can't free resource.
+            throw new RuntimeException(Messages.getString("awt.22")); //$NON-NLS-1$
+        }
 
-            storedStates.put(curThread, new Integer(acquestCounter));
-            acquestCounter = 1;
-            unlock();
+        if (storedStates.containsKey(curThread)) {
+            // awt.23=One thread can't store state several times in a row.
+            throw new RuntimeException(Messages.getString("awt.23")); //$NON-NLS-1$
         }
+
+        storedStates.put(curThread, new Integer(acquestCounter));
+        acquestCounter = 1;
+        unlock();
     }
 
     /**
@@ -165,23 +160,24 @@
      * Do not call it directly.
      */
     public void lockAndRestoreState() {
-        synchronized (this) {
-            Thread curThread = Thread.currentThread();
+        final Integer counter;
+        final Thread curThread = Thread.currentThread();
 
-            if (owner == curThread) {
-                // awt.24=Owner can't overwrite resource state. Lock operations may be lost.
-                throw new RuntimeException(
-                        Messages.getString("awt.24")); //$NON-NLS-1$
-            }
-            if (!storedStates.containsKey(curThread)) {
-                // awt.25=No state stored for current thread.
-                throw new RuntimeException(Messages.getString("awt.25")); //$NON-NLS-1$
-            }
+        if (owner == curThread) {
+            // awt.24=Owner can't overwrite resource state. Lock operations
+            // may be lost.
+            throw new RuntimeException(Messages.getString("awt.24")); //$NON-NLS-1$
+        }
 
-            lock();
-            acquestCounter = storedStates.get(curThread).intValue();
-            storedStates.remove(curThread);
+        counter = storedStates.remove(curThread);
+
+        if (counter == null) {
+            // awt.25=No state stored for current thread.
+            throw new RuntimeException(Messages.getString("awt.25")); //$NON-NLS-1$
         }
+
+        lock();
+        acquestCounter = counter.intValue();
     }
 
     /**
@@ -191,10 +187,25 @@
      * @param wtk - reference to WTK instance
      * @param dispatchThread - reference to event dispatch thread
      */
-    public void setEnvironment(WTK wtk, Thread dispatchThread) {
-        synchronized (this) {
-            this.dispatchThread = dispatchThread;
+    public void setEnvironment(WTK wtk, Thread dispatchThread) { 
+        this.dispatchThread = dispatchThread;
+    }
+    
+    private void park(final Thread t) {
+        synchronized (lock) {
+            try {
+                lock.wait();
+                
+                if (owner == null) { 
+                    owner = t;
+                    acquestCounter = 1;
+                } else {
+                    park(t);
+                }
+            } catch (InterruptedException ex) {
+                // event dispatch thread unlocked or the waiting thread has been 
+                // interrupted from another thread
+            }
         }
     }
-
 }

Modified: harmony/enhanced/classlib/trunk/modules/awt/src/test/api/java/common/org/apache/harmony/awt/wtk/SynchronizerTest.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/awt/src/test/api/java/common/org/apache/harmony/awt/wtk/SynchronizerTest.java?view=diff&rev=538117&r1=538116&r2=538117
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/awt/src/test/api/java/common/org/apache/harmony/awt/wtk/SynchronizerTest.java (original)
+++ harmony/enhanced/classlib/trunk/modules/awt/src/test/api/java/common/org/apache/harmony/awt/wtk/SynchronizerTest.java Tue May 15 03:02:33 2007
@@ -104,4 +104,33 @@
         s.unlock();
     }
 
+    // Regression test for HARMONY-3601
+    public void testHarmony_3601() throws Exception {
+        final Thread[] threads = new Thread[10];
+        final boolean[] errFlag = { false };
+
+        for (int i = 0; i < threads.length; i++) {
+            threads[i] = new Thread() {
+                public void run() {
+                    try {
+                        java.awt.Toolkit.getDefaultToolkit().createImage(
+                                new java.net.URL("file://any/thing"));
+                    } catch (Throwable t) {
+                        errFlag[0] = true;
+                        fail(t.getMessage());
+                    }
+                }
+            };
+        }
+
+        for (int i = 0; i < threads.length; i++) {
+            threads[i].start();
+        }
+
+        for (int i = 0; i < threads.length; i++) {
+            threads[i].join();
+        }
+
+        assertFalse("Exception in child thread", errFlag[0]);
+    }
 }