xref: /aosp_15_r20/art/test/jvmti-common/Monitors.java (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2017 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker package art;
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker import java.lang.reflect.Method;
20*795d594fSAndroid Build Coastguard Worker import java.util.concurrent.atomic.*;
21*795d594fSAndroid Build Coastguard Worker import java.util.function.Function;
22*795d594fSAndroid Build Coastguard Worker import java.util.stream.Stream;
23*795d594fSAndroid Build Coastguard Worker import java.util.Arrays;
24*795d594fSAndroid Build Coastguard Worker import java.util.Objects;
25*795d594fSAndroid Build Coastguard Worker 
26*795d594fSAndroid Build Coastguard Worker public class Monitors {
setupMonitorEvents( Class<?> method_klass, Method monitor_contended_enter_event, Method monitor_contended_entered_event, Method monitor_wait_event, Method monitor_waited_event, Class<?> lock_klass, Thread thr)27*795d594fSAndroid Build Coastguard Worker   public native static void setupMonitorEvents(
28*795d594fSAndroid Build Coastguard Worker       Class<?> method_klass,
29*795d594fSAndroid Build Coastguard Worker       Method monitor_contended_enter_event,
30*795d594fSAndroid Build Coastguard Worker       Method monitor_contended_entered_event,
31*795d594fSAndroid Build Coastguard Worker       Method monitor_wait_event,
32*795d594fSAndroid Build Coastguard Worker       Method monitor_waited_event,
33*795d594fSAndroid Build Coastguard Worker       Class<?> lock_klass,
34*795d594fSAndroid Build Coastguard Worker       Thread thr);
stopMonitorEvents()35*795d594fSAndroid Build Coastguard Worker   public native static void stopMonitorEvents();
36*795d594fSAndroid Build Coastguard Worker 
37*795d594fSAndroid Build Coastguard Worker   public static class NamedLock {
38*795d594fSAndroid Build Coastguard Worker     public final String name;
39*795d594fSAndroid Build Coastguard Worker     private volatile int calledNotify;
NamedLock(String name)40*795d594fSAndroid Build Coastguard Worker     public NamedLock(String name) {
41*795d594fSAndroid Build Coastguard Worker       this.name = name;
42*795d594fSAndroid Build Coastguard Worker       calledNotify = 0;
43*795d594fSAndroid Build Coastguard Worker     }
44*795d594fSAndroid Build Coastguard Worker 
toString()45*795d594fSAndroid Build Coastguard Worker     public String toString() {
46*795d594fSAndroid Build Coastguard Worker       return String.format("NamedLock[%s]", name);
47*795d594fSAndroid Build Coastguard Worker     }
48*795d594fSAndroid Build Coastguard Worker 
DoWait()49*795d594fSAndroid Build Coastguard Worker     public final void DoWait() throws Exception {
50*795d594fSAndroid Build Coastguard Worker       final int v = calledNotify;
51*795d594fSAndroid Build Coastguard Worker       while (v == calledNotify) {
52*795d594fSAndroid Build Coastguard Worker         wait();
53*795d594fSAndroid Build Coastguard Worker       }
54*795d594fSAndroid Build Coastguard Worker     }
55*795d594fSAndroid Build Coastguard Worker 
DoWait(long t)56*795d594fSAndroid Build Coastguard Worker     public final void DoWait(long t) throws Exception {
57*795d594fSAndroid Build Coastguard Worker       final int v = calledNotify;
58*795d594fSAndroid Build Coastguard Worker       final long target = System.currentTimeMillis() + (t / 2);
59*795d594fSAndroid Build Coastguard Worker       while (v == calledNotify && (t < 0 || System.currentTimeMillis() < target)) {
60*795d594fSAndroid Build Coastguard Worker         wait(t);
61*795d594fSAndroid Build Coastguard Worker       }
62*795d594fSAndroid Build Coastguard Worker     }
63*795d594fSAndroid Build Coastguard Worker 
DoNotifyAll()64*795d594fSAndroid Build Coastguard Worker     public final void DoNotifyAll() throws Exception {
65*795d594fSAndroid Build Coastguard Worker       calledNotify++;
66*795d594fSAndroid Build Coastguard Worker       notifyAll();
67*795d594fSAndroid Build Coastguard Worker     }
68*795d594fSAndroid Build Coastguard Worker 
DoNotify()69*795d594fSAndroid Build Coastguard Worker     public final void DoNotify() throws Exception {
70*795d594fSAndroid Build Coastguard Worker       calledNotify++;
71*795d594fSAndroid Build Coastguard Worker       notify();
72*795d594fSAndroid Build Coastguard Worker     }
73*795d594fSAndroid Build Coastguard Worker   }
74*795d594fSAndroid Build Coastguard Worker 
75*795d594fSAndroid Build Coastguard Worker   public static final class MonitorUsage {
76*795d594fSAndroid Build Coastguard Worker     public final Object monitor;
77*795d594fSAndroid Build Coastguard Worker     public final Thread owner;
78*795d594fSAndroid Build Coastguard Worker     public final int entryCount;
79*795d594fSAndroid Build Coastguard Worker     public final Thread[] waiters;
80*795d594fSAndroid Build Coastguard Worker     public final Thread[] notifyWaiters;
81*795d594fSAndroid Build Coastguard Worker 
MonitorUsage( Object monitor, Thread owner, int entryCount, Thread[] waiters, Thread[] notifyWaiters)82*795d594fSAndroid Build Coastguard Worker     public MonitorUsage(
83*795d594fSAndroid Build Coastguard Worker         Object monitor,
84*795d594fSAndroid Build Coastguard Worker         Thread owner,
85*795d594fSAndroid Build Coastguard Worker         int entryCount,
86*795d594fSAndroid Build Coastguard Worker         Thread[] waiters,
87*795d594fSAndroid Build Coastguard Worker         Thread[] notifyWaiters) {
88*795d594fSAndroid Build Coastguard Worker       this.monitor = monitor;
89*795d594fSAndroid Build Coastguard Worker       this.entryCount = entryCount;
90*795d594fSAndroid Build Coastguard Worker       this.owner = owner;
91*795d594fSAndroid Build Coastguard Worker       this.waiters = waiters;
92*795d594fSAndroid Build Coastguard Worker       this.notifyWaiters = notifyWaiters;
93*795d594fSAndroid Build Coastguard Worker     }
94*795d594fSAndroid Build Coastguard Worker 
toNameList(Thread[] ts)95*795d594fSAndroid Build Coastguard Worker     private static String toNameList(Thread[] ts) {
96*795d594fSAndroid Build Coastguard Worker       return Arrays.toString(Arrays.stream(ts).map((Thread t) -> t.getName()).toArray());
97*795d594fSAndroid Build Coastguard Worker     }
98*795d594fSAndroid Build Coastguard Worker 
toString()99*795d594fSAndroid Build Coastguard Worker     public String toString() {
100*795d594fSAndroid Build Coastguard Worker       return String.format(
101*795d594fSAndroid Build Coastguard Worker           "MonitorUsage{ monitor: %s, owner: %s, entryCount: %d, waiters: %s, notify_waiters: %s }",
102*795d594fSAndroid Build Coastguard Worker           monitor,
103*795d594fSAndroid Build Coastguard Worker           (owner != null) ? owner.getName() : "<NULL>",
104*795d594fSAndroid Build Coastguard Worker           entryCount,
105*795d594fSAndroid Build Coastguard Worker           toNameList(waiters),
106*795d594fSAndroid Build Coastguard Worker           toNameList(notifyWaiters));
107*795d594fSAndroid Build Coastguard Worker     }
108*795d594fSAndroid Build Coastguard Worker   }
109*795d594fSAndroid Build Coastguard Worker 
getObjectMonitorUsage(Object monitor)110*795d594fSAndroid Build Coastguard Worker   public static native MonitorUsage getObjectMonitorUsage(Object monitor);
getCurrentContendedMonitor(Thread thr)111*795d594fSAndroid Build Coastguard Worker   public static native Object getCurrentContendedMonitor(Thread thr);
112*795d594fSAndroid Build Coastguard Worker 
113*795d594fSAndroid Build Coastguard Worker   public static class TestException extends Error {
TestException()114*795d594fSAndroid Build Coastguard Worker     public TestException() { super(); }
TestException(String s)115*795d594fSAndroid Build Coastguard Worker     public TestException(String s) { super(s); }
TestException(String s, Throwable c)116*795d594fSAndroid Build Coastguard Worker     public TestException(String s, Throwable c) { super(s, c); }
117*795d594fSAndroid Build Coastguard Worker   }
118*795d594fSAndroid Build Coastguard Worker 
119*795d594fSAndroid Build Coastguard Worker   public static class LockController {
120*795d594fSAndroid Build Coastguard Worker     private static enum Action { HOLD, RELEASE, NOTIFY, NOTIFY_ALL, WAIT, TIMED_WAIT }
121*795d594fSAndroid Build Coastguard Worker 
122*795d594fSAndroid Build Coastguard Worker     public final NamedLock lock;
123*795d594fSAndroid Build Coastguard Worker     public final long timeout;
124*795d594fSAndroid Build Coastguard Worker     private final AtomicStampedReference<Action> action;
125*795d594fSAndroid Build Coastguard Worker     private volatile Thread runner = null;
126*795d594fSAndroid Build Coastguard Worker     private volatile boolean started = false;
127*795d594fSAndroid Build Coastguard Worker     private volatile boolean held = false;
128*795d594fSAndroid Build Coastguard Worker     private static final AtomicInteger cnt = new AtomicInteger(0);
129*795d594fSAndroid Build Coastguard Worker     private volatile Throwable exe;
130*795d594fSAndroid Build Coastguard Worker 
LockController(NamedLock lock)131*795d594fSAndroid Build Coastguard Worker     public LockController(NamedLock lock) {
132*795d594fSAndroid Build Coastguard Worker       this(lock, 10 * 1000);
133*795d594fSAndroid Build Coastguard Worker     }
LockController(NamedLock lock, long timeout)134*795d594fSAndroid Build Coastguard Worker     public LockController(NamedLock lock, long timeout) {
135*795d594fSAndroid Build Coastguard Worker       this.lock = lock;
136*795d594fSAndroid Build Coastguard Worker       this.timeout = timeout;
137*795d594fSAndroid Build Coastguard Worker       this.action = new AtomicStampedReference(Action.HOLD, 0);
138*795d594fSAndroid Build Coastguard Worker       this.exe = null;
139*795d594fSAndroid Build Coastguard Worker     }
140*795d594fSAndroid Build Coastguard Worker 
IsWorkerThread(Thread thd)141*795d594fSAndroid Build Coastguard Worker     public boolean IsWorkerThread(Thread thd) {
142*795d594fSAndroid Build Coastguard Worker       return Objects.equals(runner, thd);
143*795d594fSAndroid Build Coastguard Worker     }
144*795d594fSAndroid Build Coastguard Worker 
IsLocked()145*795d594fSAndroid Build Coastguard Worker     public boolean IsLocked() {
146*795d594fSAndroid Build Coastguard Worker       checkException();
147*795d594fSAndroid Build Coastguard Worker       return held;
148*795d594fSAndroid Build Coastguard Worker     }
149*795d594fSAndroid Build Coastguard Worker 
checkException()150*795d594fSAndroid Build Coastguard Worker     public void checkException() {
151*795d594fSAndroid Build Coastguard Worker       if (exe != null) {
152*795d594fSAndroid Build Coastguard Worker         throw new TestException("Exception thrown by other thread!", exe);
153*795d594fSAndroid Build Coastguard Worker       }
154*795d594fSAndroid Build Coastguard Worker     }
155*795d594fSAndroid Build Coastguard Worker 
setAction(Action a)156*795d594fSAndroid Build Coastguard Worker     private void setAction(Action a) {
157*795d594fSAndroid Build Coastguard Worker       int stamp = action.getStamp();
158*795d594fSAndroid Build Coastguard Worker       // Wait for it to be HOLD before updating.
159*795d594fSAndroid Build Coastguard Worker       while (!action.compareAndSet(Action.HOLD, a, stamp, stamp + 1)) {
160*795d594fSAndroid Build Coastguard Worker         stamp = action.getStamp();
161*795d594fSAndroid Build Coastguard Worker       }
162*795d594fSAndroid Build Coastguard Worker     }
163*795d594fSAndroid Build Coastguard Worker 
suspendWorker()164*795d594fSAndroid Build Coastguard Worker     public synchronized void suspendWorker() throws Exception {
165*795d594fSAndroid Build Coastguard Worker       checkException();
166*795d594fSAndroid Build Coastguard Worker       if (runner == null) {
167*795d594fSAndroid Build Coastguard Worker         throw new TestException("We don't have any runner holding  " + lock);
168*795d594fSAndroid Build Coastguard Worker       }
169*795d594fSAndroid Build Coastguard Worker       Suspension.suspend(runner);
170*795d594fSAndroid Build Coastguard Worker     }
171*795d594fSAndroid Build Coastguard Worker 
getWorkerContendedMonitor()172*795d594fSAndroid Build Coastguard Worker     public Object getWorkerContendedMonitor() throws Exception {
173*795d594fSAndroid Build Coastguard Worker       checkException();
174*795d594fSAndroid Build Coastguard Worker       if (runner == null) {
175*795d594fSAndroid Build Coastguard Worker         return null;
176*795d594fSAndroid Build Coastguard Worker       }
177*795d594fSAndroid Build Coastguard Worker       return getCurrentContendedMonitor(runner);
178*795d594fSAndroid Build Coastguard Worker     }
179*795d594fSAndroid Build Coastguard Worker 
DoLock()180*795d594fSAndroid Build Coastguard Worker     public synchronized void DoLock() {
181*795d594fSAndroid Build Coastguard Worker       if (IsLocked()) {
182*795d594fSAndroid Build Coastguard Worker         throw new Error("lock is already acquired or being acquired.");
183*795d594fSAndroid Build Coastguard Worker       }
184*795d594fSAndroid Build Coastguard Worker       if (runner != null) {
185*795d594fSAndroid Build Coastguard Worker         throw new Error("Already have thread!");
186*795d594fSAndroid Build Coastguard Worker       }
187*795d594fSAndroid Build Coastguard Worker       runner = new Thread(() -> {
188*795d594fSAndroid Build Coastguard Worker         started = true;
189*795d594fSAndroid Build Coastguard Worker         try {
190*795d594fSAndroid Build Coastguard Worker           synchronized (lock) {
191*795d594fSAndroid Build Coastguard Worker             held = true;
192*795d594fSAndroid Build Coastguard Worker             int[] stamp_h = new int[] { -1 };
193*795d594fSAndroid Build Coastguard Worker             Action cur_action = Action.HOLD;
194*795d594fSAndroid Build Coastguard Worker             try {
195*795d594fSAndroid Build Coastguard Worker               while (true) {
196*795d594fSAndroid Build Coastguard Worker                 cur_action = action.get(stamp_h);
197*795d594fSAndroid Build Coastguard Worker                 int stamp = stamp_h[0];
198*795d594fSAndroid Build Coastguard Worker                 if (cur_action == Action.RELEASE) {
199*795d594fSAndroid Build Coastguard Worker                   // The other thread will deal with reseting action.
200*795d594fSAndroid Build Coastguard Worker                   break;
201*795d594fSAndroid Build Coastguard Worker                 }
202*795d594fSAndroid Build Coastguard Worker                 try {
203*795d594fSAndroid Build Coastguard Worker                   switch (cur_action) {
204*795d594fSAndroid Build Coastguard Worker                     case HOLD:
205*795d594fSAndroid Build Coastguard Worker                       Thread.yield();
206*795d594fSAndroid Build Coastguard Worker                       break;
207*795d594fSAndroid Build Coastguard Worker                     case NOTIFY:
208*795d594fSAndroid Build Coastguard Worker                       lock.DoNotify();
209*795d594fSAndroid Build Coastguard Worker                       break;
210*795d594fSAndroid Build Coastguard Worker                     case NOTIFY_ALL:
211*795d594fSAndroid Build Coastguard Worker                       lock.DoNotifyAll();
212*795d594fSAndroid Build Coastguard Worker                       break;
213*795d594fSAndroid Build Coastguard Worker                     case TIMED_WAIT:
214*795d594fSAndroid Build Coastguard Worker                       lock.DoWait(timeout);
215*795d594fSAndroid Build Coastguard Worker                       break;
216*795d594fSAndroid Build Coastguard Worker                     case WAIT:
217*795d594fSAndroid Build Coastguard Worker                       lock.DoWait();
218*795d594fSAndroid Build Coastguard Worker                       break;
219*795d594fSAndroid Build Coastguard Worker                     default:
220*795d594fSAndroid Build Coastguard Worker                       throw new Error("Unknown action " + action);
221*795d594fSAndroid Build Coastguard Worker                   }
222*795d594fSAndroid Build Coastguard Worker                 } finally {
223*795d594fSAndroid Build Coastguard Worker                   // reset action back to hold if it isn't something else.
224*795d594fSAndroid Build Coastguard Worker                   action.compareAndSet(cur_action, Action.HOLD, stamp, stamp+1);
225*795d594fSAndroid Build Coastguard Worker                 }
226*795d594fSAndroid Build Coastguard Worker               }
227*795d594fSAndroid Build Coastguard Worker             } catch (Exception e) {
228*795d594fSAndroid Build Coastguard Worker               throw new TestException("Got an error while performing action " + cur_action, e);
229*795d594fSAndroid Build Coastguard Worker             }
230*795d594fSAndroid Build Coastguard Worker           }
231*795d594fSAndroid Build Coastguard Worker         } finally {
232*795d594fSAndroid Build Coastguard Worker           held = false;
233*795d594fSAndroid Build Coastguard Worker           started = false;
234*795d594fSAndroid Build Coastguard Worker         }
235*795d594fSAndroid Build Coastguard Worker       }, "Locker thread " + cnt.getAndIncrement() + " for " + lock);
236*795d594fSAndroid Build Coastguard Worker       // Make sure we can get any exceptions this throws.
237*795d594fSAndroid Build Coastguard Worker       runner.setUncaughtExceptionHandler((t, e) -> { exe = e; });
238*795d594fSAndroid Build Coastguard Worker       runner.start();
239*795d594fSAndroid Build Coastguard Worker     }
240*795d594fSAndroid Build Coastguard Worker 
waitForLockToBeHeld()241*795d594fSAndroid Build Coastguard Worker     public void waitForLockToBeHeld() throws Exception {
242*795d594fSAndroid Build Coastguard Worker       while (true) {
243*795d594fSAndroid Build Coastguard Worker         if (IsLocked() && Objects.equals(runner, Monitors.getObjectMonitorUsage(lock).owner)) {
244*795d594fSAndroid Build Coastguard Worker           return;
245*795d594fSAndroid Build Coastguard Worker         }
246*795d594fSAndroid Build Coastguard Worker       }
247*795d594fSAndroid Build Coastguard Worker     }
248*795d594fSAndroid Build Coastguard Worker 
waitForNotifySleep()249*795d594fSAndroid Build Coastguard Worker     public synchronized void waitForNotifySleep() throws Exception {
250*795d594fSAndroid Build Coastguard Worker       if (runner == null) {
251*795d594fSAndroid Build Coastguard Worker         throw new Error("No thread trying to lock!");
252*795d594fSAndroid Build Coastguard Worker       }
253*795d594fSAndroid Build Coastguard Worker       do {
254*795d594fSAndroid Build Coastguard Worker         checkException();
255*795d594fSAndroid Build Coastguard Worker       } while (!started ||
256*795d594fSAndroid Build Coastguard Worker           !Arrays.asList(Monitors.getObjectMonitorUsage(lock).notifyWaiters).contains(runner));
257*795d594fSAndroid Build Coastguard Worker     }
258*795d594fSAndroid Build Coastguard Worker 
waitForContendedSleep()259*795d594fSAndroid Build Coastguard Worker     public synchronized void waitForContendedSleep() throws Exception {
260*795d594fSAndroid Build Coastguard Worker       if (runner == null) {
261*795d594fSAndroid Build Coastguard Worker         throw new Error("No thread trying to lock!");
262*795d594fSAndroid Build Coastguard Worker       }
263*795d594fSAndroid Build Coastguard Worker       do {
264*795d594fSAndroid Build Coastguard Worker         checkException();
265*795d594fSAndroid Build Coastguard Worker       } while (!started ||
266*795d594fSAndroid Build Coastguard Worker           runner.getState() != Thread.State.BLOCKED ||
267*795d594fSAndroid Build Coastguard Worker           !Arrays.asList(Monitors.getObjectMonitorUsage(lock).waiters).contains(runner));
268*795d594fSAndroid Build Coastguard Worker     }
269*795d594fSAndroid Build Coastguard Worker 
DoNotify()270*795d594fSAndroid Build Coastguard Worker     public synchronized void DoNotify() {
271*795d594fSAndroid Build Coastguard Worker       if (!IsLocked()) {
272*795d594fSAndroid Build Coastguard Worker         throw new Error("Not locked");
273*795d594fSAndroid Build Coastguard Worker       }
274*795d594fSAndroid Build Coastguard Worker       setAction(Action.NOTIFY);
275*795d594fSAndroid Build Coastguard Worker     }
276*795d594fSAndroid Build Coastguard Worker 
DoNotifyAll()277*795d594fSAndroid Build Coastguard Worker     public synchronized void DoNotifyAll() {
278*795d594fSAndroid Build Coastguard Worker       if (!IsLocked()) {
279*795d594fSAndroid Build Coastguard Worker         throw new Error("Not locked");
280*795d594fSAndroid Build Coastguard Worker       }
281*795d594fSAndroid Build Coastguard Worker       setAction(Action.NOTIFY_ALL);
282*795d594fSAndroid Build Coastguard Worker     }
283*795d594fSAndroid Build Coastguard Worker 
DoTimedWait()284*795d594fSAndroid Build Coastguard Worker     public synchronized void DoTimedWait() throws Exception {
285*795d594fSAndroid Build Coastguard Worker       if (!IsLocked()) {
286*795d594fSAndroid Build Coastguard Worker         throw new Error("Not locked");
287*795d594fSAndroid Build Coastguard Worker       }
288*795d594fSAndroid Build Coastguard Worker       setAction(Action.TIMED_WAIT);
289*795d594fSAndroid Build Coastguard Worker     }
290*795d594fSAndroid Build Coastguard Worker 
DoWait()291*795d594fSAndroid Build Coastguard Worker     public synchronized void DoWait() throws Exception {
292*795d594fSAndroid Build Coastguard Worker       if (!IsLocked()) {
293*795d594fSAndroid Build Coastguard Worker         throw new Error("Not locked");
294*795d594fSAndroid Build Coastguard Worker       }
295*795d594fSAndroid Build Coastguard Worker       setAction(Action.WAIT);
296*795d594fSAndroid Build Coastguard Worker     }
297*795d594fSAndroid Build Coastguard Worker 
interruptWorker()298*795d594fSAndroid Build Coastguard Worker     public synchronized void interruptWorker() throws Exception {
299*795d594fSAndroid Build Coastguard Worker       if (!IsLocked()) {
300*795d594fSAndroid Build Coastguard Worker         throw new Error("Not locked");
301*795d594fSAndroid Build Coastguard Worker       }
302*795d594fSAndroid Build Coastguard Worker       runner.interrupt();
303*795d594fSAndroid Build Coastguard Worker     }
304*795d594fSAndroid Build Coastguard Worker 
waitForActionToFinish()305*795d594fSAndroid Build Coastguard Worker     public synchronized void waitForActionToFinish() throws Exception {
306*795d594fSAndroid Build Coastguard Worker       checkException();
307*795d594fSAndroid Build Coastguard Worker       while (action.getReference() != Action.HOLD) { checkException(); }
308*795d594fSAndroid Build Coastguard Worker     }
309*795d594fSAndroid Build Coastguard Worker 
DoUnlock()310*795d594fSAndroid Build Coastguard Worker     public synchronized void DoUnlock() throws Exception {
311*795d594fSAndroid Build Coastguard Worker       Error throwing = null;
312*795d594fSAndroid Build Coastguard Worker       if (!IsLocked()) {
313*795d594fSAndroid Build Coastguard Worker         // We might just be racing some exception that was thrown by the worker thread. Cache the
314*795d594fSAndroid Build Coastguard Worker         // exception, we will throw one from the worker before this one.
315*795d594fSAndroid Build Coastguard Worker         throwing = new Error("Not locked!");
316*795d594fSAndroid Build Coastguard Worker       }
317*795d594fSAndroid Build Coastguard Worker       setAction(Action.RELEASE);
318*795d594fSAndroid Build Coastguard Worker       Thread run = runner;
319*795d594fSAndroid Build Coastguard Worker       runner = null;
320*795d594fSAndroid Build Coastguard Worker       while (held) {}
321*795d594fSAndroid Build Coastguard Worker       run.join();
322*795d594fSAndroid Build Coastguard Worker       action.set(Action.HOLD, 0);
323*795d594fSAndroid Build Coastguard Worker       // Make sure to throw any exception that occurred since it might not have unlocked due to our
324*795d594fSAndroid Build Coastguard Worker       // request.
325*795d594fSAndroid Build Coastguard Worker       checkException();
326*795d594fSAndroid Build Coastguard Worker       DoCleanup();
327*795d594fSAndroid Build Coastguard Worker       if (throwing != null) {
328*795d594fSAndroid Build Coastguard Worker         throw throwing;
329*795d594fSAndroid Build Coastguard Worker       }
330*795d594fSAndroid Build Coastguard Worker     }
331*795d594fSAndroid Build Coastguard Worker 
DoCleanup()332*795d594fSAndroid Build Coastguard Worker     public synchronized void DoCleanup() throws Exception {
333*795d594fSAndroid Build Coastguard Worker       if (runner != null) {
334*795d594fSAndroid Build Coastguard Worker         Thread run = runner;
335*795d594fSAndroid Build Coastguard Worker         runner = null;
336*795d594fSAndroid Build Coastguard Worker         while (held) {}
337*795d594fSAndroid Build Coastguard Worker         run.join();
338*795d594fSAndroid Build Coastguard Worker       }
339*795d594fSAndroid Build Coastguard Worker       action.set(Action.HOLD, 0);
340*795d594fSAndroid Build Coastguard Worker       exe = null;
341*795d594fSAndroid Build Coastguard Worker     }
342*795d594fSAndroid Build Coastguard Worker   }
343*795d594fSAndroid Build Coastguard Worker }
344*795d594fSAndroid Build Coastguard Worker 
345