X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.simulation.sequences%2Fsrc%2Forg%2Fsimantics%2Fsimulation%2Fsequences%2Faction%2FAbstractActionContext.java;fp=bundles%2Forg.simantics.simulation.sequences%2Fsrc%2Forg%2Fsimantics%2Fsimulation%2Fsequences%2Faction%2FAbstractActionContext.java;h=4cba91d066e900a3c58f4c33fd4521960a5de5e1;hp=0000000000000000000000000000000000000000;hb=969bd23cab98a79ca9101af33334000879fb60c5;hpb=866dba5cd5a3929bbeae85991796acb212338a08 diff --git a/bundles/org.simantics.simulation.sequences/src/org/simantics/simulation/sequences/action/AbstractActionContext.java b/bundles/org.simantics.simulation.sequences/src/org/simantics/simulation/sequences/action/AbstractActionContext.java new file mode 100644 index 000000000..4cba91d06 --- /dev/null +++ b/bundles/org.simantics.simulation.sequences/src/org/simantics/simulation/sequences/action/AbstractActionContext.java @@ -0,0 +1,115 @@ +package org.simantics.simulation.sequences.action; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.PriorityQueue; + +import org.simantics.scl.runtime.SCLContext; +import org.simantics.scl.runtime.function.Function1; +import org.simantics.scl.runtime.tuple.Tuple0; + +public abstract class AbstractActionContext implements ActionContext { + public static final double TIME_TOLERANCE = 1e-6; + + double currentTime; + volatile boolean stopped; + ArrayList> scheduledNow = new ArrayList>(); + ArrayList> scheduledNextStep = new ArrayList>(); + PriorityQueue scheduledAt = new PriorityQueue(); + + public List exceptions; + + private static class Task implements Comparable { + final double time; + final Function1 continuation; + + public Task(double time, Function1 continuation) { + this.time = time; + this.continuation = continuation; + } + + @Override + public int compareTo(Task o) { + return Double.compare(time, o.time); + } + } + + @Override + public double time() { + return currentTime; + } + + @Override + public void scheduleNow(Function1 continuation) { + scheduledNow.add(continuation); + } + + @Override + public void scheduleNextStep(Function1 continuation) { + scheduledNextStep.add(continuation); + } + + @Override + public void scheduleAt(double time, Function1 continuation) { + if(time <= currentTime) + scheduleNow(continuation); + else + scheduledAt.add(new Task(time, continuation)); + } + + @Override + public void stop() { + stopped = true; + } + + public boolean isStopped() { + synchronized (this) { + return stopped || (scheduledNextStep.isEmpty() && scheduledAt.isEmpty()); + } + } + + public double handleStep(double currentTime) { + synchronized (this) { + this.currentTime = currentTime; + { + ArrayList> temp = scheduledNow; + scheduledNow = scheduledNextStep; + scheduledNextStep = temp; + Collections.reverse(scheduledNow); + } + + SCLContext context = SCLContext.getCurrent(); + Object oldActionContext = context.put("sequenceAction", this); + try { + Task firstTask = scheduledAt.peek(); + while(true) { + while(!scheduledNow.isEmpty()) { + try { + Function1 currentContinuation = scheduledNow.remove(scheduledNow.size()-1); + currentContinuation.apply(Tuple0.INSTANCE); + currentContinuation = null; + } catch (Exception e) { + if (this.exceptions == null) + this.exceptions = new ArrayList(); + this.exceptions.add(new RuntimeException("Action failure at " + currentTime + ": " + e.getMessage(), e)); + } + } + if(firstTask == null) + return Double.POSITIVE_INFINITY; + else if(firstTask.time > currentTime+TIME_TOLERANCE) + return firstTask.time; + else { + firstTask.continuation.apply(Tuple0.INSTANCE); + synchronized (this) { + scheduledAt.remove(); + } + firstTask = scheduledAt.peek(); + } + } + } finally { + context.put("sequenceAction", oldActionContext); + } + } + } +}