package org.jerlang.vm; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.jerlang.Process; import org.jerlang.ProcessRegistry; import org.jerlang.erts.erlang.Error; import org.jerlang.type.Atom; import org.jerlang.type.Fun; import org.jerlang.type.List; import org.jerlang.type.PID; import org.jerlang.type.PortID; import org.jerlang.type.Term; import org.jerlang.type.TimerReference; import org.jerlang.type.Tuple; /** * */ public class VirtualMachine { private Scheduler[] schedulers; private volatile int nextScheduler = 0; private static final AtomicInteger nextPID = new AtomicInteger(); private ScheduledThreadPoolExecutor timerExecutor; private static final VirtualMachine VIRTUAL_MACHINE = new VirtualMachine(); private VirtualMachine() { int processors = Runtime.getRuntime().availableProcessors(); schedulers = new Scheduler[processors]; for (int index = 0; index < processors; index++) { schedulers[index] = new Scheduler(); } timerExecutor = new ScheduledThreadPoolExecutor(processors); } public Term cancel(TimerReference timerReference) { timerReference.future().cancel(false); return Tuple.of(Atom.of("ok"), Atom.of("cancel")); } public static Process self() { return (Process) ProcessRegistry.self(); } public void start() { int processors = Runtime.getRuntime().availableProcessors(); schedulers = new Scheduler[processors]; for (int index = 0; index < processors; index++) { schedulers[index] = new Scheduler(); schedulers[index].start(); } timerExecutor = new ScheduledThreadPoolExecutor(processors); ProcessRegistry.instance().cleanup(); } public void shutdown() { for (Scheduler scheduler : schedulers) { scheduler.interrupt(); } for (Scheduler scheduler : schedulers) { try { scheduler.join(); } catch (InterruptedException e) { e.printStackTrace(); } } ProcessRegistry.instance().cleanup(); } public static VirtualMachine instance() { return VIRTUAL_MACHINE; } public Process resolve(PID pid) { return (Process) ProcessRegistry.resolve(pid); } public TimerReference send_after(int time, Term message, PID pid) { return new TimerReference(timerExecutor.schedule( new Runnable() { @Override public void run() { resolve(pid).send(message); } }, time, TimeUnit.MILLISECONDS)); } public Process spawn(Fun fun) { PID pid = new PID(nextPID.incrementAndGet()); Process process = new Process(pid, fun); ProcessRegistry.register(process); // Round-robin process assignment schedulers[nextScheduler++ % schedulers.length].add(process); return process; } public Process spawn(Atom module, Atom fun, List args) { PID pid = new PID(nextPID.incrementAndGet()); Process process = new Process(pid, module, fun, args); ProcessRegistry.register(process); // Round-robin process assignment schedulers[nextScheduler++ % schedulers.length].add(process); return process; } public PortID spawn_port(Term command, List portSettings) { throw new Error("not implemented"); } public PortID spawn_driver_port(Term command, List portSettings) { throw new Error("not implemented"); } public PortID spawn_executable_port(Term fileName, List portSettings) { throw new Error("not implemented"); } }