static L evalWithTimeout_running = synchroList(); static Set evalWithTimeout_zombieThreads = synchroWeakHashSet(); // Either calculation result or Thread with timed-out computation // Tries to interrupt thread after timeout static Either evalWithTimeout(int timeoutMS, fO r) { final new Flag done; final new Flag doneWaiting; final new Var var; final new Var error; Thread t = startThread(r { try { try { var.set(callF(r)); } finally { evalWithTimeout_zombieThreads.remove(this); } } catch e { error.set(e); if (doneWaiting.isUp()) printStackTrace(e); } done.raise(); }); evalWithTimeout_running.add(t); try { done.waitUntilUp(timeoutMS); doneWaiting.raise(); // timeout! cancel/interrupt and return thread object if (!done.isUp()) { evalWithTimeout_running.remove(t); evalWithTimeout_zombieThreads.add(t); cancelAndInterruptThread(t); ret either2(t); } // thread ended with error if (error! != null) rethrow(error!); // thread ended naturally ret either1(var!); } finally { evalWithTimeout_running.remove(t); } } static Either evalWithTimeout(double timeoutSeconds, fO r) { ret evalWithTimeout(toMS_int(timeoutSeconds), r); }