| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| /** |
| * @author Mikhail Danilov |
| * @version $Revision$ |
| */ |
| package org.apache.harmony.awt.wtk; |
| |
| import java.util.Hashtable; |
| import java.util.LinkedList; |
| |
| import org.apache.harmony.awt.internal.nls.Messages; |
| |
| /** |
| * Class synchronizer is to protect AWT state integrity in multithreading environment. |
| * It is supposed to have a child class per native platform. |
| * The only instance is created on the first use of one of the core AWT classes. |
| * Registers WTK on the dispatch thread startup. |
| * It is just a special kind of mutex. |
| * |
| */ |
| |
| 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. |
| * To free synchronizer unlock method must be called $acquestCounter times. |
| * Equals to 0 when synchronizer is free. |
| */ |
| protected int acquestCounter; |
| |
| /** |
| * This field holds the owner of synchronizer. |
| * Owner of synchronizer is a last thread that successfully locked synchronizer and |
| * still havn't freed it. Equals to null when synchronizer is free. |
| */ |
| 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>(); |
| |
| /** |
| * Acquire the lock for this synchronizer. Nested lock is supported. |
| * If the mutex is already locked by another thread, the current thread will be put |
| * into wait queue until the lock becomes available. |
| * All user threads are served in FIFO order. Dispatch thread has higher priority. |
| * Supposed to be used in Toolkit.lockAWT() only. |
| */ |
| public void lock() { |
| synchronized (this) { |
| Thread curThread = Thread.currentThread(); |
| |
| if (acquestCounter == 0) { |
| acquestCounter = 1; |
| 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$ |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * 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) { |
| // 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) { |
| acquestCounter = 1; |
| owner = waitQueue.removeFirst(); |
| owner.interrupt(); |
| } else { |
| owner = null; |
| } |
| } |
| } |
| } |
| |
| /** |
| * Stores state of this synchronizer and frees it. |
| * Supposed to be used in Toolkit.unsafeInvokeAndWaitUnderAWTLock() only in pair with |
| * lockAndRestoreState(). |
| * Do not call it directly. |
| */ |
| public void storeStateAndFree() { |
| synchronized (this) { |
| 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$ |
| } |
| |
| storedStates.put(curThread, new Integer(acquestCounter)); |
| acquestCounter = 1; |
| unlock(); |
| } |
| } |
| |
| /** |
| * Locks this synchronizer and restores it's state. |
| * Supposed to be used in Toolkit.unsafeInvokeAndWaitUnderAWTLock() only in pair with |
| * storeStateAndFree(). |
| * Do not call it directly. |
| */ |
| public void lockAndRestoreState() { |
| synchronized (this) { |
| 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$ |
| } |
| |
| lock(); |
| acquestCounter = storedStates.get(curThread).intValue(); |
| storedStates.remove(curThread); |
| } |
| } |
| |
| /** |
| * Sets references to WTK and event dispatch thread. |
| * Called on toolkit startup. |
| * |
| * @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; |
| } |
| } |
| |
| } |