blob: 3eeaa0b07c1a8905a88f67ecb29e649169c98657 [file] [log] [blame]
/*
* 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;
}
}
}