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