Allow simulation stop handling in Simantics/Sequences 72/3272/2
authorTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Fri, 20 Sep 2019 11:17:46 +0000 (14:17 +0300)
committerTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Fri, 20 Sep 2019 11:35:23 +0000 (14:35 +0300)
`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

bundles/org.simantics.simulation.sequences/scl/Simantics/Sequences.scl
bundles/org.simantics.simulation.sequences/src/org/simantics/simulation/sequences/action/AbstractActionContext.java
bundles/org.simantics.simulation.sequences/src/org/simantics/simulation/sequences/action/ActionContext.java
bundles/org.simantics.simulation.sequences/src/org/simantics/simulation/sequences/action/StopReason.java [new file with mode: 0644]

index b2f9ba5fcb99ef1eaaa3ccf32274b64de356f8cf..e84ca61953d53eba37c1eee7a4d7bc0f1efcc9c0 100644 (file)
@@ -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 :: (() -> <Action,Proc> a) -> <Action> ()
     scheduleNextStep :: (() -> <Action,Proc> a) -> <Action> ()
     scheduleAt :: Double -> (() -> <Action,Proc> a) -> <Action> ()
+    scheduleWhenStopped :: (StopReason -> <Action,Proc> a) -> <Action> ()
     @JavaName stop
     stop_ :: <Action> ()
 
@@ -62,6 +70,10 @@ The sequence `execute action` is an instantious sequence that executes the opera
 execute :: (<Action,Proc> a) -> Sequence a
 execute action = Sequence (\cont -> cont action)
 
+@inline
+executeWhenStopped :: (StopReason -> <Action,Proc> 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`.
 """
index 4fabd2243c98dedea07bb50de9dd9ac6b099270c..2adb9a045cf8a06fb525124b1a109b73f2163559 100644 (file)
@@ -14,9 +14,10 @@ public abstract class AbstractActionContext implements ActionContext {
     
     double currentTime;
     volatile boolean stopped;
-    ArrayList<Function1<Tuple0, Object>> scheduledNow = new ArrayList<Function1<Tuple0, Object>>();
-    ArrayList<Function1<Tuple0, Object>> scheduledNextStep = new ArrayList<Function1<Tuple0, Object>>();
-    PriorityQueue<Task> scheduledAt = new PriorityQueue<Task>();
+    ArrayList<Function1<Tuple0, Object>> scheduledNow = new ArrayList<>();
+    ArrayList<Function1<Tuple0, Object>> scheduledNextStep = new ArrayList<>();
+    ArrayList<Function1<StopReason, Object>> scheduledWhenStopped = new ArrayList<>();
+    PriorityQueue<Task> scheduledAt = new PriorityQueue<>();
 
        public List<Exception> exceptions; 
     
@@ -57,12 +58,22 @@ public abstract class AbstractActionContext implements ActionContext {
         else
             scheduledAt.add(new Task(time, continuation));
     }
-    
+
+    @Override
+    public void scheduleWhenStopped(Function1<StopReason, Object> 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<Exception>();
+                                               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<Function1<StopReason, Object>> 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);
+            }
+        }
+    }
 }
index d5b64762e096029f666e6c4d5bd25b23ab312424..f03c938a78a02748c6723dfa066c42edc7a7c984 100644 (file)
@@ -11,5 +11,6 @@ public interface ActionContext {
     void scheduleNow(Function1<Tuple0,Object> continuation);
     void scheduleNextStep(Function1<Tuple0,Object> continuation);
     void scheduleAt(double time, Function1<Tuple0,Object> continuation);
+    void scheduleWhenStopped(Function1<StopReason,Object> 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 (file)
index 0000000..3a038c8
--- /dev/null
@@ -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.
+ * 
+ * <p>
+ * {@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:
+     * <ul>
+     * <li>Incompatible solver and model</li>
+     * <li>Missing required files or other dependencies such as dynamic libraries</li>
+     * <li>License issues</li>
+     * </ul>
+     */
+    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