From ef489d3cf5ece299019099e3d5c7f8fc378dea6e Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Tue, 28 Feb 2023 15:41:47 +0100 Subject: [PATCH 01/37] generate a wrapper reactor for enclave --- .../generator/cpp/CppInstanceGenerator.kt | 81 ++++++++++--------- .../generator/cpp/CppReactionGenerator.kt | 3 +- 2 files changed, 46 insertions(+), 38 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/cpp/CppInstanceGenerator.kt b/org.lflang/src/org/lflang/generator/cpp/CppInstanceGenerator.kt index 4aee21202f..5f92d528b8 100644 --- a/org.lflang/src/org/lflang/generator/cpp/CppInstanceGenerator.kt +++ b/org.lflang/src/org/lflang/generator/cpp/CppInstanceGenerator.kt @@ -36,29 +36,54 @@ class CppInstanceGenerator( private val fileConfig: CppFileConfig, private val errorReporter: ErrorReporter ) { - private val Instantiation.isEnclave: Boolean get() = AttributeUtils.isEnclave(this) + companion object { + val Instantiation.isEnclave: Boolean get() = AttributeUtils.isEnclave(this) - private val Instantiation.hasEachParameter: Boolean - get() = AttributeUtils.getBooleanAttributeParameter( - AttributeUtils.getEnclaveAttribute(this), AttributeSpec.EACH_ATTR - ) ?: false + val Instantiation.hasEachParameter: Boolean + get() = AttributeUtils.getBooleanAttributeParameter( + AttributeUtils.getEnclaveAttribute(this), AttributeSpec.EACH_ATTR + ) ?: false - val Instantiation.cppType: String - get() { - return if (reactor.isGeneric) + private val Instantiation.reactorType: String + get() = if (reactor.isGeneric) """${reactor.name}<${typeParms.joinToString(", ") { it.toText() }}>""" else reactor.name - } + + val Instantiation.cppClass: String + get() = if (isEnclave) enclaveWrapperClassName else reactorType + + val Instantiation.enclaveWrapperClassName get() = "EnclaveWrapper_$name" + } + + private fun Instantiation.generateWrapper(): String = """ + |class $enclaveWrapperClassName : public reactor::Reactor { + | private: + | ${if (!hasEachParameter) "inline static " else ""}std::unique_ptr __lf_env{nullptr}; + | std::unique_ptr<$reactorType> __lf_instance{nullptr}; + | + | public: + | EnclaveWrapper_$name(const std::string& name, reactor::Reactor* container, $reactorType::Parameters&& params) + | : Reactor("enclave_wrapper_" + name, container) { + | if (__lf_env == nullptr) { + | __lf_env = std::make_unique(container->fqn() + name, container->environment()); + | } + | __lf_instance = std::make_unique<$reactorType>(name, __lf_env.get(), std::forward<$reactorType::Parameters>(params)); + | } + | + | void assemble() override {} + |}; + """.trimMargin() private fun generateDeclaration(inst: Instantiation): String = with(inst) { - val instance = if (isBank) "std::vector>" else "std::unique_ptr<$cppType>" + val instance = if (isBank) "std::vector>" else "std::unique_ptr<$cppClass>" if (isEnclave) { - val env = if (hasEachParameter) "std::vector>" else "reactor::Environment" - return """ - $env __lf_env_$name; - $instance $name; - """.trimIndent() + return with(PrependOperator) { + """ + ${" |"..inst.generateWrapper()} + |$instance $name; + """.trimMargin() + } } return "$instance $name;" } @@ -91,43 +116,25 @@ class CppInstanceGenerator( // by iterating over the reactor parameters we make sure that the parameters are assigned in declaration order return reactor.parameters.mapNotNull { if (it.name in assignments) ".${it.name} = ${assignments[it.name]}" else null - }.joinToString(", ", "$cppType::Parameters{", "}") + }.joinToString(", ", "$reactorType::Parameters{", "}") } private fun generateInitializer(inst: Instantiation): String? = with(inst) { - when { - !isBank && !isEnclave -> """, $name(std::make_unique<$cppType>("$name", this, ${getParameterStruct()}))""" - !isBank && isEnclave -> """ - , __lf_env_$name(this->fqn() + ".$name", this->environment()) - , $name(std::make_unique<$cppType>("$name", &__lf_env_$name, ${getParameterStruct()})) - """.trimIndent() - - isBank && isEnclave && !hasEachParameter -> """, __lf_env_$name(this->fqn() + ".$name", this->environment())""" - else -> null - } + if (isBank) null else """, $name(std::make_unique<$cppClass>("$name", this, ${getParameterStruct()}))""" } private fun generateConstructorInitializer(inst: Instantiation): String { with(inst) { assert(isBank) - val containerRef = when { - hasEachParameter -> "__lf_env_$name[__lf_idx].get()" - isEnclave -> "&__lf_env_$name" - else -> "this" - } - val width = inst.widthSpec.toCppCode() - return with(PrependOperator) { - """ + return """ |// initialize instance $name |$name.reserve($width); |for (size_t __lf_idx = 0; __lf_idx < $width; __lf_idx++) { | std::string __lf_inst_name = "${name}_" + std::to_string(__lf_idx); - ${"| "..if (hasEachParameter) """__lf_env_$name.emplace_back(std::make_unique(this->fqn() + "." + __lf_inst_name, this->environment()));""" else ""} - | $name.emplace_back(std::make_unique<$cppType>(__lf_inst_name, $containerRef, ${inst.getParameterStruct()})); + | $name.emplace_back(std::make_unique<$cppClass>(__lf_inst_name, this, ${inst.getParameterStruct()})); |} """.trimMargin() - } } } diff --git a/org.lflang/src/org/lflang/generator/cpp/CppReactionGenerator.kt b/org.lflang/src/org/lflang/generator/cpp/CppReactionGenerator.kt index c1e66f3632..5baa075fe6 100644 --- a/org.lflang/src/org/lflang/generator/cpp/CppReactionGenerator.kt +++ b/org.lflang/src/org/lflang/generator/cpp/CppReactionGenerator.kt @@ -25,6 +25,7 @@ package org.lflang.generator.cpp import org.lflang.generator.PrependOperator +import org.lflang.generator.cpp.CppInstanceGenerator.Companion.cppClass import org.lflang.isBank import org.lflang.joinWithLn import org.lflang.label @@ -172,7 +173,7 @@ class CppReactionGenerator( } private fun generateViewForContainer(r: Reaction, container: Instantiation): String { - val reactorClass = with(instanceGenerator) { container.cppType } + val reactorClass = container.cppClass val viewClass = r.getViewClassName(container) val viewInstance = r.getViewInstanceName(container) From 3eeaf50a36af2f4d45bf8c971968aa1feebd7533 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Thu, 9 Mar 2023 14:43:19 +0100 Subject: [PATCH 02/37] use a struct instead of a reactor to wrap enclaves --- .../src/org/lflang/generator/cpp/CppInstanceGenerator.kt | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/cpp/CppInstanceGenerator.kt b/org.lflang/src/org/lflang/generator/cpp/CppInstanceGenerator.kt index 5f92d528b8..98b7a0f2c5 100644 --- a/org.lflang/src/org/lflang/generator/cpp/CppInstanceGenerator.kt +++ b/org.lflang/src/org/lflang/generator/cpp/CppInstanceGenerator.kt @@ -57,21 +57,16 @@ class CppInstanceGenerator( } private fun Instantiation.generateWrapper(): String = """ - |class $enclaveWrapperClassName : public reactor::Reactor { - | private: + |struct $enclaveWrapperClassName { | ${if (!hasEachParameter) "inline static " else ""}std::unique_ptr __lf_env{nullptr}; | std::unique_ptr<$reactorType> __lf_instance{nullptr}; | - | public: - | EnclaveWrapper_$name(const std::string& name, reactor::Reactor* container, $reactorType::Parameters&& params) - | : Reactor("enclave_wrapper_" + name, container) { + | $enclaveWrapperClassName(const std::string& name, reactor::Reactor* container, $reactorType::Parameters&& params) { | if (__lf_env == nullptr) { | __lf_env = std::make_unique(container->fqn() + name, container->environment()); | } | __lf_instance = std::make_unique<$reactorType>(name, __lf_env.get(), std::forward<$reactorType::Parameters>(params)); | } - | - | void assemble() override {} |}; """.trimMargin() From 619a7663e79a3ed6ce761e4397a61328900bd10b Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Thu, 9 Mar 2023 19:41:41 +0100 Subject: [PATCH 03/37] first support for simple enclave communication --- org.lflang/src/lib/cpp/reactor-cpp | 2 +- .../generator/cpp/CppConnectionGenerator.kt | 37 ++++++++++++++++--- .../org/lflang/generator/cpp/CppExtensions.kt | 8 +++- .../lflang/generator/cpp/CppPortGenerator.kt | 19 ++++++---- 4 files changed, 50 insertions(+), 16 deletions(-) diff --git a/org.lflang/src/lib/cpp/reactor-cpp b/org.lflang/src/lib/cpp/reactor-cpp index a63a870180..9e11793a8f 160000 --- a/org.lflang/src/lib/cpp/reactor-cpp +++ b/org.lflang/src/lib/cpp/reactor-cpp @@ -1 +1 @@ -Subproject commit a63a870180137a023b7faf875271775787a56c03 +Subproject commit 9e11793a8f7ed2ff98eff840dd6e6b8d424dca2d diff --git a/org.lflang/src/org/lflang/generator/cpp/CppConnectionGenerator.kt b/org.lflang/src/org/lflang/generator/cpp/CppConnectionGenerator.kt index 2ff818b517..3ec27fc571 100644 --- a/org.lflang/src/org/lflang/generator/cpp/CppConnectionGenerator.kt +++ b/org.lflang/src/org/lflang/generator/cpp/CppConnectionGenerator.kt @@ -2,6 +2,8 @@ package org.lflang.generator.cpp import org.lflang.* import org.lflang.generator.cpp.CppConnectionGenerator.Companion.cppType +import org.lflang.generator.cpp.CppConnectionGenerator.Companion.isEnclaveConnection +import org.lflang.generator.cpp.CppInstanceGenerator.Companion.isEnclave import org.lflang.generator.cpp.CppPortGenerator.Companion.dataType import org.lflang.lf.Connection import org.lflang.lf.Port @@ -25,13 +27,33 @@ class CppConnectionGenerator(private val reactor: Reactor) { get() { val leftPort = leftPorts.first() return when { - isPhysical -> "reactor::PhysicalConnection<${leftPort.dataType}>" - delay != null -> "reactor::DelayedConnection<${leftPort.dataType}>" - else -> throw IllegalArgumentException("Connection is neither physical nor delayed") + isEnclaveConnection && !isPhysical && delay == null -> "reactor::EnclaveConnection<${leftPort.dataType}>" + isPhysical -> "reactor::PhysicalConnection<${leftPort.dataType}>" + delay != null -> "reactor::DelayedConnection<${leftPort.dataType}>" + else -> throw IllegalArgumentException("Unsupported connection type") } } - val Connection.requiresConnectionClass: Boolean get() = isPhysical || delay != null + val Connection.isEnclaveConnection: Boolean + get() { + if (leftPorts.size == 1 && rightPorts.size == 1) { + val leftIsEnclave = leftPorts[0].container?.isEnclave == true + val rightIsEnclave = rightPorts[0].container?.isEnclave == true + return when { + leftIsEnclave && rightIsEnclave -> true + !leftIsEnclave && !rightIsEnclave -> false + else -> TODO("Connections between enclaves and normal reactors are not supported") + } + } + for (port in leftPorts + rightPorts) { + if (port.container?.isEnclave == true) { + TODO("Enclaves can only be used in simple connections") + } + } + return false + } + + val Connection.requiresConnectionClass: Boolean get() = isPhysical || delay != null || isEnclaveConnection; } fun generateDeclarations() = @@ -52,8 +74,11 @@ class CppConnectionGenerator(private val reactor: Reactor) { private fun generateConstructorInitializer(connection: Connection): String? = if (connection.requiresConnectionClass && !connection.hasMultipleConnections) { - val delay = connection.delay.toCppTime() val name = connection.name - """, $name{"$name", this, $delay}""" + val delay = connection.delay?.toCppTime() + if (connection.isEnclaveConnection) + """, $name{"$name", ${connection.rightPorts[0].container.name}->__lf_env.get()}""" + else + """, $name{"$name", this, $delay}""" } else null } diff --git a/org.lflang/src/org/lflang/generator/cpp/CppExtensions.kt b/org.lflang/src/org/lflang/generator/cpp/CppExtensions.kt index f2386bf96a..a081bdd551 100644 --- a/org.lflang/src/org/lflang/generator/cpp/CppExtensions.kt +++ b/org.lflang/src/org/lflang/generator/cpp/CppExtensions.kt @@ -2,6 +2,7 @@ package org.lflang.generator.cpp import org.eclipse.emf.ecore.resource.Resource import org.lflang.* +import org.lflang.generator.cpp.CppInstanceGenerator.Companion.isEnclave import org.lflang.lf.BuiltinTriggerRef import org.lflang.lf.Expression import org.lflang.lf.Port @@ -111,8 +112,11 @@ val Reactor.templateName: String get() = if (isGeneric) "$name<${typeParms.joinT /** Get a C++ code representation of the given variable */ val VarRef.name: String - get() = if (this.container == null) this.variable.name - else "${this.container.name}->${this.variable.name}" + get() = when { + container == null -> variable.name + container.isEnclave -> "${container.name}->__lf_instance->${variable.name}" + else -> "${container.name}->${variable.name}" + } /** Get a C++ code representation of the given trigger */ val TriggerRef.name: String diff --git a/org.lflang/src/org/lflang/generator/cpp/CppPortGenerator.kt b/org.lflang/src/org/lflang/generator/cpp/CppPortGenerator.kt index 69ca1d27f6..79dd4ad93a 100644 --- a/org.lflang/src/org/lflang/generator/cpp/CppPortGenerator.kt +++ b/org.lflang/src/org/lflang/generator/cpp/CppPortGenerator.kt @@ -24,6 +24,8 @@ package org.lflang.generator.cpp +import org.lflang.generator.cpp.CppInstanceGenerator.Companion.enclaveWrapperClassName +import org.lflang.generator.cpp.CppInstanceGenerator.Companion.isEnclave import org.lflang.inferredType import org.lflang.isBank import org.lflang.isMultiport @@ -34,7 +36,6 @@ class CppPortGenerator(private val reactor: Reactor) { companion object { private val VarRef.isMultiport get() = (variable as? Port)?.isMultiport == true - private val VarRef.isInBank get() = container?.isBank == true /** * Return the C++ type of a port reference. @@ -44,11 +45,15 @@ class CppPortGenerator(private val reactor: Reactor) { * statement and let the C++ compiler do the job. */ val VarRef.dataType: String - get() = when { - isInBank && isMultiport -> "std::remove_reference${variable.name}[0])>::type::value_type" - isInBank && !isMultiport -> "std::remove_reference${variable.name})>::type::value_type" - !isInBank && isMultiport -> "std::remove_reference::type::value_type" - else -> "std::remove_reference::type::value_type" + get() { + val variableRef = when { + this == null -> "" + container.isBank && container.isEnclave -> "${container.name}[0]->__lf_instance->${variable.name}" + container.isBank && !container.isEnclave -> "${container.name}[0]->${variable.name}" + else -> this.name + } + val multiportRef = if (isMultiport) "$variableRef[0]" else variableRef + return "std::remove_reference::type::value_type" } } @@ -62,7 +67,7 @@ class CppPortGenerator(private val reactor: Reactor) { } /** Get the C++ type for the receiving port. */ - val Port.cppType: String + private val Port.cppType: String get() { val portType = when (this) { is Input -> "reactor::Input" From b1d6dcaeb628abb8afb22f0a6d39db64dda68fdf Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Thu, 9 Mar 2023 19:43:16 +0100 Subject: [PATCH 04/37] add test case --- test/Cpp/src/enclave/EnclaveCommunication.lf | 29 ++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 test/Cpp/src/enclave/EnclaveCommunication.lf diff --git a/test/Cpp/src/enclave/EnclaveCommunication.lf b/test/Cpp/src/enclave/EnclaveCommunication.lf new file mode 100644 index 0000000000..00cd314e50 --- /dev/null +++ b/test/Cpp/src/enclave/EnclaveCommunication.lf @@ -0,0 +1,29 @@ +target Cpp { + timeout: 1s, + workers: 1 +} + +reactor Src { + timer t(0, 100ms) + output out: int + state counter: int(0); + reaction(t) -> out {= + out.set(counter++); + =} +} + +reactor Sink { + input in: int + reaction(in) {= + reactor::log::Info() << "Received " << *in.get(); + =} +} + +main reactor { + @enclave + src = new Src() + @enclave + sink = new Sink() + + src.out -> sink.in +} \ No newline at end of file From b7f2d008db2c76294bf29315a44cbbaf1d4d64c6 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Tue, 14 Mar 2023 14:51:29 +0100 Subject: [PATCH 05/37] update reactor-cpp --- org.lflang/src/lib/cpp/reactor-cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/lib/cpp/reactor-cpp b/org.lflang/src/lib/cpp/reactor-cpp index e80cd36ce5..08310933bb 160000 --- a/org.lflang/src/lib/cpp/reactor-cpp +++ b/org.lflang/src/lib/cpp/reactor-cpp @@ -1 +1 @@ -Subproject commit e80cd36ce5bd625a7b167e7dfd65d25f78b0dd01 +Subproject commit 08310933bbf03b3c2b678f7da2d0a69d73384353 From 07adeac12214c73c80265b57e08abf952346ab35 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Sat, 18 Mar 2023 09:28:00 +0100 Subject: [PATCH 06/37] add simple enclave communication test --- test/Cpp/src/enclave/EnclaveCommunication.lf | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/test/Cpp/src/enclave/EnclaveCommunication.lf b/test/Cpp/src/enclave/EnclaveCommunication.lf index 00cd314e50..c8d0c50c1c 100644 --- a/test/Cpp/src/enclave/EnclaveCommunication.lf +++ b/test/Cpp/src/enclave/EnclaveCommunication.lf @@ -6,7 +6,7 @@ target Cpp { reactor Src { timer t(0, 100ms) output out: int - state counter: int(0); + state counter: int = 0 reaction(t) -> out {= out.set(counter++); =} @@ -14,8 +14,21 @@ reactor Src { reactor Sink { input in: int + state received: bool = false reaction(in) {= - reactor::log::Info() << "Received " << *in.get(); + received = true; + auto value = *in.get(); + reactor::log::Info() << "Received " << value; + auto expected = 100ms * value; + if (get_elapsed_logical_time() != expected) { + reactor::log::Error() << "Expecded value at " << expected << " but received it at " << get_elapsed_logical_time(); + } + =} + reaction(shutdown) {= + if(!received) { + reactor::log::Error() << "Nothing received."; + exit(1); + } =} } From 9aaa80e99b40014de1ffc6d137ae7528f2acc3e4 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Sat, 18 Mar 2023 09:29:58 +0100 Subject: [PATCH 07/37] add test combining simple enclave communication with other events --- .../EnclaveCommunicationLocalEvents.lf | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 test/Cpp/src/enclave/EnclaveCommunicationLocalEvents.lf diff --git a/test/Cpp/src/enclave/EnclaveCommunicationLocalEvents.lf b/test/Cpp/src/enclave/EnclaveCommunicationLocalEvents.lf new file mode 100644 index 0000000000..b5b8f43a63 --- /dev/null +++ b/test/Cpp/src/enclave/EnclaveCommunicationLocalEvents.lf @@ -0,0 +1,46 @@ +target Cpp { + timeout: 1s, + workers: 1 +} + +reactor Src { + timer t(0, 100ms) + output out: int + state counter: int = 0 + reaction(t) -> out {= + out.set(counter++); + =} +} + +reactor Sink { + timer t(0, 50ms) + input in: int + state received: bool = false + reaction(in) {= + received = true; + auto value = *in.get(); + reactor::log::Info() << "Received " << value; + auto expected = 100ms * value; + if (get_elapsed_logical_time() != expected) { + reactor::log::Error() << "Expecded value at " << expected << " but received it at " << get_elapsed_logical_time(); + } + =} + reaction(shutdown) {= + if(!received) { + reactor::log::Error() << "Nothing received."; + exit(1); + } + =} + reaction(t) {= + reactor::log::Info() << "Tick"; + =} +} + +main reactor { + @enclave + src = new Src() + @enclave + sink = new Sink() + + src.out -> sink.in +} \ No newline at end of file From 36fc3612202b71acd0a2e0b6fe5bbd33631bda61 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Sat, 18 Mar 2023 10:05:38 +0100 Subject: [PATCH 08/37] updater reactor-cpp --- org.lflang/src/lib/cpp/reactor-cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/lib/cpp/reactor-cpp b/org.lflang/src/lib/cpp/reactor-cpp index 08310933bb..5e51fc684c 160000 --- a/org.lflang/src/lib/cpp/reactor-cpp +++ b/org.lflang/src/lib/cpp/reactor-cpp @@ -1 +1 @@ -Subproject commit 08310933bbf03b3c2b678f7da2d0a69d73384353 +Subproject commit 5e51fc684c6c4475b557b36a3d6118ea76ecba8e From 46db0528e40fc37053c6f6f4783584a5b2161f5f Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Sat, 18 Mar 2023 10:06:05 +0100 Subject: [PATCH 09/37] code generation for delayed and physical enclave connections --- .../generator/cpp/CppConnectionGenerator.kt | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/cpp/CppConnectionGenerator.kt b/org.lflang/src/org/lflang/generator/cpp/CppConnectionGenerator.kt index 3ec27fc571..2379a4c08d 100644 --- a/org.lflang/src/org/lflang/generator/cpp/CppConnectionGenerator.kt +++ b/org.lflang/src/org/lflang/generator/cpp/CppConnectionGenerator.kt @@ -27,10 +27,15 @@ class CppConnectionGenerator(private val reactor: Reactor) { get() { val leftPort = leftPorts.first() return when { - isEnclaveConnection && !isPhysical && delay == null -> "reactor::EnclaveConnection<${leftPort.dataType}>" - isPhysical -> "reactor::PhysicalConnection<${leftPort.dataType}>" - delay != null -> "reactor::DelayedConnection<${leftPort.dataType}>" - else -> throw IllegalArgumentException("Unsupported connection type") + isEnclaveConnection -> when { + isPhysical -> "reactor::PhysicalEnclaveConnection<${leftPort.dataType}>" + delay != null -> "reactor::DelayedEnclaveConnection<${leftPort.dataType}>" + else -> "reactor::EnclaveConnection<${leftPort.dataType}>" + } + + isPhysical -> "reactor::PhysicalConnection<${leftPort.dataType}>" + delay != null -> "reactor::DelayedConnection<${leftPort.dataType}>" + else -> throw IllegalArgumentException("Unsupported connection type") } } @@ -72,13 +77,14 @@ class CppConnectionGenerator(private val reactor: Reactor) { } } else null - private fun generateConstructorInitializer(connection: Connection): String? = - if (connection.requiresConnectionClass && !connection.hasMultipleConnections) { - val name = connection.name - val delay = connection.delay?.toCppTime() - if (connection.isEnclaveConnection) - """, $name{"$name", ${connection.rightPorts[0].container.name}->__lf_env.get()}""" - else - """, $name{"$name", this, $delay}""" + private fun generateConstructorInitializer(connection: Connection): String? = with(connection) { + if (requiresConnectionClass && !hasMultipleConnections) { + when { + isEnclaveConnection && delay == null -> """, $name{"$name", ${rightPorts[0].container.name}->__lf_env.get()}""" + isEnclaveConnection && delay != null -> """, $name{"$name", ${rightPorts[0].container.name}->__lf_env.get(), ${delay.toCppTime()}}""" + else -> """, $name{"$name", this, ${delay.toCppTime()}}""" + } } else null + } + } From 06f36fd0f0e61fd1200c6efd0389155af377ffe9 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Sat, 18 Mar 2023 10:07:06 +0100 Subject: [PATCH 10/37] add tests for physical and delayed enclave connections --- test/Cpp/src/enclave/EnclaveCommunication.lf | 1 + .../enclave/EnclaveCommunicationDelayed.lf | 43 +++++++++++++++++ .../EnclaveCommunicationDelayedLocalEvents.lf | 47 +++++++++++++++++++ .../EnclaveCommunicationLocalEvents.lf | 1 + .../enclave/EnclaveCommunicationPhysical.lf | 42 +++++++++++++++++ ...EnclaveCommunicationPhysicalLocalEvents.lf | 47 +++++++++++++++++++ 6 files changed, 181 insertions(+) create mode 100644 test/Cpp/src/enclave/EnclaveCommunicationDelayed.lf create mode 100644 test/Cpp/src/enclave/EnclaveCommunicationDelayedLocalEvents.lf create mode 100644 test/Cpp/src/enclave/EnclaveCommunicationPhysical.lf create mode 100644 test/Cpp/src/enclave/EnclaveCommunicationPhysicalLocalEvents.lf diff --git a/test/Cpp/src/enclave/EnclaveCommunication.lf b/test/Cpp/src/enclave/EnclaveCommunication.lf index c8d0c50c1c..81430ea4ac 100644 --- a/test/Cpp/src/enclave/EnclaveCommunication.lf +++ b/test/Cpp/src/enclave/EnclaveCommunication.lf @@ -22,6 +22,7 @@ reactor Sink { auto expected = 100ms * value; if (get_elapsed_logical_time() != expected) { reactor::log::Error() << "Expecded value at " << expected << " but received it at " << get_elapsed_logical_time(); + exit(1); } =} reaction(shutdown) {= diff --git a/test/Cpp/src/enclave/EnclaveCommunicationDelayed.lf b/test/Cpp/src/enclave/EnclaveCommunicationDelayed.lf new file mode 100644 index 0000000000..eee3ea979e --- /dev/null +++ b/test/Cpp/src/enclave/EnclaveCommunicationDelayed.lf @@ -0,0 +1,43 @@ +target Cpp { + timeout: 1s, + workers: 1 +} + +reactor Src { + timer t(0, 100ms) + output out: int + state counter: int = 0 + reaction(t) -> out {= + out.set(counter++); + =} +} + +reactor Sink { + input in: int + state received: bool = false + reaction(in) {= + received = true; + auto value = *in.get(); + reactor::log::Info() << "Received " << value; + auto expected = 100ms * value + 50ms; + if (get_elapsed_logical_time() != expected) { + reactor::log::Error() << "Expecded value at " << expected << " but received it at " << get_elapsed_logical_time(); + exit(1); + } + =} + reaction(shutdown) {= + if(!received) { + reactor::log::Error() << "Nothing received."; + exit(1); + } + =} +} + +main reactor { + @enclave + src = new Src() + @enclave + sink = new Sink() + + src.out -> sink.in after 50ms +} \ No newline at end of file diff --git a/test/Cpp/src/enclave/EnclaveCommunicationDelayedLocalEvents.lf b/test/Cpp/src/enclave/EnclaveCommunicationDelayedLocalEvents.lf new file mode 100644 index 0000000000..966608f390 --- /dev/null +++ b/test/Cpp/src/enclave/EnclaveCommunicationDelayedLocalEvents.lf @@ -0,0 +1,47 @@ +target Cpp { + timeout: 1s, + workers: 1 +} + +reactor Src { + timer t(0, 100ms) + output out: int + state counter: int = 0 + reaction(t) -> out {= + out.set(counter++); + =} +} + +reactor Sink { + timer t(0, 50ms) + input in: int + state received: bool = false + reaction(in) {= + received = true; + auto value = *in.get(); + reactor::log::Info() << "Received " << value; + auto expected = 100ms * value + 50ms; + if (get_elapsed_logical_time() != expected) { + reactor::log::Error() << "Expecded value at " << expected << " but received it at " << get_elapsed_logical_time(); + exit(1); + } + =} + reaction(shutdown) {= + if(!received) { + reactor::log::Error() << "Nothing received."; + exit(1); + } + =} + reaction(t) {= + reactor::log::Info() << "Tick"; + =} +} + +main reactor { + @enclave + src = new Src() + @enclave + sink = new Sink() + + src.out -> sink.in after 50ms +} \ No newline at end of file diff --git a/test/Cpp/src/enclave/EnclaveCommunicationLocalEvents.lf b/test/Cpp/src/enclave/EnclaveCommunicationLocalEvents.lf index b5b8f43a63..236f262303 100644 --- a/test/Cpp/src/enclave/EnclaveCommunicationLocalEvents.lf +++ b/test/Cpp/src/enclave/EnclaveCommunicationLocalEvents.lf @@ -23,6 +23,7 @@ reactor Sink { auto expected = 100ms * value; if (get_elapsed_logical_time() != expected) { reactor::log::Error() << "Expecded value at " << expected << " but received it at " << get_elapsed_logical_time(); + exit(1); } =} reaction(shutdown) {= diff --git a/test/Cpp/src/enclave/EnclaveCommunicationPhysical.lf b/test/Cpp/src/enclave/EnclaveCommunicationPhysical.lf new file mode 100644 index 0000000000..4ba19a68cb --- /dev/null +++ b/test/Cpp/src/enclave/EnclaveCommunicationPhysical.lf @@ -0,0 +1,42 @@ +target Cpp { + timeout: 1s, + workers: 1 +} + +reactor Src { + timer t(0, 100ms) + output out: int + state counter: int = 0 + reaction(t) -> out {= + out.set(counter++); + =} +} + +reactor Sink { + input in: int + state received: bool = false + reaction(in) {= + received = true; + auto value = *in.get(); + reactor::log::Info() << "Received " << value << " at " << get_elapsed_logical_time(); + auto expected = 100ms * value; + if (get_elapsed_logical_time() < expected) { + reactor::log::Error() << "Expecded value not before " << expected; + } + =} + reaction(shutdown) {= + if(!received) { + reactor::log::Error() << "Nothing received."; + exit(1); + } + =} +} + +main reactor { + @enclave + src = new Src() + @enclave + sink = new Sink() + + src.out ~> sink.in +} \ No newline at end of file diff --git a/test/Cpp/src/enclave/EnclaveCommunicationPhysicalLocalEvents.lf b/test/Cpp/src/enclave/EnclaveCommunicationPhysicalLocalEvents.lf new file mode 100644 index 0000000000..00ba3dc720 --- /dev/null +++ b/test/Cpp/src/enclave/EnclaveCommunicationPhysicalLocalEvents.lf @@ -0,0 +1,47 @@ +target Cpp { + timeout: 1s, + workers: 1 +} + +reactor Src { + timer t(0, 100ms) + output out: int + state counter: int = 0 + reaction(t) -> out {= + out.set(counter++); + =} +} + +reactor Sink { + timer t(0, 50ms) + input in: int + state received: bool = false + reaction(in) {= + received = true; + auto value = *in.get(); + reactor::log::Info() << "Received " << value << " at " << get_elapsed_logical_time(); + auto expected = 100ms * value; + if (get_elapsed_logical_time() < expected) { + reactor::log::Error() << "Expecded value not before " << expected; + exit(1); + } + =} + reaction(shutdown) {= + if(!received) { + reactor::log::Error() << "Nothing received."; + exit(1); + } + =} + reaction(t) {= + reactor::log::Info() << "Tick"; + =} +} + +main reactor { + @enclave + src = new Src() + @enclave + sink = new Sink() + + src.out ~> sink.in +} \ No newline at end of file From 3fb05f5fc07d91e3ce0e1ae81a84197b2a7654f7 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Sat, 18 Mar 2023 12:09:07 +0100 Subject: [PATCH 11/37] first (incomplete) implementation of enclave multiport connections --- org.lflang/src/lib/cpp/lfutil.hh | 2 ++ .../cpp/CppAssembleMethodGenerator.kt | 21 ++++++++++++++++--- .../generator/cpp/CppConnectionGenerator.kt | 16 +++++++------- .../generator/cpp/CppReactorGenerator.kt | 2 +- 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/org.lflang/src/lib/cpp/lfutil.hh b/org.lflang/src/lib/cpp/lfutil.hh index e95a99f62b..4ed850e571 100644 --- a/org.lflang/src/lib/cpp/lfutil.hh +++ b/org.lflang/src/lib/cpp/lfutil.hh @@ -27,6 +27,8 @@ #include #include +#include + namespace lfutil { template diff --git a/org.lflang/src/org/lflang/generator/cpp/CppAssembleMethodGenerator.kt b/org.lflang/src/org/lflang/generator/cpp/CppAssembleMethodGenerator.kt index 45f6f10b0a..9ef5aa10ef 100644 --- a/org.lflang/src/org/lflang/generator/cpp/CppAssembleMethodGenerator.kt +++ b/org.lflang/src/org/lflang/generator/cpp/CppAssembleMethodGenerator.kt @@ -26,8 +26,10 @@ package org.lflang.generator.cpp import org.lflang.* import org.lflang.generator.PrependOperator +import org.lflang.generator.cpp.CppConnectionGenerator.Companion.isEnclaveConnection import org.lflang.generator.cpp.CppConnectionGenerator.Companion.name import org.lflang.generator.cpp.CppConnectionGenerator.Companion.requiresConnectionClass +import org.lflang.generator.cpp.CppInstanceGenerator.Companion.isEnclave import org.lflang.generator.cpp.CppPortGenerator.Companion.dataType import org.lflang.lf.Action import org.lflang.lf.Connection @@ -86,7 +88,7 @@ class CppAssembleMethodGenerator(private val reactor: Reactor) { // is in a bank, but not a multiport """ |for (auto& __lf_instance : ${container.name}) { - ${" | "..generateCode("__lf_instance->${port.name}")} + ${" | "..generateCode("__lf_instance->${if(container.isEnclave) "__lf_instance->" else ""}${port.name}")} |} """.trimMargin() } else { @@ -182,7 +184,7 @@ class CppAssembleMethodGenerator(private val reactor: Reactor) { // Generate code which adds all left hand ports and all right hand ports to a vector each. If we are handling multiports // within a bank, then we normally iterate over all banks in an outer loop and over all ports in an inner loop. However, - // if the connection is a cross connection, than we change the order on the right side and iterate over ports before banks. + // if the connection is an interleaved connection, than we change the order on the right side and iterate over ports before banks. return with(PrependOperator) { if (!c.requiresConnectionClass) { """ @@ -193,7 +195,7 @@ class CppAssembleMethodGenerator(private val reactor: Reactor) { ${" |"..c.rightPorts.joinWithLn { addAllPortsToVector(it, "__lf_right_ports_$idx") }} |lfutil::bind_multiple_ports(__lf_left_ports_$idx, __lf_right_ports_$idx, ${c.isIterated}); """.trimMargin() - } else { + } else if (!c.isEnclaveConnection) { """ |// connection $idx |std::vector<$portType> __lf_left_ports_$idx; @@ -211,6 +213,19 @@ class CppAssembleMethodGenerator(private val reactor: Reactor) { ${" |"..c.rightPorts.joinWithLn { addAllPortsToVector(it, "__lf_right_ports_$idx") }} |lfutil::bind_multiple_connections_with_ports(__lf_connection_pointers_$idx, __lf_right_ports_$idx, ${c.isIterated}); """.trimMargin() + } else { + """ + |// connection $idx + |std::vector<$portType> __lf_left_ports_$idx; + ${" |"..c.leftPorts.joinWithLn { addAllPortsToVector(it, "__lf_left_ports_$idx") }} + |std::vector<$portType> __lf_right_ports_$idx; + ${" |"..c.rightPorts.joinWithLn { addAllPortsToVector(it, "__lf_right_ports_$idx") }} + |for(size_t __lf_idx{0}; __lf_idx < std::min(__lf_right_ports_$idx.size(), __lf_left_ports_$idx.size()); __lf_idx++) { + | ${c.name}.emplace_back("${c.name}" + std::to_string(__lf_idx), __lf_right_ports_$idx[__lf_idx]->environment()${if(c.delay != null) ", ${c.delay.toCppTime()}" else ""}); + | ${c.name}.back().bind_upstream_port(__lf_left_ports_$idx[__lf_idx]); + | ${c.name}.back().bind_downstream_port(__lf_right_ports_$idx[__lf_idx]); + |} + """.trimMargin() } } } diff --git a/org.lflang/src/org/lflang/generator/cpp/CppConnectionGenerator.kt b/org.lflang/src/org/lflang/generator/cpp/CppConnectionGenerator.kt index 2379a4c08d..897fe01202 100644 --- a/org.lflang/src/org/lflang/generator/cpp/CppConnectionGenerator.kt +++ b/org.lflang/src/org/lflang/generator/cpp/CppConnectionGenerator.kt @@ -69,13 +69,15 @@ class CppConnectionGenerator(private val reactor: Reactor) { reactor.connections.mapNotNull { generateConstructorInitializer(it) }.joinLn() private fun generateDecleration(connection: Connection): String? = - if (connection.requiresConnectionClass) { - if (connection.hasMultipleConnections) { - "std::vector<${connection.cppType}> ${connection.name};" - } else { - "${connection.cppType} ${connection.name};" - } - } else null + with(connection) { + if (requiresConnectionClass) { + when { + hasMultipleConnections && isEnclaveConnection -> "std::list<${connection.cppType}> ${connection.name};" + hasMultipleConnections && !isEnclaveConnection -> "std::vector<${connection.cppType}> ${connection.name};" + else -> "${connection.cppType} ${connection.name};" + } + } else null + } private fun generateConstructorInitializer(connection: Connection): String? = with(connection) { if (requiresConnectionClass && !hasMultipleConnections) { diff --git a/org.lflang/src/org/lflang/generator/cpp/CppReactorGenerator.kt b/org.lflang/src/org/lflang/generator/cpp/CppReactorGenerator.kt index 50fff0bdb5..78df4519f2 100644 --- a/org.lflang/src/org/lflang/generator/cpp/CppReactorGenerator.kt +++ b/org.lflang/src/org/lflang/generator/cpp/CppReactorGenerator.kt @@ -187,8 +187,8 @@ class CppReactorGenerator(private val reactor: Reactor, fileConfig: CppFileConfi ${" | "..instances.generateInitializers()} ${" | "..timers.generateInitializers()} ${" | "..actions.generateInitializers()} - ${" | "..connections.generateInitializers()} ${" | "..reactions.generateReactionViewInitializers()} + ${" | "..connections.generateInitializers()} |{ ${" | "..ports.generateConstructorInitializers()} ${" | "..instances.generateConstructorInitializers()} From d5f90f2918c6279b2d13e2c90d3d69d7c38771ee Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Sat, 18 Mar 2023 12:10:12 +0100 Subject: [PATCH 12/37] update reactor-cpp --- org.lflang/src/lib/cpp/reactor-cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/lib/cpp/reactor-cpp b/org.lflang/src/lib/cpp/reactor-cpp index 5e51fc684c..07e74c307e 160000 --- a/org.lflang/src/lib/cpp/reactor-cpp +++ b/org.lflang/src/lib/cpp/reactor-cpp @@ -1 +1 @@ -Subproject commit 5e51fc684c6c4475b557b36a3d6118ea76ecba8e +Subproject commit 07e74c307ef4378846265c1490ac8144227c5a4d From 66129104069a06cf8a20626f89decc1eca1858f7 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Sat, 18 Mar 2023 12:16:42 +0100 Subject: [PATCH 13/37] add various multiport tests --- .../EnclaveCommunicationMultiportToBank.lf | 55 +++++++++++++++++++ ...laveCommunicationMultiportToBankDelayed.lf | 55 +++++++++++++++++++ ...EnclaveCommunicationMultiportToBankEach.lf | 55 +++++++++++++++++++ ...CommunicationMultiportToBankEachDelayed.lf | 55 +++++++++++++++++++ ...ommunicationMultiportToBankEachPhysical.lf | 55 +++++++++++++++++++ ...aveCommunicationMultiportToBankPhysical.lf | 55 +++++++++++++++++++ .../enclave/EnclaveCommunicationPhysical.lf | 1 + 7 files changed, 331 insertions(+) create mode 100644 test/Cpp/src/enclave/EnclaveCommunicationMultiportToBank.lf create mode 100644 test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankDelayed.lf create mode 100644 test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankEach.lf create mode 100644 test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankEachDelayed.lf create mode 100644 test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankEachPhysical.lf create mode 100644 test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankPhysical.lf diff --git a/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBank.lf b/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBank.lf new file mode 100644 index 0000000000..d69d0042db --- /dev/null +++ b/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBank.lf @@ -0,0 +1,55 @@ +target Cpp { + timeout: 1s, + workers: 1 +} + +reactor Src { + timer t(0, 100ms) + output[4] out: int + state counter: int = 0 + reaction(t) -> out {= + for (auto& port : out) { + port.set(counter++); + } + =} +} + +reactor Sink(bank_index: std::size_t = 0) { + timer t(0, 50ms) + input in: int + state received: bool = false + state iteration: int = 0 + reaction(in) {= + received = true; + auto value = *in.get(); + reactor::log::Info() << "Received " << value << " at " << get_elapsed_logical_time(); + auto expected = 100ms * iteration; + if (value != iteration*4 + bank_index) { + reactor::log::Error() << "Expected to recive " << iteration*4 + bank_index; + exit(1); + } + iteration++; + if (get_elapsed_logical_time() != expected) { + reactor::log::Error() << "Expected value at " << expected; + exit(1); + } + =} + reaction(shutdown) {= + if(!received) { + reactor::log::Error() << "Nothing received."; + exit(1); + } + =} + reaction(t) {= + reactor::log::Info() << "Tick"; + =} +} + +main reactor { + @enclave + src = new Src() + @enclave + sink = new[4] Sink() + + src.out -> sink.in +} \ No newline at end of file diff --git a/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankDelayed.lf b/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankDelayed.lf new file mode 100644 index 0000000000..86f7c07aa0 --- /dev/null +++ b/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankDelayed.lf @@ -0,0 +1,55 @@ +target Cpp { + timeout: 1s, + workers: 1 +} + +reactor Src { + timer t(0, 100ms) + output[4] out: int + state counter: int = 0 + reaction(t) -> out {= + for (auto& port : out) { + port.set(counter++); + } + =} +} + +reactor Sink(bank_index: std::size_t = 0) { + timer t(0, 50ms) + input in: int + state received: bool = false + state iteration: int = 0 + reaction(in) {= + received = true; + auto value = *in.get(); + reactor::log::Info() << "Received " << value << " at " << get_elapsed_logical_time(); + auto expected = 100ms * iteration + 50ms; + if (value != iteration*4 + bank_index) { + reactor::log::Error() << "Expected to recive " << iteration*4 + bank_index; + exit(1); + } + iteration++; + if (get_elapsed_logical_time() != expected) { + reactor::log::Error() << "Expected value at " << expected; + exit(1); + } + =} + reaction(shutdown) {= + if(!received) { + reactor::log::Error() << "Nothing received."; + exit(1); + } + =} + reaction(t) {= + reactor::log::Info() << "Tick"; + =} +} + +main reactor { + @enclave + src = new Src() + @enclave + sink = new[4] Sink() + + src.out -> sink.in after 50ms +} \ No newline at end of file diff --git a/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankEach.lf b/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankEach.lf new file mode 100644 index 0000000000..a67f25a384 --- /dev/null +++ b/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankEach.lf @@ -0,0 +1,55 @@ +target Cpp { + timeout: 1s, + workers: 1 +} + +reactor Src { + timer t(0, 100ms) + output[4] out: int + state counter: int = 0 + reaction(t) -> out {= + for (auto& port : out) { + port.set(counter++); + } + =} +} + +reactor Sink(bank_index: std::size_t = 0) { + timer t(0, 50ms) + input in: int + state received: bool = false + state iteration: int = 0 + reaction(in) {= + received = true; + auto value = *in.get(); + reactor::log::Info() << "Received " << value << " at " << get_elapsed_logical_time(); + auto expected = 100ms * iteration; + if (value != iteration*4 + bank_index) { + reactor::log::Error() << "Expected to recive " << iteration*4 + bank_index; + exit(1); + } + iteration++; + if (get_elapsed_logical_time() != expected) { + reactor::log::Error() << "Expected value at " << expected; + exit(1); + } + =} + reaction(shutdown) {= + if(!received) { + reactor::log::Error() << "Nothing received."; + exit(1); + } + =} + reaction(t) {= + reactor::log::Info() << "Tick"; + =} +} + +main reactor { + @enclave + src = new Src() + @enclave(each=true) + sink = new[4] Sink() + + src.out -> sink.in +} \ No newline at end of file diff --git a/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankEachDelayed.lf b/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankEachDelayed.lf new file mode 100644 index 0000000000..77569285f2 --- /dev/null +++ b/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankEachDelayed.lf @@ -0,0 +1,55 @@ +target Cpp { + timeout: 1s, + workers: 1 +} + +reactor Src { + timer t(0, 100ms) + output[4] out: int + state counter: int = 0 + reaction(t) -> out {= + for (auto& port : out) { + port.set(counter++); + } + =} +} + +reactor Sink(bank_index: std::size_t = 0) { + timer t(0, 50ms) + input in: int + state received: bool = false + state iteration: int = 0 + reaction(in) {= + received = true; + auto value = *in.get(); + reactor::log::Info() << "Received " << value << " at " << get_elapsed_logical_time(); + auto expected = 100ms * iteration + 50ms; + if (value != iteration*4 + bank_index) { + reactor::log::Error() << "Expected to recive " << iteration*4 + bank_index; + exit(1); + } + iteration++; + if (get_elapsed_logical_time() != expected) { + reactor::log::Error() << "Expected value at " << expected; + exit(1); + } + =} + reaction(shutdown) {= + if(!received) { + reactor::log::Error() << "Nothing received."; + exit(1); + } + =} + reaction(t) {= + reactor::log::Info() << "Tick"; + =} +} + +main reactor { + @enclave + src = new Src() + @enclave(each=true) + sink = new[4] Sink() + + src.out -> sink.in after 50ms +} \ No newline at end of file diff --git a/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankEachPhysical.lf b/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankEachPhysical.lf new file mode 100644 index 0000000000..d0ab0218ad --- /dev/null +++ b/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankEachPhysical.lf @@ -0,0 +1,55 @@ +target Cpp { + timeout: 1s, + workers: 1 +} + +reactor Src { + timer t(0, 100ms) + output[4] out: int + state counter: int = 0 + reaction(t) -> out {= + for (auto& port : out) { + port.set(counter++); + } + =} +} + +reactor Sink(bank_index: std::size_t = 0) { + timer t(0, 50ms) + input in: int + state received: bool = false + state iteration: int = 0 + reaction(in) {= + received = true; + auto value = *in.get(); + reactor::log::Info() << "Received " << value << " at " << get_elapsed_logical_time(); + auto expected = 100ms * iteration; + if (value != iteration*4 + bank_index) { + reactor::log::Error() << "Expected to recive " << iteration*4 + bank_index; + exit(1); + } + iteration++; + if (get_elapsed_logical_time() < expected) { + reactor::log::Error() << "Expected value not before " << expected; + exit(1); + } + =} + reaction(shutdown) {= + if(!received) { + reactor::log::Error() << "Nothing received."; + exit(1); + } + =} + reaction(t) {= + reactor::log::Info() << "Tick"; + =} +} + +main reactor { + @enclave + src = new Src() + @enclave(each=true) + sink = new[4] Sink() + + src.out ~> sink.in +} \ No newline at end of file diff --git a/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankPhysical.lf b/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankPhysical.lf new file mode 100644 index 0000000000..9aa88eb248 --- /dev/null +++ b/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankPhysical.lf @@ -0,0 +1,55 @@ +target Cpp { + timeout: 1s, + workers: 1 +} + +reactor Src { + timer t(0, 100ms) + output[4] out: int + state counter: int = 0 + reaction(t) -> out {= + for (auto& port : out) { + port.set(counter++); + } + =} +} + +reactor Sink(bank_index: std::size_t = 0) { + timer t(0, 50ms) + input in: int + state received: bool = false + state iteration: int = 0 + reaction(in) {= + received = true; + auto value = *in.get(); + reactor::log::Info() << "Received " << value << " at " << get_elapsed_logical_time(); + auto expected = 100ms * iteration; + if (value != iteration*4 + bank_index) { + reactor::log::Error() << "Expected to recive " << iteration*4 + bank_index; + exit(1); + } + iteration++; + if (get_elapsed_logical_time() < expected) { + reactor::log::Error() << "Expected value not before " << expected; + exit(1); + } + =} + reaction(shutdown) {= + if(!received) { + reactor::log::Error() << "Nothing received."; + exit(1); + } + =} + reaction(t) {= + reactor::log::Info() << "Tick"; + =} +} + +main reactor { + @enclave + src = new Src() + @enclave + sink = new[4] Sink() + + src.out ~> sink.in +} \ No newline at end of file diff --git a/test/Cpp/src/enclave/EnclaveCommunicationPhysical.lf b/test/Cpp/src/enclave/EnclaveCommunicationPhysical.lf index 4ba19a68cb..539a3c34b7 100644 --- a/test/Cpp/src/enclave/EnclaveCommunicationPhysical.lf +++ b/test/Cpp/src/enclave/EnclaveCommunicationPhysical.lf @@ -22,6 +22,7 @@ reactor Sink { auto expected = 100ms * value; if (get_elapsed_logical_time() < expected) { reactor::log::Error() << "Expecded value not before " << expected; + exit(1); } =} reaction(shutdown) {= From bd27e1f917a21d49778387c2c909be49d32a8190 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Sat, 18 Mar 2023 12:17:46 +0100 Subject: [PATCH 14/37] formatting --- test/Cpp/src/enclave/EnclaveCommunication.lf | 13 ++++++----- .../enclave/EnclaveCommunicationDelayed.lf | 15 +++++++------ .../EnclaveCommunicationDelayedLocalEvents.lf | 22 +++++++++---------- .../EnclaveCommunicationLocalEvents.lf | 20 ++++++++--------- .../EnclaveCommunicationMultiportToBank.lf | 16 ++++++++------ ...laveCommunicationMultiportToBankDelayed.lf | 18 ++++++++------- ...EnclaveCommunicationMultiportToBankEach.lf | 18 ++++++++------- ...CommunicationMultiportToBankEachDelayed.lf | 20 +++++++++-------- ...ommunicationMultiportToBankEachPhysical.lf | 18 ++++++++------- ...aveCommunicationMultiportToBankPhysical.lf | 16 ++++++++------ .../enclave/EnclaveCommunicationPhysical.lf | 13 ++++++----- ...EnclaveCommunicationPhysicalLocalEvents.lf | 20 ++++++++--------- 12 files changed, 112 insertions(+), 97 deletions(-) diff --git a/test/Cpp/src/enclave/EnclaveCommunication.lf b/test/Cpp/src/enclave/EnclaveCommunication.lf index 81430ea4ac..b780dad109 100644 --- a/test/Cpp/src/enclave/EnclaveCommunication.lf +++ b/test/Cpp/src/enclave/EnclaveCommunication.lf @@ -1,20 +1,20 @@ target Cpp { - timeout: 1s, + timeout: 1 s, workers: 1 } reactor Src { - timer t(0, 100ms) + timer t(0, 100 ms) output out: int state counter: int = 0 - reaction(t) -> out {= - out.set(counter++); - =} + + reaction(t) -> out {= out.set(counter++); =} } reactor Sink { input in: int state received: bool = false + reaction(in) {= received = true; auto value = *in.get(); @@ -25,6 +25,7 @@ reactor Sink { exit(1); } =} + reaction(shutdown) {= if(!received) { reactor::log::Error() << "Nothing received."; @@ -40,4 +41,4 @@ main reactor { sink = new Sink() src.out -> sink.in -} \ No newline at end of file +} diff --git a/test/Cpp/src/enclave/EnclaveCommunicationDelayed.lf b/test/Cpp/src/enclave/EnclaveCommunicationDelayed.lf index eee3ea979e..6bbab0a700 100644 --- a/test/Cpp/src/enclave/EnclaveCommunicationDelayed.lf +++ b/test/Cpp/src/enclave/EnclaveCommunicationDelayed.lf @@ -1,20 +1,20 @@ target Cpp { - timeout: 1s, + timeout: 1 s, workers: 1 } reactor Src { - timer t(0, 100ms) + timer t(0, 100 ms) output out: int state counter: int = 0 - reaction(t) -> out {= - out.set(counter++); - =} + + reaction(t) -> out {= out.set(counter++); =} } reactor Sink { input in: int state received: bool = false + reaction(in) {= received = true; auto value = *in.get(); @@ -25,6 +25,7 @@ reactor Sink { exit(1); } =} + reaction(shutdown) {= if(!received) { reactor::log::Error() << "Nothing received."; @@ -39,5 +40,5 @@ main reactor { @enclave sink = new Sink() - src.out -> sink.in after 50ms -} \ No newline at end of file + src.out -> sink.in after 50 ms +} diff --git a/test/Cpp/src/enclave/EnclaveCommunicationDelayedLocalEvents.lf b/test/Cpp/src/enclave/EnclaveCommunicationDelayedLocalEvents.lf index 966608f390..fa9c7b25e4 100644 --- a/test/Cpp/src/enclave/EnclaveCommunicationDelayedLocalEvents.lf +++ b/test/Cpp/src/enclave/EnclaveCommunicationDelayedLocalEvents.lf @@ -1,21 +1,21 @@ target Cpp { - timeout: 1s, + timeout: 1 s, workers: 1 } reactor Src { - timer t(0, 100ms) + timer t(0, 100 ms) output out: int state counter: int = 0 - reaction(t) -> out {= - out.set(counter++); - =} + + reaction(t) -> out {= out.set(counter++); =} } reactor Sink { - timer t(0, 50ms) + timer t(0, 50 ms) input in: int state received: bool = false + reaction(in) {= received = true; auto value = *in.get(); @@ -26,15 +26,15 @@ reactor Sink { exit(1); } =} + reaction(shutdown) {= if(!received) { reactor::log::Error() << "Nothing received."; exit(1); } =} - reaction(t) {= - reactor::log::Info() << "Tick"; - =} + + reaction(t) {= reactor::log::Info() << "Tick"; =} } main reactor { @@ -43,5 +43,5 @@ main reactor { @enclave sink = new Sink() - src.out -> sink.in after 50ms -} \ No newline at end of file + src.out -> sink.in after 50 ms +} diff --git a/test/Cpp/src/enclave/EnclaveCommunicationLocalEvents.lf b/test/Cpp/src/enclave/EnclaveCommunicationLocalEvents.lf index 236f262303..3a0edfd7e5 100644 --- a/test/Cpp/src/enclave/EnclaveCommunicationLocalEvents.lf +++ b/test/Cpp/src/enclave/EnclaveCommunicationLocalEvents.lf @@ -1,21 +1,21 @@ target Cpp { - timeout: 1s, + timeout: 1 s, workers: 1 } reactor Src { - timer t(0, 100ms) + timer t(0, 100 ms) output out: int state counter: int = 0 - reaction(t) -> out {= - out.set(counter++); - =} + + reaction(t) -> out {= out.set(counter++); =} } reactor Sink { - timer t(0, 50ms) + timer t(0, 50 ms) input in: int state received: bool = false + reaction(in) {= received = true; auto value = *in.get(); @@ -26,15 +26,15 @@ reactor Sink { exit(1); } =} + reaction(shutdown) {= if(!received) { reactor::log::Error() << "Nothing received."; exit(1); } =} - reaction(t) {= - reactor::log::Info() << "Tick"; - =} + + reaction(t) {= reactor::log::Info() << "Tick"; =} } main reactor { @@ -44,4 +44,4 @@ main reactor { sink = new Sink() src.out -> sink.in -} \ No newline at end of file +} diff --git a/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBank.lf b/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBank.lf index d69d0042db..4a74085dbc 100644 --- a/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBank.lf +++ b/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBank.lf @@ -1,12 +1,13 @@ target Cpp { - timeout: 1s, + timeout: 1 s, workers: 1 } reactor Src { - timer t(0, 100ms) + timer t(0, 100 ms) output[4] out: int state counter: int = 0 + reaction(t) -> out {= for (auto& port : out) { port.set(counter++); @@ -15,10 +16,11 @@ reactor Src { } reactor Sink(bank_index: std::size_t = 0) { - timer t(0, 50ms) + timer t(0, 50 ms) input in: int state received: bool = false state iteration: int = 0 + reaction(in) {= received = true; auto value = *in.get(); @@ -34,15 +36,15 @@ reactor Sink(bank_index: std::size_t = 0) { exit(1); } =} + reaction(shutdown) {= if(!received) { reactor::log::Error() << "Nothing received."; exit(1); } =} - reaction(t) {= - reactor::log::Info() << "Tick"; - =} + + reaction(t) {= reactor::log::Info() << "Tick"; =} } main reactor { @@ -52,4 +54,4 @@ main reactor { sink = new[4] Sink() src.out -> sink.in -} \ No newline at end of file +} diff --git a/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankDelayed.lf b/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankDelayed.lf index 86f7c07aa0..682b812d4a 100644 --- a/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankDelayed.lf +++ b/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankDelayed.lf @@ -1,12 +1,13 @@ target Cpp { - timeout: 1s, + timeout: 1 s, workers: 1 } reactor Src { - timer t(0, 100ms) + timer t(0, 100 ms) output[4] out: int state counter: int = 0 + reaction(t) -> out {= for (auto& port : out) { port.set(counter++); @@ -15,10 +16,11 @@ reactor Src { } reactor Sink(bank_index: std::size_t = 0) { - timer t(0, 50ms) + timer t(0, 50 ms) input in: int state received: bool = false state iteration: int = 0 + reaction(in) {= received = true; auto value = *in.get(); @@ -34,15 +36,15 @@ reactor Sink(bank_index: std::size_t = 0) { exit(1); } =} + reaction(shutdown) {= if(!received) { reactor::log::Error() << "Nothing received."; exit(1); } =} - reaction(t) {= - reactor::log::Info() << "Tick"; - =} + + reaction(t) {= reactor::log::Info() << "Tick"; =} } main reactor { @@ -51,5 +53,5 @@ main reactor { @enclave sink = new[4] Sink() - src.out -> sink.in after 50ms -} \ No newline at end of file + src.out -> sink.in after 50 ms +} diff --git a/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankEach.lf b/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankEach.lf index a67f25a384..e926019572 100644 --- a/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankEach.lf +++ b/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankEach.lf @@ -1,12 +1,13 @@ target Cpp { - timeout: 1s, + timeout: 1 s, workers: 1 } reactor Src { - timer t(0, 100ms) + timer t(0, 100 ms) output[4] out: int state counter: int = 0 + reaction(t) -> out {= for (auto& port : out) { port.set(counter++); @@ -15,10 +16,11 @@ reactor Src { } reactor Sink(bank_index: std::size_t = 0) { - timer t(0, 50ms) + timer t(0, 50 ms) input in: int state received: bool = false state iteration: int = 0 + reaction(in) {= received = true; auto value = *in.get(); @@ -34,22 +36,22 @@ reactor Sink(bank_index: std::size_t = 0) { exit(1); } =} + reaction(shutdown) {= if(!received) { reactor::log::Error() << "Nothing received."; exit(1); } =} - reaction(t) {= - reactor::log::Info() << "Tick"; - =} + + reaction(t) {= reactor::log::Info() << "Tick"; =} } main reactor { @enclave src = new Src() - @enclave(each=true) + @enclave(each = true) sink = new[4] Sink() src.out -> sink.in -} \ No newline at end of file +} diff --git a/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankEachDelayed.lf b/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankEachDelayed.lf index 77569285f2..238edf7bfc 100644 --- a/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankEachDelayed.lf +++ b/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankEachDelayed.lf @@ -1,12 +1,13 @@ target Cpp { - timeout: 1s, + timeout: 1 s, workers: 1 } reactor Src { - timer t(0, 100ms) + timer t(0, 100 ms) output[4] out: int state counter: int = 0 + reaction(t) -> out {= for (auto& port : out) { port.set(counter++); @@ -15,10 +16,11 @@ reactor Src { } reactor Sink(bank_index: std::size_t = 0) { - timer t(0, 50ms) + timer t(0, 50 ms) input in: int state received: bool = false state iteration: int = 0 + reaction(in) {= received = true; auto value = *in.get(); @@ -34,22 +36,22 @@ reactor Sink(bank_index: std::size_t = 0) { exit(1); } =} + reaction(shutdown) {= if(!received) { reactor::log::Error() << "Nothing received."; exit(1); } =} - reaction(t) {= - reactor::log::Info() << "Tick"; - =} + + reaction(t) {= reactor::log::Info() << "Tick"; =} } main reactor { @enclave src = new Src() - @enclave(each=true) + @enclave(each = true) sink = new[4] Sink() - src.out -> sink.in after 50ms -} \ No newline at end of file + src.out -> sink.in after 50 ms +} diff --git a/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankEachPhysical.lf b/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankEachPhysical.lf index d0ab0218ad..15eb6faf68 100644 --- a/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankEachPhysical.lf +++ b/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankEachPhysical.lf @@ -1,12 +1,13 @@ target Cpp { - timeout: 1s, + timeout: 1 s, workers: 1 } reactor Src { - timer t(0, 100ms) + timer t(0, 100 ms) output[4] out: int state counter: int = 0 + reaction(t) -> out {= for (auto& port : out) { port.set(counter++); @@ -15,10 +16,11 @@ reactor Src { } reactor Sink(bank_index: std::size_t = 0) { - timer t(0, 50ms) + timer t(0, 50 ms) input in: int state received: bool = false state iteration: int = 0 + reaction(in) {= received = true; auto value = *in.get(); @@ -34,22 +36,22 @@ reactor Sink(bank_index: std::size_t = 0) { exit(1); } =} + reaction(shutdown) {= if(!received) { reactor::log::Error() << "Nothing received."; exit(1); } =} - reaction(t) {= - reactor::log::Info() << "Tick"; - =} + + reaction(t) {= reactor::log::Info() << "Tick"; =} } main reactor { @enclave src = new Src() - @enclave(each=true) + @enclave(each = true) sink = new[4] Sink() src.out ~> sink.in -} \ No newline at end of file +} diff --git a/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankPhysical.lf b/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankPhysical.lf index 9aa88eb248..3867a7a627 100644 --- a/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankPhysical.lf +++ b/test/Cpp/src/enclave/EnclaveCommunicationMultiportToBankPhysical.lf @@ -1,12 +1,13 @@ target Cpp { - timeout: 1s, + timeout: 1 s, workers: 1 } reactor Src { - timer t(0, 100ms) + timer t(0, 100 ms) output[4] out: int state counter: int = 0 + reaction(t) -> out {= for (auto& port : out) { port.set(counter++); @@ -15,10 +16,11 @@ reactor Src { } reactor Sink(bank_index: std::size_t = 0) { - timer t(0, 50ms) + timer t(0, 50 ms) input in: int state received: bool = false state iteration: int = 0 + reaction(in) {= received = true; auto value = *in.get(); @@ -34,15 +36,15 @@ reactor Sink(bank_index: std::size_t = 0) { exit(1); } =} + reaction(shutdown) {= if(!received) { reactor::log::Error() << "Nothing received."; exit(1); } =} - reaction(t) {= - reactor::log::Info() << "Tick"; - =} + + reaction(t) {= reactor::log::Info() << "Tick"; =} } main reactor { @@ -52,4 +54,4 @@ main reactor { sink = new[4] Sink() src.out ~> sink.in -} \ No newline at end of file +} diff --git a/test/Cpp/src/enclave/EnclaveCommunicationPhysical.lf b/test/Cpp/src/enclave/EnclaveCommunicationPhysical.lf index 539a3c34b7..ee3ab7f80b 100644 --- a/test/Cpp/src/enclave/EnclaveCommunicationPhysical.lf +++ b/test/Cpp/src/enclave/EnclaveCommunicationPhysical.lf @@ -1,20 +1,20 @@ target Cpp { - timeout: 1s, + timeout: 1 s, workers: 1 } reactor Src { - timer t(0, 100ms) + timer t(0, 100 ms) output out: int state counter: int = 0 - reaction(t) -> out {= - out.set(counter++); - =} + + reaction(t) -> out {= out.set(counter++); =} } reactor Sink { input in: int state received: bool = false + reaction(in) {= received = true; auto value = *in.get(); @@ -25,6 +25,7 @@ reactor Sink { exit(1); } =} + reaction(shutdown) {= if(!received) { reactor::log::Error() << "Nothing received."; @@ -40,4 +41,4 @@ main reactor { sink = new Sink() src.out ~> sink.in -} \ No newline at end of file +} diff --git a/test/Cpp/src/enclave/EnclaveCommunicationPhysicalLocalEvents.lf b/test/Cpp/src/enclave/EnclaveCommunicationPhysicalLocalEvents.lf index 00ba3dc720..aa9c042502 100644 --- a/test/Cpp/src/enclave/EnclaveCommunicationPhysicalLocalEvents.lf +++ b/test/Cpp/src/enclave/EnclaveCommunicationPhysicalLocalEvents.lf @@ -1,21 +1,21 @@ target Cpp { - timeout: 1s, + timeout: 1 s, workers: 1 } reactor Src { - timer t(0, 100ms) + timer t(0, 100 ms) output out: int state counter: int = 0 - reaction(t) -> out {= - out.set(counter++); - =} + + reaction(t) -> out {= out.set(counter++); =} } reactor Sink { - timer t(0, 50ms) + timer t(0, 50 ms) input in: int state received: bool = false + reaction(in) {= received = true; auto value = *in.get(); @@ -26,15 +26,15 @@ reactor Sink { exit(1); } =} + reaction(shutdown) {= if(!received) { reactor::log::Error() << "Nothing received."; exit(1); } =} - reaction(t) {= - reactor::log::Info() << "Tick"; - =} + + reaction(t) {= reactor::log::Info() << "Tick"; =} } main reactor { @@ -44,4 +44,4 @@ main reactor { sink = new Sink() src.out ~> sink.in -} \ No newline at end of file +} From 9c114c347424ad0741c88c2487dae85299a30669 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Mon, 20 Mar 2023 09:29:03 +0100 Subject: [PATCH 15/37] fix NPE --- .../src/org/lflang/generator/cpp/CppPortGenerator.kt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/cpp/CppPortGenerator.kt b/org.lflang/src/org/lflang/generator/cpp/CppPortGenerator.kt index 79dd4ad93a..990ede56c6 100644 --- a/org.lflang/src/org/lflang/generator/cpp/CppPortGenerator.kt +++ b/org.lflang/src/org/lflang/generator/cpp/CppPortGenerator.kt @@ -47,10 +47,11 @@ class CppPortGenerator(private val reactor: Reactor) { val VarRef.dataType: String get() { val variableRef = when { - this == null -> "" - container.isBank && container.isEnclave -> "${container.name}[0]->__lf_instance->${variable.name}" - container.isBank && !container.isEnclave -> "${container.name}[0]->${variable.name}" - else -> this.name + this == null -> "" + container == null -> this.name + container.isBank && container.isEnclave -> "${container.name}[0]->__lf_instance->${variable.name}" + container.isBank && !container.isEnclave -> "${container.name}[0]->${variable.name}" + else -> this.name } val multiportRef = if (isMultiport) "$variableRef[0]" else variableRef return "std::remove_reference::type::value_type" From 85a21efa41692e3d97a1d08b1d085a3d44051c1f Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Tue, 21 Mar 2023 10:05:51 +0100 Subject: [PATCH 16/37] disable keepalive warning in C++ --- org.lflang/src/org/lflang/Target.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/org/lflang/Target.java b/org.lflang/src/org/lflang/Target.java index c3bfda067a..59398963cd 100644 --- a/org.lflang/src/org/lflang/Target.java +++ b/org.lflang/src/org/lflang/Target.java @@ -527,7 +527,7 @@ public String getSingleLineCommentPrefix() { * program (and keepalive was not explicitly unset by the user). */ public boolean setsKeepAliveOptionAutomatically() { - return this != Rust; + return this != Rust && this != CPP; } /** From e17852da6683fe140480c6b2d2b416daf2719d22 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Tue, 21 Mar 2023 11:53:42 +0100 Subject: [PATCH 17/37] update reactor-cpp and add new tests --- org.lflang/src/lib/cpp/reactor-cpp | 2 +- .../EnclaveSparseUpstreamEventsDelayed.lf | 52 +++++++++++++++++++ .../EnclaveSparseUpstreamEventsPhysical.lf | 52 +++++++++++++++++++ 3 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 test/Cpp/src/enclave/EnclaveSparseUpstreamEventsDelayed.lf create mode 100644 test/Cpp/src/enclave/EnclaveSparseUpstreamEventsPhysical.lf diff --git a/org.lflang/src/lib/cpp/reactor-cpp b/org.lflang/src/lib/cpp/reactor-cpp index 07e74c307e..eecfdd22e7 160000 --- a/org.lflang/src/lib/cpp/reactor-cpp +++ b/org.lflang/src/lib/cpp/reactor-cpp @@ -1 +1 @@ -Subproject commit 07e74c307ef4378846265c1490ac8144227c5a4d +Subproject commit eecfdd22e71f1f6738403fd6c0bbdd6e137e54d4 diff --git a/test/Cpp/src/enclave/EnclaveSparseUpstreamEventsDelayed.lf b/test/Cpp/src/enclave/EnclaveSparseUpstreamEventsDelayed.lf new file mode 100644 index 0000000000..341b91dfbe --- /dev/null +++ b/test/Cpp/src/enclave/EnclaveSparseUpstreamEventsDelayed.lf @@ -0,0 +1,52 @@ +// The purpose of this test is to check that the downstream enclave respects the +// after delay when aquiring tags from its upstream. +target Cpp { + timeout: 10 s, + workers: 1 +} + +reactor Src { + timer t(0, 2 s) + output out: int + state counter: int = 0 + + reaction(t) -> out {= out.set(counter++); =} +} + +reactor Sink { + timer t(0, 100 ms) + input in: int + state received: bool = false + + reaction(in) {= + received = true; + auto value = *in.get(); + reactor::log::Info() << "Received " << value; + auto expected = 2s + 2s * value; + if (get_elapsed_logical_time() != expected) { + reactor::log::Error() << "Expected value at " << expected << " but received it at " << get_elapsed_logical_time(); + exit(1); + } + =} + + reaction(shutdown) {= + if(!received) { + reactor::log::Error() << "Nothing received."; + exit(1); + } + =} + + reaction(t) {= reactor::log::Info() << "Tick"; =} deadline(1 s) {= + reactor::log::Error() << "Deadline violated."; + exit(2); + =} +} + +main reactor { + @enclave + src = new Src() + @enclave + sink = new Sink() + + src.out -> sink.in after 2 s +} diff --git a/test/Cpp/src/enclave/EnclaveSparseUpstreamEventsPhysical.lf b/test/Cpp/src/enclave/EnclaveSparseUpstreamEventsPhysical.lf new file mode 100644 index 0000000000..f48445f369 --- /dev/null +++ b/test/Cpp/src/enclave/EnclaveSparseUpstreamEventsPhysical.lf @@ -0,0 +1,52 @@ +// The purpose of this test is to check that the downstream enclave advances +// time independenty of the upstraem if the connection is physical. +target Cpp { + timeout: 10 s, + workers: 1 +} + +reactor Src { + timer t(0, 2 s) + output out: int + state counter: int = 0 + + reaction(t) -> out {= out.set(counter++); =} +} + +reactor Sink { + timer t(0, 100 ms) + input in: int + state received: bool = false + + reaction(in) {= + received = true; + auto value = *in.get(); + reactor::log::Info() << "Received " << value; + auto expected = 2s * value; + if (get_elapsed_logical_time() < expected) { + reactor::log::Error() << "Expected value not before " << expected << " but received it at " << get_elapsed_logical_time(); + exit(1); + } + =} + + reaction(shutdown) {= + if(!received) { + reactor::log::Error() << "Nothing received."; + exit(1); + } + =} + + reaction(t) {= reactor::log::Info() << "Tick"; =} deadline(1 s) {= + reactor::log::Error() << "Deadline violated."; + exit(2); + =} +} + +main reactor { + @enclave + src = new Src() + @enclave + sink = new Sink() + + src.out ~> sink.in +} From 97632d816cfe0afca7917761166185d4d99a07f2 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Tue, 21 Mar 2023 14:18:48 +0100 Subject: [PATCH 18/37] update reactor-cpp and at tests covering sparse upstream events --- org.lflang/src/lib/cpp/reactor-cpp | 2 +- .../enclave/EnclaveSparseUpstreamEvents.lf | 52 +++++++++++++ .../EnclaveSparseUpstreamEventsDelayed.lf | 2 +- .../EnclaveSparseUpstreamEventsPhysical.lf | 2 +- .../enclave/EnclaveUpstreamPhysicalAction.lf | 76 +++++++++++++++++++ 5 files changed, 131 insertions(+), 3 deletions(-) create mode 100644 test/Cpp/src/enclave/EnclaveSparseUpstreamEvents.lf create mode 100644 test/Cpp/src/enclave/EnclaveUpstreamPhysicalAction.lf diff --git a/org.lflang/src/lib/cpp/reactor-cpp b/org.lflang/src/lib/cpp/reactor-cpp index eecfdd22e7..b260ebc83c 160000 --- a/org.lflang/src/lib/cpp/reactor-cpp +++ b/org.lflang/src/lib/cpp/reactor-cpp @@ -1 +1 @@ -Subproject commit eecfdd22e71f1f6738403fd6c0bbdd6e137e54d4 +Subproject commit b260ebc83cea97335e984d1eb26d6b581e900280 diff --git a/test/Cpp/src/enclave/EnclaveSparseUpstreamEvents.lf b/test/Cpp/src/enclave/EnclaveSparseUpstreamEvents.lf new file mode 100644 index 0000000000..a65abc3533 --- /dev/null +++ b/test/Cpp/src/enclave/EnclaveSparseUpstreamEvents.lf @@ -0,0 +1,52 @@ +// The purpose of this test is to check that the downstream enclave can progress, even if there +// are only sparse upstream events. +target Cpp { + timeout: 6 s, + workers: 1 +} + +reactor Src { + timer t(0, 2 s) + output out: int + state counter: int = 0 + + reaction(t) -> out {= out.set(counter++); =} +} + +reactor Sink { + timer t(0, 100 ms) + input in: int + state received: bool = false + + reaction(in) {= + received = true; + auto value = *in.get(); + reactor::log::Info() << "Received " << value; + auto expected = 2s * value; + if (get_elapsed_logical_time() != expected) { + reactor::log::Error() << "Expected value at " << expected << " but received it at " << get_elapsed_logical_time(); + exit(1); + } + =} + + reaction(shutdown) {= + if(!received) { + reactor::log::Error() << "Nothing received."; + exit(1); + } + =} + + reaction(t) {= reactor::log::Info() << "Tick"; =} deadline(1 s) {= + reactor::log::Error() << "Deadline violated."; + exit(2); + =} +} + +main reactor { + @enclave + src = new Src() + @enclave + sink = new Sink() + + src.out -> sink.in +} diff --git a/test/Cpp/src/enclave/EnclaveSparseUpstreamEventsDelayed.lf b/test/Cpp/src/enclave/EnclaveSparseUpstreamEventsDelayed.lf index 341b91dfbe..e299f921ad 100644 --- a/test/Cpp/src/enclave/EnclaveSparseUpstreamEventsDelayed.lf +++ b/test/Cpp/src/enclave/EnclaveSparseUpstreamEventsDelayed.lf @@ -1,7 +1,7 @@ // The purpose of this test is to check that the downstream enclave respects the // after delay when aquiring tags from its upstream. target Cpp { - timeout: 10 s, + timeout: 6 s, workers: 1 } diff --git a/test/Cpp/src/enclave/EnclaveSparseUpstreamEventsPhysical.lf b/test/Cpp/src/enclave/EnclaveSparseUpstreamEventsPhysical.lf index f48445f369..6e1e579bd0 100644 --- a/test/Cpp/src/enclave/EnclaveSparseUpstreamEventsPhysical.lf +++ b/test/Cpp/src/enclave/EnclaveSparseUpstreamEventsPhysical.lf @@ -1,7 +1,7 @@ // The purpose of this test is to check that the downstream enclave advances // time independenty of the upstraem if the connection is physical. target Cpp { - timeout: 10 s, + timeout: 6 s, workers: 1 } diff --git a/test/Cpp/src/enclave/EnclaveUpstreamPhysicalAction.lf b/test/Cpp/src/enclave/EnclaveUpstreamPhysicalAction.lf new file mode 100644 index 0000000000..2da36c03b6 --- /dev/null +++ b/test/Cpp/src/enclave/EnclaveUpstreamPhysicalAction.lf @@ -0,0 +1,76 @@ +// The purpose of this test is to check that the downstream enclave can progress, even if there +// are only sparse upstream events. +target Cpp { + timeout: 10 s, + workers: 1 +} + +reactor Src { + public preamble {= + #include + =} + + state thread: std::thread{} + + physical action a: int + output out: int + + reaction(startup) -> a {= + // start new thread + this->thread = std::thread([&] () { + for (int i{0}; i < 3; i++) { + a.schedule(i); + std::this_thread::sleep_for(2s); + } + }); + =} + + reaction(a) -> out {= + out.set(a.get()); + =} + + reaction(shutdown) {= + // make sure to join the thread before shutting down + if(thread.joinable()) { + thread.join(); + } + =} +} + +reactor Sink { + timer t(0, 100 ms) + input in: int + state received: bool = false + + reaction(in) {= + received = true; + auto value = *in.get(); + reactor::log::Info() << "Received " << value; + auto expected = 2s * value; + if (get_elapsed_logical_time() < expected) { + reactor::log::Error() << "Expected value not before " << expected << " but received it at " << get_elapsed_logical_time(); + exit(1); + } + =} + + reaction(shutdown) {= + if(!received) { + reactor::log::Error() << "Nothing received."; + exit(1); + } + =} + + reaction(t) {= reactor::log::Info() << "Tick"; =} deadline(1 s) {= + reactor::log::Error() << "Deadline violated."; + exit(2); + =} +} + +main reactor { + @enclave + src = new Src() + @enclave + sink = new Sink() + + src.out -> sink.in +} From 4d8bf85169673094289ea34340e02ad0035c3d1b Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Fri, 24 Mar 2023 12:08:03 +0100 Subject: [PATCH 19/37] format tests --- .../src/enclave/EnclaveSparseUpstreamEvents.lf | 4 ++-- .../enclave/EnclaveUpstreamPhysicalAction.lf | 17 +++++++++-------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/test/Cpp/src/enclave/EnclaveSparseUpstreamEvents.lf b/test/Cpp/src/enclave/EnclaveSparseUpstreamEvents.lf index a65abc3533..3bade0f63e 100644 --- a/test/Cpp/src/enclave/EnclaveSparseUpstreamEvents.lf +++ b/test/Cpp/src/enclave/EnclaveSparseUpstreamEvents.lf @@ -1,5 +1,5 @@ -// The purpose of this test is to check that the downstream enclave can progress, even if there -// are only sparse upstream events. +// The purpose of this test is to check that the downstream enclave can +// progress, even if there are only sparse upstream events. target Cpp { timeout: 6 s, workers: 1 diff --git a/test/Cpp/src/enclave/EnclaveUpstreamPhysicalAction.lf b/test/Cpp/src/enclave/EnclaveUpstreamPhysicalAction.lf index 2da36c03b6..18ac74b091 100644 --- a/test/Cpp/src/enclave/EnclaveUpstreamPhysicalAction.lf +++ b/test/Cpp/src/enclave/EnclaveUpstreamPhysicalAction.lf @@ -1,5 +1,5 @@ -// The purpose of this test is to check that the downstream enclave can progress, even if there -// are only sparse upstream events. +// The purpose of this test is to check that the downstream enclave can +// progress, even if there are only sparse upstream events. target Cpp { timeout: 10 s, workers: 1 @@ -11,11 +11,11 @@ reactor Src { =} state thread: std::thread{} - + physical action a: int output out: int - reaction(startup) -> a {= + reaction(startup) -> a {= // start new thread this->thread = std::thread([&] () { for (int i{0}; i < 3; i++) { @@ -25,9 +25,7 @@ reactor Src { }); =} - reaction(a) -> out {= - out.set(a.get()); - =} + reaction(a) -> out {= out.set(a.get()); =} reaction(shutdown) {= // make sure to join the thread before shutting down @@ -60,7 +58,10 @@ reactor Sink { } =} - reaction(t) {= reactor::log::Info() << "Tick"; =} deadline(1 s) {= + reaction(t) {= + reactor::log::Info() << "Tick - " << "logical time: " << get_elapsed_logical_time() + << "; physical time: " << get_elapsed_physical_time(); + =} deadline(1 s) {= reactor::log::Error() << "Deadline violated."; exit(2); =} From 9cabad27f5c8214af7f4b4b2bf5113ce5fa1d3f5 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Tue, 28 Mar 2023 15:00:25 +0200 Subject: [PATCH 20/37] update reactor-cpp --- org.lflang/src/lib/cpp/reactor-cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/lib/cpp/reactor-cpp b/org.lflang/src/lib/cpp/reactor-cpp index b260ebc83c..fe5e6c2d1c 160000 --- a/org.lflang/src/lib/cpp/reactor-cpp +++ b/org.lflang/src/lib/cpp/reactor-cpp @@ -1 +1 @@ -Subproject commit b260ebc83cea97335e984d1eb26d6b581e900280 +Subproject commit fe5e6c2d1cbc38b46b7298facb5f77e5ba6f387c From a7afcee0193ce9b2252f90cae05a56407442fc0c Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Fri, 31 Mar 2023 15:25:52 +0200 Subject: [PATCH 21/37] update reactor-cpp --- org.lflang/src/lib/cpp/reactor-cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/lib/cpp/reactor-cpp b/org.lflang/src/lib/cpp/reactor-cpp index fe5e6c2d1c..6bdf8c9f05 160000 --- a/org.lflang/src/lib/cpp/reactor-cpp +++ b/org.lflang/src/lib/cpp/reactor-cpp @@ -1 +1 @@ -Subproject commit fe5e6c2d1cbc38b46b7298facb5f77e5ba6f387c +Subproject commit 6bdf8c9f054e463359f46170eb073928aea33ff9 From 9626826ce83b06b5f3573e03b990372c57a23ceb Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Fri, 31 Mar 2023 15:27:17 +0200 Subject: [PATCH 22/37] add tests with cycles --- test/Cpp/src/enclave/EnclaveCycle.lf | 67 ++++++++++++++++ test/Cpp/src/enclave/EnclaveCycleTwoTimers.lf | 70 +++++++++++++++++ .../EnclaveUpstreamPhysicalActionDelayed.lf | 77 +++++++++++++++++++ 3 files changed, 214 insertions(+) create mode 100644 test/Cpp/src/enclave/EnclaveCycle.lf create mode 100644 test/Cpp/src/enclave/EnclaveCycleTwoTimers.lf create mode 100644 test/Cpp/src/enclave/EnclaveUpstreamPhysicalActionDelayed.lf diff --git a/test/Cpp/src/enclave/EnclaveCycle.lf b/test/Cpp/src/enclave/EnclaveCycle.lf new file mode 100644 index 0000000000..d073c801c8 --- /dev/null +++ b/test/Cpp/src/enclave/EnclaveCycle.lf @@ -0,0 +1,67 @@ +target Cpp { + timeout: 1 s, + workers: 1 +} + +reactor Ping { + timer t(0, 100 ms) + input in: int + output out: int + state counter: int = 0 + state received: bool = false + + reaction(t) -> out {= out.set(counter++); =} + + reaction(in) {= + received = true; + auto value = *in.get(); + reactor::log::Info() << "Ping Received " << value; + auto expected = 50ms + 100ms * value; + if (get_elapsed_logical_time() != expected) { + reactor::log::Error() << "Expecded value at " << expected << " but received it at " << get_elapsed_logical_time(); + exit(1); + } + =} + + reaction(shutdown) {= + if(!received) { + reactor::log::Error() << "Nothing received."; + exit(1); + } + =} +} + +reactor Pong { + input in: int + output out: int + state received: bool = false + + reaction(in) -> out {= + received = true; + auto value = *in.get(); + reactor::log::Info() << "Pong Received " << value; + auto expected = 100ms * value; + if (get_elapsed_logical_time() != expected) { + reactor::log::Error() << "Expecded value at " << expected << " but received it at " << get_elapsed_logical_time(); + exit(1); + } + out.set(value); + =} + + reaction(shutdown) {= + if(!received) { + reactor::log::Error() << "Nothing received."; + exit(1); + } + =} +} + +main reactor { + @enclave + ping = new Ping() + @enclave + pong = new Pong() + + ping.out -> pong.in + pong.out -> ping.in after 50 ms +} diff --git a/test/Cpp/src/enclave/EnclaveCycleTwoTimers.lf b/test/Cpp/src/enclave/EnclaveCycleTwoTimers.lf new file mode 100644 index 0000000000..f347aa53a4 --- /dev/null +++ b/test/Cpp/src/enclave/EnclaveCycleTwoTimers.lf @@ -0,0 +1,70 @@ +target Cpp { + timeout: 1 s, + workers: 1 +} + +reactor Ping { + timer t(0, 100 ms) + input in: int + output out: int + state counter: int = 0 + state received: bool = false + + reaction(t) -> out {= out.set(counter++); =} + + reaction(in) {= + received = true; + auto value = *in.get(); + reactor::log::Info() << "Ping Received " << value; + auto expected = 50ms + 100ms * value; + if (get_elapsed_logical_time() != expected) { + reactor::log::Error() << "Expecded value at " << expected << " but received it at " << get_elapsed_logical_time(); + exit(1); + } + =} + + reaction(shutdown) {= + if(!received) { + reactor::log::Error() << "Nothing received."; + exit(1); + } + =} +} + +reactor Pong { + timer t(0, 100 ms) + input in: int + output out: int + state counter: int = 0 + state received: bool = false + + reaction(t) -> out {= out.set(counter++); =} + + reaction(in) {= + received = true; + auto value = *in.get(); + reactor::log::Info() << "Pong Received " << value; + auto expected = 50ms + 100ms * value; + if (get_elapsed_logical_time() != expected) { + reactor::log::Error() << "Expecded value at " << expected << " but received it at " << get_elapsed_logical_time(); + exit(1); + } + =} + + reaction(shutdown) {= + if(!received) { + reactor::log::Error() << "Nothing received."; + exit(1); + } + =} +} + +main reactor { + @enclave + ping = new Ping() + @enclave + pong = new Pong() + + ping.out -> pong.in after 50 ms + pong.out -> ping.in after 50 ms +} diff --git a/test/Cpp/src/enclave/EnclaveUpstreamPhysicalActionDelayed.lf b/test/Cpp/src/enclave/EnclaveUpstreamPhysicalActionDelayed.lf new file mode 100644 index 0000000000..f87895f960 --- /dev/null +++ b/test/Cpp/src/enclave/EnclaveUpstreamPhysicalActionDelayed.lf @@ -0,0 +1,77 @@ +// The purpose of this test is to check that the downstream enclave can +// progress, even if there are only sparse upstream events. +target Cpp { + timeout: 10 s, + workers: 1 +} + +reactor Src { + public preamble {= + #include + =} + + state thread: std::thread{} + + physical action a: int + output out: int + + reaction(startup) -> a {= + // start new thread + this->thread = std::thread([&] () { + for (int i{0}; i < 3; i++) { + a.schedule(i); + std::this_thread::sleep_for(2s); + } + }); + =} + + reaction(a) -> out {= out.set(a.get()); =} + + reaction(shutdown) {= + // make sure to join the thread before shutting down + if(thread.joinable()) { + thread.join(); + } + =} +} + +reactor Sink { + timer t(0, 100 ms) + input in: int + state received: bool = false + + reaction(in) {= + received = true; + auto value = *in.get(); + reactor::log::Info() << "Received " << value; + auto expected = 2s * value; + if (get_elapsed_logical_time() < expected) { + reactor::log::Error() << "Expected value not before " << expected << " but received it at " << get_elapsed_logical_time(); + exit(1); + } + =} + + reaction(shutdown) {= + if(!received) { + reactor::log::Error() << "Nothing received."; + exit(1); + } + =} + + reaction(t) {= + reactor::log::Info() << "Tick - " << "logical time: " << get_elapsed_logical_time() + << "; physical time: " << get_elapsed_physical_time(); + =} deadline(1 s) {= + reactor::log::Error() << "Deadline violated."; + exit(2); + =} +} + +main reactor { + @enclave + src = new Src() + @enclave + sink = new Sink() + + src.out -> sink.in after 2 s +} From a36d8a3e872d95b80dadecb0113d9c8575029cfc Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Mon, 8 May 2023 14:08:27 +0200 Subject: [PATCH 23/37] update reactor-cpp --- org.lflang/src/lib/cpp/reactor-cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/lib/cpp/reactor-cpp b/org.lflang/src/lib/cpp/reactor-cpp index 6bdf8c9f05..4e75aec034 160000 --- a/org.lflang/src/lib/cpp/reactor-cpp +++ b/org.lflang/src/lib/cpp/reactor-cpp @@ -1 +1 @@ -Subproject commit 6bdf8c9f054e463359f46170eb073928aea33ff9 +Subproject commit 4e75aec034f709de1236381ac9dcd7dbd3c8affe From de0af0c4314bec1c06f6cef9aaa6235831fbde1b Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Mon, 8 May 2023 16:29:48 +0200 Subject: [PATCH 24/37] unify connection generation using a lambda function this simplifies the connection procedure. Instead of generating different code for normal, enclaved, or just delayed connections, we use the same code for all and insert a lambda that is called to instantiate the concrete connection. --- org.lflang/src/lib/cpp/lfutil.hh | 53 +++----------- .../cpp/CppAssembleMethodGenerator.kt | 73 ++++++++----------- .../generator/cpp/CppConnectionGenerator.kt | 30 ++++---- test/Cpp/src/enclave/EnclaveBroadcast.lf | 37 ++++++++++ .../Cpp/src/enclave/EnclaveMultiportToPort.lf | 49 +++++++++++++ test/Cpp/src/multiport/Broadcast.lf | 9 +++ 6 files changed, 151 insertions(+), 100 deletions(-) create mode 100644 test/Cpp/src/enclave/EnclaveBroadcast.lf create mode 100644 test/Cpp/src/enclave/EnclaveMultiportToPort.lf diff --git a/org.lflang/src/lib/cpp/lfutil.hh b/org.lflang/src/lib/cpp/lfutil.hh index 4ed850e571..292bd1db5e 100644 --- a/org.lflang/src/lib/cpp/lfutil.hh +++ b/org.lflang/src/lib/cpp/lfutil.hh @@ -65,12 +65,13 @@ class LFScope { void request_stop() const { return environment()->sync_shutdown(); } }; -template +template void bind_multiple_ports( - std::vector*>& left_ports, - std::vector*>& right_ports, - bool repeat_left) { - + std::vector& left_ports, + std::vector& right_ports, + bool repeat_left, + std::function connect) +{ if (repeat_left) { auto l_size = left_ports.size(); auto r_size = right_ports.size(); @@ -94,50 +95,14 @@ void bind_multiple_ports( << "Not all ports will be connected!"; } + std::size_t idx{0}; while (left_it != left_ports.end() && right_it != right_ports.end()) { auto left = *left_it; auto right = *right_it; - left->bind_to(right); - left_it++; - right_it++; - } -} - -template -void bind_multiple_connections_with_ports( - std::vector*>& connections, - std::vector*>& ports, - bool repeat_left) { - - if (repeat_left) { - auto l_size = connections.size(); - auto r_size = ports.size(); - // divide and round up - auto repetitions = r_size / l_size + (r_size % l_size != 0); - // repeat repetitions-1 times - connections.reserve(repetitions * l_size); - for (std::size_t i{1}; i < repetitions; i++) { - std::copy_n(connections.begin(), l_size, std::back_inserter(connections)); - } - } - - auto left_it = connections.begin(); - auto right_it = ports.begin(); - - if (connections.size() < ports.size()) { - reactor::log::Warn() << "There are more right ports than left ports. " - << "Not all ports will be connected!"; - } else if (connections.size() > ports.size()) { - reactor::log::Warn() << "There are more left ports than right ports. " - << "Not all ports will be connected!"; - } - - while (left_it != connections.end() && right_it != ports.end()) { - auto left = *left_it; - auto right = *right_it; - left->bind_downstream_port(right); + connect(left, right, idx); left_it++; right_it++; + idx++; } } diff --git a/org.lflang/src/org/lflang/generator/cpp/CppAssembleMethodGenerator.kt b/org.lflang/src/org/lflang/generator/cpp/CppAssembleMethodGenerator.kt index 45112487bd..60f2ff62a7 100644 --- a/org.lflang/src/org/lflang/generator/cpp/CppAssembleMethodGenerator.kt +++ b/org.lflang/src/org/lflang/generator/cpp/CppAssembleMethodGenerator.kt @@ -186,47 +186,38 @@ class CppAssembleMethodGenerator(private val reactor: Reactor) { // within a bank, then we normally iterate over all banks in an outer loop and over all ports in an inner loop. However, // if the connection is an interleaved connection, than we change the order on the right side and iterate over ports before banks. return with(PrependOperator) { - if (!c.requiresConnectionClass) { - """ - |// connection $idx - |std::vector<$portType> __lf_left_ports_$idx; - ${" |"..c.leftPorts.joinWithLn { addAllPortsToVector(it, "__lf_left_ports_$idx") }} - |std::vector<$portType> __lf_right_ports_$idx; - ${" |"..c.rightPorts.joinWithLn { addAllPortsToVector(it, "__lf_right_ports_$idx") }} - |lfutil::bind_multiple_ports(__lf_left_ports_$idx, __lf_right_ports_$idx, ${c.isIterated}); - """.trimMargin() - } else if (!c.isEnclaveConnection) { - """ - |// connection $idx - |std::vector<$portType> __lf_left_ports_$idx; - ${" |"..c.leftPorts.joinWithLn { addAllPortsToVector(it, "__lf_left_ports_$idx") }} - |${c.name}.reserve(__lf_left_ports_$idx.size()); - |for(size_t __lf_idx{0}; __lf_idx < __lf_left_ports_$idx.size(); __lf_idx++) { - | ${c.name}.emplace_back("${c.name}" + std::to_string(__lf_idx), this, ${c.delay.toCppTime()}); - | ${c.name}.back().bind_upstream_port(__lf_left_ports_$idx[__lf_idx]); - |} - |std::vector*> __lf_connection_pointers_$idx; - |for (auto& connection : ${c.name}) { - | __lf_connection_pointers_$idx.push_back(&connection); - |} - |std::vector<$portType> __lf_right_ports_$idx; - ${" |"..c.rightPorts.joinWithLn { addAllPortsToVector(it, "__lf_right_ports_$idx") }} - |lfutil::bind_multiple_connections_with_ports(__lf_connection_pointers_$idx, __lf_right_ports_$idx, ${c.isIterated}); - """.trimMargin() - } else { - """ - |// connection $idx - |std::vector<$portType> __lf_left_ports_$idx; - ${" |"..c.leftPorts.joinWithLn { addAllPortsToVector(it, "__lf_left_ports_$idx") }} - |std::vector<$portType> __lf_right_ports_$idx; - ${" |"..c.rightPorts.joinWithLn { addAllPortsToVector(it, "__lf_right_ports_$idx") }} - |for(size_t __lf_idx{0}; __lf_idx < std::min(__lf_right_ports_$idx.size(), __lf_left_ports_$idx.size()); __lf_idx++) { - | ${c.name}.emplace_back("${c.name}" + std::to_string(__lf_idx), __lf_right_ports_$idx[__lf_idx]->environment()${if(c.delay != null) ", ${c.delay.toCppTime()}" else ""}); - | ${c.name}.back().bind_upstream_port(__lf_left_ports_$idx[__lf_idx]); - | ${c.name}.back().bind_downstream_port(__lf_right_ports_$idx[__lf_idx]); - |} - """.trimMargin() - } + """ + |// connection $idx + |std::vector<$portType> __lf_left_ports_$idx; + ${" |"..c.leftPorts.joinWithLn { addAllPortsToVector(it, "__lf_left_ports_$idx") }} + |std::vector<$portType> __lf_right_ports_$idx; + ${" |"..c.rightPorts.joinWithLn { addAllPortsToVector(it, "__lf_right_ports_$idx") }} + |lfutil::bind_multiple_ports<$portType>(__lf_left_ports_$idx, __lf_right_ports_$idx, ${c.isIterated}, + ${" |"..c.getConnectionLambda(portType)} + |); + """.trimMargin() + } + } + + private fun Connection.getConnectionLambda(portType: String): String { + return when { + isEnclaveConnection -> """ + [this]($portType left, $portType right, std::size_t idx) { + $name.emplace_back("$name" + std::to_string(idx), right->environment()${if (delay != null) ", ${delay.toCppTime()}" else ""}); + $name.back().bind_upstream_port(left); + $name.back().bind_downstream_port(right); + } + """.trimIndent() + + requiresConnectionClass -> """ + [this]($portType left, $portType right, std::size_t idx) { + $name.emplace_back("$name" + std::to_string(idx), this, ${delay.toCppTime()}); + $name.back().bind_upstream_port(left); + $name.back().bind_downstream_port(right); + } + """.trimIndent() + + else -> "[]($portType left, $portType right, [[maybe_unused]]std::size_t idx) { left->bind_to(right); }" } } diff --git a/org.lflang/src/org/lflang/generator/cpp/CppConnectionGenerator.kt b/org.lflang/src/org/lflang/generator/cpp/CppConnectionGenerator.kt index 897fe01202..4be190314d 100644 --- a/org.lflang/src/org/lflang/generator/cpp/CppConnectionGenerator.kt +++ b/org.lflang/src/org/lflang/generator/cpp/CppConnectionGenerator.kt @@ -41,21 +41,19 @@ class CppConnectionGenerator(private val reactor: Reactor) { val Connection.isEnclaveConnection: Boolean get() { - if (leftPorts.size == 1 && rightPorts.size == 1) { - val leftIsEnclave = leftPorts[0].container?.isEnclave == true - val rightIsEnclave = rightPorts[0].container?.isEnclave == true - return when { - leftIsEnclave && rightIsEnclave -> true - !leftIsEnclave && !rightIsEnclave -> false - else -> TODO("Connections between enclaves and normal reactors are not supported") - } - } + var foundEnclave = false + var allEnclave = true for (port in leftPorts + rightPorts) { if (port.container?.isEnclave == true) { - TODO("Enclaves can only be used in simple connections") + foundEnclave = true + } else { + allEnclave = false } } - return false + if (foundEnclave && !allEnclave) { + TODO("Connections between enclaves and normal reactors are not supported") + } + return foundEnclave } val Connection.requiresConnectionClass: Boolean get() = isPhysical || delay != null || isEnclaveConnection; @@ -71,10 +69,12 @@ class CppConnectionGenerator(private val reactor: Reactor) { private fun generateDecleration(connection: Connection): String? = with(connection) { if (requiresConnectionClass) { - when { - hasMultipleConnections && isEnclaveConnection -> "std::list<${connection.cppType}> ${connection.name};" - hasMultipleConnections && !isEnclaveConnection -> "std::vector<${connection.cppType}> ${connection.name};" - else -> "${connection.cppType} ${connection.name};" + if (hasMultipleConnections) { + // We use an std::list here as connections currently cannot be safely moved and std::vector requires + // objects to be movable. + "std::list<${connection.cppType}> ${connection.name};" + } else { + "${connection.cppType} ${connection.name};" } } else null } diff --git a/test/Cpp/src/enclave/EnclaveBroadcast.lf b/test/Cpp/src/enclave/EnclaveBroadcast.lf new file mode 100644 index 0000000000..d00fbbf059 --- /dev/null +++ b/test/Cpp/src/enclave/EnclaveBroadcast.lf @@ -0,0 +1,37 @@ +target Cpp{timeout: 1 sec} + +reactor Source { + output out: unsigned + + reaction(startup) -> out {= out.set(42); =} +} + +reactor Sink(bank_index: size_t = 0) { + input in: unsigned + + state received: bool = false + + reaction(in) {= + received = true; + std::cout << "Received " << *in.get() << '\n'; + if (*in.get() != 42) { + std::cerr << "Error: expected " << 42 << "!\n"; + exit(1); + } + =} + + reaction(shutdown) {= + if (!received) { + std::cerr << "Error: Sink " << bank_index << " didn't receive anything.\n"; + exit(2); + } + =} +} + +main reactor { + @enclave + source = new Source() + @enclave(each=true) + sink = new[4] Sink() + (source.out)+ -> sink.in +} diff --git a/test/Cpp/src/enclave/EnclaveMultiportToPort.lf b/test/Cpp/src/enclave/EnclaveMultiportToPort.lf new file mode 100644 index 0000000000..027de94bfb --- /dev/null +++ b/test/Cpp/src/enclave/EnclaveMultiportToPort.lf @@ -0,0 +1,49 @@ +// Check multiport output to multiport input. Destination port is wider than +// sending port. +target Cpp { + timeout: 2 sec, + fast: true +} + +reactor Source { + output[2] out: int + + reaction(startup) -> out {= + for(int i = 0; i < out.size(); i++) { + std::cout << "Source sending " << i << ".\n"; + out[i].set(i); + } + =} +} + +reactor Destination(expected: int = 0) { + input in: int + state received: bool = false + + reaction(in) {= + std::cout << "Received: " << *in.get() << ".\n"; + received = true; + if (*in.get() != expected) { + std::cerr << "ERROR: Expected " << expected << ".\n"; + exit(1); + } + =} + + reaction(shutdown) {= + if (!received) { + std::cerr << "ERROR: Destination received no input!\n"; + exit(1); + } + std::cout << "Success.\n"; + =} +} + +main reactor { + @enclave + a = new Source() + @enclave + b1 = new Destination() + @enclave + b2 = new Destination(expected = 1) + a.out -> b1.in, b2.in +} diff --git a/test/Cpp/src/multiport/Broadcast.lf b/test/Cpp/src/multiport/Broadcast.lf index 077ca75247..202a30c5f7 100644 --- a/test/Cpp/src/multiport/Broadcast.lf +++ b/test/Cpp/src/multiport/Broadcast.lf @@ -8,14 +8,23 @@ reactor Source { reactor Sink(bank_index: size_t = 0) { input in: unsigned + state received: bool = false reaction(in) {= + received = true; std::cout << "Received " << *in.get() << '\n'; if (*in.get() != 42) { std::cerr << "Error: expected " << 42 << "!\n"; exit(1); } =} + + reaction(shutdown) {= + if (!received) { + std::cerr << "Error: Sink " << bank_index << " didn't receive anything.\n"; + exit(2); + } + =} } main reactor { From d6c4e5afa06ec8e143eec5d1e8452d3fee8ed132 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Mon, 8 May 2023 16:54:04 +0200 Subject: [PATCH 25/37] allow connections where not all ports belong to enclaves --- .../generator/cpp/CppConnectionGenerator.kt | 11 +--- test/Cpp/src/enclave/EnclaveCommunication2.lf | 43 ++++++++++++ .../enclave/EnclaveCommunicationDelayed2.lf | 43 ++++++++++++ test/Cpp/src/enclave/EnclaveCycle2lf | 66 +++++++++++++++++++ .../src/enclave/EnclaveMultiportToPort2.lf | 48 ++++++++++++++ 5 files changed, 202 insertions(+), 9 deletions(-) create mode 100644 test/Cpp/src/enclave/EnclaveCommunication2.lf create mode 100644 test/Cpp/src/enclave/EnclaveCommunicationDelayed2.lf create mode 100644 test/Cpp/src/enclave/EnclaveCycle2lf create mode 100644 test/Cpp/src/enclave/EnclaveMultiportToPort2.lf diff --git a/org.lflang/src/org/lflang/generator/cpp/CppConnectionGenerator.kt b/org.lflang/src/org/lflang/generator/cpp/CppConnectionGenerator.kt index 4be190314d..83c3f5554a 100644 --- a/org.lflang/src/org/lflang/generator/cpp/CppConnectionGenerator.kt +++ b/org.lflang/src/org/lflang/generator/cpp/CppConnectionGenerator.kt @@ -41,19 +41,12 @@ class CppConnectionGenerator(private val reactor: Reactor) { val Connection.isEnclaveConnection: Boolean get() { - var foundEnclave = false - var allEnclave = true for (port in leftPorts + rightPorts) { if (port.container?.isEnclave == true) { - foundEnclave = true - } else { - allEnclave = false + return true } } - if (foundEnclave && !allEnclave) { - TODO("Connections between enclaves and normal reactors are not supported") - } - return foundEnclave + return false } val Connection.requiresConnectionClass: Boolean get() = isPhysical || delay != null || isEnclaveConnection; diff --git a/test/Cpp/src/enclave/EnclaveCommunication2.lf b/test/Cpp/src/enclave/EnclaveCommunication2.lf new file mode 100644 index 0000000000..648223fb0b --- /dev/null +++ b/test/Cpp/src/enclave/EnclaveCommunication2.lf @@ -0,0 +1,43 @@ +target Cpp { + timeout: 1 s, + workers: 1 +} + +reactor Src { + timer t(0, 100 ms) + output out: int + state counter: int = 0 + + reaction(t) -> out {= out.set(counter++); =} +} + +reactor Sink { + input in: int + state received: bool = false + + reaction(in) {= + received = true; + auto value = *in.get(); + reactor::log::Info() << "Received " << value; + auto expected = 100ms * value; + if (get_elapsed_logical_time() != expected) { + reactor::log::Error() << "Expecded value at " << expected << " but received it at " << get_elapsed_logical_time(); + exit(1); + } + =} + + reaction(shutdown) {= + if(!received) { + reactor::log::Error() << "Nothing received."; + exit(1); + } + =} +} + +main reactor { + src = new Src() + @enclave + sink = new Sink() + + src.out -> sink.in +} diff --git a/test/Cpp/src/enclave/EnclaveCommunicationDelayed2.lf b/test/Cpp/src/enclave/EnclaveCommunicationDelayed2.lf new file mode 100644 index 0000000000..9cfa3f0a11 --- /dev/null +++ b/test/Cpp/src/enclave/EnclaveCommunicationDelayed2.lf @@ -0,0 +1,43 @@ +target Cpp { + timeout: 1 s, + workers: 1 +} + +reactor Src { + timer t(0, 100 ms) + output out: int + state counter: int = 0 + + reaction(t) -> out {= out.set(counter++); =} +} + +reactor Sink { + input in: int + state received: bool = false + + reaction(in) {= + received = true; + auto value = *in.get(); + reactor::log::Info() << "Received " << value; + auto expected = 100ms * value + 50ms; + if (get_elapsed_logical_time() != expected) { + reactor::log::Error() << "Expecded value at " << expected << " but received it at " << get_elapsed_logical_time(); + exit(1); + } + =} + + reaction(shutdown) {= + if(!received) { + reactor::log::Error() << "Nothing received."; + exit(1); + } + =} +} + +main reactor { + src = new Src() + @enclave + sink = new Sink() + + src.out -> sink.in after 50 ms +} diff --git a/test/Cpp/src/enclave/EnclaveCycle2lf b/test/Cpp/src/enclave/EnclaveCycle2lf new file mode 100644 index 0000000000..34e0b2bdfa --- /dev/null +++ b/test/Cpp/src/enclave/EnclaveCycle2lf @@ -0,0 +1,66 @@ +target Cpp { + timeout: 1 s, + workers: 1 +} + +reactor Ping { + timer t(0, 100 ms) + input in: int + output out: int + state counter: int = 0 + state received: bool = false + + reaction(t) -> out {= out.set(counter++); =} + + reaction(in) {= + received = true; + auto value = *in.get(); + reactor::log::Info() << "Ping Received " << value; + auto expected = 50ms + 100ms * value; + if (get_elapsed_logical_time() != expected) { + reactor::log::Error() << "Expecded value at " << expected << " but received it at " << get_elapsed_logical_time(); + exit(1); + } + =} + + reaction(shutdown) {= + if(!received) { + reactor::log::Error() << "Nothing received."; + exit(1); + } + =} +} + +reactor Pong { + input in: int + output out: int + state received: bool = false + + reaction(in) -> out {= + received = true; + auto value = *in.get(); + reactor::log::Info() << "Pong Received " << value; + auto expected = 100ms * value; + if (get_elapsed_logical_time() != expected) { + reactor::log::Error() << "Expecded value at " << expected << " but received it at " << get_elapsed_logical_time(); + exit(1); + } + out.set(value); + =} + + reaction(shutdown) {= + if(!received) { + reactor::log::Error() << "Nothing received."; + exit(1); + } + =} +} + +main reactor { + ping = new Ping() + @enclave + pong = new Pong() + + ping.out -> pong.in + pong.out -> ping.in after 50 ms +} diff --git a/test/Cpp/src/enclave/EnclaveMultiportToPort2.lf b/test/Cpp/src/enclave/EnclaveMultiportToPort2.lf new file mode 100644 index 0000000000..5d8d72494d --- /dev/null +++ b/test/Cpp/src/enclave/EnclaveMultiportToPort2.lf @@ -0,0 +1,48 @@ +// Check multiport output to multiport input. Destination port is wider than +// sending port. +target Cpp { + timeout: 2 sec, + fast: true +} + +reactor Source { + output[2] out: int + + reaction(startup) -> out {= + for(int i = 0; i < out.size(); i++) { + std::cout << "Source sending " << i << ".\n"; + out[i].set(i); + } + =} +} + +reactor Destination(expected: int = 0) { + input in: int + state received: bool = false + + reaction(in) {= + std::cout << "Received: " << *in.get() << ".\n"; + received = true; + if (*in.get() != expected) { + std::cerr << "ERROR: Expected " << expected << ".\n"; + exit(1); + } + =} + + reaction(shutdown) {= + if (!received) { + std::cerr << "ERROR: Destination received no input!\n"; + exit(1); + } + std::cout << "Success.\n"; + =} +} + +main reactor { + @enclave + a = new Source() + @enclave + b1 = new Destination() + b2 = new Destination(expected = 1) + a.out -> b1.in, b2.in +} From 814e0bfec29c4d958f9a92b83fa0550709fd5fb6 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Mon, 8 May 2023 17:17:57 +0200 Subject: [PATCH 26/37] use vector of unique pointers to store connections --- org.lflang/src/lib/cpp/lfutil.hh | 2 -- .../generator/cpp/CppAssembleMethodGenerator.kt | 17 ++++++++++------- .../generator/cpp/CppConnectionGenerator.kt | 4 +--- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/org.lflang/src/lib/cpp/lfutil.hh b/org.lflang/src/lib/cpp/lfutil.hh index 292bd1db5e..77116dcbe1 100644 --- a/org.lflang/src/lib/cpp/lfutil.hh +++ b/org.lflang/src/lib/cpp/lfutil.hh @@ -27,8 +27,6 @@ #include #include -#include - namespace lfutil { template diff --git a/org.lflang/src/org/lflang/generator/cpp/CppAssembleMethodGenerator.kt b/org.lflang/src/org/lflang/generator/cpp/CppAssembleMethodGenerator.kt index 60f2ff62a7..0aef4a9b65 100644 --- a/org.lflang/src/org/lflang/generator/cpp/CppAssembleMethodGenerator.kt +++ b/org.lflang/src/org/lflang/generator/cpp/CppAssembleMethodGenerator.kt @@ -26,6 +26,7 @@ package org.lflang.generator.cpp import org.lflang.* import org.lflang.generator.PrependOperator +import org.lflang.generator.cpp.CppConnectionGenerator.Companion.cppType import org.lflang.generator.cpp.CppConnectionGenerator.Companion.isEnclaveConnection import org.lflang.generator.cpp.CppConnectionGenerator.Companion.name import org.lflang.generator.cpp.CppConnectionGenerator.Companion.requiresConnectionClass @@ -172,7 +173,7 @@ class CppAssembleMethodGenerator(private val reactor: Reactor) { * complex logic for finding the actual type, we return a decltype statement and let the C++ compiler do the job. */ private val VarRef.portType: String - get() = "reactor::Port<${dataType}>*" + get() = "reactor::Port*" private fun declareMultiportConnection(c: Connection, idx: Int): String { // It should be safe to assume that all ports have the same type. Thus we just pick the @@ -192,6 +193,7 @@ class CppAssembleMethodGenerator(private val reactor: Reactor) { ${" |"..c.leftPorts.joinWithLn { addAllPortsToVector(it, "__lf_left_ports_$idx") }} |std::vector<$portType> __lf_right_ports_$idx; ${" |"..c.rightPorts.joinWithLn { addAllPortsToVector(it, "__lf_right_ports_$idx") }} + |${c.name}.reserve(std::max(__lf_left_ports_$idx.size(), __lf_right_ports_$idx.size())); |lfutil::bind_multiple_ports<$portType>(__lf_left_ports_$idx, __lf_right_ports_$idx, ${c.isIterated}, ${" |"..c.getConnectionLambda(portType)} |); @@ -203,17 +205,18 @@ class CppAssembleMethodGenerator(private val reactor: Reactor) { return when { isEnclaveConnection -> """ [this]($portType left, $portType right, std::size_t idx) { - $name.emplace_back("$name" + std::to_string(idx), right->environment()${if (delay != null) ", ${delay.toCppTime()}" else ""}); - $name.back().bind_upstream_port(left); - $name.back().bind_downstream_port(right); + $name.push_back(std::make_unique<$cppType>( + "$name" + std::to_string(idx), right->environment()${if (delay != null) ", ${delay.toCppTime()}" else ""})); + $name.back()->bind_upstream_port(left); + $name.back()->bind_downstream_port(right); } """.trimIndent() requiresConnectionClass -> """ [this]($portType left, $portType right, std::size_t idx) { - $name.emplace_back("$name" + std::to_string(idx), this, ${delay.toCppTime()}); - $name.back().bind_upstream_port(left); - $name.back().bind_downstream_port(right); + $name.push_back(std::make_unique<$cppType>("$name" + std::to_string(idx), this, ${delay.toCppTime()})}); + $name.back()->bind_upstream_port(left); + $name.back()->bind_downstream_port(right); } """.trimIndent() diff --git a/org.lflang/src/org/lflang/generator/cpp/CppConnectionGenerator.kt b/org.lflang/src/org/lflang/generator/cpp/CppConnectionGenerator.kt index 83c3f5554a..c9af656291 100644 --- a/org.lflang/src/org/lflang/generator/cpp/CppConnectionGenerator.kt +++ b/org.lflang/src/org/lflang/generator/cpp/CppConnectionGenerator.kt @@ -63,9 +63,7 @@ class CppConnectionGenerator(private val reactor: Reactor) { with(connection) { if (requiresConnectionClass) { if (hasMultipleConnections) { - // We use an std::list here as connections currently cannot be safely moved and std::vector requires - // objects to be movable. - "std::list<${connection.cppType}> ${connection.name};" + "std::vector> ${connection.name};" } else { "${connection.cppType} ${connection.name};" } From 3d84b6c9fd4ea781d9e5085ce7c453c79f84f0f7 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Mon, 8 May 2023 17:27:17 +0200 Subject: [PATCH 27/37] format test --- test/Cpp/src/enclave/EnclaveBroadcast.lf | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/Cpp/src/enclave/EnclaveBroadcast.lf b/test/Cpp/src/enclave/EnclaveBroadcast.lf index d00fbbf059..04a2a77941 100644 --- a/test/Cpp/src/enclave/EnclaveBroadcast.lf +++ b/test/Cpp/src/enclave/EnclaveBroadcast.lf @@ -1,4 +1,6 @@ -target Cpp{timeout: 1 sec} +target Cpp { + timeout: 1 sec +} reactor Source { output out: unsigned @@ -31,7 +33,7 @@ reactor Sink(bank_index: size_t = 0) { main reactor { @enclave source = new Source() - @enclave(each=true) + @enclave(each = true) sink = new[4] Sink() (source.out)+ -> sink.in } From c0b51270dbe41cfa468b951f69ae909c2d2e2562 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Wed, 10 May 2023 12:42:52 +0200 Subject: [PATCH 28/37] only reserve if we have a dedicated connection vector --- .../org/lflang/generator/cpp/CppAssembleMethodGenerator.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/cpp/CppAssembleMethodGenerator.kt b/org.lflang/src/org/lflang/generator/cpp/CppAssembleMethodGenerator.kt index 0aef4a9b65..f944af8d90 100644 --- a/org.lflang/src/org/lflang/generator/cpp/CppAssembleMethodGenerator.kt +++ b/org.lflang/src/org/lflang/generator/cpp/CppAssembleMethodGenerator.kt @@ -180,9 +180,6 @@ class CppAssembleMethodGenerator(private val reactor: Reactor) { // first left port to determine the type of the entire connection val portType = c.leftPorts[0].portType - val leftPort = c.leftPorts[0].variable as Port - val dataType = leftPort.inferredType.cppType - // Generate code which adds all left hand ports and all right hand ports to a vector each. If we are handling multiports // within a bank, then we normally iterate over all banks in an outer loop and over all ports in an inner loop. However, // if the connection is an interleaved connection, than we change the order on the right side and iterate over ports before banks. @@ -193,7 +190,7 @@ class CppAssembleMethodGenerator(private val reactor: Reactor) { ${" |"..c.leftPorts.joinWithLn { addAllPortsToVector(it, "__lf_left_ports_$idx") }} |std::vector<$portType> __lf_right_ports_$idx; ${" |"..c.rightPorts.joinWithLn { addAllPortsToVector(it, "__lf_right_ports_$idx") }} - |${c.name}.reserve(std::max(__lf_left_ports_$idx.size(), __lf_right_ports_$idx.size())); + ${" |"..if (c.requiresConnectionClass) "{c.name}.reserve(std::max(__lf_left_ports_$idx.size(), __lf_right_ports_$idx.size()))" else ""} |lfutil::bind_multiple_ports<$portType>(__lf_left_ports_$idx, __lf_right_ports_$idx, ${c.isIterated}, ${" |"..c.getConnectionLambda(portType)} |); From 3b49f12e5bd26419411de0d6e299e47e44c15300 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Wed, 10 May 2023 13:20:57 +0200 Subject: [PATCH 29/37] update reactor-cpp --- org.lflang/src/lib/cpp/reactor-cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/lib/cpp/reactor-cpp b/org.lflang/src/lib/cpp/reactor-cpp index 4e75aec034..b4c6963ea6 160000 --- a/org.lflang/src/lib/cpp/reactor-cpp +++ b/org.lflang/src/lib/cpp/reactor-cpp @@ -1 +1 @@ -Subproject commit 4e75aec034f709de1236381ac9dcd7dbd3c8affe +Subproject commit b4c6963ea6a5d951a5cf71b947f550117bd9f688 From fa0e05806e429cc1d8a0250b2d9a37c775a93376 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Wed, 10 May 2023 13:22:08 +0200 Subject: [PATCH 30/37] bugfix --- .../src/org/lflang/generator/cpp/CppAssembleMethodGenerator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/org/lflang/generator/cpp/CppAssembleMethodGenerator.kt b/org.lflang/src/org/lflang/generator/cpp/CppAssembleMethodGenerator.kt index f944af8d90..503f5c950c 100644 --- a/org.lflang/src/org/lflang/generator/cpp/CppAssembleMethodGenerator.kt +++ b/org.lflang/src/org/lflang/generator/cpp/CppAssembleMethodGenerator.kt @@ -190,7 +190,7 @@ class CppAssembleMethodGenerator(private val reactor: Reactor) { ${" |"..c.leftPorts.joinWithLn { addAllPortsToVector(it, "__lf_left_ports_$idx") }} |std::vector<$portType> __lf_right_ports_$idx; ${" |"..c.rightPorts.joinWithLn { addAllPortsToVector(it, "__lf_right_ports_$idx") }} - ${" |"..if (c.requiresConnectionClass) "{c.name}.reserve(std::max(__lf_left_ports_$idx.size(), __lf_right_ports_$idx.size()))" else ""} + ${" |"..if (c.requiresConnectionClass) "${c.name}.reserve(std::max(__lf_left_ports_$idx.size(), __lf_right_ports_$idx.size()));" else ""} |lfutil::bind_multiple_ports<$portType>(__lf_left_ports_$idx, __lf_right_ports_$idx, ${c.isIterated}, ${" |"..c.getConnectionLambda(portType)} |); From f7261ea522426b4f0136ad895ef0523ea1e57042 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Wed, 10 May 2023 14:08:44 +0200 Subject: [PATCH 31/37] another C++ syntax fix --- .../src/org/lflang/generator/cpp/CppAssembleMethodGenerator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/org/lflang/generator/cpp/CppAssembleMethodGenerator.kt b/org.lflang/src/org/lflang/generator/cpp/CppAssembleMethodGenerator.kt index 503f5c950c..0bb63e24c3 100644 --- a/org.lflang/src/org/lflang/generator/cpp/CppAssembleMethodGenerator.kt +++ b/org.lflang/src/org/lflang/generator/cpp/CppAssembleMethodGenerator.kt @@ -211,7 +211,7 @@ class CppAssembleMethodGenerator(private val reactor: Reactor) { requiresConnectionClass -> """ [this]($portType left, $portType right, std::size_t idx) { - $name.push_back(std::make_unique<$cppType>("$name" + std::to_string(idx), this, ${delay.toCppTime()})}); + $name.push_back(std::make_unique<$cppType>("$name" + std::to_string(idx), this, ${delay.toCppTime()})); $name.back()->bind_upstream_port(left); $name.back()->bind_downstream_port(right); } From aae5cae30fbf753ef74d76eb0825d4bb9d497d04 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Wed, 10 May 2023 15:04:11 +0200 Subject: [PATCH 32/37] relax deadline --- test/Cpp/src/enclave/EnclaveSparseUpstreamEvents.lf | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/Cpp/src/enclave/EnclaveSparseUpstreamEvents.lf b/test/Cpp/src/enclave/EnclaveSparseUpstreamEvents.lf index 3bade0f63e..58bd641387 100644 --- a/test/Cpp/src/enclave/EnclaveSparseUpstreamEvents.lf +++ b/test/Cpp/src/enclave/EnclaveSparseUpstreamEvents.lf @@ -1,12 +1,12 @@ // The purpose of this test is to check that the downstream enclave can // progress, even if there are only sparse upstream events. target Cpp { - timeout: 6 s, + timeout: 12 s, workers: 1 } -reactor Src { - timer t(0, 2 s) +reactor Src {s + timer t(0, 4 s) output out: int state counter: int = 0 @@ -36,7 +36,7 @@ reactor Sink { } =} - reaction(t) {= reactor::log::Info() << "Tick"; =} deadline(1 s) {= + reaction(t) {= reactor::log::Info() << "Tick"; =} deadline(2 s) {= reactor::log::Error() << "Deadline violated."; exit(2); =} From 0554c99f93cf5176a4322844cf593e9a1164ff49 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Fri, 12 May 2023 09:55:48 +0200 Subject: [PATCH 33/37] fix test file --- test/Cpp/src/enclave/EnclaveSparseUpstreamEvents.lf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Cpp/src/enclave/EnclaveSparseUpstreamEvents.lf b/test/Cpp/src/enclave/EnclaveSparseUpstreamEvents.lf index 58bd641387..73a90dbd21 100644 --- a/test/Cpp/src/enclave/EnclaveSparseUpstreamEvents.lf +++ b/test/Cpp/src/enclave/EnclaveSparseUpstreamEvents.lf @@ -5,7 +5,7 @@ target Cpp { workers: 1 } -reactor Src {s +reactor Src { timer t(0, 4 s) output out: int state counter: int = 0 From a3055968837d34d8f8600adefdd0b65588bf5615 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Fri, 12 May 2023 10:37:30 +0200 Subject: [PATCH 34/37] relax more deadlines and update timings --- test/Cpp/src/enclave/EnclaveSparseUpstreamEvents.lf | 2 +- .../Cpp/src/enclave/EnclaveSparseUpstreamEventsDelayed.lf | 8 ++++---- .../src/enclave/EnclaveSparseUpstreamEventsPhysical.lf | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/test/Cpp/src/enclave/EnclaveSparseUpstreamEvents.lf b/test/Cpp/src/enclave/EnclaveSparseUpstreamEvents.lf index 73a90dbd21..431c2cd60a 100644 --- a/test/Cpp/src/enclave/EnclaveSparseUpstreamEvents.lf +++ b/test/Cpp/src/enclave/EnclaveSparseUpstreamEvents.lf @@ -22,7 +22,7 @@ reactor Sink { received = true; auto value = *in.get(); reactor::log::Info() << "Received " << value; - auto expected = 2s * value; + auto expected = 4s * value; if (get_elapsed_logical_time() != expected) { reactor::log::Error() << "Expected value at " << expected << " but received it at " << get_elapsed_logical_time(); exit(1); diff --git a/test/Cpp/src/enclave/EnclaveSparseUpstreamEventsDelayed.lf b/test/Cpp/src/enclave/EnclaveSparseUpstreamEventsDelayed.lf index e299f921ad..691e80f4bf 100644 --- a/test/Cpp/src/enclave/EnclaveSparseUpstreamEventsDelayed.lf +++ b/test/Cpp/src/enclave/EnclaveSparseUpstreamEventsDelayed.lf @@ -1,12 +1,12 @@ // The purpose of this test is to check that the downstream enclave respects the // after delay when aquiring tags from its upstream. target Cpp { - timeout: 6 s, + timeout: 12 s, workers: 1 } reactor Src { - timer t(0, 2 s) + timer t(0, 4 s) output out: int state counter: int = 0 @@ -22,7 +22,7 @@ reactor Sink { received = true; auto value = *in.get(); reactor::log::Info() << "Received " << value; - auto expected = 2s + 2s * value; + auto expected = 2s + 4s * value; if (get_elapsed_logical_time() != expected) { reactor::log::Error() << "Expected value at " << expected << " but received it at " << get_elapsed_logical_time(); exit(1); @@ -36,7 +36,7 @@ reactor Sink { } =} - reaction(t) {= reactor::log::Info() << "Tick"; =} deadline(1 s) {= + reaction(t) {= reactor::log::Info() << "Tick"; =} deadline(2 s) {= reactor::log::Error() << "Deadline violated."; exit(2); =} diff --git a/test/Cpp/src/enclave/EnclaveSparseUpstreamEventsPhysical.lf b/test/Cpp/src/enclave/EnclaveSparseUpstreamEventsPhysical.lf index 6e1e579bd0..10b5a8c4af 100644 --- a/test/Cpp/src/enclave/EnclaveSparseUpstreamEventsPhysical.lf +++ b/test/Cpp/src/enclave/EnclaveSparseUpstreamEventsPhysical.lf @@ -1,12 +1,12 @@ // The purpose of this test is to check that the downstream enclave advances // time independenty of the upstraem if the connection is physical. target Cpp { - timeout: 6 s, + timeout: 12 s, workers: 1 } reactor Src { - timer t(0, 2 s) + timer t(0, 4 s) output out: int state counter: int = 0 @@ -22,7 +22,7 @@ reactor Sink { received = true; auto value = *in.get(); reactor::log::Info() << "Received " << value; - auto expected = 2s * value; + auto expected = 4s * value; if (get_elapsed_logical_time() < expected) { reactor::log::Error() << "Expected value not before " << expected << " but received it at " << get_elapsed_logical_time(); exit(1); @@ -36,7 +36,7 @@ reactor Sink { } =} - reaction(t) {= reactor::log::Info() << "Tick"; =} deadline(1 s) {= + reaction(t) {= reactor::log::Info() << "Tick"; =} deadline(2 s) {= reactor::log::Error() << "Deadline violated."; exit(2); =} From 48898a273cacaaee9360da69268c2da5bd3b9332 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Fri, 12 May 2023 14:02:54 +0200 Subject: [PATCH 35/37] update reactor-cpp --- org.lflang/src/lib/cpp/reactor-cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/lib/cpp/reactor-cpp b/org.lflang/src/lib/cpp/reactor-cpp index b4c6963ea6..1b6b996af5 160000 --- a/org.lflang/src/lib/cpp/reactor-cpp +++ b/org.lflang/src/lib/cpp/reactor-cpp @@ -1 +1 @@ -Subproject commit b4c6963ea6a5d951a5cf71b947f550117bd9f688 +Subproject commit 1b6b996af5a33e16665113d52311316e37825520 From b7d0cd1b820c154ceebb80cf4fa9e0099258c51f Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Mon, 15 May 2023 17:43:45 +0200 Subject: [PATCH 36/37] update reactor-cpp --- org.lflang/src/lib/cpp/reactor-cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/lib/cpp/reactor-cpp b/org.lflang/src/lib/cpp/reactor-cpp index 1b6b996af5..1d17d9c543 160000 --- a/org.lflang/src/lib/cpp/reactor-cpp +++ b/org.lflang/src/lib/cpp/reactor-cpp @@ -1 +1 @@ -Subproject commit 1b6b996af5a33e16665113d52311316e37825520 +Subproject commit 1d17d9c5439d57e00145798e4dbd87d18342b891 From 036625c6a9759e40fb73e061d34455b0763562b0 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Tue, 16 May 2023 09:23:13 +0200 Subject: [PATCH 37/37] update reactor-cpp --- org.lflang/src/lib/cpp/reactor-cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/lib/cpp/reactor-cpp b/org.lflang/src/lib/cpp/reactor-cpp index 1d17d9c543..10a8055a65 160000 --- a/org.lflang/src/lib/cpp/reactor-cpp +++ b/org.lflang/src/lib/cpp/reactor-cpp @@ -1 +1 @@ -Subproject commit 1d17d9c5439d57e00145798e4dbd87d18342b891 +Subproject commit 10a8055a65ce4aec8b4c560b363046f08d46342f