OSDN Git Service

auto import from //depot/cupcake/@132589
[android-x86/frameworks-native.git] / awt / org / apache / harmony / awt / wtk / Synchronizer.java
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  */
21 package org.apache.harmony.awt.wtk;
22
23 import java.util.Hashtable;
24 import java.util.LinkedList;
25
26 import 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
37 public 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 }