1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17/** 18 * @author Mikhail Danilov 19 * @version $Revision$ 20 */ 21package org.apache.harmony.awt.wtk; 22 23import java.util.Hashtable; 24import java.util.LinkedList; 25 26import org.apache.harmony.awt.internal.nls.Messages; 27 28/** 29 * Class synchronizer is to protect AWT state integrity in multithreading environment. 30 * It is supposed to have a child class per native platform. 31 * The only instance is created on the first use of one of the core AWT classes. 32 * Registers WTK on the dispatch thread startup. 33 * It is just a special kind of mutex. 34 * 35 */ 36 37public class Synchronizer { 38 //TODO: think about java.util.concurrent use for faster blocking/awaking operations 39 //TODO: think about all synchronized methods. Is there need to synchronize everything? 40 41 /** 42 * This field holds the counter of lock operation. 43 * To free synchronizer unlock method must be called $acquestCounter times. 44 * Equals to 0 when synchronizer is free. 45 */ 46 protected int acquestCounter; 47 48 /** 49 * This field holds the owner of synchronizer. 50 * Owner of synchronizer is a last thread that successfully locked synchronizer and 51 * still havn't freed it. Equals to null when synchronizer is free. 52 */ 53 protected Thread owner; 54 55 /** 56 * This field holds the wait queue. 57 * Wait queue is a queue where thread wait for synchronizer access. 58 * Empty when synchronizer is free. 59 */ 60 protected final LinkedList<Thread> waitQueue = new LinkedList<Thread>(); 61 62 /** 63 * The event dispatch thread 64 */ 65 protected Thread dispatchThread; 66 67 private final Hashtable<Thread, Integer> storedStates = new Hashtable<Thread, Integer>(); 68 69 /** 70 * Acquire the lock for this synchronizer. Nested lock is supported. 71 * If the mutex is already locked by another thread, the current thread will be put 72 * into wait queue until the lock becomes available. 73 * All user threads are served in FIFO order. Dispatch thread has higher priority. 74 * Supposed to be used in Toolkit.lockAWT() only. 75 */ 76 public void lock() { 77 synchronized (this) { 78 Thread curThread = Thread.currentThread(); 79 80 if (acquestCounter == 0) { 81 acquestCounter = 1; 82 owner = curThread; 83 } else { 84 if (owner == curThread) { 85 acquestCounter++; 86 } else { 87 if (curThread == dispatchThread) { 88 waitQueue.addFirst(curThread); 89 } else { 90 waitQueue.addLast(curThread); 91 } 92 try { 93 wait(); 94 } catch (InterruptedException e) { 95 if (owner != curThread) { 96 waitQueue.remove(curThread); 97 // awt.1F=Waiting for resource access thread interrupted not from unlock method. 98 throw new RuntimeException(Messages 99 .getString("awt.1F")); //$NON-NLS-1$ 100 } 101 } 102 } 103 } 104 } 105 } 106 107 /** 108 * Release the lock for this synchronizer. 109 * If wait queue is not empty the first waiting thread acquires the lock. 110 * Supposed to be used in Toolkit.unlockAWT() only. 111 */ 112 public void unlock() { 113 synchronized (this) { 114 if (acquestCounter == 0) { 115 // awt.20=Can't unlock not locked resource. 116 throw new RuntimeException(Messages.getString("awt.20")); //$NON-NLS-1$ 117 } 118 if (owner != Thread.currentThread()) { 119 // awt.21=Not owner can't unlock resource. 120 throw new RuntimeException(Messages.getString("awt.21")); //$NON-NLS-1$ 121 } 122 123 acquestCounter--; 124 if (acquestCounter == 0) { 125 if (waitQueue.size() > 0) { 126 acquestCounter = 1; 127 owner = waitQueue.removeFirst(); 128 owner.interrupt(); 129 } else { 130 owner = null; 131 } 132 } 133 } 134 } 135 136 /** 137 * Stores state of this synchronizer and frees it. 138 * Supposed to be used in Toolkit.unsafeInvokeAndWaitUnderAWTLock() only in pair with 139 * lockAndRestoreState(). 140 * Do not call it directly. 141 */ 142 public void storeStateAndFree() { 143 synchronized (this) { 144 Thread curThread = Thread.currentThread(); 145 146 if (owner != curThread) { 147 // awt.22=Not owner can't free resource. 148 throw new RuntimeException(Messages.getString("awt.22")); //$NON-NLS-1$ 149 } 150 if (storedStates.containsKey(curThread)) { 151 // awt.23=One thread can't store state several times in a row. 152 throw new RuntimeException(Messages.getString("awt.23")); //$NON-NLS-1$ 153 } 154 155 storedStates.put(curThread, new Integer(acquestCounter)); 156 acquestCounter = 1; 157 unlock(); 158 } 159 } 160 161 /** 162 * Locks this synchronizer and restores it's state. 163 * Supposed to be used in Toolkit.unsafeInvokeAndWaitUnderAWTLock() only in pair with 164 * storeStateAndFree(). 165 * Do not call it directly. 166 */ 167 public void lockAndRestoreState() { 168 synchronized (this) { 169 Thread curThread = Thread.currentThread(); 170 171 if (owner == curThread) { 172 // awt.24=Owner can't overwrite resource state. Lock operations may be lost. 173 throw new RuntimeException( 174 Messages.getString("awt.24")); //$NON-NLS-1$ 175 } 176 if (!storedStates.containsKey(curThread)) { 177 // awt.25=No state stored for current thread. 178 throw new RuntimeException(Messages.getString("awt.25")); //$NON-NLS-1$ 179 } 180 181 lock(); 182 acquestCounter = storedStates.get(curThread).intValue(); 183 storedStates.remove(curThread); 184 } 185 } 186 187 /** 188 * Sets references to WTK and event dispatch thread. 189 * Called on toolkit startup. 190 * 191 * @param wtk - reference to WTK instance 192 * @param dispatchThread - reference to event dispatch thread 193 */ 194 public void setEnvironment(WTK wtk, Thread dispatchThread) { 195 synchronized (this) { 196 this.dispatchThread = dispatchThread; 197 } 198 } 199 200} 201