From 8d1b4f05e2b2302ad9dabc74f54bd45997ab3a4b Mon Sep 17 00:00:00 2001 From: Tuukka Lehtonen Date: Fri, 20 Sep 2019 14:17:46 +0300 Subject: [PATCH] Allow simulation stop handling in Simantics/Sequences `StopReason` enumerates supported reasons for simulation stops which is delivered once to functions registered through `executeWhenStopped`. It is up to the domain-specific sequence runners to implement the actual identification of simulation stopping situations and to invoke AbstractActionContext.stop(StopReason reason) when needed. gitlab #385 Change-Id: I2bc354b3bf433909c5224f82c98c17b1ec564920 (cherry picked from commit 2dd0e97bbe55e691d86a4254e1495ebddd7d494a) --- .../scl/Simantics/Sequences.scl | 12 +++++ .../action/AbstractActionContext.java | 46 +++++++++++++--- .../sequences/action/ActionContext.java | 1 + .../sequences/action/StopReason.java | 53 +++++++++++++++++++ 4 files changed, 106 insertions(+), 6 deletions(-) create mode 100644 bundles/org.simantics.simulation.sequences/src/org/simantics/simulation/sequences/action/StopReason.java diff --git a/bundles/org.simantics.simulation.sequences/scl/Simantics/Sequences.scl b/bundles/org.simantics.simulation.sequences/scl/Simantics/Sequences.scl index b2f9ba5fc..e84ca6195 100644 --- a/bundles/org.simantics.simulation.sequences/scl/Simantics/Sequences.scl +++ b/bundles/org.simantics.simulation.sequences/scl/Simantics/Sequences.scl @@ -5,6 +5,13 @@ effect Action "sequenceAction" "org.simantics.simulation.sequences.action.ActionContext" +importJava "org.simantics.simulation.sequences.action.StopReason" where + data StopReason + STOPPED :: StopReason + SIMULATION_DID_NOT_START :: StopReason + DIVERGED :: StopReason + INTERRUPTED :: StopReason + importJava "org.simantics.simulation.sequences.action.ActionContext" where data ActionContext @@ -21,6 +28,7 @@ importJava "org.simantics.simulation.sequences.action.ActionContext" where scheduleNow :: (() -> a) -> () scheduleNextStep :: (() -> a) -> () scheduleAt :: Double -> (() -> a) -> () + scheduleWhenStopped :: (StopReason -> a) -> () @JavaName stop stop_ :: () @@ -62,6 +70,10 @@ The sequence `execute action` is an instantious sequence that executes the opera execute :: ( a) -> Sequence a execute action = Sequence (\cont -> cont action) +@inline +executeWhenStopped :: (StopReason -> a) -> Sequence () +executeWhenStopped handler = execute (scheduleWhenStopped handler) + """ The sequence `fork seq` is an instantious sequence that creates a new sequence thread behaving like the sequence `seq`. """ 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 index 4fabd2243..2adb9a045 100644 --- 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 @@ -14,9 +14,10 @@ public abstract class AbstractActionContext implements ActionContext { double currentTime; volatile boolean stopped; - ArrayList> scheduledNow = new ArrayList>(); - ArrayList> scheduledNextStep = new ArrayList>(); - PriorityQueue scheduledAt = new PriorityQueue(); + ArrayList> scheduledNow = new ArrayList<>(); + ArrayList> scheduledNextStep = new ArrayList<>(); + ArrayList> scheduledWhenStopped = new ArrayList<>(); + PriorityQueue scheduledAt = new PriorityQueue<>(); public List exceptions; @@ -57,12 +58,22 @@ public abstract class AbstractActionContext implements ActionContext { else scheduledAt.add(new Task(time, continuation)); } - + + @Override + public void scheduleWhenStopped(Function1 continuation) { + scheduledWhenStopped.add(continuation); + } + @Override public void stop() { + stop(StopReason.STOPPED); + } + + public void stop(StopReason reason) { stopped = true; + handleStop(reason); } - + public boolean isStopped() { synchronized (this) { return stopped || (scheduledNextStep.isEmpty() && scheduledAt.isEmpty()); @@ -91,7 +102,7 @@ public abstract class AbstractActionContext implements ActionContext { currentContinuation = null; } catch (Exception e) { if (this.exceptions == null) - this.exceptions = new ArrayList(); + this.exceptions = new ArrayList<>(); this.exceptions.add(new RuntimeException("Action failure at " + currentTime + ": " + e.getMessage(), e)); } } @@ -112,4 +123,27 @@ public abstract class AbstractActionContext implements ActionContext { } } } + + private void handleStop(StopReason reason) { + synchronized (this) { + List> stopFunctions = new ArrayList<>(scheduledWhenStopped); + scheduledWhenStopped.clear(); + + SCLContext context = SCLContext.getCurrent(); + Object oldActionContext = context.put("sequenceAction", this); + try { + stopFunctions.forEach(f -> { + try { + f.apply(reason); + } catch (Exception e) { + if (this.exceptions == null) + this.exceptions = new ArrayList<>(); + this.exceptions.add(new RuntimeException("Stop action failure at " + currentTime + ": " + e.getMessage(), e)); + } + }); + } finally { + context.put("sequenceAction", oldActionContext); + } + } + } } diff --git a/bundles/org.simantics.simulation.sequences/src/org/simantics/simulation/sequences/action/ActionContext.java b/bundles/org.simantics.simulation.sequences/src/org/simantics/simulation/sequences/action/ActionContext.java index d5b64762e..f03c938a7 100644 --- a/bundles/org.simantics.simulation.sequences/src/org/simantics/simulation/sequences/action/ActionContext.java +++ b/bundles/org.simantics.simulation.sequences/src/org/simantics/simulation/sequences/action/ActionContext.java @@ -11,5 +11,6 @@ public interface ActionContext { void scheduleNow(Function1 continuation); void scheduleNextStep(Function1 continuation); void scheduleAt(double time, Function1 continuation); + void scheduleWhenStopped(Function1 continuation); void stop(); } diff --git a/bundles/org.simantics.simulation.sequences/src/org/simantics/simulation/sequences/action/StopReason.java b/bundles/org.simantics.simulation.sequences/src/org/simantics/simulation/sequences/action/StopReason.java new file mode 100644 index 000000000..3a038c800 --- /dev/null +++ b/bundles/org.simantics.simulation.sequences/src/org/simantics/simulation/sequences/action/StopReason.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2019 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Semantum Oy - initial API and implementation + *******************************************************************************/ +package org.simantics.simulation.sequences.action; + +/** + * Reasons for why a simulation sequence stops. + * + *

+ * {@link ActionContext#scheduleWhenStopped(org.simantics.scl.runtime.function.Function1)} + * allows sequences to handle stop reasons. + * + * @author Tuukka Lehtonen + * @since 1.41.0, 1.35.2 + */ +public enum StopReason { + /** + * Appropriately stopped by the sequence itself. This is the normal course of + * action if the everything works as intended. All the other enumerated cases + * are exceptional situations marking some kind of failure to complete the + * sequence normally. + */ + STOPPED, + + /** + * Means simulation did not commence at all for some reason. + * A few possible reasons for failure are: + *

    + *
  • Incompatible solver and model
  • + *
  • Missing required files or other dependencies such as dynamic libraries
  • + *
  • License issues
  • + *
+ */ + SIMULATION_DID_NOT_START, + + /** + * Simulation diverged before reaching its specified end. + */ + DIVERGED, + + /** + * Client or some other party abruptly interrupted the sequence. + */ + INTERRUPTED, +} \ No newline at end of file -- 2.47.1