/** * Returns, and if necessary creates, the submodule interpreter actor for the given submodule. * * <p>A submodule interpreter actor is created at most once during the lifetime of the current * actor. If the submodule actor is created, it will be supervised by the current actor. * * <p>This method starts one asynchronous action for each out-port of the submodule that satisfies * {@link #isOutPortNeeded(RuntimeOutPort)}; these will be finished in {@link * #submoduleOutPortNoLongerNeeded}. This prevents this actor from terminating even though a child * interpreter may still send values for out-ports. * * <p>One additional asynchronous action is started for the child actor, which will be finished in * {@link #childActorTerminated(ActorRef)}. * * @param submodule submodule * @return reference to the submodule actor */ private ActorRef getChildExecutor(RuntimeModule submodule) { assert state == State.REPLAY || state == State.RUNNING || state == State.ALL_OUTPUTS; int submoduleId = submodule.getIndex(); if (childExecutors[submoduleId] == null) { List<SubmoduleInPortNode> submoduleInPortNodes = dependencyGraph.submodulesInPortNodes().get(submoduleId); ImmutableList<HasValue> submoduleInPortHasValueList = submoduleInPortNodes .stream() .map(SubmoduleInPortNode::getHasValue) .collect(ImmutableList.collector()); BitSet submoduleRecomputedInPorts = new BitSet(submodule.getInPorts().size()); submoduleInPortNodes .stream() .filter(node -> node.getPortState() == PortState.RECOMPUTE) .forEach(node -> submoduleRecomputedInPorts.set(node.getElement().getInIndex())); BitSet submoduleRequestedOutPorts = computeResumeState.getSubmodulesNeededOutPorts()[submoduleId]; submoduleRequestedOutPorts .stream() .mapToObj(id -> submodule.getOutPorts().get(id)) .forEach( outPort -> startAsynchronousAction( outPort, "waiting for value to pass through submodule out-port %s#%s", submodule.getSimpleName(), outPort.getSimpleName())); childExecutors[submoduleId] = getContext() .actorOf( interpreterPropsProvider.provideInterpreterProps( getInterpreterProperties(), stagingArea.resolveDescendant( ExecutionTrace.empty() .resolveContent() .resolveModule(submodule.getSimpleName())), submoduleId, submoduleInPortHasValueList, submoduleRecomputedInPorts, submoduleRequestedOutPorts), submodule.getSimpleName().toString()); getContext().watch(childExecutors[submoduleId]); childActorMap.put(childExecutors[submoduleId], submodule); startAsynchronousAction( childExecutors[submoduleId], "supervising interpreter for submodule %s", submodule.getSimpleName()); } return childExecutors[submoduleId]; }
/** * Starts the interpretation of the current parent module if algorithm ComputeResumeState has * finished. * * <p>This method sets the state of this actor to {@link State#RUNNING} and thus also finished the * asynchronous action that was started in {@link #preStart()}. */ private void startRunningIfQueueEmpty() { assert state == State.STARTING; if (!computeResumeState.isFinished()) { return; } // Trigger in-ports initialInPortsTrigger(); state = State.RUNNING; // Start child interpreters for all submodules that have at least one in-port whose state is // READY submodules: for (List<SubmoduleInPortNode> submoduleInPortNodes : dependencyGraph.submodulesInPortNodes()) { for (SubmoduleInPortNode submoduleInPortNode : submoduleInPortNodes) { if (submoduleInPortNode.getPortState() == PortState.READY) { getChildExecutor(submoduleInPortNode.getElement().getModule()); continue submodules; } } } // Start child interpreters for all submodules that have no in-ports and whose state is READY for (SubmoduleNode submoduleNode : dependencyGraph.submoduleNodes()) { if (submoduleNode.getElement().getInPorts().isEmpty() && submoduleNode.getPortState() == PortState.READY) { getChildExecutor(submoduleNode.getElement()); } } // Trigger all out-ports whose state is READY dependencyGraph .outPortNodes() .stream() .filter(node -> node.getPortState() == PortState.READY) .forEach(node -> outportCarriesSignal(node.getElement().getOutIndex())); if (outPortsRequiringValue.isEmpty()) { state = State.ALL_OUTPUTS; } // Finish the asynchronous action started in #preStart(). checkIfNoAsynchronousActions(); }