package jetbrains.mps.testbench.util;
/*Generated by MPS */
import java.util.regex.Pattern;
import gnu.trove.TLongObjectHashMap;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.lang.management.ManagementFactory;
/**
* fyodor, Sep 8, 2010
*/
public class ThreadWatcher implements Output {
private ThreadWatcher.ThreadState myState;
private String myErrors;
private String myDescription = "threads difference";
private static class ThreadState {
private static Pattern IGNORED_THREAD = Pattern.compile("(AWT\\-.*)|(Image Fetch.*)|(Progress Cancel Checker)|(Flushing thread)" + "|(Keep\\-Alive.*)|(Finalizer.*)|(MPS interrupting thread)" + "|(caret blinker.*)|(ApplicationImpl.*)|(AnimatorThread)" + "|(MPS EDT Executor Thread.*)|(ChangesManager command queue)|(TimerQueue)" + "|(Change List.*)|(Reference.*)|(Periodic task.*)" + "|(Java2D.*)|(LowMemoryWatcher janitor)|(Timer\\-.*)|(FS Sync.*)" + "|(timed reference disposer)|(Alarm pool\\(own\\))|(Alarm pool\\(shared\\))" + "|(Poller SunPKCS11-Darwin)|(MPS interrupt.*)|(process reaper)" + "|(RefCountingStorage.*)|(Encoding detection thread)" + "|(ProcessWaitFor: .*git(\\.exe)?.*)|(BaseDataReader: error stream of .*git(\\.exe)?.*)" + "|(BaseDataReader: output stream of .*git(\\.exe)?.*)" + "|(Process I/O pool [0-9]+)");
private TLongObjectHashMap<ThreadInfo> myAllThreads = new TLongObjectHashMap<ThreadInfo>();
private TLongObjectHashMap<ThreadInfo> myRunningThreads = new TLongObjectHashMap<ThreadInfo>();
private ThreadState() {
}
private void captureState() {
myAllThreads.clear();
myRunningThreads.clear();
long cid = Thread.currentThread().getId();
ThreadMXBean bean = ManagementFactory.getThreadMXBean();
for (ThreadInfo info : bean.getThreadInfo(bean.getAllThreadIds())) {
if (info != null && cid != info.getThreadId() && info.getThreadState() != Thread.State.NEW && info.getThreadState() != Thread.State.TERMINATED && !(IGNORED_THREAD.matcher(info.getThreadName()).matches())) {
myAllThreads.put(info.getThreadId(), info);
if (Thread.State.RUNNABLE == info.getThreadState()) {
myRunningThreads.put(info.getThreadId(), info);
}
}
}
}
public void dump(StringBuilder sb, String pref) {
String sep = "";
for (long id : myRunningThreads.keys()) {
sb.append(sep).append(pref).append("Running thread ").append(id).append(" \"").append(myRunningThreads.get(id).getThreadName()).append("\"");
sep = "\n";
}
for (long id : myAllThreads.keys()) {
if (!(myRunningThreads.contains(id))) {
sb.append(sep).append(pref).append("Inactive thread ").append(id).append(" \"").append(myAllThreads.get(id).getThreadName()).append("\"");
sep = "\n";
}
}
}
public ThreadWatcher.ThreadState[] diff(ThreadWatcher.ThreadState baseLine) {
ThreadWatcher.ThreadState newDiff = new ThreadWatcher.ThreadState();
ThreadWatcher.ThreadState oldDiff = new ThreadWatcher.ThreadState();
for (long id : this.myAllThreads.keys()) {
if (!((baseLine.myAllThreads.containsKey(id)))) {
newDiff.myAllThreads.put(id, this.myAllThreads.get(id));
if (this.myRunningThreads.containsKey(id)) {
newDiff.myRunningThreads.put(id, myRunningThreads.get(id));
}
}
}
for (long id : baseLine.myAllThreads.keys()) {
if (!((this.myAllThreads.containsKey(id)))) {
oldDiff.myAllThreads.put(id, baseLine.myAllThreads.get(id));
if (baseLine.myRunningThreads.containsKey(id)) {
oldDiff.myRunningThreads.put(id, baseLine.myRunningThreads.get(id));
}
}
}
for (long id : this.myRunningThreads.keys()) {
if (!((baseLine.myRunningThreads.containsKey(id)))) {
newDiff.myRunningThreads.put(id, this.myRunningThreads.get(id));
newDiff.myAllThreads.put(id, this.myAllThreads.get(id));
}
}
for (long id : baseLine.myRunningThreads.keys()) {
if (!((this.myRunningThreads.containsKey(id)))) {
oldDiff.myRunningThreads.put(id, baseLine.myRunningThreads.get(id));
oldDiff.myAllThreads.put(id, baseLine.myAllThreads.get(id));
}
}
return new ThreadWatcher.ThreadState[]{newDiff, oldDiff};
}
}
public ThreadWatcher(boolean capture) {
if (capture) {
this.myState = new ThreadWatcher.ThreadState();
myState.captureState();
}
}
@Override
public boolean isNotEmpty() {
return myErrors != null;
}
@Override
public String getDescription() {
return myDescription;
}
@Override
public String getText() {
return myErrors;
}
public boolean waitUntilSettled(long millis) {
if (myState == null) {
return true;
}
if (myErrors != null) {
throw new IllegalStateException("Settled already");
}
ThreadWatcher.ThreadState current = new ThreadWatcher.ThreadState();
ThreadWatcher.ThreadState[] diff;
long step = 100;
long leftMillis = millis;
do {
current.captureState();
diff = current.diff(myState);
if (diff[0].myAllThreads.isEmpty() && diff[1].myAllThreads.isEmpty()) {
return true;
}
if (diff[0].myAllThreads.isEmpty()) {
break;
}
try {
Thread.sleep(step);
} catch (InterruptedException ignore) {
}
leftMillis -= step;
} while (leftMillis >= 0);
StringBuilder sb = new StringBuilder();
sb.append("After ").append(millis).append(" ms. --\n");
StringBuilder sb2 = new StringBuilder();
String sep2 = "";
String pr2 = "no";
if (!(diff[0].myAllThreads.isEmpty())) {
sb2.append(String.valueOf(diff[0].myAllThreads.size())).append(" new");
sep2 = ", ";
pr2 = "";
sb.append(" New:\n");
diff[0].dump(sb, " ");
sb.append("\n");
}
if (!(diff[1].myAllThreads.isEmpty())) {
sb2.append(sep2).append(String.valueOf(diff[1].myAllThreads.size())).append(" killed");
pr2 = "";
sb.append(" Killed:\n");
diff[1].dump(sb, " ");
sb.append("\n");
}
sb2.append(pr2).append(" threads");
this.myDescription = sb2.toString();
this.myErrors = sb.toString();
return false;
}
}