blob: f5bcb4c412c3cbbb22c88898114164d11973ae5a [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
public class RacyMisbehavingLoader extends DefiningLoader {
static {
// For JVM, register as parallel capable.
// Android treats all class loaders as parallel capable and makes this a no-op.
registerAsParallelCapable();
}
private Object lock = new Object();
private int index = 0;
private int count;
private boolean throw_error;
private DefiningLoader[] defining_loaders;
public RacyMisbehavingLoader(ClassLoader parent, int count, boolean throw_error) {
super(parent);
this.count = count;
this.throw_error = throw_error;
defining_loaders = new DefiningLoader[2];
for (int i = 0; i != defining_loaders.length; ++i) {
defining_loaders[i] = new DefiningLoader(parent);
}
}
public void reportAfterLoading() {
synchronized (lock) {
++index;
if (index == 2 * count) {
lock.notifyAll();
}
}
}
protected Class<?> findClass(String name) throws ClassNotFoundException
{
if (name.equals("Test")) {
throw new Error("Unexpected RacyLoader.findClass(\"" + name + "\")");
}
return super.findClass(name);
}
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
if (name.equals("Test")) {
int my_index = syncWithOtherInstances(count);
Class<?> result;
if ((my_index & 1) == 0) {
// Do not delay loading the correct class.
result = defining_loaders[my_index & 1].loadClass(name, resolve);
} else {
// Delay loading the wrong class.
syncWithOtherInstances(2 * count);
if (throw_error) {
throw new Error("RacyMisbehavingLoader throw_error=true");
}
result = defining_loaders[my_index & 1].loadClass("Test3", resolve);
}
return result;
}
return super.loadClass(name, resolve);
}
private int syncWithOtherInstances(int limit) {
int my_index;
synchronized (lock) {
my_index = index;
++index;
if (index != limit) {
do {
try {
lock.wait();
} catch (InterruptedException ie) {
throw new Error(ie);
}
} while (index < limit);
} else {
lock.notifyAll();
}
}
return my_index;
}
}