/*******************************************************************************
* Copyright 2014,
* Luis Pina <luis@luispina.me>,
* Michael Hicks <mwh@cs.umd.edu>
*
* This file is part of Rubah.
*
* Rubah is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Rubah is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Rubah. If not, see <http://www.gnu.org/licenses/>.
*******************************************************************************/
package rubah.runtime;
import java.io.IOException;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import rubah.RubahException;
import rubah.RubahThread;
import rubah.runtime.classloader.RubahClassloader;
import rubah.runtime.state.Installer;
import rubah.runtime.state.NotUpdating;
import rubah.runtime.state.Options;
import rubah.runtime.state.RubahState;
public class RubahRuntime {
private static RubahState state = new NotUpdating();
private static RubahClassloader loader;
private static ReadWriteLock lock = new ReentrantReadWriteLock();
protected static void changeState(RubahState newState) {
if (newState != null) {
lock.writeLock().lock();;
try {
state = newState;
} finally {
lock.writeLock().unlock();
}
System.out.println("Changing state to " + newState);
changeState(state.start());
}
}
// Not synchronized but concurrent.
// However, missing an update point is benign:
// - Thread is running, it will reach the update point again in the future
// - Thread is blocked, it was interrupted and that creates an happens-before
// - Thread is running but will block immediately after:
// - To block, must acquire monitor, which creates an happens-before
// - Then, must query current state about a possible requested update
// - So, the blocking call fails and the thread reaches the next update point
public static void update(String updatePoint) {
lock.readLock().lock();
try {
state.update(updatePoint);
} finally {
lock.readLock().unlock();
}
// // This yield helps breaking tight loops calling update,
// // which may never see the state changing due to it being cached
// Thread.yield();
}
public static void installNewVersion(final Options options) {
changeState(state.installUpdate(new Installer() {
@Override
public void installVersion() throws IOException {
VersionManager.getInstance().installVersion(options);
}
}, options));
}
public static void installV0V0(final Options options) {
changeState(state.installUpdate(new Installer() {
@Override
public void installVersion() throws IOException {
VersionManager.getInstance().installV0V0(options);
}
}, options));
}
public static void registerRunningThread(RubahThread t) {
lock.readLock().lock();
try {
state.registerRunningThread(t);
} finally {
lock.readLock().unlock();
}
}
public static void deregisterRunningThread(RubahThread t) {
deregisterRunningThread(t, null);
}
public static void deregisterRunningThread(
RubahThread t, RubahException e) {
lock.readLock().lock();
try {
state.deregisterRunningThread(t, e);
} finally {
lock.readLock().unlock();
}
}
public static boolean isUpdateRequested() {
lock.readLock().lock();
try {
return state.isUpdateRequested();
} finally {
lock.readLock().unlock();
}
}
public static boolean isUpdating() {
lock.readLock().lock();
try {
return state.isUpdating();
} finally {
lock.readLock().unlock();
}
}
public static void setRubahClassloader(RubahClassloader rubahloader) {
loader = rubahloader;
}
public static RubahClassloader getLoader() {
return loader ;
}
public static void redirectThreadAfterUpdate(RubahThread t0, RubahThread t1) {
state.redirectThread(t0, t1);
}
public static void ensureStaticFieldsMigrated(Class<?> c) {
state.ensureStaticFieldsMigrated(c);
}
public static Object getConverted(Object pre) {
Object ret = state.getConverted(pre);
return ret;
}
public static byte[] getClassBytes(String className) throws IOException {
return state.getClassBytes(className);
}
}