/*******************************************************************************
* 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.state;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import rubah.runtime.state.UpdateState.StoppedThread;
public class MigratingControlFlow extends RubahState {
private Map<Thread, String> migrating = new HashMap<>();
private Lock stateLock = new ReentrantLock();
private Condition migratingChanged = this.stateLock.newCondition();
private Condition allMigrated = this.stateLock.newCondition();
private boolean updating = true;
public MigratingControlFlow(UpdateState state) {
super(state);
}
@Override
public void doStart() {
System.out.println("Restarting threads");
this.stateLock.lock();
long time = System.currentTimeMillis();
int nThreads = this.state.getStopped().size();
try {
// Restart stopped threads on new threads
for (StoppedThread stoppedThread : this.state.getStopped()) {
this.startThread(stoppedThread);
}
// Wait for control flow migration to finish
while(!this.migrating.isEmpty()) {
try {
this.migratingChanged.await();
} catch (InterruptedException e) {
continue;
}
}
System.out.println("Control migration finished, notifying threads");
// Program updated, notify all threads to proceed executing the new version
this.state.getStopped().clear();
this.updating = false;
this.allMigrated.signalAll();
} finally {
this.stateLock.unlock();
time = System.currentTimeMillis() - time;
System.out.println("Restarted " + nThreads + " threads in " + time + "ms");
}
}
protected void startThread(StoppedThread stoppedThread) {
Thread t = stoppedThread.thread;
this.migrating.put(t, stoppedThread.updatePoint);
stoppedThread.rubahThread.restart();
}
@Override
public void update(String updatePoint) {
Thread thisThread = Thread.currentThread();
System.out.println("Thread " + thisThread + " reached update point \"" + updatePoint + "\"");
if (updatePoint.equals(this.migrating.get(thisThread))) {
this.stateLock.lock();
try {
this.migrating.remove(thisThread);
this.migratingChanged.signalAll();
while (this.updating) {
try {
this.allMigrated.await();
} catch (InterruptedException e) {
continue;
}
}
} finally {
this.stateLock.unlock();
}
}
System.out.println("Thread " + thisThread + " released");
}
@Override
public boolean isUpdating() {
return this.updating;
}
@Override
public boolean isUpdateRequested() {
return false;
}
}