package org.simantics.interop.scl; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; import org.simantics.scl.runtime.SCLContext; import org.simantics.scl.runtime.function.Function; import org.simantics.scl.runtime.tuple.Tuple0; public class Threads { private static final AtomicInteger threadCount = new AtomicInteger(0); private static final ThreadFactory threadFactory = r -> { Thread t = new Thread(r, "scl-interop-thread-" + threadCount.incrementAndGet()); t.setDaemon(true); return t; }; private static final ScheduledThreadPoolExecutor scheduledExecutor; static { scheduledExecutor = new ScheduledThreadPoolExecutor(2, threadFactory); scheduledExecutor.setMaximumPoolSize(2); } public static void setMaximumPoolSize(int size) { if (size < 2) return; scheduledExecutor.setMaximumPoolSize(size); } @SuppressWarnings({ "rawtypes", "unchecked" }) public static SCLThread runAsync(Function f) { SCLContext context = SCLContext.createDerivedContext(); SCLThread t = new SCLThread(context,f); scheduledExecutor.submit(t); return t; } public static class SCLThread implements Runnable { SCLContext context; Function f; boolean running = false; boolean completed = false; Object returnValue = null; Throwable error; public SCLThread(SCLContext context, Function f) { this.context = context; this.f = f; } @Override public void run() { SCLContext.push(context); running = true; try { returnValue = f.apply(Tuple0.INSTANCE); } catch (Throwable t) { error = t; } finally { SCLContext.pop(); } running = false; completed = true; } public boolean isRunning() { return running; } public boolean isCompleted() { return completed; } public boolean hasErrors() { return error != null; } public Object getReturnValue() { return returnValue; } public Throwable getError() { return error; } } }