001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Mikhail Danilov
019: * @version $Revision$
020: */package org.apache.harmony.awt.wtk;
021:
022: import java.util.IdentityHashMap;
023: import java.util.Map;
024:
025: import org.apache.harmony.awt.internal.nls.Messages;
026:
027: /**
028: * Class synchronizer is to protect AWT state integrity in multithreading environment.
029: * It is supposed to have a child class per native platform.
030: * The only instance is created on the first use of one of the core AWT classes.
031: * Registers WTK on the dispatch thread startup.
032: * It is just a special kind of mutex.
033: *
034: */
035:
036: public class Synchronizer {
037: //TODO: think about java.util.concurrent use for faster blocking/awaking operations
038:
039: /**
040: * This field holds the counter of lock operation.
041: * To free synchronizer unlock method must be called $acquestCounter times.
042: * Equals to 0 when synchronizer is free.
043: */
044: protected int acquestCounter;
045:
046: /**
047: * This field holds the owner of synchronizer.
048: * Owner of synchronizer is a last thread that successfully locked synchronizer and
049: * still havn't freed it. Equals to null when synchronizer is free.
050: */
051: protected Thread owner;
052:
053: /**
054: * The event dispatch thread
055: */
056: protected Thread dispatchThread;
057:
058: /**
059: * Indicates whether the event dispatch thread, which has the highest
060: * priority, is waiting to acquire the lock.
061: */
062: private boolean isDispatchThreadWaiting;
063:
064: /**
065: * This object is used for threads locking. A locked thread could be
066: * unlocked only in one of two ways: the unlock() method of this class has
067: * been invoked; the thread has been interrupted from another thread.
068: */
069: private final Object lock = new Object();
070:
071: private final Map<Thread, Integer> storedStates = new IdentityHashMap<Thread, Integer>();
072:
073: /**
074: * Acquire the lock for this synchronizer. Nested lock is supported.
075: * If the mutex is already locked by another thread, the current thread will be put
076: * into wait queue until the lock becomes available.
077: * All user threads are served in FIFO order. Dispatch thread has higher priority.
078: * Supposed to be used in Toolkit.lockAWT() only.
079: */
080: public void lock() {
081: final Thread curThread = Thread.currentThread();
082:
083: synchronized (lock) {
084: if (owner == null) {
085: owner = curThread;
086: acquestCounter = 1;
087: return;
088: } else if (owner == curThread) {
089: acquestCounter++;
090: return;
091: }
092:
093: isDispatchThreadWaiting = (curThread == dispatchThread);
094: park(curThread);
095: }
096: }
097:
098: /**
099: * Release the lock for this synchronizer.
100: * If wait queue is not empty the first waiting thread acquires the lock.
101: * Supposed to be used in Toolkit.unlockAWT() only.
102: */
103: public void unlock() {
104: synchronized (lock) {
105: if (owner == null) {
106: // awt.20=Can't unlock not locked resource.
107: throw new RuntimeException(Messages.getString("awt.20")); //$NON-NLS-1$
108: }
109:
110: if (owner != Thread.currentThread()) {
111: // awt.21=Not owner can't unlock resource.
112: throw new RuntimeException(Messages.getString("awt.21")); //$NON-NLS-1$
113: }
114:
115: acquestCounter--;
116:
117: if (acquestCounter == 0) {
118: if (isDispatchThreadWaiting) {
119: isDispatchThreadWaiting = false;
120: owner = dispatchThread;
121: acquestCounter = 1;
122: dispatchThread.interrupt();
123: } else {
124: owner = null;
125: lock.notify();
126: }
127: }
128: }
129: }
130:
131: /**
132: * Stores state of this synchronizer and frees it.
133: * Supposed to be used in Toolkit.unsafeInvokeAndWaitUnderAWTLock() only in pair with
134: * lockAndRestoreState().
135: * Do not call it directly.
136: */
137: public void storeStateAndFree() {
138: final Thread curThread = Thread.currentThread();
139:
140: if (owner != curThread) {
141: // awt.22=Not owner can't free resource.
142: throw new RuntimeException(Messages.getString("awt.22")); //$NON-NLS-1$
143: }
144:
145: if (storedStates.containsKey(curThread)) {
146: // awt.23=One thread can't store state several times in a row.
147: throw new RuntimeException(Messages.getString("awt.23")); //$NON-NLS-1$
148: }
149:
150: storedStates.put(curThread, new Integer(acquestCounter));
151: acquestCounter = 1;
152: unlock();
153: }
154:
155: /**
156: * Locks this synchronizer and restores it's state.
157: * Supposed to be used in Toolkit.unsafeInvokeAndWaitUnderAWTLock() only in pair with
158: * storeStateAndFree().
159: * Do not call it directly.
160: */
161: public void lockAndRestoreState() {
162: final Integer counter;
163: final Thread curThread = Thread.currentThread();
164:
165: if (owner == curThread) {
166: // awt.24=Owner can't overwrite resource state. Lock operations
167: // may be lost.
168: throw new RuntimeException(Messages.getString("awt.24")); //$NON-NLS-1$
169: }
170:
171: counter = storedStates.remove(curThread);
172:
173: if (counter == null) {
174: // awt.25=No state stored for current thread.
175: throw new RuntimeException(Messages.getString("awt.25")); //$NON-NLS-1$
176: }
177:
178: lock();
179: acquestCounter = counter.intValue();
180: }
181:
182: /**
183: * Sets references to WTK and event dispatch thread.
184: * Called on toolkit startup.
185: *
186: * @param wtk - reference to WTK instance
187: * @param dispatchThread - reference to event dispatch thread
188: */
189: public void setEnvironment(WTK wtk, Thread dispatchThread) {
190: this .dispatchThread = dispatchThread;
191: }
192:
193: private void park(final Thread t) {
194: synchronized (lock) {
195: try {
196: lock.wait();
197:
198: if (owner == null) {
199: owner = t;
200: acquestCounter = 1;
201: } else {
202: park(t);
203: }
204: } catch (InterruptedException ex) {
205: // event dispatch thread unlocked or the waiting thread has been
206: // interrupted from another thread
207: }
208: }
209: }
210: }
|