blob: 1d0bd852bca2958d562741e42ad8aa033f80281e [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional information regarding
* copyright ownership. The ASF licenses this file to You 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.
*/
package org.apache.geode.distributed.internal.deadlock;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* Most of this thread local is safe to use, except for the getValue(Thread) method. That is not
* guaranteed to be correct. But for our deadlock detection tool I think it's good enough, and this
* class provides a very low overhead way for us to record what thread holds a particular resource.
*
*
*/
public class UnsafeThreadLocal<T> extends ThreadLocal<T> {
/**
* Dangerous method. Uses reflection to extract the thread local for a given thread.
*
* Unlike get(), this method does not set the initial value if none is found
*
*/
public T get(Thread thread) {
return (T) get(this, thread);
}
private static Object get(ThreadLocal threadLocal, Thread thread) {
try {
Object threadLocalMap =
invokePrivate(threadLocal, "getMap", new Class[] {Thread.class}, new Object[] {thread});
if (threadLocalMap != null) {
Object entry = invokePrivate(threadLocalMap, "getEntry", new Class[] {ThreadLocal.class},
new Object[] {threadLocal});
if (entry != null)
return getPrivate(entry, "value");
}
return null;
} catch (Exception e) {
throw new RuntimeException("Unable to extract thread local", e);
}
}
private static Object getPrivate(Object object, String fieldName) throws SecurityException,
NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
Field field = object.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(object);
}
private static Object invokePrivate(Object object, String methodName, Class[] argTypes,
Object[] args) throws SecurityException, NoSuchMethodException, IllegalArgumentException,
IllegalAccessException, InvocationTargetException {
Method method = null;
Class clazz = object.getClass();
while (method == null) {
try {
method = clazz.getDeclaredMethod(methodName, argTypes);
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
if (clazz == null) {
throw e;
}
}
}
method.setAccessible(true);
Object result = method.invoke(object, args);
return result;
}
}