`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)
"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
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> ()
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`.
"""
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;
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());
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));
}
}
}
}
}
+
+ 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);
+ }
+ }
+ }
}
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();
}
--- /dev/null
+/*******************************************************************************
+ * 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