From b7104b4b03687f04b6af6d638eb07c557c2acae4 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Thu, 11 Jan 2024 13:41:45 +0100 Subject: [PATCH 01/42] Add isTransient member to a federated instance and parse the transient attribute --- core/src/main/java/org/lflang/AttributeUtils.java | 5 +++++ .../org/lflang/federated/generator/FederateInstance.java | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/core/src/main/java/org/lflang/AttributeUtils.java b/core/src/main/java/org/lflang/AttributeUtils.java index 147a4b6d0d..2b09831107 100644 --- a/core/src/main/java/org/lflang/AttributeUtils.java +++ b/core/src/main/java/org/lflang/AttributeUtils.java @@ -234,6 +234,11 @@ public static boolean isSparse(EObject node) { return findAttributeByName(node, "sparse") != null; } + /** Return true if the node has an {@code @transient} attribute. */ + public static boolean isTransient(Instantiation node) { + return findAttributeByName(node, "transient") != null; + } + /** Return true if the reactor is marked to be a federate. */ public static boolean isFederate(Reactor reactor) { return findAttributeByName(reactor, "_fed_config") != null; diff --git a/core/src/main/java/org/lflang/federated/generator/FederateInstance.java b/core/src/main/java/org/lflang/federated/generator/FederateInstance.java index 975000c7cb..31c9c21bfb 100644 --- a/core/src/main/java/org/lflang/federated/generator/FederateInstance.java +++ b/core/src/main/java/org/lflang/federated/generator/FederateInstance.java @@ -36,6 +36,7 @@ import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.lflang.AttributeUtils; import org.lflang.MessageReporter; import org.lflang.TimeValue; import org.lflang.ast.ASTUtils; @@ -95,6 +96,7 @@ public FederateInstance( this.bankWidth = bankWidth; this.messageReporter = messageReporter; this.targetConfig = targetConfig; + this.isTransient = AttributeUtils.isTransient(instantiation); // If the instantiation is in a bank, then we have to append // the bank index to the name. @@ -156,6 +158,9 @@ public Instantiation getInstantiation() { /** The integer ID of this federate. */ public int id; + /** Type of the federate: transient if true, and peristent if false . */ + public boolean isTransient = false; + /** * The name of this federate instance. This will be the instantiation name, possibly appended with * "__n", where n is the bank position of this instance if the instantiation is of a bank of From d01b2bf317ce22facf5126dc0def017b28a6b687 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Thu, 11 Jan 2024 13:47:43 +0100 Subject: [PATCH 02/42] Set the transient indicator --- .../main/java/org/lflang/federated/extensions/CExtension.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/src/main/java/org/lflang/federated/extensions/CExtension.java b/core/src/main/java/org/lflang/federated/extensions/CExtension.java index 49ae228f68..d44e3af1d7 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtension.java @@ -713,6 +713,8 @@ private String generateCodeToInitializeFederate(FederateInstance federate, RtiCo } // Set global variable identifying the federate. code.pr("_lf_my_fed_id = " + federate.id + ";"); + // Set indicator variable that specifies whether the federate is transient or not. + code.pr("_fed.is_transient = " + federate.isTransient + ";"); // We keep separate record for incoming and outgoing p2p connections to allow incoming traffic // to be processed in a separate From ccc6b6a5b4aa8a3d0b41d66389901c83daa12c69 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Tue, 20 Feb 2024 21:49:01 +0100 Subject: [PATCH 03/42] Make federates bin directory visible --- core/src/main/java/org/lflang/generator/c/CCompiler.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/src/main/java/org/lflang/generator/c/CCompiler.java b/core/src/main/java/org/lflang/generator/c/CCompiler.java index 98ca19aacf..b9945b0ed5 100644 --- a/core/src/main/java/org/lflang/generator/c/CCompiler.java +++ b/core/src/main/java/org/lflang/generator/c/CCompiler.java @@ -219,6 +219,7 @@ private static List cmakeOptions(TargetConfig targetConfig, FileConfig f String maybeQuote = ""; // Windows seems to require extra level of quoting. String srcPath = fileConfig.srcPath.toString(); // Windows requires escaping the backslashes. String rootPath = fileConfig.srcPkgPath.toString(); + String binPath = fileConfig.binPath.toString(); String srcGenPath = fileConfig.getSrcGenPath().toString(); if (separator.equals("\\")) { separator = "\\\\\\\\"; @@ -226,6 +227,7 @@ private static List cmakeOptions(TargetConfig targetConfig, FileConfig f srcPath = srcPath.replaceAll("\\\\", "\\\\\\\\"); rootPath = rootPath.replaceAll("\\\\", "\\\\\\\\"); srcGenPath = srcGenPath.replaceAll("\\\\", "\\\\\\\\"); + binPath = binPath.replaceAll("\\\\", "\\\\\\\\"); } arguments.addAll( List.of( @@ -245,6 +247,8 @@ private static List cmakeOptions(TargetConfig targetConfig, FileConfig f arguments.add("-DLF_SOURCE_DIRECTORY=\"" + maybeQuote + srcPath + maybeQuote + "\""); arguments.add("-DLF_PACKAGE_DIRECTORY=\"" + maybeQuote + rootPath + maybeQuote + "\""); arguments.add("-DLF_SOURCE_GEN_DIRECTORY=\"" + maybeQuote + srcGenPath + maybeQuote + "\""); + } else { + arguments.add("-DLF_FEDERATES_BIN_DIRECTORY=\"" + maybeQuote + binPath + maybeQuote + "\""); } arguments.add(FileUtil.toUnixString(fileConfig.getSrcGenPath())); From 5d23ac069904a4ab2a82ecfcebdb0e6edb98df9e Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Thu, 11 Jan 2024 13:54:42 +0100 Subject: [PATCH 04/42] Add support of transient attribute --- core/src/main/java/org/lflang/validation/AttributeSpec.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/src/main/java/org/lflang/validation/AttributeSpec.java b/core/src/main/java/org/lflang/validation/AttributeSpec.java index a685e98ca7..cb13cca247 100644 --- a/core/src/main/java/org/lflang/validation/AttributeSpec.java +++ b/core/src/main/java/org/lflang/validation/AttributeSpec.java @@ -205,6 +205,8 @@ enum AttrParamType { new AttributeSpec(List.of(new AttrParamSpec(VALUE_ATTR, AttrParamType.STRING, false)))); // @sparse ATTRIBUTE_SPECS_BY_NAME.put("sparse", new AttributeSpec(null)); + // @transient + ATTRIBUTE_SPECS_BY_NAME.put("transient", new AttributeSpec(null)); // @icon("value") ATTRIBUTE_SPECS_BY_NAME.put( "icon", From d49a7ed2954b22a8d9645ffaa7c8ce57664fa2af Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Thu, 11 Jan 2024 14:08:23 +0100 Subject: [PATCH 05/42] Transient annotation is only allowed for federates + Leave fixmes about the coordination and the target --- .../java/org/lflang/validation/LFValidator.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/core/src/main/java/org/lflang/validation/LFValidator.java b/core/src/main/java/org/lflang/validation/LFValidator.java index e12ab17061..6a8b139094 100644 --- a/core/src/main/java/org/lflang/validation/LFValidator.java +++ b/core/src/main/java/org/lflang/validation/LFValidator.java @@ -534,6 +534,21 @@ public void checkInstantiation(Instantiation instantiation) { error("Variable-width banks are not supported.", Literals.INSTANTIATION__WIDTH_SPEC); } } + + // If the Instantiation is annotated as '@transient', then: + // - The container has to be a federated reactor, + // - The coordination is centralized, + // - And the target is C. + // FIXME: Conditions 2 and 3 need to be checked + // FIXME: Add support of transients in decentralized coordination. + if (AttributeUtils.isTransient(instantiation)) { + Reactor container = (Reactor) instantiation.eContainer(); + if (!container.isFederated()) { + error( + "Only federates can be transients: " + instantiation.getReactorClass().getName(), + Literals.INSTANTIATION__REACTOR_CLASS); + } + } } @Check(CheckType.FAST) From 4908b60d613c17d77a7fcab212dd37bd637cea33 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Wed, 14 Feb 2024 16:21:02 +0100 Subject: [PATCH 06/42] Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 188fb3c983..292a3385d3 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 188fb3c983aac9ea7bcafa4e5172daaa5f8a883d +Subproject commit 292a3385d3ac83ea62b17fd3c9b9fd19cf15d4be From 70ea192d90b061eb72fd2e1449c9780e0b30217c Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Mon, 19 Feb 2024 16:27:09 +0100 Subject: [PATCH 07/42] Add the number of transients option to the fderation launcher script --- .../lflang/federated/launcher/FedLauncherGenerator.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java index 67cc8085f0..9020f4ed60 100644 --- a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java +++ b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java @@ -323,9 +323,17 @@ private String getRtiCommand(List federates, boolean isRemote) if (targetConfig.getOrDefault(TracingProperty.INSTANCE).isEnabled()) { commands.add(" -t \\"); } + // Identify the transient federates number + int transientFederatesNumber = 0; + for (FederateInstance federate : federates) { + if (federate.isTransient) { + transientFederatesNumber++; + } + } commands.addAll( List.of( " -n " + federates.size() + " \\", + " -nt " + transientFederatesNumber + " \\", " -c " + targetConfig.getOrDefault(ClockSyncModeProperty.INSTANCE).toString() + " \\")); From 55e54136510a586065a6de60a728cd710bce76b2 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Mon, 19 Feb 2024 16:33:32 +0100 Subject: [PATCH 08/42] Fix script identation --- .../org/lflang/federated/launcher/FedLauncherGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java index 9020f4ed60..719419c89a 100644 --- a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java +++ b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java @@ -333,7 +333,7 @@ private String getRtiCommand(List federates, boolean isRemote) commands.addAll( List.of( " -n " + federates.size() + " \\", - " -nt " + transientFederatesNumber + " \\", + " -nt " + transientFederatesNumber + " \\", " -c " + targetConfig.getOrDefault(ClockSyncModeProperty.INSTANCE).toString() + " \\")); From cf396689efe60b91f998301067654ea2c26722d3 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Tue, 20 Feb 2024 22:16:12 +0100 Subject: [PATCH 09/42] Add transients tests --- .../transient/TransientDownstreamWithTimer.lf | 157 ++++++++++++++++++ .../TransientDownstreamWithTwoUpstream.lf | 125 ++++++++++++++ .../federated/transient/TransientHotSwap.lf | 154 +++++++++++++++++ 3 files changed, 436 insertions(+) create mode 100644 test/C/src/federated/transient/TransientDownstreamWithTimer.lf create mode 100644 test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf create mode 100644 test/C/src/federated/transient/TransientHotSwap.lf diff --git a/test/C/src/federated/transient/TransientDownstreamWithTimer.lf b/test/C/src/federated/transient/TransientDownstreamWithTimer.lf new file mode 100644 index 0000000000..9bfedfc89a --- /dev/null +++ b/test/C/src/federated/transient/TransientDownstreamWithTimer.lf @@ -0,0 +1,157 @@ +/** + * This LF program tests if a transient federate corretly leaves then joins the federation. It also + * tests if the transient's downstream executes as expected, that is it received correct TAGs, + * regardless of the transient being absent or present. In this test: + * - the transient federate spontaneously leaves the federation after 2 reactions to input port `in`, + * - the downstream of the transient federate has only one transient as upstream. + */ +target C { + timeout: 2 s +} + +preamble {= + #include + #include +=} + +/** Persistent federate that is responsible for lauching the transient federate */ +reactor TransientExec(offset: time = 0, period: time = 0, fed_instance_name: char* = "instance") { + timer t(offset, period) + + reaction(t) {= + // Construct the command to launch the transient federate + char mid_launch_cmd[512]; + sprintf(mid_launch_cmd, + "%s/federate__%s -i %s", + lf_get_federates_bin_directory(), + self->fed_instance_name, + lf_get_federation_id() + ); + + lf_print("Launching federate federate__%s at physical time " PRINTF_TIME ".", + mid_launch_cmd, + lf_time_physical()); + + int status = system(mid_launch_cmd); + + // Exit if error + if (status == 0) { + lf_print("Successfully launched federate__%s.", self->fed_instance_name); + } else { + lf_print_error_and_exit("Unable to launch federate__%s. Abort!", self->fed_instance_name); + } + =} +} + +/** + * Persistent federate, upstream of the transient. It reacts to its timer by sending increments to + * output port out. + */ +reactor Up(period: time = 500 ms) { + output out: int + timer t(0, period) + state count: int = 0 + + reaction(t) -> out {= + lf_set(out, self->count); + self->count++; + =} +} + +/** + * Transient federate that forwards whatever it receives from `Up` to `Down`. It reacts twice to + * input port `in`, then stops. It will execute twice during the lifetime of the federation. + * The second launch is done by `TransientExec` at logical time 1 s. Each time `Middle` joins, + * it notifies `Down`. + */ +reactor Middle { + input in: int + output out: int + output join: int + state count: int = 0 + + // Middle notifies its downstream that he joined, but make sure first that the effective start + // tag is correct + reaction(startup) -> join {= + if(lf_get_effective_start_time() < lf_get_start_time()) { + lf_print_error_and_exit("Fatal error: the transient's effective start time is less than the federation start time"); + } + + lf_set(join, 0); + =} + + // Pass the input value to the output port and stop spontaneously after two reactions to in + reaction(in) -> out {= + self->count++; + lf_set(out, in->value); + + if (self->count == 2) { + lf_stop(); + } + =} +} + +/** + * Persistent federate, which is downstream of the transient. It has to keep reacting to its + * internal timer and also to inputs from the tansient, if any. + */ +reactor Down { + timer t(0, 500 ms) + + input in: int + input join: int + + state count_timer: int = 0 + state count_join: int = 0 + state count_in_mid_reactions: int = 0 + + reaction(t) {= + self->count_timer++; + =} + + reaction(in) {= + self->count_in_mid_reactions++; + =} + + reaction(join) {= + self->count_join++; + =} + + reaction(shutdown) {= + // Check that the TAG has been successfully issued to Down + if (self->count_timer != 5) { + lf_print_error_and_exit("Federate's timer reacted %d times, while it had to react %d times.", + self->count_timer, + 5); + } + + // Check that `Middle` have joined 2 times + if (self->count_join != 2) { + lf_print_error_and_exit("Transient federate did not join twice, but %d times!", self->count_join); + } + + // Check that `Middle` have reacted correctly + if (self->count_in_mid_reactions < 4) { + lf_print_error_and_exit("Transient federate Mid did not execute and pass values from up corretly! Expected >= 4, but had: %d.", + self->count_in_mid_reactions); + } + =} +} + +federated reactor { + // Persistent federate that is responsible for lauching the transient once, after 1s + midExec = new TransientExec(offset = 1 s, fed_instance_name="mid") + + // Persistent downstream and upstream federates of the transient + up = new Up() + down = new Down() + + // Transient federate + @transient + mid = new Middle() + + // Connections + up.out -> mid.in + mid.join -> down.join + mid.out -> down.in +} diff --git a/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf b/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf new file mode 100644 index 0000000000..d71179f8b3 --- /dev/null +++ b/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf @@ -0,0 +1,125 @@ +/** + * This LF program tests if a transient federate corretly leaves then joins the federation. It also + * tests if the transient's downstream executes as expected, that is it received correct TAGs, + * regardless of the transient being absent or present. In this test: + * - the transient federate spontaneously leaves the federation after 2 reactions to input port in, + * - the downstream of the transient federate has one persistent and one transient upstreams. + */ +target C { + timeout: 2 s +} + +import Up from "TransientDownstreamWithTimer.lf" +import Middle from "TransientDownstreamWithTimer.lf" + +preamble {= + #include + #include +=} + +/** Persistent federate that is responsible for lauching the transient federate */ +reactor TransientExec(offset: time = 0, period: time = 0, fed_instance_name: char* = "instance") { + timer t(offset, period) + + reaction(t) {= + // Construct the command to launch the transient federate + char mid_launch_cmd[512]; + sprintf(mid_launch_cmd, + "%s/federate__%s -i %s", + lf_get_federates_bin_directory(), + self->fed_instance_name, + lf_get_federation_id() + ); + + lf_print("Launching federate federate__%s at physical time " PRINTF_TIME ".", + mid_launch_cmd, + lf_time_physical()); + + int status = system(mid_launch_cmd); + + // Exit if error + if (status == 0) { + lf_print("Successfully launched federate__%s.", self->fed_instance_name); + } else { + lf_print_error_and_exit("Unable to launch federate__%s. Abort!", self->fed_instance_name); + } + =} +} + +/** + * Persistent federate, which is downstream of the transient. It has to keep reacting to its + * internal timer and also to inputs from the tansient, if any. + */ +reactor Down { + timer t(0, 500 ms) + + input in_mid: int + input in_up: int + input join: int + + state count_timer: int = 0 + state count_join: int = 0 + state count_in_mid_reactions: int = 0 + state count_in_up_reactions: int = 0 + + reaction(t) {= + self->count_timer++; + =} + + reaction(in_mid) {= + self->count_in_mid_reactions++; + =} + + reaction(in_up) {= + self->count_in_up_reactions++; + =} + + reaction(join) {= + self->count_join++; + =} + + reaction(shutdown) {= + // Check that the TAG have been successfully issued to Down + if (self->count_timer != 5) { + lf_print_error_and_exit("Federate's timer reacted %d times, while it had to react %d times.", + self->count_timer, + 5); + } + if (self->count_in_up_reactions != 7) { + lf_print_error_and_exit("Federate's timer reacted %d times, while it had to react %d times.", + self->count_in_up_reactions, + 7); + } + + // Check that Middle have joined 2 times + if (self->count_join != 2) { + lf_print_error_and_exit("Transient federate did not join twice, but %d times!", self->count_join); + } + + // Check that Middle have reacted correctly + if (self->count_in_mid_reactions < 4) { + lf_print_error_and_exit("Transient federate Mid did not execute and pass values from up corretly! Expected >= 4, but had: %d.", + self->count_in_mid_reactions); + } + =} +} + +federated reactor { + // Persistent federate that is responsible for lauching the transient once, after 1s + midExec = new TransientExec(offset = 1 s, fed_instance_name="mid") + + // Persistent downstream and upstream federates of the transient + up1 = new Up() + up2 = new Up(period = 300 msec) + down = new Down() + + // Transient federate + @transient + mid = new Middle() + + // Connections + up1.out -> mid.in + mid.join -> down.join + mid.out -> down.in_mid + up2.out -> down.in_up +} diff --git a/test/C/src/federated/transient/TransientHotSwap.lf b/test/C/src/federated/transient/TransientHotSwap.lf new file mode 100644 index 0000000000..9083bbe86a --- /dev/null +++ b/test/C/src/federated/transient/TransientHotSwap.lf @@ -0,0 +1,154 @@ +/** + * This LF program is a variant of TransientDownstreamWithTimer that tests the Hot Swap + * mechanism. For this, it tests if the transient's downstream executes as expected. + * In this test: + * - the transient federate DO NOT spontaneously leave the federation. + * - the downstream of the transient federate has only one transient as upstream. + * - A persistent federate `HotSwapMiddle` executes `mid` after 1s to launch the hot swap. + */ +target C { + timeout: 2 s +} + +preamble {= + #include + #include +=} + +/** Persistent federate that is responsible for lauching the transient federate */ +reactor TransientExec(offset: time = 0, period: time = 0, fed_instance_name: char* = "instance") { + timer t(offset, period) + + reaction(t) {= + // Construct the command to launch the transient federate + char mid_launch_cmd[512]; + sprintf(mid_launch_cmd, + "%s/federate__%s -i %s", + lf_get_federates_bin_directory(), + self->fed_instance_name, + lf_get_federation_id() + ); + + lf_print("Launching federate federate__%s at physical time " PRINTF_TIME ".", + mid_launch_cmd, + lf_time_physical()); + + int status = system(mid_launch_cmd); + + // Exit if error + if (status == 0) { + lf_print("Successfully launched federate__%s.", self->fed_instance_name); + } else { + lf_print_error_and_exit("Unable to launch federate__%s. Abort!", self->fed_instance_name); + } + =} +} + +/** + * Persistent federate, upstream of the transient. It reacts to its timer by sending increments to + * output port out. + */ +reactor Up(period: time = 500 ms) { + output out: int + timer t(0, period) + state count: int = 0 + + reaction(t) -> out {= + lf_set(out, self->count); + self->count++; + =} +} + +/** + * Transient federate that forwards whatever it receives from `Up` to `Down`. It reacts twice to + * input port `in`, then stops. It will execute twice during the lifetime of the federation. + * The second launch is done by `TransientExec` at logical time 1 s. Each time `Middle` joins, + * it notifies `Down`. + */ +reactor Middle { + input in: int + output out: int + output join: int + state count: int = 0 + + // Middle notifies its downstream that he joined, but make sure first that the effective start + // tag is correct + reaction(startup) -> join {= + if(lf_get_effective_start_time() < lf_get_start_time()) { + lf_print_error_and_exit("Fatal error: the transient's effective start time is less than the federation start time"); + } + + lf_set(join, 0); + =} + + // Pass the input value to the output port + reaction(in) -> out {= + self->count++; + lf_set(out, in->value); + =} +} + +/** + * Persistent federate, which is downstream of the transient. It has to keep reacting to its + * internal timer and also to inputs from the tansient, if any. + */ +reactor Down { + timer t(0, 500 ms) + + input in: int + input join: int + + state count_timer: int = 0 + state count_join: int = 0 + state count_in_mid_reactions: int = 0 + + reaction(t) {= + self->count_timer++; + =} + + reaction(in) {= + self->count_in_mid_reactions++; + =} + + reaction(join) {= + self->count_join++; + =} + + reaction(shutdown) {= + // Check that the TAG has been successfully issued to Down + if (self->count_timer != 5) { + lf_print_error_and_exit("Federate's timer reacted %d times, while it had to react %d times.", + self->count_timer, + 5); + } + + // Check that `Middle` have joined 2 times + if (self->count_join != 2) { + lf_print_error_and_exit("Transient federate did not join twice, but %d times!", self->count_join); + } + + // Check that `Middle` have reacted correctly + if (self->count_in_mid_reactions < 4) { + lf_print_error_and_exit("Transient federate Mid did not execute and pass values from up corretly! Expected >= 4, but had: %d.", + self->count_in_mid_reactions); + } + =} +} + +federated reactor { + // Persistent federate that is responsible for lauching the transient once, after 1s + midExec = new TransientExec(offset = 1 s, fed_instance_name="mid") + + // Persistent downstream and upstream federates of the transient + up = new Up() + down = new Down() + + // Transient federate + @transient + mid = new Middle() + + // Connections + up.out -> mid.in + mid.join -> down.join + mid.out -> down.in +} From b31140239d58953b16f90072ac4b3b6a072ad562 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Tue, 20 Feb 2024 22:18:00 +0100 Subject: [PATCH 10/42] Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 292a3385d3..1406e3ce18 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 292a3385d3ac83ea62b17fd3c9b9fd19cf15d4be +Subproject commit 1406e3ce18d4a4eeda48943cdf89f007e26bf3f4 From bed73cfb207091aacbbf35b336a3cb7d8052e644 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Tue, 20 Feb 2024 22:56:28 +0100 Subject: [PATCH 11/42] Apply spotless --- .../federated/generator/FederateInstance.java | 2 +- .../java/org/lflang/validation/LFValidator.java | 4 ++-- .../transient/TransientDownstreamWithTimer.lf | 9 +++++---- .../C/src/federated/transient/TransientHotSwap.lf | 15 +++++++-------- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/core/src/main/java/org/lflang/federated/generator/FederateInstance.java b/core/src/main/java/org/lflang/federated/generator/FederateInstance.java index 31c9c21bfb..e63fb63201 100644 --- a/core/src/main/java/org/lflang/federated/generator/FederateInstance.java +++ b/core/src/main/java/org/lflang/federated/generator/FederateInstance.java @@ -160,7 +160,7 @@ public Instantiation getInstantiation() { /** Type of the federate: transient if true, and peristent if false . */ public boolean isTransient = false; - + /** * The name of this federate instance. This will be the instantiation name, possibly appended with * "__n", where n is the bank position of this instance if the instantiation is of a bank of diff --git a/core/src/main/java/org/lflang/validation/LFValidator.java b/core/src/main/java/org/lflang/validation/LFValidator.java index 6a8b139094..7a97ac0a02 100644 --- a/core/src/main/java/org/lflang/validation/LFValidator.java +++ b/core/src/main/java/org/lflang/validation/LFValidator.java @@ -536,10 +536,10 @@ public void checkInstantiation(Instantiation instantiation) { } // If the Instantiation is annotated as '@transient', then: - // - The container has to be a federated reactor, + // - The container has to be a federated reactor, // - The coordination is centralized, // - And the target is C. - // FIXME: Conditions 2 and 3 need to be checked + // FIXME: Conditions 2 and 3 need to be checked // FIXME: Add support of transients in decentralized coordination. if (AttributeUtils.isTransient(instantiation)) { Reactor container = (Reactor) instantiation.eContainer(); diff --git a/test/C/src/federated/transient/TransientDownstreamWithTimer.lf b/test/C/src/federated/transient/TransientDownstreamWithTimer.lf index 9bfedfc89a..ad4bd0d86d 100644 --- a/test/C/src/federated/transient/TransientDownstreamWithTimer.lf +++ b/test/C/src/federated/transient/TransientDownstreamWithTimer.lf @@ -2,7 +2,8 @@ * This LF program tests if a transient federate corretly leaves then joins the federation. It also * tests if the transient's downstream executes as expected, that is it received correct TAGs, * regardless of the transient being absent or present. In this test: - * - the transient federate spontaneously leaves the federation after 2 reactions to input port `in`, + * - the transient federate spontaneously leaves the federation after 2 reactions to input port + * `in`, * - the downstream of the transient federate has only one transient as upstream. */ target C { @@ -60,9 +61,9 @@ reactor Up(period: time = 500 ms) { /** * Transient federate that forwards whatever it receives from `Up` to `Down`. It reacts twice to - * input port `in`, then stops. It will execute twice during the lifetime of the federation. - * The second launch is done by `TransientExec` at logical time 1 s. Each time `Middle` joins, - * it notifies `Down`. + * input port `in`, then stops. It will execute twice during the lifetime of the federation. The + * second launch is done by `TransientExec` at logical time 1 s. Each time `Middle` joins, it + * notifies `Down`. */ reactor Middle { input in: int diff --git a/test/C/src/federated/transient/TransientHotSwap.lf b/test/C/src/federated/transient/TransientHotSwap.lf index 9083bbe86a..e2220cee94 100644 --- a/test/C/src/federated/transient/TransientHotSwap.lf +++ b/test/C/src/federated/transient/TransientHotSwap.lf @@ -1,10 +1,9 @@ /** - * This LF program is a variant of TransientDownstreamWithTimer that tests the Hot Swap - * mechanism. For this, it tests if the transient's downstream executes as expected. - * In this test: + * This LF program is a variant of TransientDownstreamWithTimer that tests the Hot Swap mechanism. + * For this, it tests if the transient's downstream executes as expected. In this test: * - the transient federate DO NOT spontaneously leave the federation. * - the downstream of the transient federate has only one transient as upstream. - * - A persistent federate `HotSwapMiddle` executes `mid` after 1s to launch the hot swap. + * - A persistent federate `HotSwapMiddle` executes `mid` after 1s to launch the hot swap. */ target C { timeout: 2 s @@ -61,9 +60,9 @@ reactor Up(period: time = 500 ms) { /** * Transient federate that forwards whatever it receives from `Up` to `Down`. It reacts twice to - * input port `in`, then stops. It will execute twice during the lifetime of the federation. - * The second launch is done by `TransientExec` at logical time 1 s. Each time `Middle` joins, - * it notifies `Down`. + * input port `in`, then stops. It will execute twice during the lifetime of the federation. The + * second launch is done by `TransientExec` at logical time 1 s. Each time `Middle` joins, it + * notifies `Down`. */ reactor Middle { input in: int @@ -81,7 +80,7 @@ reactor Middle { lf_set(join, 0); =} - // Pass the input value to the output port + // Pass the input value to the output port reaction(in) -> out {= self->count++; lf_set(out, in->value); From 41ba62a40944b422d5fdeb714bd86547f8558537 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Tue, 20 Feb 2024 22:57:04 +0100 Subject: [PATCH 12/42] Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 1406e3ce18..6810a281fd 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 1406e3ce18d4a4eeda48943cdf89f007e26bf3f4 +Subproject commit 6810a281fd1e2008c32b6f6198443361e63617c0 From f45ae3127ce5bf532d6c3f2997e04460f883ff99 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Tue, 20 Feb 2024 23:13:11 +0100 Subject: [PATCH 13/42] Apply spotless --- .../java/org/lflang/federated/generator/FederateInstance.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/main/java/org/lflang/federated/generator/FederateInstance.java b/core/src/main/java/org/lflang/federated/generator/FederateInstance.java index e63fb63201..2834a74984 100644 --- a/core/src/main/java/org/lflang/federated/generator/FederateInstance.java +++ b/core/src/main/java/org/lflang/federated/generator/FederateInstance.java @@ -159,7 +159,6 @@ public Instantiation getInstantiation() { public int id; /** Type of the federate: transient if true, and peristent if false . */ - public boolean isTransient = false; /** * The name of this federate instance. This will be the instantiation name, possibly appended with From e18eb020e2c28c8dcd702bc671355ca7b42f46b8 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Wed, 21 Feb 2024 12:26:09 +0100 Subject: [PATCH 14/42] Fix accidentally removed line from FederateInstance.java --- .../java/org/lflang/federated/generator/FederateInstance.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/java/org/lflang/federated/generator/FederateInstance.java b/core/src/main/java/org/lflang/federated/generator/FederateInstance.java index 2834a74984..e63fb63201 100644 --- a/core/src/main/java/org/lflang/federated/generator/FederateInstance.java +++ b/core/src/main/java/org/lflang/federated/generator/FederateInstance.java @@ -159,6 +159,7 @@ public Instantiation getInstantiation() { public int id; /** Type of the federate: transient if true, and peristent if false . */ + public boolean isTransient = false; /** * The name of this federate instance. This will be the instantiation name, possibly appended with From eb6fe8154b96e238a22d2343b3beaa3579cf4bfd Mon Sep 17 00:00:00 2001 From: Chadlia Jerad <37504116+ChadliaJerad@users.noreply.github.com> Date: Thu, 22 Feb 2024 09:22:34 +0100 Subject: [PATCH 15/42] Update core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java Co-authored-by: Edward A. Lee --- .../org/lflang/federated/launcher/FedLauncherGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java index 719419c89a..37f62f5586 100644 --- a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java +++ b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java @@ -323,7 +323,7 @@ private String getRtiCommand(List federates, boolean isRemote) if (targetConfig.getOrDefault(TracingProperty.INSTANCE).isEnabled()) { commands.add(" -t \\"); } - // Identify the transient federates number + // Identify the number of transient federates. int transientFederatesNumber = 0; for (FederateInstance federate : federates) { if (federate.isTransient) { From 3c6802d54193eaca73349288750fd6a79854257c Mon Sep 17 00:00:00 2001 From: Chadlia Jerad <37504116+ChadliaJerad@users.noreply.github.com> Date: Thu, 22 Feb 2024 09:33:39 +0100 Subject: [PATCH 16/42] Update test/C/src/federated/transient/TransientHotSwap.lf Co-authored-by: Edward A. Lee --- test/C/src/federated/transient/TransientHotSwap.lf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/C/src/federated/transient/TransientHotSwap.lf b/test/C/src/federated/transient/TransientHotSwap.lf index e2220cee94..f69f82b3fa 100644 --- a/test/C/src/federated/transient/TransientHotSwap.lf +++ b/test/C/src/federated/transient/TransientHotSwap.lf @@ -1,7 +1,7 @@ /** * This LF program is a variant of TransientDownstreamWithTimer that tests the Hot Swap mechanism. * For this, it tests if the transient's downstream executes as expected. In this test: - * - the transient federate DO NOT spontaneously leave the federation. + * - the transient federate DOES NOT spontaneously leave the federation. * - the downstream of the transient federate has only one transient as upstream. * - A persistent federate `HotSwapMiddle` executes `mid` after 1s to launch the hot swap. */ From 0989e72528426586cc3c2e5d0b6b44a4b3538914 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Thu, 22 Feb 2024 09:57:18 +0100 Subject: [PATCH 17/42] Address review by removing FIXMEs and open an issue instead --- core/src/main/java/org/lflang/validation/LFValidator.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/src/main/java/org/lflang/validation/LFValidator.java b/core/src/main/java/org/lflang/validation/LFValidator.java index 7a97ac0a02..c9545f45bf 100644 --- a/core/src/main/java/org/lflang/validation/LFValidator.java +++ b/core/src/main/java/org/lflang/validation/LFValidator.java @@ -539,8 +539,6 @@ public void checkInstantiation(Instantiation instantiation) { // - The container has to be a federated reactor, // - The coordination is centralized, // - And the target is C. - // FIXME: Conditions 2 and 3 need to be checked - // FIXME: Add support of transients in decentralized coordination. if (AttributeUtils.isTransient(instantiation)) { Reactor container = (Reactor) instantiation.eContainer(); if (!container.isFederated()) { From 1bc4a6ca863e4db46f725dcf07e41a862de0dabd Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Thu, 22 Feb 2024 09:58:39 +0100 Subject: [PATCH 18/42] Address review by removing period from TransientExec in transients tests and reduce redundancy --- .../transient/TransientDownstreamWithTimer.lf | 6 +- .../TransientDownstreamWithTwoUpstream.lf | 6 +- .../federated/transient/TransientHotSwap.lf | 71 ++----------------- 3 files changed, 12 insertions(+), 71 deletions(-) diff --git a/test/C/src/federated/transient/TransientDownstreamWithTimer.lf b/test/C/src/federated/transient/TransientDownstreamWithTimer.lf index ad4bd0d86d..2b0d7a1d88 100644 --- a/test/C/src/federated/transient/TransientDownstreamWithTimer.lf +++ b/test/C/src/federated/transient/TransientDownstreamWithTimer.lf @@ -16,8 +16,8 @@ preamble {= =} /** Persistent federate that is responsible for lauching the transient federate */ -reactor TransientExec(offset: time = 0, period: time = 0, fed_instance_name: char* = "instance") { - timer t(offset, period) +reactor TransientExec(launch_time: time = 0, fed_instance_name: char* = "instance") { + timer t(launch_time, 0) reaction(t) {= // Construct the command to launch the transient federate @@ -141,7 +141,7 @@ reactor Down { federated reactor { // Persistent federate that is responsible for lauching the transient once, after 1s - midExec = new TransientExec(offset = 1 s, fed_instance_name="mid") + midExec = new TransientExec(launch_time = 1 s, fed_instance_name="mid") // Persistent downstream and upstream federates of the transient up = new Up() diff --git a/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf b/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf index d71179f8b3..b3dbcd08d4 100644 --- a/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf +++ b/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf @@ -18,8 +18,8 @@ preamble {= =} /** Persistent federate that is responsible for lauching the transient federate */ -reactor TransientExec(offset: time = 0, period: time = 0, fed_instance_name: char* = "instance") { - timer t(offset, period) +reactor TransientExec(launch_time: time = 0, fed_instance_name: char* = "instance") { + timer t(launch_time, 0) reaction(t) {= // Construct the command to launch the transient federate @@ -106,7 +106,7 @@ reactor Down { federated reactor { // Persistent federate that is responsible for lauching the transient once, after 1s - midExec = new TransientExec(offset = 1 s, fed_instance_name="mid") + midExec = new TransientExec(launch_time = 1 s, fed_instance_name="mid") // Persistent downstream and upstream federates of the transient up1 = new Up() diff --git a/test/C/src/federated/transient/TransientHotSwap.lf b/test/C/src/federated/transient/TransientHotSwap.lf index f69f82b3fa..f53616de51 100644 --- a/test/C/src/federated/transient/TransientHotSwap.lf +++ b/test/C/src/federated/transient/TransientHotSwap.lf @@ -9,14 +9,17 @@ target C { timeout: 2 s } +import Up from "TransientDownstreamWithTimer.lf" +import Down from "TransientDownstreamWithTimer.lf" + preamble {= #include #include =} /** Persistent federate that is responsible for lauching the transient federate */ -reactor TransientExec(offset: time = 0, period: time = 0, fed_instance_name: char* = "instance") { - timer t(offset, period) +reactor TransientExec(launch_time: time = 0, fed_instance_name: char* = "instance") { + timer t(launch_time, 0) reaction(t) {= // Construct the command to launch the transient federate @@ -43,21 +46,6 @@ reactor TransientExec(offset: time = 0, period: time = 0, fed_instance_name: cha =} } -/** - * Persistent federate, upstream of the transient. It reacts to its timer by sending increments to - * output port out. - */ -reactor Up(period: time = 500 ms) { - output out: int - timer t(0, period) - state count: int = 0 - - reaction(t) -> out {= - lf_set(out, self->count); - self->count++; - =} -} - /** * Transient federate that forwards whatever it receives from `Up` to `Down`. It reacts twice to * input port `in`, then stops. It will execute twice during the lifetime of the federation. The @@ -87,56 +75,9 @@ reactor Middle { =} } -/** - * Persistent federate, which is downstream of the transient. It has to keep reacting to its - * internal timer and also to inputs from the tansient, if any. - */ -reactor Down { - timer t(0, 500 ms) - - input in: int - input join: int - - state count_timer: int = 0 - state count_join: int = 0 - state count_in_mid_reactions: int = 0 - - reaction(t) {= - self->count_timer++; - =} - - reaction(in) {= - self->count_in_mid_reactions++; - =} - - reaction(join) {= - self->count_join++; - =} - - reaction(shutdown) {= - // Check that the TAG has been successfully issued to Down - if (self->count_timer != 5) { - lf_print_error_and_exit("Federate's timer reacted %d times, while it had to react %d times.", - self->count_timer, - 5); - } - - // Check that `Middle` have joined 2 times - if (self->count_join != 2) { - lf_print_error_and_exit("Transient federate did not join twice, but %d times!", self->count_join); - } - - // Check that `Middle` have reacted correctly - if (self->count_in_mid_reactions < 4) { - lf_print_error_and_exit("Transient federate Mid did not execute and pass values from up corretly! Expected >= 4, but had: %d.", - self->count_in_mid_reactions); - } - =} -} - federated reactor { // Persistent federate that is responsible for lauching the transient once, after 1s - midExec = new TransientExec(offset = 1 s, fed_instance_name="mid") + midExec = new TransientExec(launch_time = 1 s, fed_instance_name="mid") // Persistent downstream and upstream federates of the transient up = new Up() From 3503ee13cc1c72cd370363b36ee5e998f59f6cca Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Thu, 22 Feb 2024 10:54:28 +0100 Subject: [PATCH 19/42] Reduce the probability of flaky failiures due to indeterminate amount of launching time in transient federates. This is simply done by increasing the timeout to 3s instead of 2s, and adjusting the check accordingly --- .../src/federated/transient/TransientDownstreamWithTimer.lf | 6 +++--- .../transient/TransientDownstreamWithTwoUpstream.lf | 6 +++--- test/C/src/federated/transient/TransientHotSwap.lf | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/test/C/src/federated/transient/TransientDownstreamWithTimer.lf b/test/C/src/federated/transient/TransientDownstreamWithTimer.lf index 2b0d7a1d88..d9f608ba85 100644 --- a/test/C/src/federated/transient/TransientDownstreamWithTimer.lf +++ b/test/C/src/federated/transient/TransientDownstreamWithTimer.lf @@ -7,7 +7,7 @@ * - the downstream of the transient federate has only one transient as upstream. */ target C { - timeout: 2 s + timeout: 3 s } preamble {= @@ -120,8 +120,8 @@ reactor Down { reaction(shutdown) {= // Check that the TAG has been successfully issued to Down - if (self->count_timer != 5) { - lf_print_error_and_exit("Federate's timer reacted %d times, while it had to react %d times.", + if (self->count_timer < 5) { + lf_print_error_and_exit("Down federate's timer reacted %d times, while it had to react more than %d times.", self->count_timer, 5); } diff --git a/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf b/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf index b3dbcd08d4..94a1dde2a6 100644 --- a/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf +++ b/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf @@ -6,7 +6,7 @@ * - the downstream of the transient federate has one persistent and one transient upstreams. */ target C { - timeout: 2 s + timeout: 3 s } import Up from "TransientDownstreamWithTimer.lf" @@ -80,8 +80,8 @@ reactor Down { reaction(shutdown) {= // Check that the TAG have been successfully issued to Down - if (self->count_timer != 5) { - lf_print_error_and_exit("Federate's timer reacted %d times, while it had to react %d times.", + if (self->count_timer < 5) { + lf_print_error_and_exit("Federate's timer reacted %d times, while it had to react more than %d times.", self->count_timer, 5); } diff --git a/test/C/src/federated/transient/TransientHotSwap.lf b/test/C/src/federated/transient/TransientHotSwap.lf index f53616de51..3127eb1a87 100644 --- a/test/C/src/federated/transient/TransientHotSwap.lf +++ b/test/C/src/federated/transient/TransientHotSwap.lf @@ -6,7 +6,7 @@ * - A persistent federate `HotSwapMiddle` executes `mid` after 1s to launch the hot swap. */ target C { - timeout: 2 s + timeout: 3 s } import Up from "TransientDownstreamWithTimer.lf" From c7e1befcbe7d5670af6b7e76430d0efe5660c609 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Thu, 22 Feb 2024 11:12:37 +0100 Subject: [PATCH 20/42] Fix TransientHotSwap documentation based on review --- test/C/src/federated/transient/TransientHotSwap.lf | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/C/src/federated/transient/TransientHotSwap.lf b/test/C/src/federated/transient/TransientHotSwap.lf index 3127eb1a87..21fc0e1fa7 100644 --- a/test/C/src/federated/transient/TransientHotSwap.lf +++ b/test/C/src/federated/transient/TransientHotSwap.lf @@ -1,9 +1,11 @@ /** * This LF program is a variant of TransientDownstreamWithTimer that tests the Hot Swap mechanism. - * For this, it tests if the transient's downstream executes as expected. In this test: + * For this, it tests if the transient's downstream executes as expected and if `mid` + * is stopped and the second instance joins as expected. In this test: * - the transient federate DOES NOT spontaneously leave the federation. * - the downstream of the transient federate has only one transient as upstream. - * - A persistent federate `HotSwapMiddle` executes `mid` after 1s to launch the hot swap. + * - A persistent federate `TransientExec` launches `mid` after 1s to activate the hot + * mechanism swap. */ target C { timeout: 3 s From 8b8920c86d749fb63bf2ca4743c5051ad0344454 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Thu, 22 Feb 2024 11:23:58 +0100 Subject: [PATCH 21/42] Apply spotless --- test/C/src/federated/transient/TransientHotSwap.lf | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/C/src/federated/transient/TransientHotSwap.lf b/test/C/src/federated/transient/TransientHotSwap.lf index 21fc0e1fa7..869b7f2cc3 100644 --- a/test/C/src/federated/transient/TransientHotSwap.lf +++ b/test/C/src/federated/transient/TransientHotSwap.lf @@ -1,11 +1,11 @@ /** * This LF program is a variant of TransientDownstreamWithTimer that tests the Hot Swap mechanism. - * For this, it tests if the transient's downstream executes as expected and if `mid` - * is stopped and the second instance joins as expected. In this test: + * For this, it tests if the transient's downstream executes as expected and if `mid` is stopped and + * the second instance joins as expected. In this test: * - the transient federate DOES NOT spontaneously leave the federation. * - the downstream of the transient federate has only one transient as upstream. - * - A persistent federate `TransientExec` launches `mid` after 1s to activate the hot - * mechanism swap. + * - A persistent federate `TransientExec` launches `mid` after 1s to activate the hot mechanism + * swap. */ target C { timeout: 3 s From d0e0bdfcf25a1afe4e5e39b61d69b501ae3d37ec Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Thu, 22 Feb 2024 12:14:46 +0100 Subject: [PATCH 22/42] Fix TransientDownstreamWithTwoUpstreams error condition to account do the increase in the timeout --- .../federated/transient/TransientDownstreamWithTwoUpstream.lf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf b/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf index 94a1dde2a6..716c36062b 100644 --- a/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf +++ b/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf @@ -85,8 +85,8 @@ reactor Down { self->count_timer, 5); } - if (self->count_in_up_reactions != 7) { - lf_print_error_and_exit("Federate's timer reacted %d times, while it had to react %d times.", + if (self->count_in_up_reactions < 7) { + lf_print_error_and_exit("Federate's timer reacted %d times, while it had to react more than %d times.", self->count_in_up_reactions, 7); } From 094719fa2020d0d1beb252cf46db6172735bdd8a Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Thu, 29 Feb 2024 16:16:34 +0100 Subject: [PATCH 23/42] Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 58e97b4e6e..581f242bce 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 58e97b4e6e10256e88f80001e7adfddeb888a42b +Subproject commit 581f242bce9f1777d226ffbc32654c61e579801b From b6d1a9350be314b6028eaff787810f0cc668793f Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Thu, 29 Feb 2024 18:38:46 +0100 Subject: [PATCH 24/42] Add TransientStatePersistence test and align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- .../transient/TransientStatePersistence.lf | 191 ++++++++++++++++++ 2 files changed, 192 insertions(+), 1 deletion(-) create mode 100644 test/C/src/federated/transient/TransientStatePersistence.lf diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 581f242bce..51bafd6ec7 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 581f242bce9f1777d226ffbc32654c61e579801b +Subproject commit 51bafd6ec7eeee65c28a1c55074ceb5088b9d78e diff --git a/test/C/src/federated/transient/TransientStatePersistence.lf b/test/C/src/federated/transient/TransientStatePersistence.lf new file mode 100644 index 0000000000..ada29434d2 --- /dev/null +++ b/test/C/src/federated/transient/TransientStatePersistence.lf @@ -0,0 +1,191 @@ +/** + * This LF program showcases and tests the persistance of the internal state of a + * transient federate across executions. + * Using the hot swap mechanism, the transient federate `Middle` leaves and then + * joins. Whenever the state to save changes (of type `federate_state_t`), it + * notifies `Persistence`. + * `Middle` notifies `Persistence` also when it joins. When it joins the second time + * or after, it receives the saved state and sets it. In this, the order of the + * reactions is important. + */ +target C { + timeout: 2900ms +} + +preamble {= + #include + #include + + // The internal federate state to be persistent across executions + typedef struct federate_state_t { + char state_char; + int state_count; + } federate_state_t; + +=} + +/** Persistent federate that is responsible for lauching the transient federate */ +reactor TransientExec(launch_time: time = 0, fed_instance_name: char* = "instance") { + timer t(launch_time, 0) + + reaction(t) {= + // Construct the command to launch the transient federate + char mid_launch_cmd[512]; + sprintf(mid_launch_cmd, + "%s/federate__%s -i %s", + lf_get_federates_bin_directory(), + self->fed_instance_name, + lf_get_federation_id() + ); + + lf_print("Launching federate federate__%s at physical time " PRINTF_TIME ".", + mid_launch_cmd, + lf_time_physical()); + + int status = system(mid_launch_cmd); + + // Exit if error + if (status == 0) { + lf_print("Successfully launched federate__%s.", self->fed_instance_name); + } else { + lf_print_error_and_exit("Unable to launch federate__%s. Abort!", self->fed_instance_name); + } + =} + } + +reactor Persistence { + state middle_state: federate_state_t = {'A', 0} + state middle_first_join: bool = true + + input in_from_middle: federate_state_t + input in_middle_join: bool + output out_to_middle: federate_state_t + + // Only send the previous state if it not the first time Middle joins + reaction(in_middle_join) -> out_to_middle {= + if (!self->middle_first_join) { + lf_set(out_to_middle, self->middle_state); + } + self->middle_first_join = false; + =} + + reaction(in_from_middle) {= + self->middle_state.state_char = in_from_middle->value.state_char; + self->middle_state.state_count = in_from_middle->value.state_count; + =} +} + +/** + * Persistent federate, upstream of the transient. It reacts to its timer by sending increments to + * out output port. + */ +reactor Up(period: time = 500 ms) { + output out: int + timer t(0, period) + state count: int = 0 + + reaction(t) -> out {= + lf_set(out, self->count); + self->count++; + lf_print("Up timer sent %d", self->count); + =} +} + +/** + * Transient federate that forwards whatever it receives from Up to down. It reacts twice to in + * input ports, then stops. It will execute twice during the lifetime of the federation. The second + * launch is done by TransientExec at logical time 1 s. Each time Middle joins, it notifies Down. + */ +reactor Middle { + input in: int + output out: int + output join: bool + state middle_state: federate_state_t = {'A', 0} + + output out_to_persistence: federate_state_t // State Persistence + input in_from_persistence: federate_state_t + + // Middle notifies its downstream that he joined, but make sure first that the effective start + // tag is correct + reaction(startup) -> join {= + lf_set(join, true); + =} + + reaction(in_from_persistence) {= + self->middle_state = in_from_persistence->value; + =} + + // When an input is received, the internal state is updated, and then sent to + // Persistance. + reaction(in) -> out, out_to_persistence {= + self->middle_state.state_char++; + self->middle_state.state_count += 2; + lf_set(out, self->middle_state.state_count); + lf_set(out_to_persistence, self->middle_state); + lf_print("Mid state is: {count='%c', count=%d}", + self->middle_state.state_char, + self->middle_state.state_count); + + if (self->middle_state.state_count == 4) { + lf_stop(); + } + =} +} + +/** + * Persistent federate, which is downstream of the transient. It has to keep reacting to its + * internal timer and also to inputs from the tansient, if any. + */ +reactor Down { + timer t(0, 500 ms) + + input in: int + input join: bool + + state count_timer: int = 0 + state count_join: int = 0 + state count_in_mid_reactions: int = 0 + + reaction(t) {= + self->count_timer++; + lf_print("Down timer count %d", self->count_timer); + =} + + reaction(in) {= + self->count_in_mid_reactions++; + lf_print("Down in %d", self->count_in_mid_reactions); + =} + + reaction(join) {= + self->count_join++; + lf_print("Down count join %d", self->count_join); + =} + + reaction(shutdown) in {= + if(self->count_join == 2 && in->value < 4) { + lf_print_error_and_exit("Mid Joined twise, but the state did not persist \ + across executions! state_count is %d, while is should be > then %d.", + in->value, + 4); + } + =} +} + +federated reactor { + up = new Up() // Persistent downstream and upstream federates of the transient + down = new Down() + persistence = new Persistence() + // Persistent federate that is responsible for lauching the transient once, after 1s + midExec = new TransientExec(launch_time = 1 s, fed_instance_name="mid") + + // Transient federate + @transient + mid = new Middle() + + up.out -> mid.in // Connections + mid.join -> down.join + mid.join -> persistence.in_middle_join + mid.out -> down.in + persistence.out_to_middle -> mid.in_from_persistence + mid.out_to_persistence -> persistence.in_from_middle +} From a1eef8d2135619974d85636572e87ae4d135158d Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Thu, 29 Feb 2024 19:13:57 +0100 Subject: [PATCH 25/42] Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 51bafd6ec7..b8404d67d4 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 51bafd6ec7eeee65c28a1c55074ceb5088b9d78e +Subproject commit b8404d67d48e378a791eb4350d1225a33961c2d1 From a511cea7e2607b02f2d589f85a703c0c6d273054 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Thu, 29 Feb 2024 19:33:39 +0100 Subject: [PATCH 26/42] Apply Spotless --- .../transient/TransientStatePersistence.lf | 79 +++++++++---------- 1 file changed, 39 insertions(+), 40 deletions(-) diff --git a/test/C/src/federated/transient/TransientStatePersistence.lf b/test/C/src/federated/transient/TransientStatePersistence.lf index ada29434d2..92d9e467cc 100644 --- a/test/C/src/federated/transient/TransientStatePersistence.lf +++ b/test/C/src/federated/transient/TransientStatePersistence.lf @@ -1,15 +1,13 @@ /** - * This LF program showcases and tests the persistance of the internal state of a - * transient federate across executions. - * Using the hot swap mechanism, the transient federate `Middle` leaves and then - * joins. Whenever the state to save changes (of type `federate_state_t`), it - * notifies `Persistence`. - * `Middle` notifies `Persistence` also when it joins. When it joins the second time - * or after, it receives the saved state and sets it. In this, the order of the - * reactions is important. + * This LF program showcases and tests the persistance of the internal state of a transient federate + * across executions. Using the hot swap mechanism, the transient federate `Middle` leaves and then + * joins. Whenever the state to save changes (of type `federate_state_t`), it notifies + * `Persistence`. `Middle` notifies `Persistence` also when it joins. When it joins the second time + * or after, it receives the saved state and sets it. In this, the order of the reactions is + * important. */ target C { - timeout: 2900ms + timeout: 2900 ms } preamble {= @@ -21,38 +19,37 @@ preamble {= char state_char; int state_count; } federate_state_t; - =} /** Persistent federate that is responsible for lauching the transient federate */ reactor TransientExec(launch_time: time = 0, fed_instance_name: char* = "instance") { - timer t(launch_time, 0) - - reaction(t) {= - // Construct the command to launch the transient federate - char mid_launch_cmd[512]; - sprintf(mid_launch_cmd, - "%s/federate__%s -i %s", - lf_get_federates_bin_directory(), - self->fed_instance_name, - lf_get_federation_id() - ); - - lf_print("Launching federate federate__%s at physical time " PRINTF_TIME ".", - mid_launch_cmd, - lf_time_physical()); - - int status = system(mid_launch_cmd); - - // Exit if error - if (status == 0) { - lf_print("Successfully launched federate__%s.", self->fed_instance_name); - } else { - lf_print_error_and_exit("Unable to launch federate__%s. Abort!", self->fed_instance_name); - } - =} - } - + timer t(launch_time, 0) + + reaction(t) {= + // Construct the command to launch the transient federate + char mid_launch_cmd[512]; + sprintf(mid_launch_cmd, + "%s/federate__%s -i %s", + lf_get_federates_bin_directory(), + self->fed_instance_name, + lf_get_federation_id() + ); + + lf_print("Launching federate federate__%s at physical time " PRINTF_TIME ".", + mid_launch_cmd, + lf_time_physical()); + + int status = system(mid_launch_cmd); + + // Exit if error + if (status == 0) { + lf_print("Successfully launched federate__%s.", self->fed_instance_name); + } else { + lf_print_error_and_exit("Unable to launch federate__%s. Abort!", self->fed_instance_name); + } + =} +} + reactor Persistence { state middle_state: federate_state_t = {'A', 0} state middle_first_join: bool = true @@ -122,7 +119,7 @@ reactor Middle { self->middle_state.state_count += 2; lf_set(out, self->middle_state.state_count); lf_set(out_to_persistence, self->middle_state); - lf_print("Mid state is: {count='%c', count=%d}", + lf_print("Mid state is: {count='%c', count=%d}", self->middle_state.state_char, self->middle_state.state_count); @@ -172,7 +169,8 @@ reactor Down { } federated reactor { - up = new Up() // Persistent downstream and upstream federates of the transient + // Persistent downstream and upstream federates of the transient + up = new Up() down = new Down() persistence = new Persistence() // Persistent federate that is responsible for lauching the transient once, after 1s @@ -182,7 +180,8 @@ federated reactor { @transient mid = new Middle() - up.out -> mid.in // Connections + // Connections + up.out -> mid.in mid.join -> down.join mid.join -> persistence.in_middle_join mid.out -> down.in From bc17f00379689d15022c3a859c1318b616ddae67 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Mon, 18 Mar 2024 05:58:59 +0100 Subject: [PATCH 27/42] Typo + Adjust message --- test/C/src/federated/transient/TransientStatePersistence.lf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/C/src/federated/transient/TransientStatePersistence.lf b/test/C/src/federated/transient/TransientStatePersistence.lf index 92d9e467cc..8f73c6f18f 100644 --- a/test/C/src/federated/transient/TransientStatePersistence.lf +++ b/test/C/src/federated/transient/TransientStatePersistence.lf @@ -35,8 +35,8 @@ reactor TransientExec(launch_time: time = 0, fed_instance_name: char* = "instanc lf_get_federation_id() ); - lf_print("Launching federate federate__%s at physical time " PRINTF_TIME ".", - mid_launch_cmd, + lf_print("Launching federate %s at physical time " PRINTF_TIME ".", + self->fed_instance_name, lf_time_physical()); int status = system(mid_launch_cmd); @@ -160,7 +160,7 @@ reactor Down { reaction(shutdown) in {= if(self->count_join == 2 && in->value < 4) { - lf_print_error_and_exit("Mid Joined twise, but the state did not persist \ + lf_print_error_and_exit("Mid Joined twice, but the state did not persist \ across executions! state_count is %d, while is should be > then %d.", in->value, 4); From 4ea922ce3697ffe41f28d25f520c1e253792c33d Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Mon, 18 Mar 2024 05:59:53 +0100 Subject: [PATCH 28/42] Align reactor-c to transient-fed-use-pqueue --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 2530145e48..4dbb6d7da6 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 2530145e4879ee39d5d24ffeaf5ad0a4ed690224 +Subproject commit 4dbb6d7da6e253840443b0775085d1a5f7c989b0 From 90c947c56fe79c2aafd063d9421ed1240b8fb0b2 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Mon, 18 Mar 2024 14:15:40 +0100 Subject: [PATCH 29/42] Use lf_tag_effective_start() instead of lf_get_effective_start_tag() --- test/C/src/federated/transient/TransientDownstreamWithTimer.lf | 2 +- test/C/src/federated/transient/TransientHotSwap.lf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/C/src/federated/transient/TransientDownstreamWithTimer.lf b/test/C/src/federated/transient/TransientDownstreamWithTimer.lf index d9f608ba85..074d32f852 100644 --- a/test/C/src/federated/transient/TransientDownstreamWithTimer.lf +++ b/test/C/src/federated/transient/TransientDownstreamWithTimer.lf @@ -74,7 +74,7 @@ reactor Middle { // Middle notifies its downstream that he joined, but make sure first that the effective start // tag is correct reaction(startup) -> join {= - if(lf_get_effective_start_time() < lf_get_start_time()) { + if(lf_tag_start_effective().time < lf_time_start()) { lf_print_error_and_exit("Fatal error: the transient's effective start time is less than the federation start time"); } diff --git a/test/C/src/federated/transient/TransientHotSwap.lf b/test/C/src/federated/transient/TransientHotSwap.lf index 869b7f2cc3..bd70cf136c 100644 --- a/test/C/src/federated/transient/TransientHotSwap.lf +++ b/test/C/src/federated/transient/TransientHotSwap.lf @@ -63,7 +63,7 @@ reactor Middle { // Middle notifies its downstream that he joined, but make sure first that the effective start // tag is correct reaction(startup) -> join {= - if(lf_get_effective_start_time() < lf_get_start_time()) { + if(lf_tag_start_effective().time < lf_time_start()) { lf_print_error_and_exit("Fatal error: the transient's effective start time is less than the federation start time"); } From b5cfe84f25744db607ae287493ee257aed8fea1c Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Mon, 18 Mar 2024 14:16:16 +0100 Subject: [PATCH 30/42] Fix comment --- test/C/src/federated/transient/TransientStatePersistence.lf | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/C/src/federated/transient/TransientStatePersistence.lf b/test/C/src/federated/transient/TransientStatePersistence.lf index 8f73c6f18f..4d923256a1 100644 --- a/test/C/src/federated/transient/TransientStatePersistence.lf +++ b/test/C/src/federated/transient/TransientStatePersistence.lf @@ -102,8 +102,7 @@ reactor Middle { output out_to_persistence: federate_state_t // State Persistence input in_from_persistence: federate_state_t - // Middle notifies its downstream that he joined, but make sure first that the effective start - // tag is correct + // Middle notifies its downstream that he joined reaction(startup) -> join {= lf_set(join, true); =} From 93354689cb53ff8e4463775a3fbf68ec6183a937 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Mon, 18 Mar 2024 22:25:05 +0100 Subject: [PATCH 31/42] Align reactor-c (transient-fed-use-pqueue) --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 4dbb6d7da6..7b66c6f4bd 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 4dbb6d7da6e253840443b0775085d1a5f7c989b0 +Subproject commit 7b66c6f4bd9bfc2db8b2ed0abd0da537526cfcff From 66102478f88481bdf8aa51ef37f53468a0630574 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Tue, 19 Mar 2024 00:05:39 +0100 Subject: [PATCH 32/42] Minor updates to transient tests --- .../federated/transient/TransientDownstreamWithTimer.lf | 9 ++++----- .../transient/TransientDownstreamWithTwoUpstream.lf | 3 +-- test/C/src/federated/transient/TransientHotSwap.lf | 6 +++--- .../src/federated/transient/TransientStatePersistence.lf | 3 +-- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/test/C/src/federated/transient/TransientDownstreamWithTimer.lf b/test/C/src/federated/transient/TransientDownstreamWithTimer.lf index 074d32f852..ebfa6681b7 100644 --- a/test/C/src/federated/transient/TransientDownstreamWithTimer.lf +++ b/test/C/src/federated/transient/TransientDownstreamWithTimer.lf @@ -30,8 +30,7 @@ reactor TransientExec(launch_time: time = 0, fed_instance_name: char* = "instanc ); lf_print("Launching federate federate__%s at physical time " PRINTF_TIME ".", - mid_launch_cmd, - lf_time_physical()); + self->fed_instance_name, lf_time_physical()); int status = system(mid_launch_cmd); @@ -74,7 +73,8 @@ reactor Middle { // Middle notifies its downstream that he joined, but make sure first that the effective start // tag is correct reaction(startup) -> join {= - if(lf_tag_start_effective().time < lf_time_start()) { + tag_t t = lf_tag_start_effective(); + if(t.time < lf_time_start()) { lf_print_error_and_exit("Fatal error: the transient's effective start time is less than the federation start time"); } @@ -122,8 +122,7 @@ reactor Down { // Check that the TAG has been successfully issued to Down if (self->count_timer < 5) { lf_print_error_and_exit("Down federate's timer reacted %d times, while it had to react more than %d times.", - self->count_timer, - 5); + self->count_timer, 5); } // Check that `Middle` have joined 2 times diff --git a/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf b/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf index 716c36062b..54587f2785 100644 --- a/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf +++ b/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf @@ -32,8 +32,7 @@ reactor TransientExec(launch_time: time = 0, fed_instance_name: char* = "instanc ); lf_print("Launching federate federate__%s at physical time " PRINTF_TIME ".", - mid_launch_cmd, - lf_time_physical()); + self->fed_instance_name, lf_time_physical()); int status = system(mid_launch_cmd); diff --git a/test/C/src/federated/transient/TransientHotSwap.lf b/test/C/src/federated/transient/TransientHotSwap.lf index bd70cf136c..6ee3b371a5 100644 --- a/test/C/src/federated/transient/TransientHotSwap.lf +++ b/test/C/src/federated/transient/TransientHotSwap.lf @@ -34,8 +34,7 @@ reactor TransientExec(launch_time: time = 0, fed_instance_name: char* = "instanc ); lf_print("Launching federate federate__%s at physical time " PRINTF_TIME ".", - mid_launch_cmd, - lf_time_physical()); + self->fed_instance_name, lf_time_physical()); int status = system(mid_launch_cmd); @@ -63,7 +62,8 @@ reactor Middle { // Middle notifies its downstream that he joined, but make sure first that the effective start // tag is correct reaction(startup) -> join {= - if(lf_tag_start_effective().time < lf_time_start()) { + tag_t t = lf_tag_start_effective(); + if(t.time < lf_time_start()) { lf_print_error_and_exit("Fatal error: the transient's effective start time is less than the federation start time"); } diff --git a/test/C/src/federated/transient/TransientStatePersistence.lf b/test/C/src/federated/transient/TransientStatePersistence.lf index 4d923256a1..71f3ed2b2d 100644 --- a/test/C/src/federated/transient/TransientStatePersistence.lf +++ b/test/C/src/federated/transient/TransientStatePersistence.lf @@ -36,8 +36,7 @@ reactor TransientExec(launch_time: time = 0, fed_instance_name: char* = "instanc ); lf_print("Launching federate %s at physical time " PRINTF_TIME ".", - self->fed_instance_name, - lf_time_physical()); + self->fed_instance_name, lf_time_physical()); int status = system(mid_launch_cmd); From 316a8099f3255c1c16f44d008bb82f38402bd37e Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Tue, 19 Mar 2024 00:06:34 +0100 Subject: [PATCH 33/42] Align reactor-c (transient-fed-use-pqueue) --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 7b66c6f4bd..f91081db42 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 7b66c6f4bd9bfc2db8b2ed0abd0da537526cfcff +Subproject commit f91081db42c8f7465bfada321a63f1d3dd409eb4 From 74666036af0f726d020f655ea01efe9a3a97ebea Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Mon, 15 Apr 2024 10:24:35 +0100 Subject: [PATCH 34/42] Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index b8f63d0acd..fcff552cc0 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit b8f63d0acd921a04b12765936d18e82a7d0b0517 +Subproject commit fcff552cc03ab6c22f8802dbda8ab5d730560741 From e482e49b20a089fb9c59da28192190c346f19d8d Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Mon, 15 Apr 2024 10:46:40 +0100 Subject: [PATCH 35/42] Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index fcff552cc0..91266da0ff 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit fcff552cc03ab6c22f8802dbda8ab5d730560741 +Subproject commit 91266da0ff45a7bbaa355b82fd05bcbc3e25b3f9 From 9a53f26b87884ce3bad7ba970a6695fd8f6cc860 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Wed, 24 Apr 2024 13:00:51 +0100 Subject: [PATCH 36/42] Add authentication to TransientDownstreamWithTimer.lf test --- .../federated/transient/TransientDownstreamWithTimer.lf | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/C/src/federated/transient/TransientDownstreamWithTimer.lf b/test/C/src/federated/transient/TransientDownstreamWithTimer.lf index ebfa6681b7..34a3a11aa3 100644 --- a/test/C/src/federated/transient/TransientDownstreamWithTimer.lf +++ b/test/C/src/federated/transient/TransientDownstreamWithTimer.lf @@ -1,13 +1,17 @@ /** * This LF program tests if a transient federate corretly leaves then joins the federation. It also - * tests if the transient's downstream executes as expected, that is it received correct TAGs, + * tests if the transient's downstream executes as expected, that is it receives correct TAGs, * regardless of the transient being absent or present. In this test: * - the transient federate spontaneously leaves the federation after 2 reactions to input port * `in`, * - the downstream of the transient federate has only one transient as upstream. + * + * In addition, the program tests if authentication works in case of a federation with transients, + * by adding `auth` target property. */ target C { - timeout: 3 s + timeout: 3 s, + auth: true } preamble {= From c8f831565bdc1067e418ed346a9d36f3906f3f9b Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Sat, 18 May 2024 09:01:42 +0100 Subject: [PATCH 37/42] TransientHotSwap test uses authentication + Align reactorC --- test/C/src/federated/transient/TransientHotSwap.lf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/C/src/federated/transient/TransientHotSwap.lf b/test/C/src/federated/transient/TransientHotSwap.lf index 6ee3b371a5..5937053d99 100644 --- a/test/C/src/federated/transient/TransientHotSwap.lf +++ b/test/C/src/federated/transient/TransientHotSwap.lf @@ -8,7 +8,8 @@ * swap. */ target C { - timeout: 3 s + timeout: 3 s. + auth: on } import Up from "TransientDownstreamWithTimer.lf" From ba634211970a00ba543b4a8d0f3b0969adab9501 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Sat, 18 May 2024 12:15:58 +0100 Subject: [PATCH 38/42] Align reator-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 3c90f79a88..5e6b03da68 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 3c90f79a889943cd4b786100723eed980956e32b +Subproject commit 5e6b03da682dcb3f17cd6c330d6698257e550e4e From 928067b090366b94391879aa35d081b4112b7c4f Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Wed, 19 Jun 2024 22:16:15 +0100 Subject: [PATCH 39/42] Fix the usage of authentication is transient tests --- .../src/federated/transient/TransientDownstreamWithTimer.lf | 6 +----- .../transient/TransientDownstreamWithTwoUpstream.lf | 6 +++++- test/C/src/federated/transient/TransientHotSwap.lf | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/test/C/src/federated/transient/TransientDownstreamWithTimer.lf b/test/C/src/federated/transient/TransientDownstreamWithTimer.lf index 34a3a11aa3..a403057e48 100644 --- a/test/C/src/federated/transient/TransientDownstreamWithTimer.lf +++ b/test/C/src/federated/transient/TransientDownstreamWithTimer.lf @@ -5,13 +5,9 @@ * - the transient federate spontaneously leaves the federation after 2 reactions to input port * `in`, * - the downstream of the transient federate has only one transient as upstream. - * - * In addition, the program tests if authentication works in case of a federation with transients, - * by adding `auth` target property. */ target C { - timeout: 3 s, - auth: true + timeout: 3 s } preamble {= diff --git a/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf b/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf index 54587f2785..49960b05b4 100644 --- a/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf +++ b/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf @@ -4,9 +4,13 @@ * regardless of the transient being absent or present. In this test: * - the transient federate spontaneously leaves the federation after 2 reactions to input port in, * - the downstream of the transient federate has one persistent and one transient upstreams. + * + * In addition, the program tests if authentication works in case of a federation with transients, + * by adding `auth` target property. */ target C { - timeout: 3 s + timeout: 3 s, + auth: true } import Up from "TransientDownstreamWithTimer.lf" diff --git a/test/C/src/federated/transient/TransientHotSwap.lf b/test/C/src/federated/transient/TransientHotSwap.lf index 5937053d99..a4c986d3d4 100644 --- a/test/C/src/federated/transient/TransientHotSwap.lf +++ b/test/C/src/federated/transient/TransientHotSwap.lf @@ -8,8 +8,8 @@ * swap. */ target C { - timeout: 3 s. - auth: on + timeout: 3 s, + auth: true } import Up from "TransientDownstreamWithTimer.lf" From b72bfe1d88c2ae91299e41ffd3be3ac4d891fa1e Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Wed, 19 Jun 2024 22:16:56 +0100 Subject: [PATCH 40/42] Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 5e6b03da68..f38568f254 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 5e6b03da682dcb3f17cd6c330d6698257e550e4e +Subproject commit f38568f254d1c279c90d9b4366ffc60cba430d7c From 142930a0cca65245137640802b969a745c8fe444 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Wed, 19 Jun 2024 23:54:00 +0100 Subject: [PATCH 41/42] Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index f38568f254..ac3c4b7610 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit f38568f254d1c279c90d9b4366ffc60cba430d7c +Subproject commit ac3c4b76103418a3365f26f8f987fe78f014dd76 From 855fffaca9a46318dd1aa8ed7cf0281e592331dd Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Thu, 20 Jun 2024 09:55:33 +0100 Subject: [PATCH 42/42] Include LF_FEDERATES_BIN_DIRECTORY is cmake for federaes + Align reactor-c --- .../federated/extensions/CExtensionUtils.java | 164 ++++++++++-------- core/src/main/resources/lib/c/reactor-c | 2 +- 2 files changed, 96 insertions(+), 70 deletions(-) diff --git a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java index 6e905392c9..9e4976c9dc 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java @@ -36,17 +36,20 @@ public class CExtensionUtils { // Regular expression pattern for shared_ptr types. - static final Pattern sharedPointerVariable = - Pattern.compile("^(/\\*.*?\\*/)?std::shared_ptr<(?((/\\*.*?\\*/)?(\\S+))+)>$"); + static final Pattern sharedPointerVariable = Pattern + .compile("^(/\\*.*?\\*/)?std::shared_ptr<(?((/\\*.*?\\*/)?(\\S+))+)>$"); /** * Generate C code that initializes network actions. * - *

These network actions will be triggered by federate.c whenever a message is received from + *

+ * These network actions will be triggered by federate.c whenever a message is + * received from * the network. * * @param federate The federate. - * @param main The main reactor that contains the federate (used to lookup references). + * @param main The main reactor that contains the federate (used to lookup + * references). */ public static String initializeTriggersForNetworkActions( FederateInstance federate, ReactorInstance main) { @@ -89,8 +92,11 @@ public static String initializeTriggersForNetworkActions( /** * Generate C code that holds a sorted list of STP structs by time. * - *

For decentralized execution, on every logical timestep, a thread will iterate through each - * staa struct, wait for the designated offset time, and set the associated port status to absent + *

+ * For decentralized execution, on every logical timestep, a thread will iterate + * through each + * staa struct, wait for the designated offset time, and set the associated port + * status to absent * if it isn't known. * * @param federate The federate. @@ -106,8 +112,7 @@ public static String stpStructs(FederateInstance federate) { // main reactor for each Action. for (int i = 0; i < federate.staaOffsets.size(); ++i) { // Find the corresponding ActionInstance. - List networkActions = - federate.stpToNetworkActionMap.get(federate.staaOffsets.get(i)); + List networkActions = federate.stpToNetworkActionMap.get(federate.staaOffsets.get(i)); code.pr("staa_lst[" + i + "] = (staa_t*) malloc(sizeof(staa_t));"); code.pr( @@ -140,7 +145,8 @@ public static String stpStructs(FederateInstance federate) { } /** - * Create a port status field variable for a network input port "input" in the self struct of a + * Create a port status field variable for a network input port "input" in the + * self struct of a * reactor. * * @param input The network input port @@ -148,7 +154,8 @@ public static String stpStructs(FederateInstance federate) { */ public static String createPortStatusFieldForInput(Input input) { StringBuilder builder = new StringBuilder(); - // If it is not a multiport, then we could re-use the port trigger, and nothing needs to be done + // If it is not a multiport, then we could re-use the port trigger, and nothing + // needs to be done if (ASTUtils.isMultiport(input)) { // If it is a multiport, then create an auxiliary list of port // triggers for each channel of @@ -160,15 +167,23 @@ public static String createPortStatusFieldForInput(Input input) { } /** - * Given a connection 'delay' expression, return a string that represents the interval_t value of + * Given a connection 'delay' expression, return a string that represents the + * interval_t value of * the additional delay that needs to be applied to the outgoing message. * - *

The returned additional delay in absence of after on network connection (i.e., if delay is - * passed as a null) is NEVER. This has a special meaning in C library functions that send network - * messages that carry timestamps (@see lf_send_tagged_message and lf_send_port_absent_to_federate - * in lib/core/federate.c). In this case, the sender will send its current tag as the timestamp of - * the outgoing message without adding a microstep delay. If the user has assigned an after delay - * to the network connection (that can be zero) either as a time value (e.g., 200 msec) or as a + *

+ * The returned additional delay in absence of after on network connection + * (i.e., if delay is + * passed as a null) is NEVER. This has a special meaning in C library functions + * that send network + * messages that carry timestamps (@see lf_send_tagged_message and + * lf_send_port_absent_to_federate + * in lib/core/federate.c). In this case, the sender will send its current tag + * as the timestamp of + * the outgoing message without adding a microstep delay. If the user has + * assigned an after delay + * to the network connection (that can be zero) either as a time value (e.g., + * 200 msec) or as a * literal (e.g., a parameter), that delay in nsec will be returned. * * @param delay The delay associated with a connection. @@ -212,11 +227,9 @@ public static void handleCompileDefinitions( } private static void handleAdvanceMessageInterval(FederateInstance federate) { - var advanceMessageInterval = - federate.targetConfig.get(CoordinationOptionsProperty.INSTANCE).advanceMessageInterval; + var advanceMessageInterval = federate.targetConfig.get(CoordinationOptionsProperty.INSTANCE).advanceMessageInterval; if (advanceMessageInterval != null) { - federate - .targetConfig + federate.targetConfig .get(CompileDefinitionsProperty.INSTANCE) .put("ADVANCE_MESSAGE_INTERVAL", String.valueOf(advanceMessageInterval.toNanoSeconds())); } @@ -229,16 +242,20 @@ static boolean clockSyncIsOn(FederateInstance federate, RtiConfig rtiConfig) { } /** - * Initialize clock synchronization (if enabled) and its related options for a given federate. + * Initialize clock synchronization (if enabled) and its related options for a + * given federate. * - *

Clock synchronization can be enabled using the clock-sync target property. + *

+ * Clock synchronization can be enabled using the clock-sync target property. * * @see Documentation + * href= + * "https://github.com/icyphy/lingua-franca/wiki/Distributed-Execution#clock-synchronization">Documentation */ public static void initializeClockSynchronization( FederateInstance federate, RtiConfig rtiConfig, MessageReporter messageReporter) { - // Check if clock synchronization should be enabled for this federate in the first place + // Check if clock synchronization should be enabled for this federate in the + // first place if (clockSyncIsOn(federate, rtiConfig)) { messageReporter .nowhere() @@ -260,12 +277,15 @@ public static void initializeClockSynchronization( } /** - * Initialize clock synchronization (if enabled) and its related options for a given federate. + * Initialize clock synchronization (if enabled) and its related options for a + * given federate. * - *

Clock synchronization can be enabled using the clock-sync target property. + *

+ * Clock synchronization can be enabled using the clock-sync target property. * * @see Documentation + * href= + * "https://github.com/icyphy/lingua-franca/wiki/Distributed-Execution#clock-synchronization">Documentation */ public static void addClockSyncCompileDefinitions(FederateInstance federate) { @@ -296,10 +316,9 @@ public static void generateCMakeInclude( FederateInstance federate, FederationFileConfig fileConfig) throws IOException { Files.createDirectories(fileConfig.getSrcPath().resolve("include")); - Path cmakeIncludePath = - fileConfig - .getSrcPath() - .resolve("include" + File.separator + federate.name + "_extension.cmake"); + Path cmakeIncludePath = fileConfig + .getSrcPath() + .resolve("include" + File.separator + federate.name + "_extension.cmake"); CodeBuilder cmakeIncludeCode = new CodeBuilder(); @@ -310,6 +329,8 @@ public static void generateCMakeInclude( "add_compile_definitions(LF_PACKAGE_DIRECTORY=\"" + fileConfig.srcPkgPath + "\")"); cmakeIncludeCode.pr( "add_compile_definitions(LF_SOURCE_GEN_DIRECTORY=\"" + fileConfig.getSrcGenPath() + "\")"); + cmakeIncludeCode.pr( + "add_compile_definitions(LF_FEDERATES_BIN_DIRECTORY=\"" + fileConfig.getFedBinPath() + "\")"); try (var srcWriter = Files.newBufferedWriter(cmakeIncludePath)) { srcWriter.write(cmakeIncludeCode.getCode()); } @@ -320,7 +341,8 @@ public static void generateCMakeInclude( } /** - * Generate code that sends the neighbor structure message to the RTI. See {@code + * Generate code that sends the neighbor structure message to the RTI. See + * {@code * MSG_TYPE_NEIGHBOR_STRUCTURE} in {@code federated/net_common.h}. * * @param federate The federate that is sending its neighbor structure @@ -393,14 +415,13 @@ public static String generateFederateNeighborStructure(FederateInstance federate // Use NEVER to encode no delay at all. code.pr("candidate_tmp = NEVER;"); } else { - var delayTime = - delay instanceof ParameterReference - // In that case use the default value. - ? CTypes.getInstance() - .getTargetTimeExpr( - ASTUtils.getDefaultAsTimeValue( - ((ParameterReference) delay).getParameter())) - : CTypes.getInstance().getTargetExpr(delay, InferredType.time()); + var delayTime = delay instanceof ParameterReference + // In that case use the default value. + ? CTypes.getInstance() + .getTargetTimeExpr( + ASTUtils.getDefaultAsTimeValue( + ((ParameterReference) delay).getParameter())) + : CTypes.getInstance().getTargetExpr(delay, InferredType.time()); code.pr( String.join( @@ -457,26 +478,27 @@ public static String surroundWithIfElseFederated(String insideIf, String insideE return surroundWithIfFederated(insideIf); } else { return """ - #ifdef FEDERATED - %s - #else - %s - #endif // FEDERATED - """ + #ifdef FEDERATED + %s + #else + %s + #endif // FEDERATED + """ .formatted(insideIf, insideElse); } } /** - * Surround {@code code} with blocks to ensure that code only executes if the program is + * Surround {@code code} with blocks to ensure that code only executes if the + * program is * federated. */ public static String surroundWithIfFederated(String code) { return """ - #ifdef FEDERATED - %s - #endif // FEDERATED - """ + #ifdef FEDERATED + %s + #endif // FEDERATED + """ .formatted(code); } @@ -485,39 +507,41 @@ public static String surroundWithIfElseFederatedCentralized(String insideIf, Str return surroundWithIfFederatedCentralized(insideIf); } else { return """ - #ifdef FEDERATED_CENTRALIZED - %s - #else - %s - #endif // FEDERATED_CENTRALIZED - """ + #ifdef FEDERATED_CENTRALIZED + %s + #else + %s + #endif // FEDERATED_CENTRALIZED + """ .formatted(insideIf, insideElse); } } /** - * Surround {@code code} with blocks to ensure that code only executes if the program is federated + * Surround {@code code} with blocks to ensure that code only executes if the + * program is federated * and has a centralized coordination. */ public static String surroundWithIfFederatedCentralized(String code) { return """ - #ifdef FEDERATED_CENTRALIZED - %s - #endif // FEDERATED_CENTRALIZED - """ + #ifdef FEDERATED_CENTRALIZED + %s + #endif // FEDERATED_CENTRALIZED + """ .formatted(code); } /** - * Surround {@code code} with blocks to ensure that code only executes if the program is federated + * Surround {@code code} with blocks to ensure that code only executes if the + * program is federated * and has a decentralized coordination. */ public static String surroundWithIfFederatedDecentralized(String code) { return """ - #ifdef FEDERATED_DECENTRALIZED - %s - #endif // FEDERATED_DECENTRALIZED - """ + #ifdef FEDERATED_DECENTRALIZED + %s + #endif // FEDERATED_DECENTRALIZED + """ .formatted(code); } @@ -538,7 +562,9 @@ public static String generateSerializationIncludes(FederateInstance federate) { return code.getCode(); } - /** Generate cmake-include code needed for enabled serializers of the federate. */ + /** + * Generate cmake-include code needed for enabled serializers of the federate. + */ public static String generateSerializationCMakeExtension(FederateInstance federate) { CodeBuilder code = new CodeBuilder(); for (SupportedSerializers serializer : federate.enabledSerializers) { diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index ac3c4b7610..71d706b884 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit ac3c4b76103418a3365f26f8f987fe78f014dd76 +Subproject commit 71d706b88409e48234f389320a1dc06ddd77f5d3